From 7417f14b93b2bcc4ed31696dee7e9404ab2897af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 16:54:27 +0000 Subject: [PATCH 001/465] GHA: update rojopolis/spellcheck-github-actions digest to 739a1e3 Closes #18515 --- .github/workflows/checkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index 917efc539891..36a4ff999e3a 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -117,7 +117,7 @@ jobs: run: grep -v '^#' .github/scripts/spellcheck.words > wordlist.txt - name: 'check Spelling' - uses: rojopolis/spellcheck-github-actions@35a02bae020e6999c5c37fabaf447f2eb8822ca7 # v0 + uses: rojopolis/spellcheck-github-actions@739a1e3ceb79a98a5d4a9bf76f351137f9d78892 # v0 with: config_path: .github/scripts/spellcheck.yaml From 39c2d4b54363609865fa49f0f0d7adff84a03d03 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 18:40:05 +0000 Subject: [PATCH 002/465] GHA: update github/codeql-action digest to 192325c Closes #18516 --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 25a8f8cbc0fa..9863f7624d2c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -52,10 +52,10 @@ jobs: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3 + uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3 with: languages: actions, python queries: security-extended - name: 'perform analysis' - uses: github/codeql-action/analyze@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3 + uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 From aa8a44ecfa0e46a839affb58c6640b514b062995 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 11 Sep 2025 11:20:08 +0200 Subject: [PATCH 003/465] GHA: fix and tweak installed packages for http3-linux and Windows-cross - explicitly install `libldap-dev` to not rely on test-specific packages installing it implicitly, to have the same `curl -V` output for each TLS backend build pair. Follow-up to 0455d8772a1af20ce63c46c5738582aa9b1b8441 #18509 - install `libev-dev` for tests. It's a runtime dependency for the local build of `nghttpx`. Missing it made pytest skip 178 tests. Also skewing the 'Gain' time. I estimate it to account for 3 minutes, making the total gain ~20 minutes. Follow-up to 0455d8772a1af20ce63c46c5738582aa9b1b8441 #18509 (It may be a better solution to disable libev for the local nghttp2 build, to avoid this hidden dependency.) - fix quiche jobs to use the local build of `libnghttp2`. - stop installing the `clang` package for Windows-cross. `clang` and `clang-tidy` tools are preinstalled on the Ubuntu 24.04 runner. Closes #18519 --- .github/workflows/http3-linux.yml | 7 ++++--- .github/workflows/windows.yml | 4 +--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 1a7ff07d5f25..3443b1146466 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -476,6 +476,7 @@ jobs: - name: 'quiche' install_steps: skipall + PKG_CONFIG_PATH: /home/runner/nghttp2/build/lib/pkgconfig configure: >- LDFLAGS=-Wl,-rpath,/home/runner/quiche/target/release --with-openssl=/home/runner/quiche/quiche/deps/boringssl/src @@ -484,7 +485,7 @@ jobs: --enable-unity - name: 'quiche' - PKG_CONFIG_PATH: /home/runner/quiche/target/release + PKG_CONFIG_PATH: /home/runner/nghttp2/build/lib/pkgconfig:/home/runner/quiche/target/release generate: >- -DOPENSSL_ROOT_DIR=/home/runner/quiche/quiche/deps/boringssl/src -DUSE_QUICHE=ON @@ -495,7 +496,7 @@ jobs: env: INSTALL_PACKAGES: >- ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'stunnel4 ' || '' }} - ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'apache2 apache2-dev libnghttp2-dev vsftpd dante-server' || '' }} + ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'apache2 apache2-dev libnghttp2-dev vsftpd dante-server libev-dev' || '' }} run: | sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list @@ -503,7 +504,7 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install \ libtool autoconf automake pkgconf \ - libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev libidn2-0-dev libuv1-dev \ + libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev libidn2-0-dev libldap-dev libuv1-dev \ ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} python3 -m venv ~/venv diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 0938142df92b..9acc8cbde659 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -721,11 +721,9 @@ jobs: - { build: 'cmake' , compiler: 'clang-tidy' } steps: - name: 'install packages' - env: - INSTALL_PACKAGES: ${{ matrix.compiler == 'clang-tidy' && 'clang' || '' }} run: | sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install gcc-mingw-w64-x86-64-win32 ${INSTALL_PACKAGES} + sudo apt-get -o Dpkg::Use-Pty=0 install gcc-mingw-w64-x86-64-win32 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: From bf6ae59ab1586e3cd97f27341e4964a9316dc3d5 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 11 Sep 2025 15:02:57 +0200 Subject: [PATCH 004/465] GHA/windows: drop repeated word from comment --- .github/workflows/windows.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9acc8cbde659..b519af47d66c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -950,9 +950,8 @@ jobs: # 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. + # VS2022). Since it integrates badly with CI steps and shell scripts, + # reproduce the necessary build configuration manually, 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)" From b178d58266d4d9805de6da913b5be25c0485b6c2 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 11 Sep 2025 12:59:22 +0200 Subject: [PATCH 005/465] quic: fix min TLS version handling When switching to TSLv1.2 as default in 9d8998c99408e1adf8eba629fad9f87b3235bdfa, this led to an explicit setting of 1.2 on QUIC connections when using quictls, overriding the already set min version of 1.3. This leads to a ClientHello with TLS 1.2+1.3 offered on a QUIC connect which is rejected by the Caddy server. Using ngtcp2 with OpenSSL 3.5+, GnuTLS or AWS-LC is not affected. Fixes #18518 Reported-by: fds242 on github Closes #18520 --- lib/vtls/openssl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index a49203ab07d2..5c22ad25dc94 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2865,11 +2865,12 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ static CURLcode -ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx) +ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx, + unsigned int ssl_version_min) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); /* first, TLS min version... */ - long curl_ssl_version_min = conn_config->version; + long curl_ssl_version_min = (long)ssl_version_min; long curl_ssl_version_max; /* convert curl min SSL version option to OpenSSL constant */ @@ -4110,7 +4111,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, ctx_options |= SSL_OP_NO_SSLv3; #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ - result = ossl_set_ssl_version_min_max(cf, octx->ssl_ctx); + result = ossl_set_ssl_version_min_max(cf, octx->ssl_ctx, ssl_version_min); #else result = ossl_set_ssl_version_min_max_legacy(&ctx_options, cf, data); #endif From 115fe808f2346b9c02d2720d8f575098e473a5d2 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 11 Sep 2025 14:12:04 +0200 Subject: [PATCH 006/465] ngtcp2: check error code on connect failure Access the error codes of ngtcp2 when a connect attempt failes. Trace the information for analysis. Treat errors as permanent failure by default, trigger retrying only when the server refused without indicating an error. Closes #18521 --- lib/vquic/curl_ngtcp2.c | 30 +++++++++++++++++++++++++----- tests/http/testenv/nghttpx.py | 7 ++++--- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 6470f1506d15..3f7c58d08af2 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2578,11 +2578,31 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, out: if(result == CURLE_RECV_ERROR && ctx->qconn && ngtcp2_conn_in_draining_period(ctx->qconn)) { - /* When a QUIC server instance is shutting down, it may send us a - * CONNECTION_CLOSE right away. Our connection then enters the DRAINING - * state. The CONNECT may work in the near future again. Indicate - * that as a "weird" reply. */ - result = CURLE_WEIRD_SERVER_REPLY; + const ngtcp2_ccerr *cerr = ngtcp2_conn_get_ccerr(ctx->qconn); + + result = CURLE_COULDNT_CONNECT; + if(cerr) { + CURL_TRC_CF(data, cf, "connect error, type=%d, code=%" + FMT_PRIu64, + cerr->type, (curl_uint64_t)cerr->error_code); + switch(cerr->type) { + case NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION: + CURL_TRC_CF(data, cf, "error in version negotiation"); + break; + default: + if(cerr->error_code >= NGTCP2_CRYPTO_ERROR) { + CURL_TRC_CF(data, cf, "crypto error, tls alert=%u", + (unsigned int)(cerr->error_code & 0xffu)); + } + else if(cerr->error_code == NGTCP2_CONNECTION_REFUSED) { + CURL_TRC_CF(data, cf, "connection refused by server"); + /* When a QUIC server instance is shutting down, it may send us a + * CONNECTION_CLOSE with this code right away. We want + * to keep on trying in this case. */ + result = CURLE_WEIRD_SERVER_REPLY; + } + } + } } #ifndef CURL_DISABLE_VERBOSE_STRINGS diff --git a/tests/http/testenv/nghttpx.py b/tests/http/testenv/nghttpx.py index 0bd46ac3603c..dfb416334c5a 100644 --- a/tests/http/testenv/nghttpx.py +++ b/tests/http/testenv/nghttpx.py @@ -124,15 +124,16 @@ def reload(self, timeout: timedelta = timedelta(seconds=Env.SERVER_TIMEOUT)): running = self._process self._process = None os.kill(running.pid, signal.SIGQUIT) - end_wait = datetime.now() + timeout + end_wait = datetime.now() + timedelta(seconds=5) if not self.start(wait_live=False): self._process = running return False while datetime.now() < end_wait: try: log.debug(f'waiting for nghttpx({running.pid}) to exit.') - running.wait(2) + running.wait(1) log.debug(f'nghttpx({running.pid}) terminated -> {running.returncode}') + running = None break except subprocess.TimeoutExpired: log.warning(f'nghttpx({running.pid}), not shut down yet.') @@ -142,7 +143,7 @@ def reload(self, timeout: timedelta = timedelta(seconds=Env.SERVER_TIMEOUT)): os.kill(running.pid, signal.SIGKILL) running.terminate() running.wait(1) - return self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT)) + return self.wait_live(timeout=timeout) return False def wait_dead(self, timeout: timedelta): From 839b22863e2f3dfdceab91e66c23257bc8726863 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Sep 2025 16:09:45 +0200 Subject: [PATCH 007/465] ssl-sessions.md: mark option experimental Also make managen output the experimental text with the correct prefix/margin for the ascii version. Closes #18523 --- docs/cmdline-opts/ssl-sessions.md | 1 + scripts/managen | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/cmdline-opts/ssl-sessions.md b/docs/cmdline-opts/ssl-sessions.md index bb1e251e732d..33ef984a3ec4 100644 --- a/docs/cmdline-opts/ssl-sessions.md +++ b/docs/cmdline-opts/ssl-sessions.md @@ -8,6 +8,7 @@ Help: Load/save SSL session tickets from/to this file Added: 8.12.0 Category: tls Multi: single +Experimental: yes See-also: - tls-earlydata Example: diff --git a/scripts/managen b/scripts/managen index 459b651240a6..1eb536a0e6d7 100755 --- a/scripts/managen +++ b/scripts/managen @@ -728,7 +728,8 @@ sub single { } if($experimental) { - push @leading, "**WARNING**: this option is experimental. Do not use in production.\n\n"; + my $pref = $manpage ? "" : "[1]"; + push @leading, "$pref**WARNING**: this option is experimental. Do not use in production.\n\n"; } my $pre = $manpage ? "\n": "[1]"; From 53f90cb3b5678de16a0129ff4f9f3f0e87dfd78b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 11 Sep 2025 15:05:28 +0200 Subject: [PATCH 008/465] GHA/http3-linux: fix nghttpx build and other tweaks - fix `nghttp2` build to also build the `nghttpx` application. Restore required `libc-ares-dev`. Also confirm that `libev-dev` is required too. Document these requirements. Follow-up to 0455d8772a1af20ce63c46c5738582aa9b1b8441 #18509 - explicitly enable `nghttpx` for the `nghttp2` build to make it fail if requirements aren't met: ``` configure: error: applications were requested (--enable-app) but dependencies are not met. ``` - explicitly install brotli, zstd, zlib for the dependency builds. Of these, zstd and zlib are preinstalled. zlib is required for `nghttpx`. zstd and brotli doesn't seem to be used, but keep them there just in case and to match the test env. Follow-up to 0455d8772a1af20ce63c46c5738582aa9b1b8441 #18509 - enable brotli for `nghttpx`. It doesn't change the tests, and also cost almost nothing, so I figure why not. Closes #18522 --- .github/workflows/http3-linux.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 3443b1146466..195437182f11 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -193,7 +193,10 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install \ libtool autoconf automake pkgconf \ - nettle-dev libp11-kit-dev libev-dev autopoint bison gperf gtk-doc-tools libtasn1-bin # for gnutls + libbrotli-dev libzstd-dev zlib1g-dev \ + libev-dev \ + libc-ares-dev \ + nettle-dev libp11-kit-dev autopoint bison gperf gtk-doc-tools libtasn1-bin # for GnuTLS echo 'CC=gcc-12' >> "$GITHUB_ENV" echo 'CXX=g++-12' >> "$GITHUB_ENV" @@ -256,6 +259,7 @@ jobs: cd ~ git clone --quiet --depth=1 -b "${GNUTLS_VERSION}" https://github.com/gnutls/gnutls.git cd gnutls + # required: nettle-dev libp11-kit-dev libev-dev autopoint bison gperf gtk-doc-tools libtasn1-bin ./bootstrap ./configure --disable-dependency-tracking --prefix="$PWD"/build \ LDFLAGS="-Wl,-rpath,$PWD/build/lib -L$PWD/build/lib" \ @@ -332,10 +336,13 @@ jobs: cd nghttp2 git submodule update --init --depth=1 autoreconf -fi + # required (for nghttpx application): libc-ares-dev libev-dev zlib1g-dev + # optional (for nghttpx application): libbrotli-dev ./configure --disable-dependency-tracking --prefix="$PWD"/build \ PKG_CONFIG_PATH=/home/runner/quictls/build/lib/pkgconfig:/home/runner/nghttp3/build/lib/pkgconfig:/home/runner/ngtcp2/build/lib/pkgconfig \ LDFLAGS=-Wl,-rpath,/home/runner/quictls/build/lib \ - --enable-http3 + --with-libbrotlienc --with-libbrotlidec \ + --enable-app --enable-http3 make install linux: From c184f464f795dbdf8db354b9b2bc01891ddc4fdd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Sep 2025 17:50:59 +0200 Subject: [PATCH 009/465] CURLOPT_MAXLIFETIME_CONN: make default 24 hours Set a default value to only reuse existing connections if less than 24 hours old. This makes the TLS certificate check get redone for the new connection. An application can still set it to zero. Closes #18527 --- docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md | 14 ++++++++------ lib/url.c | 2 +- lib/urldata.h | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md b/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md index b29e61a2c3e5..8c1fbf82f86b 100644 --- a/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md +++ b/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md @@ -35,16 +35,18 @@ connection to have to be considered for reuse for this request. libcurl features a connection cache that holds previously used connections. When a new request is to be done, libcurl considers any connection that -matches for reuse. The CURLOPT_MAXLIFETIME_CONN(3) limit prevents -libcurl from trying too old connections for reuse. This can be used for -client-side load balancing. If a connection is found in the cache that is -older than this set *maxlifetime*, it is instead marked for closure. +matches for reuse. The CURLOPT_MAXLIFETIME_CONN(3) limit prevents libcurl from +trying too old connections for reuse. This can be used for client-side load +balancing. If a connection is found in the cache that is older than this set +*maxlifetime*, it is instead marked for closure. -If set to 0, this behavior is disabled: all connections are eligible for reuse. +If set to 0, this behavior is disabled: all connections are eligible for +reuse. # DEFAULT -0 seconds (i.e., disabled) +24 hours (since 8.17.0). Before that, the default was 0 seconds (i.e., +disabled) # %PROTOCOLS% diff --git a/lib/url.c b/lib/url.c index 45d44bac738f..283da6d68b50 100644 --- a/lib/url.c +++ b/lib/url.c @@ -488,7 +488,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ set->conn_max_idle_ms = 118 * 1000; - set->conn_max_age_ms = 0; + set->conn_max_age_ms = 24 * 3600 * 1000; set->http09_allowed = FALSE; set->httpwant = CURL_HTTP_VERSION_NONE ; diff --git a/lib/urldata.h b/lib/urldata.h index cf181af641fd..a0ee614da838 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1390,9 +1390,9 @@ struct UserDefined { void *progress_client; /* pointer to pass to the progress callback */ void *ioctl_client; /* pointer to pass to the ioctl callback */ timediff_t conn_max_idle_ms; /* max idle time to allow a connection that - is to be reused */ + is to be reused */ timediff_t conn_max_age_ms; /* max time since creation to allow a - connection that is to be reused */ + connection that is to be reused */ curl_off_t filesize; /* size of file to upload, -1 means unknown */ long low_speed_limit; /* bytes/second */ long low_speed_time; /* number of seconds */ From 16cd81ed69b9123584dd73a6924a8f852dc2372a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Sep 2025 16:52:40 +0200 Subject: [PATCH 010/465] urldata: FILE is not a list-only protocol The struct field thus does not depend on the presence of it Closes #18525 --- lib/urldata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/urldata.h b/lib/urldata.h index a0ee614da838..4f00c8c9a093 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -116,7 +116,7 @@ typedef unsigned int curl_prot_t; #define PROTO_FAMILY_SSH (CURLPROTO_SCP|CURLPROTO_SFTP) #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) || \ - !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_FILE) + !defined(CURL_DISABLE_POP3) /* these protocols support CURLOPT_DIRLISTONLY */ #define CURL_LIST_ONLY_PROTOCOL 1 #endif From 57b195bf51ae863d93f48257039c080be4e61359 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Sep 2025 23:46:34 +0200 Subject: [PATCH 011/465] CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well Closes #18531 --- docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md index a25ac0a72c74..08b5a6d336ba 100644 --- a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md +++ b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md @@ -9,6 +9,7 @@ See-also: - curl_easy_setopt (3) Protocol: - FTP + - SFTP Added-in: 7.15.4 --- @@ -28,7 +29,7 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_FTP_ENTRY_PATH, char **path); Pass a pointer to a char pointer to receive a pointer to a string holding the path of the entry path. That is the initial path libcurl ended up in when -logging on to the remote FTP server. This stores a NULL as pointer if +logging on to the remote FTP or SFTP server. This stores a NULL as pointer if something is wrong. The **path** pointer is NULL or points to private memory. You MUST NOT free From d7d32ad9b9e9dbf7a372689affd497dcec18df6e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 11 Sep 2025 23:16:55 +0200 Subject: [PATCH 012/465] docs/libcurl: remove ancient version references To make the texts easier on the eye. - Remove most free text references to curl versions before 7.60.0 (May 2018) - Leave those present in a HISTORY section Most of them are already documented in symbols-in-versions anyway. Closes #18530 --- docs/libcurl/curl_easy_getinfo.md | 6 +-- docs/libcurl/curl_formadd.md | 15 +++---- docs/libcurl/curl_global_init.md | 2 +- docs/libcurl/curl_version_info.md | 40 ++++++++----------- docs/libcurl/libcurl-errors.md | 20 ++++------ .../opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md | 4 +- docs/libcurl/opts/CURLINFO_TLS_SESSION.md | 13 +++--- docs/libcurl/opts/CURLOPT_HTTP_VERSION.md | 10 ++--- docs/libcurl/opts/CURLOPT_ISSUERCERT.md | 4 +- docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md | 1 - .../opts/CURLOPT_OPENSOCKETFUNCTION.md | 1 - docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md | 11 ----- .../libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md | 3 +- docs/libcurl/opts/CURLOPT_QUOTE.md | 2 +- docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md | 1 - docs/libcurl/opts/CURLOPT_SSLVERSION.md | 26 ++++-------- docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md | 3 +- docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md | 2 +- docs/libcurl/opts/CURLSHOPT_SHARE.md | 10 ++--- 19 files changed, 63 insertions(+), 111 deletions(-) diff --git a/docs/libcurl/curl_easy_getinfo.md b/docs/libcurl/curl_easy_getinfo.md index dff050447748..9515fadeed2c 100644 --- a/docs/libcurl/curl_easy_getinfo.md +++ b/docs/libcurl/curl_easy_getinfo.md @@ -45,7 +45,7 @@ The session's active socket. See CURLINFO_ACTIVESOCKET(3) ## CURLINFO_APPCONNECT_TIME The time it took from the start until the SSL connect/handshake with the -remote host was completed as a double in number of seconds. (Added in 7.19.0) +remote host was completed as a double in number of seconds. ## CURLINFO_APPCONNECT_TIME_T @@ -222,7 +222,7 @@ User's private data pointer. See CURLINFO_PRIVATE(3) ## CURLINFO_PROTOCOL -(**Deprecated**) The protocol used for the connection. (Added in 7.52.0) See +(**Deprecated**) The protocol used for the connection. See CURLINFO_PROTOCOL(3) ## CURLINFO_PROXYAUTH_AVAIL @@ -303,7 +303,7 @@ RTSP session ID. See CURLINFO_RTSP_SESSION_ID(3) ## CURLINFO_SCHEME -The scheme used for the connection. (Added in 7.52.0) See CURLINFO_SCHEME(3) +The scheme used for the connection. See CURLINFO_SCHEME(3) ## CURLINFO_SIZE_DOWNLOAD diff --git a/docs/libcurl/curl_formadd.md b/docs/libcurl/curl_formadd.md index 6bef05523a9b..f35e50eab754 100644 --- a/docs/libcurl/curl_formadd.md +++ b/docs/libcurl/curl_formadd.md @@ -101,8 +101,6 @@ If you pass a 0 (zero) for this option, libcurl calls strlen() on the contents to figure out the size. If you really want to send a zero byte content then you must make sure strlen() on the data pointer returns zero. -(Option added in 7.46.0) - ## CURLFORM_CONTENTSLENGTH (This option is deprecated. Use *CURLFORM_CONTENTLEN* instead.) @@ -171,13 +169,12 @@ long which gives the length of the buffer. ## CURLFORM_STREAM -Tells libcurl to use the CURLOPT_READFUNCTION(3) callback to get -data. The parameter you pass to *CURLFORM_STREAM* is the pointer passed on -to the read callback's fourth argument. If you want the part to look like a -file upload one, set the *CURLFORM_FILENAME* parameter as well. Note that -when using *CURLFORM_STREAM*, *CURLFORM_CONTENTSLENGTH* must also be -set with the total expected length of the part unless the formpost is sent -chunked encoded. (Option added in libcurl 7.18.2) +Tells libcurl to use the CURLOPT_READFUNCTION(3) callback to get data. The +parameter you pass to *CURLFORM_STREAM* is the pointer passed on to the read +callback's fourth argument. If you want the part to look like a file upload +one, set the *CURLFORM_FILENAME* parameter as well. Note that when using +*CURLFORM_STREAM*, *CURLFORM_CONTENTSLENGTH* must also be set with the total +expected length of the part unless the formpost is sent chunked encoded. ## CURLFORM_ARRAY diff --git a/docs/libcurl/curl_global_init.md b/docs/libcurl/curl_global_init.md index 198b6e9f3058..724f90cddc8f 100644 --- a/docs/libcurl/curl_global_init.md +++ b/docs/libcurl/curl_global_init.md @@ -108,7 +108,7 @@ This bit has no point since 7.69.0 but its behavior is instead the default. Before 7.69.0: when this flag is set, curl acknowledges EINTR condition when connecting or when waiting for data. Otherwise, curl waits until full timeout -elapses. (Added in 7.30.0) +elapses. # %PROTOCOLS% diff --git a/docs/libcurl/curl_version_info.md b/docs/libcurl/curl_version_info.md index 8a8671dbf907..a9c97b39c596 100644 --- a/docs/libcurl/curl_version_info.md +++ b/docs/libcurl/curl_version_info.md @@ -165,13 +165,13 @@ HTTP Alt-Svc parsing and the associated options (Added in 7.64.1) libcurl was built with support for asynchronous name lookups, which allows more exact timeouts (even on Windows) and less blocking when using the multi -interface. (added in 7.10.7) +interface. ## `brotli` *features* mask bit: CURL_VERSION_BROTLI -supports HTTP Brotli content encoding using libbrotlidec (Added in 7.57.0) +supports HTTP Brotli content encoding using libbrotlidec ## `asyn-rr` @@ -185,7 +185,7 @@ resolves, but uses the threaded resolver for "normal" resolves (Added in *features* mask bit: CURL_VERSION_DEBUG -libcurl was built with debug capabilities (added in 7.10.6) +libcurl was built with debug capabilities ## `ECH` @@ -207,7 +207,6 @@ authentication methods. (added in 7.76.0) libcurl was built with support for GSS-API. This makes libcurl use provided functions for Kerberos and SPNEGO authentication. It also allows libcurl to use the current user credentials without the app having to pass them on. -(Added in 7.38.0) ## `HSTS` @@ -221,7 +220,6 @@ libcurl was built with support for HSTS (HTTP Strict Transport Security) *features* mask bit: CURL_VERSION_HTTP2 libcurl was built with support for HTTP2. -(Added in 7.33.0) ## `HTTP3` @@ -234,7 +232,6 @@ HTTP/3 and QUIC support are built-in (Added in 7.66.0) *features* mask bit: CURL_VERSION_HTTPS_PROXY libcurl was built with support for HTTPS-proxy. -(Added in 7.52.0) ## `HTTPSRR` @@ -248,7 +245,7 @@ in 8.12.0) *features* mask bit: CURL_VERSION_IDN libcurl was built with support for IDNA, domain names with international -letters. (Added in 7.12.0) +letters. ## `IPv6` @@ -261,19 +258,19 @@ supports IPv6 *features* mask bit: CURL_VERSION_KERBEROS5 supports Kerberos V5 authentication for FTP, IMAP, LDAP, POP3, SMTP and -SOCKSv5 proxy. (Added in 7.40.0) +SOCKSv5 proxy. ## `Largefile` *features* mask bit: CURL_VERSION_LARGEFILE -libcurl was built with support for large files. (Added in 7.11.1) +libcurl was built with support for large files. ## `libz` *features* mask bit: CURL_VERSION_LIBZ -supports HTTP deflate using libz (Added in 7.10) +supports HTTP deflate using libz ## `MultiSSL` @@ -281,20 +278,19 @@ supports HTTP deflate using libz (Added in 7.10) libcurl was built with multiple SSL backends. For details, see curl_global_sslset(3). -(Added in 7.56.0) ## `NTLM` *features* mask bit: CURL_VERSION_NTLM -supports HTTP NTLM (added in 7.10.6) +supports HTTP NTLM ## `NTLM_WB` *features* mask bit: CURL_VERSION_NTLM_WB -libcurl was built with support for NTLM delegation to a winbind helper. -(Added in 7.22.0) This feature was removed from curl in 8.8.0. +libcurl was built with support for NTLM delegation to a winbind helper. This +feature was removed from curl in 8.8.0. ## `PSL` @@ -302,20 +298,19 @@ libcurl was built with support for NTLM delegation to a winbind helper. libcurl was built with support for Mozilla's Public Suffix List. This makes libcurl ignore cookies with a domain that is on the list. -(Added in 7.47.0) ## `SPNEGO` *features* mask bit: CURL_VERSION_SPNEGO libcurl was built with support for SPNEGO authentication (Simple and Protected -GSS-API Negotiation Mechanism, defined in RFC 2478.) (added in 7.10.8) +GSS-API Negotiation Mechanism, defined in RFC 2478.) ## `SSL` *features* mask bit: CURL_VERSION_SSL -supports SSL (HTTPS/FTPS) (Added in 7.10) +supports SSL (HTTPS/FTPS) ## `SSLS-EXPORT` @@ -331,7 +326,7 @@ libcurl was built with SSL session import/export support libcurl was built with support for SSPI. This is only available on Windows and makes libcurl use Windows-provided functions for Kerberos, NTLM, SPNEGO and Digest authentication. It also allows libcurl to use the current user -credentials without the app having to pass them on. (Added in 7.13.2) +credentials without the app having to pass them on. ## `threadsafe` @@ -345,14 +340,14 @@ curl initialization. (Added in 7.84.0) See libcurl-thread(3) *features* mask bit: CURL_VERSION_TLSAUTH_SRP libcurl was built with support for TLS-SRP (in one or more of the built-in TLS -backends). (Added in 7.21.4) +backends). ## `TrackMemory` *features* mask bit: CURL_VERSION_CURLDEBUG libcurl was built with memory tracking debug capabilities. This is mainly of -interest for libcurl hackers. (added in 7.19.6) +interest for libcurl hackers. ## `Unicode` @@ -366,7 +361,6 @@ characters work in filenames and options passed to libcurl. (Added in 7.72.0) *features* mask bit: CURL_VERSION_UNIX_SOCKETS libcurl was built with support for Unix domain sockets. -(Added in 7.40.0) ## `zstd` @@ -379,13 +373,13 @@ supports HTTP zstd content encoding using zstd library (Added in 7.72.0) *features* mask bit: CURL_VERSION_CONV libcurl was built with support for character conversions provided by -callbacks. Always 0 since 7.82.0. (Added in 7.15.4, deprecated.) +callbacks. Always 0 since 7.82.0. Deprecated. ## no name *features* mask bit: CURL_VERSION_GSSNEGOTIATE -supports HTTP GSS-Negotiate (added in 7.10.6, deprecated in 7.38.0) +supports HTTP GSS-Negotiate. Deprecated. ## no name diff --git a/docs/libcurl/libcurl-errors.md b/docs/libcurl/libcurl-errors.md index 773601dae71f..25d63bf81fd3 100644 --- a/docs/libcurl/libcurl-errors.md +++ b/docs/libcurl/libcurl-errors.md @@ -349,7 +349,7 @@ Initiating the SSL Engine failed. ## CURLE_LOGIN_DENIED (67) -The remote server denied curl to login (Added in 7.13.1) +The remote server denied curl to login ## CURLE_TFTP_NOTFOUND (68) @@ -403,22 +403,20 @@ Failed to shut down the SSL connection. Socket is not ready for send/recv. Wait until it is ready and try again. This return code is only returned from curl_easy_recv(3) and curl_easy_send(3) -(Added in 7.18.2) ## CURLE_SSL_CRL_BADFILE (82) -Failed to load CRL file (Added in 7.19.0) +Failed to load CRL file ## CURLE_SSL_ISSUER_ERROR (83) -Issuer check failed (Added in 7.19.0) +Issuer check failed ## CURLE_FTP_PRET_FAILED (84) The FTP server does not understand the PRET command at all or does not support the given argument. Be careful when using CURLOPT_CUSTOMREQUEST(3), a -custom LIST command is sent with the PRET command before PASV as well. (Added -in 7.20.0) +custom LIST command is sent with the PRET command before PASV as well. ## CURLE_RTSP_CSEQ_ERROR (85) @@ -439,7 +437,7 @@ Chunk callback reported error. ## CURLE_NO_CONNECTION_AVAILABLE (89) (For internal use only, is never returned by libcurl) No connection available, -the session is queued. (added in 7.30.0) +the session is queued. ## CURLE_SSL_PINNEDPUBKEYNOTMATCH (90) @@ -509,7 +507,6 @@ used. An alias for *CURLM_CALL_MULTI_PERFORM*. Never returned by modern libcurl versions. -(Added in 7.15.5) ## CURLM_OK (0) @@ -536,17 +533,15 @@ This can only be returned if libcurl bugs. Please report it to us. ## CURLM_BAD_SOCKET (5) The passed-in socket is not a valid one that libcurl already knows about. -(Added in 7.15.4) ## CURLM_UNKNOWN_OPTION (6) curl_multi_setopt() with unsupported option -(Added in 7.15.4) ## CURLM_ADDED_ALREADY (7) An easy handle already added to a multi handle was attempted to get added a -second time. (Added in 7.32.1) +second time. ## CURLM_RECURSIVE_API_CALL (8) @@ -592,12 +587,11 @@ An invalid share object was passed to the function. ## CURLSHE_NOMEM (4) Not enough memory was available. -(Added in 7.12.0) ## CURLSHE_NOT_BUILT_IN (5) The requested sharing could not be done because the library you use do not have -that particular feature enabled. (Added in 7.23.0) +that particular feature enabled. # CURLUcode diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md index 60fae12acd89..46e8e7ba015d 100644 --- a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md +++ b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md @@ -29,8 +29,8 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, # DESCRIPTION Pass a pointer to a double to receive the content-length of the download. This -is the value read from the Content-Length: field. Since 7.19.4, this returns --1 if the size is not known. +is the value read from the Content-Length: field. This returns -1 if the size +is not known. CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3) is a newer replacement that returns a more sensible variable type. diff --git a/docs/libcurl/opts/CURLINFO_TLS_SESSION.md b/docs/libcurl/opts/CURLINFO_TLS_SESSION.md index 4fb5425f852f..f4209b45b6b0 100644 --- a/docs/libcurl/opts/CURLINFO_TLS_SESSION.md +++ b/docs/libcurl/opts/CURLINFO_TLS_SESSION.md @@ -31,14 +31,11 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_TLS_SESSION, # DESCRIPTION -**This option has been superseded** by CURLINFO_TLS_SSL_PTR(3) which -was added in 7.48.0. The only reason you would use this option instead is if -you could be using a version of libcurl earlier than 7.48.0. - -This option is exactly the same as CURLINFO_TLS_SSL_PTR(3) except in the -case of OpenSSL and wolfSSL. If the session *backend* is -CURLSSLBACKEND_OPENSSL the session *internals* pointer varies depending -on the option: +**This option has been superseded** by CURLINFO_TLS_SSL_PTR(3). + +This option is exactly the same as CURLINFO_TLS_SSL_PTR(3) except in the case +of OpenSSL and wolfSSL. If the session *backend* is CURLSSLBACKEND_OPENSSL the +session *internals* pointer varies depending on the option: ## OpenSSL: diff --git a/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md b/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md index dd791b81cb2c..4cabb09f8772 100644 --- a/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md +++ b/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md @@ -51,27 +51,27 @@ Enforce HTTP 1.1 requests. ## CURL_HTTP_VERSION_2_0 Attempt HTTP 2 requests. libcurl falls back to HTTP 1.1 if HTTP 2 cannot be -negotiated with the server. (Added in 7.33.0) +negotiated with the server. When libcurl uses HTTP/2 over HTTPS, it does not itself insist on TLS 1.2 or higher even though that is required by the specification. A user can add this version requirement with CURLOPT_SSLVERSION(3). -The alias *CURL_HTTP_VERSION_2* was added in 7.43.0 to better reflect the -actual protocol name. +The alias *CURL_HTTP_VERSION_2* was added to better reflect the actual +protocol name. ## CURL_HTTP_VERSION_2TLS Attempt HTTP 2 over TLS (HTTPS) only. libcurl falls back to HTTP 1.1 if HTTP 2 cannot be negotiated with the HTTPS server. For clear text HTTP servers, -libcurl uses 1.1. (Added in 7.47.0) +libcurl uses 1.1. ## CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE Issue non-TLS HTTP requests using HTTP/2 without HTTP/1.1 Upgrade. It requires prior knowledge that the server supports HTTP/2 straight away. HTTPS requests still do HTTP/2 the standard way with negotiated protocol version in the TLS -handshake. (Added in 7.49.0) +handshake. Since 8.10.0 if this option is set for an HTTPS request then the application layer protocol version (ALPN) offered to the server is only HTTP/2. Prior to diff --git a/docs/libcurl/opts/CURLOPT_ISSUERCERT.md b/docs/libcurl/opts/CURLOPT_ISSUERCERT.md index 0dc4c2243c50..7b6998040bcb 100644 --- a/docs/libcurl/opts/CURLOPT_ISSUERCERT.md +++ b/docs/libcurl/opts/CURLOPT_ISSUERCERT.md @@ -43,8 +43,8 @@ not considered as failure. A specific error code (CURLE_SSL_ISSUER_ERROR) is defined with the option, which is returned if the setup of the SSL/TLS session has failed due to a -mismatch with the issuer of peer certificate (CURLOPT_SSL_VERIFYPEER(3) -has to be set too for the check to fail). (Added in 7.19.0) +mismatch with the issuer of peer certificate (CURLOPT_SSL_VERIFYPEER(3) has to +be set too for the check to fail). Using this option multiple times makes the last set string override the previous ones. Set it to NULL to disable its use again. diff --git a/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md b/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md index 2962994b2ae2..d91a7da3ba7f 100644 --- a/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md +++ b/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md @@ -56,7 +56,6 @@ static curl_socket_t opensocket(void *clientp, static int sockopt_callback(void *clientp, curl_socket_t curlfd, curlsocktype purpose) { - /* This return code was added in libcurl 7.21.5 */ return CURL_SOCKOPT_ALREADY_CONNECTED; } diff --git a/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md b/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md index b8517c4f3233..89931d0e066c 100644 --- a/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md @@ -104,7 +104,6 @@ static curl_socket_t opensocket(void *clientp, static int sockopt_callback(void *clientp, curl_socket_t curlfd, curlsocktype purpose) { - /* This return code was added in libcurl 7.21.5 */ return CURL_SOCKOPT_ALREADY_CONNECTED; } diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md index 7e1f6f140066..bb35bda1ae97 100644 --- a/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md @@ -72,33 +72,22 @@ supported for wolfSSL. The flag defines the maximum supported TLS version as TLSv1.2, or the default value from the SSL library. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_0 The flag defines maximum supported TLS version as TLSv1.0. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_1 The flag defines maximum supported TLS version as TLSv1.1. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_2 The flag defines maximum supported TLS version as TLSv1.2. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_3 The flag defines maximum supported TLS version as TLSv1.3. -(Added in 7.54.0) - -## - -In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were -documented to allow *only* the specified TLS version, but behavior was -inconsistent depending on the TLS library. # DEFAULT diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md index 0729518a0df1..18b7ce6b36a1 100644 --- a/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md @@ -49,8 +49,7 @@ Transport and OpenSSL. Tells libcurl to disable certificate revocation checks for those SSL backends where such behavior is present. This option is only supported for Schannel (the native Windows SSL library), with an exception in the case of Windows' -Untrusted Publishers block list which it seems cannot be bypassed. (Added in -7.44.0) +Untrusted Publishers block list which it seems cannot be bypassed. ## CURLSSLOPT_NO_PARTIALCHAIN diff --git a/docs/libcurl/opts/CURLOPT_QUOTE.md b/docs/libcurl/opts/CURLOPT_QUOTE.md index 8687f527a9d5..5e00f45137ef 100644 --- a/docs/libcurl/opts/CURLOPT_QUOTE.md +++ b/docs/libcurl/opts/CURLOPT_QUOTE.md @@ -120,7 +120,7 @@ operand, provided it is empty. ## statvfs file The statvfs command returns statistics on the file system in which specified -file resides. (Added in 7.49.0) +file resides. ## symlink source_file target_file diff --git a/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md index 0efdd0b3be5e..a2ded45692c8 100644 --- a/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md @@ -96,7 +96,6 @@ static curl_socket_t opensocket(void *clientp, static int sockopt_callback(void *clientp, curl_socket_t curlfd, curlsocktype purpose) { - /* This return code was added in libcurl 7.21.5 */ return CURL_SOCKOPT_ALREADY_CONNECTED; } diff --git a/docs/libcurl/opts/CURLOPT_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_SSLVERSION.md index 366edc0a7e27..6aa641def9a2 100644 --- a/docs/libcurl/opts/CURLOPT_SSLVERSION.md +++ b/docs/libcurl/opts/CURLOPT_SSLVERSION.md @@ -58,58 +58,48 @@ SSL v3 - refused ## CURL_SSLVERSION_TLSv1_0 -TLS v1.0 or later (Added in 7.34.0) +TLS v1.0 or later ## CURL_SSLVERSION_TLSv1_1 -TLS v1.1 or later (Added in 7.34.0) +TLS v1.1 or later ## CURL_SSLVERSION_TLSv1_2 -TLS v1.2 or later (Added in 7.34.0) +TLS v1.2 or later ## CURL_SSLVERSION_TLSv1_3 -TLS v1.3 or later (Added in 7.52.0) +TLS v1.3 or later ## -The maximum TLS version can be set by using *one* of the -CURL_SSLVERSION_MAX_ macros below. It is also possible to OR *one* of the -CURL_SSLVERSION_ macros with *one* of the CURL_SSLVERSION_MAX_ macros. +The maximum TLS version can be set by using *one* of the CURL_SSLVERSION_MAX_ +macros below. It is also possible to OR *one* of the CURL_SSLVERSION_ macros +with *one* of the CURL_SSLVERSION_MAX_ macros. ## CURL_SSLVERSION_MAX_DEFAULT The flag defines the maximum supported TLS version by libcurl, or the default value from the SSL library is used. libcurl uses a sensible default maximum, which was TLS v1.2 up to before 7.61.0 and is TLS v1.3 since then - assuming -the TLS library support it. (Added in 7.54.0) +the TLS library support it. ## CURL_SSLVERSION_MAX_TLSv1_0 The flag defines maximum supported TLS version as TLS v1.0. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_1 The flag defines maximum supported TLS version as TLS v1.1. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_2 The flag defines maximum supported TLS version as TLS v1.2. -(Added in 7.54.0) ## CURL_SSLVERSION_MAX_TLSv1_3 The flag defines maximum supported TLS version as TLS v1.3. -(Added in 7.54.0) - -## - -In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were -documented to allow *only* the specified TLS version, but behavior was -inconsistent depending on the TLS library. # DEFAULT diff --git a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md index 89a1d430f789..2065fe6f1660 100644 --- a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md +++ b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md @@ -47,8 +47,7 @@ Transport and OpenSSL. Tells libcurl to disable certificate revocation checks for those SSL backends where such behavior is present. This option is only supported for Schannel (the native Windows SSL library), with an exception in the case of Windows' -Untrusted Publishers block list which it seems cannot be bypassed. (Added in -7.44.0) +Untrusted Publishers block list which it seems cannot be bypassed. ## CURLSSLOPT_NO_PARTIALCHAIN diff --git a/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md b/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md index 9ac65c42b411..2d664439a28b 100644 --- a/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md +++ b/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md @@ -28,7 +28,7 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPINTVL, long interval); # DESCRIPTION Pass a long. Sets the interval, in seconds, to wait between sending keepalive -probes. Not all operating systems support this option. (Added in 7.25.0) +probes. Not all operating systems support this option. The maximum value this accepts is 2147483648. Any larger value is capped to this amount. diff --git a/docs/libcurl/opts/CURLSHOPT_SHARE.md b/docs/libcurl/opts/CURLSHOPT_SHARE.md index 4171430a790a..92a279a31012 100644 --- a/docs/libcurl/opts/CURLSHOPT_SHARE.md +++ b/docs/libcurl/opts/CURLSHOPT_SHARE.md @@ -54,10 +54,9 @@ the same multi handle share the DNS cache by default without using this option. ## CURL_LOCK_DATA_SSL_SESSION -SSL sessions are shared across the easy handles using this shared -object. This reduces the time spent in the SSL handshake when reconnecting to -the same server. This symbol was added in 7.10.3 but was not implemented until -7.23.0. +SSL sessions are shared across the easy handles using this shared object. This +reduces the time spent in the SSL handshake when reconnecting to the same +server. Note that when you use the multi interface, all easy handles added to the same multi handle share the SSL session cache by default without using this option. @@ -74,9 +73,6 @@ additional transfers added to them if the existing connection is held by the same multi or easy handle. libcurl does not support doing multiplexed streams in different threads using a shared connection. -Support for **CURL_LOCK_DATA_CONNECT** was added in 7.57.0, but the symbol -existed before this. - Note that when you use the multi interface, all easy handles added to the same multi handle share the connection cache by default without using this option. From bbdb869ec7e708d12128784a13a1b9e34c67b450 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Fri, 12 Sep 2025 00:10:20 -0700 Subject: [PATCH 013/465] libcurl-security.md: mention long-running connections Some applications may want to periodically recheck the remote server certificate, which doesn't happen on a long-running connection. Ref: #18527 Closes #18533 --- docs/libcurl/libcurl-security.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/libcurl/libcurl-security.md b/docs/libcurl/libcurl-security.md index c6a10cd27151..7fbd32974d2c 100644 --- a/docs/libcurl/libcurl-security.md +++ b/docs/libcurl/libcurl-security.md @@ -98,6 +98,24 @@ Use authenticated protocols protected with HTTPS or SSH. Never ever switch off certificate verification. +# Certificates and Long-running Connections + +Certificate validation of encrypted connections is performed immediately after +a connection is established. That connection could be used for many subsequent +transfers, even if the certificate used for validation expires or is revoked, +the local certificate bundle is changed in a way that would have caused that +certificate to fail validation, the server changes its certificate to one +that would have failed validation, or even if a completely different server is +brought up under the same hostname. This could continue for many hours (or +even years) after such a change occurs, which may not be desired behavior for +some applications. + +Remedies: + +Use the CURLOPT_MAXLIFETIME_CONN(3) option to limit the amount of time that +connections are used after they have been successfully validated. Further +transfers require a new connection with validation performed again. + # Redirects The CURLOPT_FOLLOWLOCATION(3) option automatically follows HTTP From cc50f05370981e4933504e8aaec6b15880ff847f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 11 Sep 2025 19:50:40 +0200 Subject: [PATCH 014/465] GHA/codeql: re-enable for C with the default query pack Earlier we used `security-extended` and tried `security-and-quality`. Try the default to see how it works. CodeQL no longer uses the project's Actions cache, also fixing the previously seen repeat cache entry issue. - switch to `manual` build. It's 3x faster than the default `autobuild`. - enable more dependencies to increase coverage. - docs/tests/CI.md: re-add CodeQL. Ref: https://docs.github.com/en/code-security/code-scanning/managing-your-code-scanning-configuration/codeql-query-suites Ref: https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages Ref: #16263 Ref: 173805b2e76960de5c51fd5fe64286d8ac81f1ff #15798 Closes #18528 --- .github/scripts/spellcheck.words | 1 + .github/workflows/codeql.yml | 34 ++++++++++++++++++++++++++++++++ docs/tests/CI.md | 4 ++++ 3 files changed, 39 insertions(+) diff --git a/.github/scripts/spellcheck.words b/.github/scripts/spellcheck.words index 13b7b2f3674d..46c05b741bcf 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/spellcheck.words @@ -122,6 +122,7 @@ CMakeLists CNA CNAME CNAMEs +CodeQL CODESET codeset CodeSonar diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9863f7624d2c..0952eb3d1d22 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -59,3 +59,37 @@ jobs: - name: 'perform analysis' uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 + + c: + name: 'C' + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - name: 'install prereqs' + timeout-minutes: 5 + run: | + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get -o Dpkg::Use-Pty=0 update + sudo rm -f /var/lib/man-db/auto-update + sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + persist-credentials: false + + - name: 'initialize' + uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3 + with: + languages: cpp + build-mode: manual + + - name: 'build' + timeout-minutes: 10 + run: | + cmake -B . -G Ninja + cmake --build . --verbose + src/curl -V + + - name: 'perform analysis' + uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 diff --git a/docs/tests/CI.md b/docs/tests/CI.md index d101e3563c71..40c87ba14e16 100644 --- a/docs/tests/CI.md +++ b/docs/tests/CI.md @@ -31,8 +31,10 @@ Consider the following table while looking at pull request failures: | CI platform as shown in PR | State | What to look at next | | ----------------------------------- | ------ | -------------------------- | + | CI / CodeQL | stable | quality check results | | CI / fuzzing | stable | fuzzing results | | CI / macos ... | stable | all errors and failures | + | Code scanning results / CodeQL | stable | quality check results | | FreeBSD FreeBSD: ... | stable | all errors and failures | | LGTM analysis: Python | stable | new findings | | LGTM analysis: C/C++ | stable | new findings | @@ -40,6 +42,7 @@ Consider the following table while looking at pull request failures: | AppVeyor | flaky | all errors and failures | | curl.curl (linux ...) | stable | all errors and failures | | curl.curl (windows ...) | flaky | repetitive errors/failures | + | CodeQL | stable | new findings | Sometimes the tests fail due to a dependency service temporarily being offline or otherwise unavailable, for example package downloads. In this case you can @@ -58,6 +61,7 @@ GitHub Actions runs the following tests: - macOS tests with a variety of different compilation options - Fuzz tests ([see the curl-fuzzer repo for more info](https://github.com/curl/curl-fuzzer)). +- CodeQL static analysis These are each configured in different files in `.github/workflows`. From 83c457f9f3244544c4f0f13051cd00e637c6de88 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 13 Sep 2025 17:20:22 +0200 Subject: [PATCH 015/465] GHA: document permissions as required by zizmor 1.13.0 Ref: https://github.com/zizmorcore/zizmor/pull/1131 Ref: https://docs.zizmor.sh/audits/#undocumented-permissions Bug: https://github.com/curl/curl/pull/18539#issuecomment-3288151910 Closes #18541 --- .github/workflows/appveyor-status.yml | 2 +- .github/workflows/codeql.yml | 4 ++-- .github/workflows/hacktoberfest-accepted.yml | 5 ++--- .github/workflows/label.yml | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/appveyor-status.yml b/.github/workflows/appveyor-status.yml index cb7f96b1907e..5269f3ca65b9 100644 --- a/.github/workflows/appveyor-status.yml +++ b/.github/workflows/appveyor-status.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest if: ${{ github.event.sender.login == 'appveyor[bot]' }} permissions: - statuses: write + statuses: write # To update build statuses steps: - name: 'Create individual AppVeyor build statuses' if: ${{ github.event.sha && github.event.target_url }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0952eb3d1d22..ff2e91c32a42 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -45,7 +45,7 @@ jobs: name: 'GHA and Python' runs-on: ubuntu-latest permissions: - security-events: write + security-events: write # To create/update security events steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: @@ -64,7 +64,7 @@ jobs: name: 'C' runs-on: ubuntu-latest permissions: - security-events: write + security-events: write # To create/update security events steps: - name: 'install prereqs' timeout-minutes: 5 diff --git a/.github/workflows/hacktoberfest-accepted.yml b/.github/workflows/hacktoberfest-accepted.yml index 916b354481ca..3aacbd6d0c5c 100644 --- a/.github/workflows/hacktoberfest-accepted.yml +++ b/.github/workflows/hacktoberfest-accepted.yml @@ -23,9 +23,8 @@ jobs: name: 'Add hacktoberfest-accepted label' runs-on: ubuntu-latest permissions: - # requires issues AND pull-requests write permissions to edit labels on PRs! - issues: write - pull-requests: write + issues: write # To edit labels on PRs + pull-requests: write # To edit labels on PRs steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index b84702a8a1b9..cfafde14f7fe 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -19,8 +19,8 @@ jobs: name: 'Labeler' runs-on: ubuntu-latest permissions: - contents: read - pull-requests: write + contents: read # To comply with https://github.com/actions/labeler documentation + pull-requests: write # To edit labels on PRs steps: - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6 From eb319bf6ea4811e9ea19308d7f3d45f340cc7766 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2025 10:33:38 +0200 Subject: [PATCH 016/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 04e1ad4779d9..58d8fe6d02d4 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,7 +4,7 @@ curl and libcurl 8.16.1 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3499 + Contributors: 3500 This release includes the following changes: @@ -12,8 +12,17 @@ This release includes the following changes: This release includes the following bugfixes: o curl_easy_getinfo: error code on NULL arg [2] + o curl_mem_undef.h: limit to `CURLDEBUG` for non-memalloc overrides [19] + o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] + o CURLOPT_MAXLIFETIME_CONN: make default 24 hours [10] + o docs/libcurl: remove ancient version references [7] o easy_getinfo: check magic, Curl_close safety [3] + o libcurl-security.md: mention long-running connections [6] + o ngtcp2: check error code on connect failure [13] + o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o ssl-sessions.md: mark option experimental [12] + o urldata: FILE is not a list-only protocol [9] This release includes the following known bugs: @@ -37,11 +46,22 @@ Planned upcoming removals include: This release would not have looked like this without help, code, reports and advice from friends like these: - Daniel Stenberg, Ethan Everett, Stefan Eissing - (3 contributors) + Andrew Kirillov, Dan Fandrich, Daniel Stenberg, Emilio Pozuelo Monfort, + Ethan Everett, fds242 on github, renovate[bot], Stefan Eissing, + Viktor Szakats + (9 contributors) References to bug reports and discussions on issues: [2] = https://curl.se/bug/?i=18512 [3] = https://curl.se/bug/?i=18511 [4] = https://curl.se/bug/?i=18505 + [6] = https://curl.se/bug/?i=18533 + [7] = https://curl.se/bug/?i=18530 + [8] = https://curl.se/bug/?i=18531 + [9] = https://curl.se/bug/?i=18525 + [10] = https://curl.se/bug/?i=18527 + [12] = https://curl.se/bug/?i=18523 + [13] = https://curl.se/bug/?i=18521 + [14] = https://curl.se/bug/?i=18518 + [19] = https://curl.se/bug/?i=18510 From d52af3c692943377a28a5bfa270248d009a9eed1 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 14 Sep 2025 11:55:50 +0200 Subject: [PATCH 017/465] appveyor: bump to OpenSSL 3.5, adjust to dropped 1.1.1 on VS2019 - bump OpenSSL 3.4 to 3.5 on VS2022 runners. - bump OpenSSL 1.1.1 to 3.0 on VS2019 runners. 1.1.1 is documented to be present, but missing. Fixes: ``` + cmake -G 'Visual Studio 16 2019' -A x64 [...] -DOPENSSL_ROOT_DIR=C:/OpenSSL-v111-Win64 [...] CMake Error at C:/Program Files/CMake/share/cmake-4.1/Modules/FindPackageHandleStandardArgs.cmake:227 (message): Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR (missing: OPENSSL_CRYPTO_LIBRARY OPENSSL_INCLUDE_DIR) Call Stack (most recent call first): CMakeLists.txt:757 (find_package) ``` Ref: https://ci.appveyor.com/project/curlorg/curl/builds/52740431/job/tq6h4xhqpa3vgq47?fullLog=true Ref: https://www.appveyor.com/docs/windows-images-software/ Ref: https://github.com/appveyor/website/commit/9a739f7bce4a624b28ff382d58a9ebc507ab0f78 Closes #18543 --- appveyor.sh | 4 +++- appveyor.yml | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/appveyor.sh b/appveyor.sh index 1e4c16362fa5..dea58c954542 100644 --- a/appveyor.sh +++ b/appveyor.sh @@ -34,7 +34,9 @@ case "${TARGET:-}" in esac if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = 'Visual Studio 2022' ]; then - openssl_root_win="C:/OpenSSL-v34${openssl_suffix}" + openssl_root_win="C:/OpenSSL-v35${openssl_suffix}" +elif [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = 'Visual Studio 2019' ]; then + openssl_root_win="C:/OpenSSL-v30${openssl_suffix}" else openssl_root_win="C:/OpenSSL-v111${openssl_suffix}" fi diff --git a/appveyor.yml b/appveyor.yml index effd8589d17e..42b580883c3b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -46,7 +46,7 @@ environment: # generated CMake-based Visual Studio builds - - job_name: 'CMake, VS2022, Release, x64, OpenSSL 3.4, Shared, Build-tests' + - job_name: 'CMake, VS2022, Release, x64, OpenSSL 3.5, Shared, Build-tests' APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022' PRJ_GEN: 'Visual Studio 17 2022' TARGET: '-A x64' @@ -101,7 +101,7 @@ environment: OPENSSL: 'ON' SHARED: 'ON' TFLAGS: 'skipall' - - job_name: 'CMake, VS2019, Debug, x64, OpenSSL 1.1.1 + Schannel, Shared, Build-tests' + - job_name: 'CMake, VS2019, Debug, x64, OpenSSL 3.0 + Schannel, Shared, Build-tests' APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2019' PRJ_GEN: 'Visual Studio 16 2019' TARGET: '-A x64' @@ -109,7 +109,7 @@ environment: OPENSSL: 'ON' SCHANNEL: 'ON' SHARED: 'ON' - - job_name: 'CMake, VS2022, Debug, x64, OpenSSL 3.4 + Schannel, Static, Unicode, Build-tests & examples, clang-cl' + - job_name: 'CMake, VS2022, Debug, x64, OpenSSL 3.5 + Schannel, Static, Unicode, Build-tests & examples, clang-cl' APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022' PRJ_GEN: 'Visual Studio 17 2022' TARGET: '-A x64' From 6bb53f29efb7c379f3d22f9e6298e001bf1ff7da Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2025 11:44:35 +0200 Subject: [PATCH 018/465] TODO: remove already implemented or bad items - remove "connect to multiple IPs in parallel" - remove "CURLOPT_RESOLVE for any port number", It can already be accomplished with CURLOPT_CONNECT_TO - remove "dynamically load modules", we don't believe in this - remove "netrc caching and sharing", we already cache it - remove "Offer API to flush the connection pool", this is effectively what CURLMOPT_NETWORK_CHANGED now allows - remove "WebSocket read callback", introduced in 8.16.0 Closes #18542 --- docs/TODO | 53 ----------------------------------------------------- 1 file changed, 53 deletions(-) diff --git a/docs/TODO b/docs/TODO index 1e22814f385f..6075577f318f 100644 --- a/docs/TODO +++ b/docs/TODO @@ -23,24 +23,18 @@ 1.4 alt-svc sharing 1.5 get rid of PATH_MAX 1.6 thread-safe sharing - 1.8 CURLOPT_RESOLVE for any port number 1.10 auto-detect proxy - 1.11 minimize dependencies with dynamically loaded modules 1.12 updated DNS server while running 1.13 c-ares and CURLOPT_OPENSOCKETFUNCTION - 1.14 connect to multiple IPs in parallel 1.15 Monitor connections in the connection pool 1.16 Try to URL encode given URL 1.17 Add support for IRIs 1.18 try next proxy if one does not work 1.19 provide timing info for each redirect 1.20 SRV and URI DNS records - 1.21 netrc caching and sharing 1.22 CURLINFO_PAUSE_STATE - 1.23 Offer API to flush the connection pool 1.25 Expose tried IP addresses that failed 1.28 FD_CLOEXEC - 1.29 WebSocket read callback 1.30 config file parsing 1.31 erase secrets from heap/stack after use 1.32 add asynch getaddrinfo support @@ -252,14 +246,6 @@ share between multiple concurrent threads. Fixing this would enable more users to share data in more powerful ways. -1.8 CURLOPT_RESOLVE for any port number - - This option allows applications to set a replacement IP address for a given - host + port pair. Consider making support for providing a replacement address - for the hostname on all port numbers. - - See https://github.com/curl/curl/issues/1264 - 1.10 auto-detect proxy libcurl could be made to detect the system proxy setup automatically and use @@ -272,14 +258,6 @@ libdetectproxy is a (C++) library for detecting the proxy on Windows https://github.com/paulharris/libdetectproxy -1.11 minimize dependencies with dynamically loaded modules - - We can create a system with loadable modules/plug-ins, where these modules - would be the ones that link to 3rd party libs. That would allow us to avoid - having to load ALL dependencies since only the necessary ones for this - app/invoke/used protocols would be necessary to load. See - https://github.com/curl/curl/issues/349 - 1.12 updated DNS server while running If /etc/resolv.conf gets updated while a program using libcurl is running, it @@ -301,17 +279,6 @@ See https://github.com/curl/curl/issues/2734 -1.14 connect to multiple IPs in parallel - - curl currently implements the happy eyeball algorithm for connecting to the - IPv4 and IPv6 alternatives for a host in parallel, sticking with the - connection that "wins". We could implement a similar algorithm per individual - IP family as well when there are multiple available addresses: start with the - first address, then start a second attempt N milliseconds after and then a - third another N milliseconds later. That way there would be less waiting when - the first IP has problems. It also improves the connection timeout value - handling for multiple address situations. - 1.15 Monitor connections in the connection pool libcurl's connection cache or pool holds a number of open connections for the @@ -368,24 +335,11 @@ Offer support for resolving SRV and URI DNS records for libcurl to know which server to connect to for various protocols (including HTTP). -1.21 netrc caching and sharing - - The netrc file is read and parsed each time a connection is setup, which - means that if a transfer needs multiple connections for authentication or - redirects, the file might be reread (and parsed) multiple times. This makes - it impossible to provide the file as a pipe. - 1.22 CURLINFO_PAUSE_STATE Return information about the transfer's current pause state, in both directions. https://github.com/curl/curl/issues/2588 -1.23 Offer API to flush the connection pool - - Sometimes applications want to flush all the existing connections kept alive. - An API could allow a forced flush or just a forced loop that would properly - close all connections that have been closed by the server already. - 1.25 Expose tried IP addresses that failed When libcurl fails to connect to a host, it could offer the application the @@ -403,13 +357,6 @@ https://github.com/curl/curl/issues/2252 -1.29 WebSocket read callback - - Call the read callback once the connection is established to allow sending - the first message in the connection. - - https://github.com/curl/curl/issues/11402 - 1.30 config file parsing Consider providing an API, possibly in a separate companion library, for From 07837204cdd18f470594fc0caea7fbb50de286df Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 14 Sep 2025 12:38:29 +0200 Subject: [PATCH 019/465] GHA/distcheck: disable `man-db/auto-update` Make sure to not rebuild man pages after purging system curl, to make the job faster and avoid timeouts: ``` Sun, 14 Sep 2025 10:16:28 GMT Removing curl (8.5.0-2ubuntu10.6) ... Sun, 14 Sep 2025 10:16:28 GMT Processing triggers for man-db (2.12.0-4build2) ... Sun, 14 Sep 2025 10:21:22 GMT (Reading database ... 218629 files and directories currently installed.) ``` Ref: https://github.com/curl/curl/actions/runs/17709785947/job/50326910814?pr=18535#step:3:19 Closes #18544 --- .github/workflows/distcheck.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index bf6c69bfcfd0..9d893481bcfd 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -33,7 +33,9 @@ jobs: persist-credentials: false - name: 'remove preinstalled curl libcurl4{-doc}' - run: sudo apt-get -o Dpkg::Use-Pty=0 purge curl libcurl4 libcurl4-doc + run: | + sudo rm -f /var/lib/man-db/auto-update + sudo apt-get -o Dpkg::Use-Pty=0 purge curl libcurl4 libcurl4-doc - name: 'autoreconf' run: autoreconf -fi @@ -233,7 +235,9 @@ jobs: persist-credentials: false - name: 'remove preinstalled curl libcurl4{-doc}' - run: sudo apt-get -o Dpkg::Use-Pty=0 purge curl libcurl4 libcurl4-doc + run: | + sudo rm -f /var/lib/man-db/auto-update + sudo apt-get -o Dpkg::Use-Pty=0 purge curl libcurl4 libcurl4-doc - name: 'generate release tarballs' run: ./scripts/dmaketgz 9.10.11 From c1be5459d9619163e26d5732ee732b417d697e9d Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 14 Sep 2025 14:14:34 +0200 Subject: [PATCH 020/465] GHA/codeql: analyse Windows Schannel WinIDN build Follow-up to cc50f05370981e4933504e8aaec6b15880ff847f #18528 Closes #18545 --- .github/workflows/codeql.yml | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ff2e91c32a42..e33540959543 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -61,12 +61,23 @@ jobs: uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 c: - name: 'C' - runs-on: ubuntu-latest + name: 'C (${{ matrix.build.name }})' + runs-on: ${{ matrix.build.image }} permissions: security-events: write # To create/update security events + strategy: + fail-fast: false + matrix: + build: + - name: 'Linux' + image: ubuntu-latest + - name: 'Windows' + image: windows-2022 + env: + MATRIX_IMAGE: '${{ matrix.build.image }}' steps: - name: 'install prereqs' + if: ${{ contains(matrix.build.image, 'ubuntu') }} timeout-minutes: 5 run: | sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list @@ -86,10 +97,19 @@ jobs: - name: 'build' timeout-minutes: 10 + shell: bash run: | - cmake -B . -G Ninja - cmake --build . --verbose - src/curl -V + if [[ "${MATRIX_IMAGE}" = *'windows'* ]]; then + cmake -B . -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_VS_GLOBALS=TrackFileAccess=false \ + -DCURL_USE_SCHANNEL=ON -DCURL_USE_LIBPSL=OFF -DUSE_WIN32_IDN=ON + cmake --build . --verbose + src/Debug/curl.exe --disable --version + else + cmake -B . -G Ninja + cmake --build . --verbose + src/curl --disable --version + fi - name: 'perform analysis' uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 From 64347831684d3a7905fd7ef95bfab59df44b6aea Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2025 14:29:13 +0200 Subject: [PATCH 021/465] tool_getparam: split opt_filestring into two sep functions One for file name arguments and one for "strings". Closes #18546 --- src/tool_getparam.c | 232 +++++++++++++++++++++++--------------------- 1 file changed, 121 insertions(+), 111 deletions(-) diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 6be57dbd5c31..f2ad6daf2ef9 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -2163,11 +2163,123 @@ static ParameterError opt_bool(struct OperationConfig *config, return PARAM_OK; } +/* opt_file handles file options */ +static ParameterError opt_file(struct OperationConfig *config, + const struct LongShort *a, + const char *nextarg) +{ + ParameterError err = PARAM_OK; + if((nextarg[0] == '-') && nextarg[1]) { + /* if the filename looks like a command line option */ + warnf("The filename argument '%s' looks like a flag.", nextarg); + } + switch(a->cmd) { + case C_ABSTRACT_UNIX_SOCKET: /* --abstract-unix-socket */ + config->abstract_unix_socket = TRUE; + err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); + break; + case C_CACERT: /* --cacert */ + err = getstr(&config->cacert, nextarg, DENY_BLANK); + break; + case C_CAPATH: /* --capath */ + err = getstr(&config->capath, nextarg, DENY_BLANK); + break; + case C_CERT: /* --cert */ + GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); + break; + case C_CONFIG: /* --config */ + if(parseconfig(nextarg)) { + errorf("cannot read config from '%s'", nextarg); + err = PARAM_READ_ERROR; + } + break; + case C_CRLFILE: /* --crlfile */ + err = getstr(&config->crlfile, nextarg, DENY_BLANK); + break; + case C_DUMP_HEADER: /* --dump-header */ + err = getstr(&config->headerfile, nextarg, DENY_BLANK); + break; + case C_ETAG_SAVE: /* --etag-save */ + if(config->num_urls > 1) { + errorf("The etag options only work on a single URL"); + err = PARAM_BAD_USE; + } + else + err = getstr(&config->etag_save_file, nextarg, DENY_BLANK); + break; + case C_ETAG_COMPARE: /* --etag-compare */ + if(config->num_urls > 1) { + errorf("The etag options only work on a single URL"); + err = PARAM_BAD_USE; + } + else + err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK); + break; + case C_KEY: /* --key */ + err = getstr(&config->key, nextarg, DENY_BLANK); + break; + case C_NETRC_FILE: /* --netrc-file */ + err = getstr(&config->netrc_file, nextarg, DENY_BLANK); + break; + case C_OUTPUT: /* --output */ + err = parse_output(config, nextarg); + break; + case C_PROXY_CACERT: /* --proxy-cacert */ + err = getstr(&config->proxy_cacert, nextarg, DENY_BLANK); + break; + case C_PROXY_CAPATH: /* --proxy-capath */ + err = getstr(&config->proxy_capath, nextarg, DENY_BLANK); + break; + case C_PROXY_CERT: /* --proxy-cert */ + GetFileAndPassword(nextarg, &config->proxy_cert, + &config->proxy_key_passwd); + break; + case C_PROXY_CRLFILE: /* --proxy-crlfile */ + err = getstr(&config->proxy_crlfile, nextarg, DENY_BLANK); + break; + case C_PROXY_KEY: /* --proxy-key */ + err = getstr(&config->proxy_key, nextarg, ALLOW_BLANK); + break; + case C_SSL_SESSIONS: /* --ssl-sessions */ + if(feature_ssls_export) + err = getstr(&global->ssl_sessions, nextarg, DENY_BLANK); + else + err = PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case C_STDERR: /* --stderr */ + tool_set_stderr_file(nextarg); + break; + case C_TRACE: /* --trace */ + err = getstr(&global->trace_dump, nextarg, DENY_BLANK); + if(!err) { + if(global->tracetype && (global->tracetype != TRACE_BIN)) + warnf("--trace overrides an earlier trace/verbose option"); + global->tracetype = TRACE_BIN; + } + break; + case C_TRACE_ASCII: /* --trace-ascii */ + err = getstr(&global->trace_dump, nextarg, DENY_BLANK); + if(!err) { + if(global->tracetype && (global->tracetype != TRACE_ASCII)) + warnf("--trace-ascii overrides an earlier trace/verbose option"); + global->tracetype = TRACE_ASCII; + } + break; + case C_UNIX_SOCKET: /* --unix-socket */ + config->abstract_unix_socket = FALSE; + err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); + break; + case C_UPLOAD_FILE: /* --upload-file */ + err = parse_upload_file(config, nextarg); + break; + } + return err; +} -/* opt_filestring handles string and file options */ -static ParameterError opt_filestring(struct OperationConfig *config, - const struct LongShort *a, - const char *nextarg) +/* opt_string handles string options */ +static ParameterError opt_string(struct OperationConfig *config, + const struct LongShort *a, + const char *nextarg) { ParameterError err = PARAM_OK; curl_off_t value; @@ -2227,22 +2339,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, /* IP addrs of DNS servers */ err = getstr(&config->dns_servers, nextarg, DENY_BLANK); break; - case C_TRACE: /* --trace */ - err = getstr(&global->trace_dump, nextarg, DENY_BLANK); - if(!err) { - if(global->tracetype && (global->tracetype != TRACE_BIN)) - warnf("--trace overrides an earlier trace/verbose option"); - global->tracetype = TRACE_BIN; - } - break; - case C_TRACE_ASCII: /* --trace-ascii */ - err = getstr(&global->trace_dump, nextarg, DENY_BLANK); - if(!err) { - if(global->tracetype && (global->tracetype != TRACE_ASCII)) - warnf("--trace-ascii overrides an earlier trace/verbose option"); - global->tracetype = TRACE_ASCII; - } - break; case C_LIMIT_RATE: /* --limit-rate */ err = GetSizeParameter(nextarg, "rate", &value); if(!err) { @@ -2272,9 +2368,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, config->authtype |= CURLAUTH_AWS_SIGV4; err = getstr(&config->aws_sigv4, nextarg, ALLOW_BLANK); break; - case C_STDERR: /* --stderr */ - tool_set_stderr_file(nextarg); - break; case C_INTERFACE: /* --interface */ /* interface */ err = getstr(&config->iface, nextarg, DENY_BLANK); @@ -2406,10 +2499,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_SASL_AUTHZID: /* --sasl-authzid */ err = getstr(&config->sasl_authzid, nextarg, DENY_BLANK); break; - case C_UNIX_SOCKET: /* --unix-socket */ - config->abstract_unix_socket = FALSE; - err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); - break; case C_PROXY_SERVICE_NAME: /* --proxy-service-name */ err = getstr(&config->proxy_service_name, nextarg, DENY_BLANK); break; @@ -2427,10 +2516,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_CONNECT_TO: /* --connect-to */ err = add2list(&config->connect_to, nextarg); break; - case C_ABSTRACT_UNIX_SOCKET: /* --abstract-unix-socket */ - config->abstract_unix_socket = TRUE; - err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK); - break; case C_TLS_MAX: /* --tls-max */ err = str2tls_max(&config->ssl_version_max, nextarg); if(!err && (config->ssl_version_max < config->ssl_version)) { @@ -2499,9 +2584,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_URL_QUERY: /* --url-query */ err = url_query(nextarg, config); break; - case C_DUMP_HEADER: /* --dump-header */ - err = getstr(&config->headerfile, nextarg, DENY_BLANK); - break; case C_REFERER: { /* --referer */ size_t len = strlen(nextarg); /* does it end with ;auto ? */ @@ -2520,18 +2602,9 @@ static ParameterError opt_filestring(struct OperationConfig *config, tool_safefree(config->referer); } break; - case C_CERT: /* --cert */ - GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); - break; - case C_CACERT: /* --cacert */ - err = getstr(&config->cacert, nextarg, DENY_BLANK); - break; case C_CERT_TYPE: /* --cert-type */ err = getstr(&config->cert_type, nextarg, DENY_BLANK); break; - case C_KEY: /* --key */ - err = getstr(&config->key, nextarg, DENY_BLANK); - break; case C_KEY_TYPE: /* --key-type */ err = getstr(&config->key_type, nextarg, DENY_BLANK); break; @@ -2548,9 +2621,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_ECH: /* --ech */ err = parse_ech(config, nextarg); break; - case C_CAPATH: /* --capath */ - err = getstr(&config->capath, nextarg, DENY_BLANK); - break; case C_PUBKEY: /* --pubkey */ err = getstr(&config->pubkey, nextarg, DENY_BLANK); break; @@ -2567,9 +2637,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, else err = getstr(&config->hostpubsha256, nextarg, DENY_BLANK); break; - case C_CRLFILE: /* --crlfile */ - err = getstr(&config->crlfile, nextarg, DENY_BLANK); - break; case C_TLSUSER: /* --tlsuser */ if(!feature_tls_srp) err = PARAM_LIBCURL_DOESNT_SUPPORT; @@ -2597,12 +2664,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_PROXY_PINNEDPUBKEY: /* --proxy-pinnedpubkey */ err = getstr(&config->proxy_pinnedpubkey, nextarg, DENY_BLANK); break; - case C_SSL_SESSIONS: /* --ssl-sessions */ - if(feature_ssls_export) - err = getstr(&global->ssl_sessions, nextarg, DENY_BLANK); - else - err = PARAM_LIBCURL_DOESNT_SUPPORT; - break; case C_PROXY_TLSUSER: /* --proxy-tlsuser */ if(!feature_tls_srp) err = PARAM_LIBCURL_DOESNT_SUPPORT; @@ -2625,16 +2686,9 @@ static ParameterError opt_filestring(struct OperationConfig *config, err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ } break; - case C_PROXY_CERT: /* --proxy-cert */ - GetFileAndPassword(nextarg, &config->proxy_cert, - &config->proxy_key_passwd); - break; case C_PROXY_CERT_TYPE: /* --proxy-cert-type */ err = getstr(&config->proxy_cert_type, nextarg, DENY_BLANK); break; - case C_PROXY_KEY: /* --proxy-key */ - err = getstr(&config->proxy_key, nextarg, ALLOW_BLANK); - break; case C_PROXY_KEY_TYPE: /* --proxy-key-type */ err = getstr(&config->proxy_key_type, nextarg, DENY_BLANK); break; @@ -2644,34 +2698,9 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_PROXY_CIPHERS: /* --proxy-ciphers */ err = getstr(&config->proxy_cipher_list, nextarg, DENY_BLANK); break; - case C_PROXY_CRLFILE: /* --proxy-crlfile */ - err = getstr(&config->proxy_crlfile, nextarg, DENY_BLANK); - break; case C_LOGIN_OPTIONS: /* --login-options */ err = getstr(&config->login_options, nextarg, ALLOW_BLANK); break; - case C_PROXY_CACERT: /* --proxy-cacert */ - err = getstr(&config->proxy_cacert, nextarg, DENY_BLANK); - break; - case C_PROXY_CAPATH: /* --proxy-capath */ - err = getstr(&config->proxy_capath, nextarg, DENY_BLANK); - break; - case C_ETAG_SAVE: /* --etag-save */ - if(config->num_urls > 1) { - errorf("The etag options only work on a single URL"); - err = PARAM_BAD_USE; - } - else - err = getstr(&config->etag_save_file, nextarg, DENY_BLANK); - break; - case C_ETAG_COMPARE: /* --etag-compare */ - if(config->num_urls > 1) { - errorf("The etag options only work on a single URL"); - err = PARAM_BAD_USE; - } - else - err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK); - break; case C_CURVES: /* --curves */ err = getstr(&config->ssl_ec_curves, nextarg, DENY_BLANK); break; @@ -2695,25 +2724,13 @@ static ParameterError opt_filestring(struct OperationConfig *config, case C_PROXY_HEADER: /* --proxy-header */ err = parse_header(config, (cmdline_t)a->cmd, nextarg); break; - case C_CONFIG: /* --config */ - if(parseconfig(nextarg)) { - errorf("cannot read config from '%s'", nextarg); - err = PARAM_READ_ERROR; - } - break; case C_MAX_TIME: /* --max-time */ /* specified max time */ err = secs2ms(&config->timeout_ms, nextarg); break; - case C_NETRC_FILE: /* --netrc-file */ - err = getstr(&config->netrc_file, nextarg, DENY_BLANK); - break; case C_OUTPUT_DIR: /* --output-dir */ err = getstr(&config->output_dir, nextarg, DENY_BLANK); break; - case C_OUTPUT: /* --output */ - err = parse_output(config, nextarg); - break; case C_FTP_PORT: /* --ftp-port */ /* This makes the FTP sessions use PORT instead of PASV */ /* use or <192.168.10.10> style addresses. Anything except @@ -2736,9 +2753,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, /* Telnet options */ err = add2list(&config->telnet_options, nextarg); break; - case C_UPLOAD_FILE: /* --upload-file */ - err = parse_upload_file(config, nextarg); - break; case C_USER: /* --user */ /* user:password */ err = getstr(&config->userpwd, nextarg, ALLOW_BLANK); @@ -2947,18 +2961,14 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ break; } - if((ARGTYPE(a->desc) == ARG_FILE) && - (nextarg[0] == '-') && nextarg[1]) { - /* if the filename looks like a command line option */ - warnf("The filename argument '%s' looks like a flag.", - nextarg); - } - else if(has_leading_unicode((const unsigned char *)nextarg)) { + if(has_leading_unicode((const unsigned char *)nextarg)) { warnf("The argument '%s' starts with a Unicode character. " "Maybe ASCII was intended?", nextarg); } - /* ARG_FILE | ARG_STRG */ - err = opt_filestring(config, a, nextarg); + if(ARGTYPE(a->desc) == ARG_FILE) + err = opt_file(config, a, nextarg); + else /* if(ARGTYPE(a->desc) == ARG_STRG) */ + err = opt_string(config, a, nextarg); if(a->desc & ARG_CLEAR) cleanarg(CURL_UNCONST(nextarg)); } From 58bdfb4e1d643c4ba7bd8db855e3218ac7757e7c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2025 23:30:13 +0200 Subject: [PATCH 022/465] CURLOPT_SSL_VERIFYHOST.md: add see-also to two other VERIFYHOST options Closes #18548 --- docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md b/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md index 9db4d4dfd3af..b87e0a739dc4 100644 --- a/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md +++ b/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md @@ -8,6 +8,8 @@ See-also: - CURLOPT_CAINFO (3) - CURLOPT_PINNEDPUBLICKEY (3) - CURLOPT_SSL_VERIFYPEER (3) + - CURLOPT_PROXY_SSL_VERIFYHOST (3) + - CURLOPT_DOH_SSL_VERIFYHOST (3) Protocol: - TLS TLS-backend: From f7cac7cc07a45481b246c875e8113d741ba2a6e1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2025 23:28:03 +0200 Subject: [PATCH 023/465] setopt: accept *_SSL_VERIFYHOST set to 2L ... without outputing a verbose message about it. In the early days we had 2L and 1L have different functionalities. Reported-by: Jicea Bug: https://curl.se/mail/lib-2025-09/0031.html Closes #18547 --- lib/setopt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/setopt.c b/lib/setopt.c index 5adfe4dbebb0..6f98e7dce4e3 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -443,6 +443,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, long arg, bool *set) { bool enabled = !!arg; + int ok = 1; struct UserDefined *s = &data->set; switch(option) { case CURLOPT_FORBID_REUSE: @@ -619,7 +620,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, * Enable verification of the hostname in the peer certificate for proxy */ s->proxy_ssl.primary.verifyhost = enabled; - + ok = 2; /* Update the current connection proxy_ssl_config. */ Curl_ssl_conn_config_update(data, TRUE); break; @@ -723,6 +724,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, * Enable verification of the hostname in the peer certificate for DoH */ s->doh_verifyhost = enabled; + ok = 2; break; case CURLOPT_DOH_SSL_VERIFYSTATUS: /* @@ -732,6 +734,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, return CURLE_NOT_BUILT_IN; s->doh_verifystatus = enabled; + ok = 2; break; #endif /* ! CURL_DISABLE_DOH */ case CURLOPT_SSL_VERIFYHOST: @@ -743,6 +746,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, this argument took a boolean when it was not and misused it. Treat 1 and 2 the same */ s->ssl.primary.verifyhost = enabled; + ok = 2; /* Update the current connection ssl_config. */ Curl_ssl_conn_config_update(data, FALSE); @@ -844,7 +848,7 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, default: return CURLE_OK; } - if((arg > 1) || (arg < 0)) + if((arg > ok) || (arg < 0)) /* reserve other values for future use */ infof(data, "boolean setopt(%d) got unsupported argument %ld," " treated as %d", option, arg, enabled); From de3fc1d7adb78c078e4cc7ccc48e550758094ad3 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Sat, 13 Sep 2025 15:25:53 +0200 Subject: [PATCH 024/465] asyn-thrdd: drop pthread_cancel Remove use of pthread_cancel in asnyc threaded resolving. While there are system where this works, others might leak to resource leakage (memory, files, etc.). The popular nsswitch is one example where resolve code can be dragged in that is not prepared. The overall promise and mechanism of pthread_cancel() is just too brittle and the historcal design of getaddrinfo() continues to haunt us. Fixes #18532 Reported-by: Javier Blazquez Closes #18540 --- docs/libcurl/libcurl-env-dbg.md | 5 --- lib/asyn-thrdd.c | 67 +++++++-------------------------- lib/curl_threads.c | 36 ------------------ lib/curl_threads.h | 16 -------- lib/hostip.c | 19 ---------- lib/hostip.h | 4 -- tests/data/Makefile.am | 2 +- tests/data/test795 | 36 ------------------ tests/libtest/Makefile.am | 2 +- tests/libtest/test795.pl | 46 ---------------------- 10 files changed, 16 insertions(+), 217 deletions(-) delete mode 100644 tests/data/test795 delete mode 100755 tests/libtest/test795.pl diff --git a/docs/libcurl/libcurl-env-dbg.md b/docs/libcurl/libcurl-env-dbg.md index d142e94410f4..3fcc1935d5ee 100644 --- a/docs/libcurl/libcurl-env-dbg.md +++ b/docs/libcurl/libcurl-env-dbg.md @@ -83,11 +83,6 @@ When built with c-ares for name resolving, setting this environment variable to `[IP:port]` makes libcurl use that DNS server instead of the system default. This is used by the curl test suite. -## `CURL_DNS_DELAY_MS` - -Delay the DNS resolve by this many milliseconds. This is used in the test -suite to check proper handling of CURLOPT_CONNECTTIMEOUT(3). - ## `CURL_FTP_PWD_STOP` When set, the first transfer - when using ftp: - returns before sending diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index ca6830a0bee1..2edef32f7b38 100644 --- a/lib/asyn-thrdd.c +++ b/lib/asyn-thrdd.c @@ -199,14 +199,6 @@ addr_ctx_create(struct Curl_easy *data, return NULL; } -static void async_thrd_cleanup(void *arg) -{ - struct async_thrdd_addr_ctx *addr_ctx = arg; - - Curl_thread_disable_cancel(); - addr_ctx_unlink(&addr_ctx, NULL); -} - #ifdef HAVE_GETADDRINFO /* @@ -220,15 +212,6 @@ static CURL_THREAD_RETURN_T CURL_STDCALL getaddrinfo_thread(void *arg) struct async_thrdd_addr_ctx *addr_ctx = arg; bool do_abort; -/* clang complains about empty statements and the pthread_cleanup* macros - * are pretty ill defined. */ -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra-semi-stmt" -#endif - - Curl_thread_push_cleanup(async_thrd_cleanup, addr_ctx); - Curl_mutex_acquire(&addr_ctx->mutx); do_abort = addr_ctx->do_abort; Curl_mutex_release(&addr_ctx->mutx); @@ -237,9 +220,6 @@ static CURL_THREAD_RETURN_T CURL_STDCALL getaddrinfo_thread(void *arg) char service[12]; int rc; -#ifdef DEBUGBUILD - Curl_resolve_test_delay(); -#endif msnprintf(service, sizeof(service), "%d", addr_ctx->port); rc = Curl_getaddrinfo_ex(addr_ctx->hostname, service, @@ -274,11 +254,6 @@ static CURL_THREAD_RETURN_T CURL_STDCALL getaddrinfo_thread(void *arg) } - Curl_thread_pop_cleanup(); -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - addr_ctx_unlink(&addr_ctx, NULL); return 0; } @@ -293,24 +268,11 @@ static CURL_THREAD_RETURN_T CURL_STDCALL gethostbyname_thread(void *arg) struct async_thrdd_addr_ctx *addr_ctx = arg; bool do_abort; -/* clang complains about empty statements and the pthread_cleanup* macros - * are pretty ill defined. */ -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra-semi-stmt" -#endif - - Curl_thread_push_cleanup(async_thrd_cleanup, addr_ctx); - Curl_mutex_acquire(&addr_ctx->mutx); do_abort = addr_ctx->do_abort; Curl_mutex_release(&addr_ctx->mutx); if(!do_abort) { -#ifdef DEBUGBUILD - Curl_resolve_test_delay(); -#endif - addr_ctx->res = Curl_ipv4_resolve_r(addr_ctx->hostname, addr_ctx->port); if(!addr_ctx->res) { addr_ctx->sock_error = SOCKERRNO; @@ -337,12 +299,7 @@ static CURL_THREAD_RETURN_T CURL_STDCALL gethostbyname_thread(void *arg) #endif } - Curl_thread_pop_cleanup(); -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - - async_thrd_cleanup(addr_ctx); + addr_ctx_unlink(&addr_ctx, NULL); return 0; } @@ -381,12 +338,12 @@ static void async_thrdd_destroy(struct Curl_easy *data) CURL_TRC_DNS(data, "async_thrdd_destroy, thread joined"); } else { - /* thread is still running. Detach the thread while mutexed, it will - * trigger the cleanup when it releases its reference. */ + /* thread is still running. Detach it. */ Curl_thread_destroy(&addr->thread_hnd); CURL_TRC_DNS(data, "async_thrdd_destroy, thread detached"); } } + /* release our reference to the shared context */ addr_ctx_unlink(&thrdd->addr, data); } @@ -532,10 +489,12 @@ static void async_thrdd_shutdown(struct Curl_easy *data) done = addr_ctx->thrd_done; Curl_mutex_release(&addr_ctx->mutx); - DEBUGASSERT(addr_ctx->thread_hnd != curl_thread_t_null); - if(!done && (addr_ctx->thread_hnd != curl_thread_t_null)) { - CURL_TRC_DNS(data, "cancelling resolve thread"); - (void)Curl_thread_cancel(&addr_ctx->thread_hnd); + /* Wait for the thread to terminate if it is already marked done. If it is + not done yet we cannot do anything here. We had tried pthread_cancel but + it caused hanging and resource leaks (#18532). */ + if(done && (addr_ctx->thread_hnd != curl_thread_t_null)) { + Curl_thread_join(&addr_ctx->thread_hnd); + CURL_TRC_DNS(data, "async_thrdd_shutdown, thread joined"); } } @@ -553,9 +512,11 @@ static CURLcode asyn_thrdd_await(struct Curl_easy *data, if(!entry) async_thrdd_shutdown(data); - CURL_TRC_DNS(data, "resolve, wait for thread to finish"); - if(!Curl_thread_join(&addr_ctx->thread_hnd)) { - DEBUGASSERT(0); + if(addr_ctx->thread_hnd != curl_thread_t_null) { + CURL_TRC_DNS(data, "resolve, wait for thread to finish"); + if(!Curl_thread_join(&addr_ctx->thread_hnd)) { + DEBUGASSERT(0); + } } if(entry) diff --git a/lib/curl_threads.c b/lib/curl_threads.c index 2750f5ad9f78..96fd0f8a7af9 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -100,34 +100,6 @@ int Curl_thread_join(curl_thread_t *hnd) return ret; } -/* do not use pthread_cancel if: - * - pthread_cancel seems to be absent - * - on FreeBSD, as we see hangers in CI testing - * - this is a -fsanitize=thread build - * (clang sanitizer reports false positive when functions to not return) - */ -#if defined(PTHREAD_CANCEL_ENABLE) && !defined(__FreeBSD__) -#if defined(__has_feature) -# if !__has_feature(thread_sanitizer) -#define USE_PTHREAD_CANCEL -# endif -#else /* __has_feature */ -#define USE_PTHREAD_CANCEL -#endif /* !__has_feature */ -#endif /* PTHREAD_CANCEL_ENABLE && !__FreeBSD__ */ - -int Curl_thread_cancel(curl_thread_t *hnd) -{ - (void)hnd; - if(*hnd != curl_thread_t_null) -#ifdef USE_PTHREAD_CANCEL - return pthread_cancel(**hnd); -#else - return 1; /* not supported */ -#endif - return 0; -} - #elif defined(USE_THREADS_WIN32) curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T @@ -182,12 +154,4 @@ int Curl_thread_join(curl_thread_t *hnd) return ret; } -int Curl_thread_cancel(curl_thread_t *hnd) -{ - if(*hnd != curl_thread_t_null) { - return 1; /* not supported */ - } - return 0; -} - #endif /* USE_THREADS_* */ diff --git a/lib/curl_threads.h b/lib/curl_threads.h index 115277c00eaa..82f08c5fbb56 100644 --- a/lib/curl_threads.h +++ b/lib/curl_threads.h @@ -66,22 +66,6 @@ void Curl_thread_destroy(curl_thread_t *hnd); int Curl_thread_join(curl_thread_t *hnd); -int Curl_thread_cancel(curl_thread_t *hnd); - -#if defined(USE_THREADS_POSIX) && defined(PTHREAD_CANCEL_ENABLE) -#define Curl_thread_push_cleanup(a,b) pthread_cleanup_push(a,b) -#define Curl_thread_pop_cleanup() pthread_cleanup_pop(0) -#define Curl_thread_enable_cancel() \ - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) -#define Curl_thread_disable_cancel() \ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) -#else -#define Curl_thread_push_cleanup(a,b) ((void)a,(void)b) -#define Curl_thread_pop_cleanup() Curl_nop_stmt -#define Curl_thread_enable_cancel() Curl_nop_stmt -#define Curl_thread_disable_cancel() Curl_nop_stmt -#endif - #endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ #endif /* HEADER_CURL_THREADS_H */ diff --git a/lib/hostip.c b/lib/hostip.c index 2d122fb9996b..b6be2ca1f275 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -1132,10 +1132,6 @@ CURLcode Curl_resolv_timeout(struct Curl_easy *data, prev_alarm = alarm(curlx_sltoui(timeout/1000L)); } -#ifdef DEBUGBUILD - Curl_resolve_test_delay(); -#endif - #else /* !USE_ALARM_TIMEOUT */ #ifndef CURLRES_ASYNCH if(timeoutms) @@ -1639,18 +1635,3 @@ CURLcode Curl_resolver_error(struct Curl_easy *data, const char *detail) return result; } #endif /* USE_CURL_ASYNC */ - -#ifdef DEBUGBUILD -#include "curlx/wait.h" - -void Curl_resolve_test_delay(void) -{ - const char *p = getenv("CURL_DNS_DELAY_MS"); - if(p) { - curl_off_t l; - if(!curlx_str_number(&p, &l, TIME_T_MAX) && l) { - curlx_wait_ms((timediff_t)l); - } - } -} -#endif diff --git a/lib/hostip.h b/lib/hostip.h index 2f78be82c2e7..3eb82cd1498a 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -216,8 +216,4 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data, #endif -#ifdef DEBUGBUILD -void Curl_resolve_test_delay(void); -#endif - #endif /* HEADER_CURL_HOSTIP_H */ diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index daed381e4781..4523de48864f 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -112,7 +112,7 @@ test754 test755 test756 test757 test758 test759 test760 test761 test762 \ test763 \ \ test780 test781 test782 test783 test784 test785 test786 test787 test788 \ -test789 test790 test791 test792 test793 test794 test795 test796 test797 \ +test789 test790 test791 test792 test793 test794 test796 test797 \ \ test799 test800 test801 test802 test803 test804 test805 test806 test807 \ test808 test809 test810 test811 test812 test813 test814 test815 test816 \ diff --git a/tests/data/test795 b/tests/data/test795 deleted file mode 100644 index 2c98b3bcc472..000000000000 --- a/tests/data/test795 +++ /dev/null @@ -1,36 +0,0 @@ - - - -DNS - - - -# Client-side - - -http -Debug -!c-ares -!win32 - - -Delayed resolve --connect-timeout check - - -CURL_DNS_DELAY_MS=5000 - - -http://test.invalid -v --no-progress-meter --trace-config dns --connect-timeout 1 -w \%{time_total} - - - -# Verify data after the test has been "shot" - - -28 - - -%SRCDIR/libtest/test795.pl %LOGDIR/stdout%TESTNUMBER 2 >> %LOGDIR/stderr%TESTNUMBER - - - diff --git a/tests/libtest/Makefile.am b/tests/libtest/Makefile.am index 4ccfbd2b7bae..b62a359eabef 100644 --- a/tests/libtest/Makefile.am +++ b/tests/libtest/Makefile.am @@ -42,7 +42,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ include Makefile.inc EXTRA_DIST = CMakeLists.txt $(FIRST_C) $(FIRST_H) $(UTILS_C) $(UTILS_H) $(TESTS_C) \ - test307.pl test610.pl test613.pl test795.pl test1013.pl test1022.pl mk-lib1521.pl + test307.pl test610.pl test613.pl test1013.pl test1022.pl mk-lib1521.pl CFLAGS += @CURL_CFLAG_EXTRAS@ diff --git a/tests/libtest/test795.pl b/tests/libtest/test795.pl deleted file mode 100755 index 6aa793f7f65c..000000000000 --- a/tests/libtest/test795.pl +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env perl -#*************************************************************************** -# _ _ ____ _ -# 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 -# -########################################################################### -use strict; -use warnings; - -my $ok = 1; -my $exp_duration = $ARGV[1] + 0.0; - -# Read the output of curl --version -open(F, $ARGV[0]) || die "Can't open test result from $ARGV[0]\n"; -$_ = ; -chomp; -/\s*([\.\d]+)\s*/; -my $duration = $1 + 0.0; -close F; - -if ($duration <= $exp_duration) { - print "OK: duration of $duration in expected range\n"; - $ok = 0; -} -else { - print "FAILED: duration of $duration is larger than $exp_duration\n"; -} -exit $ok; From e09f45fea4fca38c5e09f858a383ad5e45a92c24 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 14 Sep 2025 23:59:41 +0200 Subject: [PATCH 025/465] dist: do not distribute `CI.md` `CI.md` slipped into the 8.15.0, 8.16.0 tarballs by accident. Remove it again and update the checker exception. Follow-up to fa3f889752e6b5034966de61a372a60773a69ca8 #17463 Closes #18549 --- .github/scripts/distfiles.sh | 4 ++-- docs/Makefile.am | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/scripts/distfiles.sh b/.github/scripts/distfiles.sh index 26370744d7fd..eaa7857af27e 100755 --- a/.github/scripts/distfiles.sh +++ b/.github/scripts/distfiles.sh @@ -19,6 +19,7 @@ gitonly=".git* ^SECURITY.md ^LICENSES/* ^docs/examples/adddocsref.pl +^docs/tests/CI.md ^docs/THANKS-filter ^projects/Windows/* ^scripts/ciconfig.pl @@ -28,8 +29,7 @@ gitonly=".git* ^scripts/delta ^scripts/installcheck.sh ^scripts/release-notes.pl -^scripts/singleuse.pl -^tests/CI.md" +^scripts/singleuse.pl" tarfiles="$(mktemp)" gitfiles="$(mktemp)" diff --git a/docs/Makefile.am b/docs/Makefile.am index 554657e8895b..65ba28c0eb50 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -42,7 +42,6 @@ CLEANFILES = $(MK_CA_DOCS) $(man_MANS) $(TEST_DOCS) endif TESTDOCS = \ - tests/CI.md \ tests/FILEFORMAT.md \ tests/HTTP.md \ tests/TEST-SUITE.md From 8de37b8cda7342e54615a9a840c076def155b023 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 15 Sep 2025 10:33:19 +0200 Subject: [PATCH 026/465] cmdline-docs: extended, clarified, refreshed Closes #18550 --- docs/cmdline-opts/abstract-unix-socket.md | 6 +++--- docs/cmdline-opts/compressed-ssh.md | 3 ++- docs/cmdline-opts/disallow-username-in-url.md | 3 +++ docs/cmdline-opts/engine.md | 7 +++++-- docs/cmdline-opts/follow.md | 4 ++++ docs/cmdline-opts/globoff.md | 3 +++ docs/cmdline-opts/http2.md | 1 + docs/cmdline-opts/http3.md | 2 ++ docs/cmdline-opts/junk-session-cookies.md | 5 ++++- docs/cmdline-opts/location.md | 4 ++++ docs/cmdline-opts/max-redirs.md | 8 +++++--- docs/cmdline-opts/proto-redir.md | 5 +++-- docs/cmdline-opts/proxy.md | 3 +-- docs/cmdline-opts/request.md | 11 ++++++----- docs/cmdline-opts/retry-connrefused.md | 6 ++++-- docs/cmdline-opts/retry.md | 13 ++++++++----- docs/cmdline-opts/sasl-ir.md | 4 +++- docs/cmdline-opts/tr-encoding.md | 5 +++++ docs/cmdline-opts/trace-ids.md | 4 ++++ docs/cmdline-opts/unix-socket.md | 5 ++++- 20 files changed, 74 insertions(+), 28 deletions(-) diff --git a/docs/cmdline-opts/abstract-unix-socket.md b/docs/cmdline-opts/abstract-unix-socket.md index 7078e642fd8b..b1b6100e1611 100644 --- a/docs/cmdline-opts/abstract-unix-socket.md +++ b/docs/cmdline-opts/abstract-unix-socket.md @@ -16,6 +16,6 @@ Example: # `--abstract-unix-socket` -Connect through an abstract Unix domain socket, instead of using the network. -Note: netstat shows the path of an abstract socket prefixed with `@`, however -the \ argument should not have this leading character. +Connect to the server through an abstract Unix domain socket, instead of using +the network. Note: netstat shows the path of an abstract socket prefixed with +`@`, however the \ argument should not have this leading character. diff --git a/docs/cmdline-opts/compressed-ssh.md b/docs/cmdline-opts/compressed-ssh.md index 955c59c2b704..07d3981b484e 100644 --- a/docs/cmdline-opts/compressed-ssh.md +++ b/docs/cmdline-opts/compressed-ssh.md @@ -16,4 +16,5 @@ Example: # `--compressed-ssh` Enable SSH compression. This is a request, not an order; the server may or may -not do it. +not do it. This allows the data to be sent compressed over the wire, and +automatically decompressed in the receiving end, to save bandwidth. diff --git a/docs/cmdline-opts/disallow-username-in-url.md b/docs/cmdline-opts/disallow-username-in-url.md index 012f2d0dc80a..0507f531cc76 100644 --- a/docs/cmdline-opts/disallow-username-in-url.md +++ b/docs/cmdline-opts/disallow-username-in-url.md @@ -16,3 +16,6 @@ Example: Exit with error if passed a URL containing a username. Probably most useful when the URL is being provided at runtime or similar. + +Accepting and using credentials in a URL is normally considered a security +hazard as they are easily leaked that way. diff --git a/docs/cmdline-opts/engine.md b/docs/cmdline-opts/engine.md index 511190023ef2..cde6949b8691 100644 --- a/docs/cmdline-opts/engine.md +++ b/docs/cmdline-opts/engine.md @@ -17,6 +17,9 @@ Example: # `--engine` -Select the OpenSSL crypto engine to use for cipher operations. Use --engine -list to print a list of build-time supported engines. Note that not all (and +Select the OpenSSL crypto engine to use for cipher operations. Use `--engine +list` to print a list of build-time supported engines. Note that not all (and possibly none) of the engines may be available at runtime. + +The OpenSSL concept "engines" has been superseded by "providers" in OpenSSL 3, +and this option should work fine to specify such as well. diff --git a/docs/cmdline-opts/follow.md b/docs/cmdline-opts/follow.md index 9d4225ab355d..47d912844180 100644 --- a/docs/cmdline-opts/follow.md +++ b/docs/cmdline-opts/follow.md @@ -9,6 +9,8 @@ Multi: boolean See-also: - request - location + - proto-redir + - max-redirs Example: - -X POST --follow $URL --- @@ -23,3 +25,5 @@ status codes 307 or 308, but may be reset to GET for 301, 302 and 303. This is subtly different than --location, as that option always set the custom method in all subsequent requests independent of response code. + +Restrict which protocols a redirect is accepted to follow with --proto-redir. diff --git a/docs/cmdline-opts/globoff.md b/docs/cmdline-opts/globoff.md index 3c8c341439d3..5ef4b2ae8843 100644 --- a/docs/cmdline-opts/globoff.md +++ b/docs/cmdline-opts/globoff.md @@ -20,3 +20,6 @@ Switch off the URL globbing function. When you set this option, you can specify URLs that contain the letters {}[] without having curl itself interpret them. Note that these letters are not normal legal URL contents but they should be encoded according to the URI standard. + +curl detects numerical IPv6 addresses when used in URLs and excludes them from +the treatment, so they can still be used without having to disable globbing. diff --git a/docs/cmdline-opts/http2.md b/docs/cmdline-opts/http2.md index ae4d26974c8b..f5180be2b533 100644 --- a/docs/cmdline-opts/http2.md +++ b/docs/cmdline-opts/http2.md @@ -14,6 +14,7 @@ See-also: - http1.1 - http3 - no-alpn + - proxy-http2 Example: - --http2 $URL --- diff --git a/docs/cmdline-opts/http3.md b/docs/cmdline-opts/http3.md index a66d7978297e..e4dfeef075be 100644 --- a/docs/cmdline-opts/http3.md +++ b/docs/cmdline-opts/http3.md @@ -33,3 +33,5 @@ still tries to proceed with an older HTTP version. The fallback performs the regular negotiation between HTTP/1 and HTTP/2. Use --http3-only for similar functionality *without* a fallback. + +curl cannot do HTTP/3 over any proxy. diff --git a/docs/cmdline-opts/junk-session-cookies.md b/docs/cmdline-opts/junk-session-cookies.md index 63971050c030..668dfce2d67f 100644 --- a/docs/cmdline-opts/junk-session-cookies.md +++ b/docs/cmdline-opts/junk-session-cookies.md @@ -18,5 +18,8 @@ Example: # `--junk-session-cookies` When curl is told to read cookies from a given file, this option makes it -discard all "session cookies". This has the same effect as if a new session is +discard all session cookies. This has the same effect as if a new session is started. Typical browsers discard session cookies when they are closed down. + +Session cookies are cookies without a set expiry time. They are meant to only +last for "a session". diff --git a/docs/cmdline-opts/location.md b/docs/cmdline-opts/location.md index 86ae7e358013..56950c2dfc1e 100644 --- a/docs/cmdline-opts/location.md +++ b/docs/cmdline-opts/location.md @@ -12,6 +12,8 @@ See-also: - resolve - alt-svc - follow + - proto-redir + - max-redirs Example: - -L $URL --- @@ -40,3 +42,5 @@ using the dedicated options for that: --post301, --post302 and --post303. The method set with --request overrides the method curl would otherwise select to use. + +Restrict which protocols a redirect is accepted to follow with --proto-redir. diff --git a/docs/cmdline-opts/max-redirs.md b/docs/cmdline-opts/max-redirs.md index 7c9f193d2c4d..02bdfaa7fb63 100644 --- a/docs/cmdline-opts/max-redirs.md +++ b/docs/cmdline-opts/max-redirs.md @@ -10,12 +10,14 @@ Added: 7.5 Multi: single See-also: - location + - follow Example: - --max-redirs 3 --location $URL --- # `--max-redirs` -Set the maximum number of redirections to follow. When --location is used, to -prevent curl from following too many redirects, by default, the limit is -set to 50 redirects. Set this option to -1 to make it unlimited. +Set the maximum number of redirections to follow. When --location or --follow +are used, this option prevents curl from following too many redirects. By +default the limit is set to 50 redirects. Set this option to -1 to make it +unlimited. diff --git a/docs/cmdline-opts/proto-redir.md b/docs/cmdline-opts/proto-redir.md index 337aa93cb682..1f75bfdfd6c9 100644 --- a/docs/cmdline-opts/proto-redir.md +++ b/docs/cmdline-opts/proto-redir.md @@ -9,8 +9,9 @@ Category: connection curl Multi: single See-also: - proto + - follow Example: - - --proto-redir =http,https $URL + - --proto-redir =http,https --follow $URL --- # `--proto-redir` @@ -20,7 +21,7 @@ not overridden by this option. See --proto for how protocols are represented. Example, allow only HTTP and HTTPS on redirect: - curl --proto-redir -all,http,https http://example.com + curl --proto-redir -all,http,https --follow http://example.com By default curl only allows HTTP, HTTPS, FTP and FTPS on redirects (added in 7.65.2). Specifying *all* or *+all* enables all protocols on diff --git a/docs/cmdline-opts/proxy.md b/docs/cmdline-opts/proxy.md index 1ed503c10844..6cd456169d34 100644 --- a/docs/cmdline-opts/proxy.md +++ b/docs/cmdline-opts/proxy.md @@ -31,8 +31,7 @@ HTTPS proxy support works with the https:// protocol prefix for OpenSSL and GnuTLS (added in 7.52.0). It also works for mbedTLS, Rustls, Schannel and wolfSSL (added in 7.87.0). -Unrecognized and unsupported proxy protocols cause an error (added in 7.52.0). -Ancient curl versions ignored unknown schemes and used http:// instead. +Unrecognized and unsupported proxy protocol schemes cause an error. If the port number is not specified in the proxy string, it is assumed to be 1080. diff --git a/docs/cmdline-opts/request.md b/docs/cmdline-opts/request.md index 86cf10deafa4..2c9d7776e587 100644 --- a/docs/cmdline-opts/request.md +++ b/docs/cmdline-opts/request.md @@ -10,8 +10,9 @@ Added: 6.0 Multi: single See-also: - request-target + - follow Example: - - -X "DELETE" $URL + - --request "DELETE" $URL - -X NLST ftp://example.com/ --- @@ -37,10 +38,10 @@ This option only changes the actual word used in the HTTP request, it does not alter the way curl behaves. For example if you want to make a proper HEAD request, using -X HEAD does not suffice. You need to use the --head option. -The method string you set with --request is used for all requests, which -if you for example use --location may cause unintended side-effects when curl -does not change request method according to the HTTP 30x response codes - and -similar. +If --location is used, the method string you set with --request is used for +all requests, which may cause unintended side-effects when curl does not +change request method according to the HTTP 30x response codes - and similar. +Consider using --follow instead in combination with --request. ## FTP Specifies a custom FTP command to use instead of *LIST* when doing file lists diff --git a/docs/cmdline-opts/retry-connrefused.md b/docs/cmdline-opts/retry-connrefused.md index 22345cd8818e..2e6ba8068696 100644 --- a/docs/cmdline-opts/retry-connrefused.md +++ b/docs/cmdline-opts/retry-connrefused.md @@ -15,5 +15,7 @@ Example: # `--retry-connrefused` -In addition to the other conditions, consider ECONNREFUSED as a transient -error too for --retry. This option is used together with --retry. +In addition to the other conditions, also consider ECONNREFUSED as a transient +error for --retry. This option is used together with --retry. Normally, a +confused connection is not considered a transient error and therefore thus not +otherwise trigger a retry. diff --git a/docs/cmdline-opts/retry.md b/docs/cmdline-opts/retry.md index 2176e8f43da1..f55d8edcca12 100644 --- a/docs/cmdline-opts/retry.md +++ b/docs/cmdline-opts/retry.md @@ -9,6 +9,8 @@ Category: curl Multi: single See-also: - retry-max-time + - retry-connrefused + - retry-delay Example: - --retry 7 $URL --- @@ -16,16 +18,17 @@ Example: # `--retry` If a transient error is returned when curl tries to perform a transfer, it -retries this number of times before giving up. Setting the number to 0 -makes curl do no retries (which is the default). Transient error means either: -a timeout, an FTP 4xx response code or an HTTP 408, 429, 500, 502, 503 or 504 +retries this number of times before giving up. Setting the number to 0 makes +curl do no retries (which is the default). Transient error means either: a +timeout, an FTP 4xx response code or an HTTP 408, 429, 500, 502, 503 or 504 response code. When curl is about to retry a transfer, it first waits one second and then for all forthcoming retries it doubles the waiting time until it reaches 10 minutes, which then remains the set fixed delay time between the rest of the -retries. By using --retry-delay you disable this exponential backoff algorithm. -See also --retry-max-time to limit the total time allowed for retries. +retries. By using --retry-delay you disable this exponential backoff +algorithm. See also --retry-max-time to limit the total time allowed for +retries. curl complies with the Retry-After: response header if one was present to know when to issue the next retry (added in 7.66.0). diff --git a/docs/cmdline-opts/sasl-ir.md b/docs/cmdline-opts/sasl-ir.md index b11137df0a63..0f759c6d1005 100644 --- a/docs/cmdline-opts/sasl-ir.md +++ b/docs/cmdline-opts/sasl-ir.md @@ -14,4 +14,6 @@ Example: # `--sasl-ir` -Enable initial response in SASL authentication. +Enable initial response in SASL authentication. Such an "initial response" is +a message sent by the client to the server after the client selects an +authentication mechanism. diff --git a/docs/cmdline-opts/tr-encoding.md b/docs/cmdline-opts/tr-encoding.md index cdd8f02d67b3..c364c07d4b23 100644 --- a/docs/cmdline-opts/tr-encoding.md +++ b/docs/cmdline-opts/tr-encoding.md @@ -17,3 +17,8 @@ Example: Request a compressed Transfer-Encoding response using one of the algorithms curl supports, and uncompress the data while receiving it. + +This method was once intended to be the way to do automatic data compression +for HTTP but for all practical purposes using Content-Encoding as done with +--compressed has superseded transfer encoding. The --tr-encoding option is +therefore often not be one you want. diff --git a/docs/cmdline-opts/trace-ids.md b/docs/cmdline-opts/trace-ids.md index b9a622260040..302631d8440e 100644 --- a/docs/cmdline-opts/trace-ids.md +++ b/docs/cmdline-opts/trace-ids.md @@ -18,3 +18,7 @@ Example: Prepend the transfer and connection identifiers to each trace or verbose line that curl displays. + +The identifiers are unique numbers assigned to each connection and transfer to +allow a user to better understand which transfer and connection each verbose +output line refers to. diff --git a/docs/cmdline-opts/unix-socket.md b/docs/cmdline-opts/unix-socket.md index 582f32dc50e1..34cc714f79df 100644 --- a/docs/cmdline-opts/unix-socket.md +++ b/docs/cmdline-opts/unix-socket.md @@ -16,4 +16,7 @@ Example: # `--unix-socket` -Connect through this Unix domain socket, instead of using the network. +Connect to the server through this Unix domain socket, instead of using the +network. + +To connect to a proxy over Unix domain socket, see --proxy. From 61b79dee7966e979cb5ae950ea773ecf4c048a62 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 15 Sep 2025 12:51:58 +0200 Subject: [PATCH 027/465] CURLOPT_TIMECONDITION.md: works for FILE and FTP as well Closes #18551 --- docs/libcurl/opts/CURLOPT_TIMECONDITION.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_TIMECONDITION.md b/docs/libcurl/opts/CURLOPT_TIMECONDITION.md index d17174c254ec..f03473f60840 100644 --- a/docs/libcurl/opts/CURLOPT_TIMECONDITION.md +++ b/docs/libcurl/opts/CURLOPT_TIMECONDITION.md @@ -9,6 +9,8 @@ See-also: - CURLOPT_TIMEVALUE (3) Protocol: - HTTP + - FILE + - FTP Added-in: 7.1 --- @@ -26,15 +28,15 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMECONDITION, long cond); # DESCRIPTION -Pass a long as parameter. This defines how the CURLOPT_TIMEVALUE(3) time -value is treated. You can set this parameter to *CURL_TIMECOND_IFMODSINCE* -or *CURL_TIMECOND_IFUNMODSINCE*. +Pass a long as parameter. This defines how the CURLOPT_TIMEVALUE(3) time value +is treated. You can set this parameter to *CURL_TIMECOND_IFMODSINCE* or +*CURL_TIMECOND_IFUNMODSINCE*. The last modification time of a file is not always known and in such instances this feature has no effect even if the given time condition would not have -been met. curl_easy_getinfo(3) with the *CURLINFO_CONDITION_UNMET* -option can be used after a transfer to learn if a zero-byte successful -"transfer" was due to this condition not matching. +been met. curl_easy_getinfo(3) with the *CURLINFO_CONDITION_UNMET* option can +be used after a transfer to learn if a zero-byte successful "transfer" was due +to this condition not matching. # DEFAULT From a4196e22493b945bc61f51767105d5922c7feb93 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 2 Sep 2025 14:20:26 +0200 Subject: [PATCH 028/465] tidy-up: whitespace Closes #18553 --- docs/examples/Makefile.example | 4 ++-- docs/examples/ephiperfifo.c | 9 --------- docs/examples/evhiperfifo.c | 8 -------- docs/examples/hiperfifo.c | 12 ------------ lib/ftp.c | 5 +---- lib/md4.c | 6 +++--- lib/md5.c | 8 ++++---- lib/memdebug.c | 10 +++++----- lib/url.c | 4 ++-- lib/vauth/digest_sspi.c | 16 ++++++++-------- lib/vauth/krb5_sspi.c | 6 +++--- lib/vauth/ntlm_sspi.c | 24 ++++++++++++------------ lib/vauth/spnego_sspi.c | 4 ++-- lib/vquic/curl_ngtcp2.c | 4 +--- lib/vquic/curl_osslq.c | 4 +--- lib/vquic/curl_quiche.c | 4 +--- lib/ws.c | 2 +- scripts/checksrc.pl | 1 - src/terminal.c | 2 +- tests/data/test1634 | 2 +- tests/data/test1635 | 2 +- tests/data/test612 | 2 +- tests/unit/unit1304.c | 2 +- 23 files changed, 51 insertions(+), 90 deletions(-) diff --git a/docs/examples/Makefile.example b/docs/examples/Makefile.example index cfb59c94ef10..9738e94bb82d 100644 --- a/docs/examples/Makefile.example +++ b/docs/examples/Makefile.example @@ -26,7 +26,7 @@ TARGET = example # Which object files that the executable consists of -OBJS= ftpget.o +OBJS = ftpget.o # What compiler to use CC = gcc @@ -48,7 +48,7 @@ LIBS = -lcurl -lsocket -lnsl -lssl -lcrypto # Link the target with all objects and libraries $(TARGET) : $(OBJS) - $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS) + $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS) # Compile the source files into object files ftpget.o : ftpget.c diff --git a/docs/examples/ephiperfifo.c b/docs/examples/ephiperfifo.c index d30b944bbc95..3fddb2b7431f 100644 --- a/docs/examples/ephiperfifo.c +++ b/docs/examples/ephiperfifo.c @@ -88,7 +88,6 @@ struct GlobalInfo { FILE *input; }; - /* Information associated with a specific easy handle */ struct ConnInfo { CURL *easy; @@ -97,7 +96,6 @@ struct ConnInfo { char error[CURL_ERROR_SIZE]; }; - /* Information associated with a specific socket */ struct SockInfo { curl_socket_t sockfd; @@ -167,7 +165,6 @@ static int multi_timer_cb(CURLM *multi, long timeout_ms, struct GlobalInfo *g) return 0; } - /* Check for completed transfers, and remove their easy handles */ static void check_multi_info(struct GlobalInfo *g) { @@ -244,7 +241,6 @@ static void timer_cb(struct GlobalInfo *g, int revents) check_multi_info(g); } - /* Clean up the SockInfo structure */ static void remsock(struct SockInfo *f, struct GlobalInfo *g) { @@ -258,7 +254,6 @@ static void remsock(struct SockInfo *f, struct GlobalInfo *g) } } - /* Assign information to a SockInfo structure */ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, struct GlobalInfo *g) @@ -284,7 +279,6 @@ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, s, strerror(errno)); } - /* Initialize a new SockInfo structure */ static void addsock(curl_socket_t s, CURL *easy, int action, struct GlobalInfo *g) @@ -324,7 +318,6 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) return 0; } - /* CURLOPT_WRITEFUNCTION */ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) { @@ -333,7 +326,6 @@ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) return size * nmemb; } - /* CURLOPT_PROGRESSFUNCTION */ static int prog_cb(void *p, double dltotal, double dlnow, double ult, double uln) @@ -346,7 +338,6 @@ static int prog_cb(void *p, double dltotal, double dlnow, double ult, return 0; } - /* Create a new easy handle, and add it to the global curl_multi */ static void new_conn(const char *url, struct GlobalInfo *g) { diff --git a/docs/examples/evhiperfifo.c b/docs/examples/evhiperfifo.c index b28f057c8242..364a0f42fefa 100644 --- a/docs/examples/evhiperfifo.c +++ b/docs/examples/evhiperfifo.c @@ -88,7 +88,6 @@ struct GlobalInfo { FILE *input; }; - /* Information associated with a specific easy handle */ struct ConnInfo { CURL *easy; @@ -97,7 +96,6 @@ struct ConnInfo { char error[CURL_ERROR_SIZE]; }; - /* Information associated with a specific socket */ struct SockInfo { curl_socket_t sockfd; @@ -164,7 +162,6 @@ static void mcode_or_die(const char *where, CURLMcode code) } } - /* Check for completed transfers, and remove their easy handles */ static void check_multi_info(struct GlobalInfo *g) { @@ -191,7 +188,6 @@ static void check_multi_info(struct GlobalInfo *g) } } - /* Called by libevent when we get action on a multi socket */ static void event_cb(EV_P_ struct ev_io *w, int revents) { @@ -240,7 +236,6 @@ static void remsock(struct SockInfo *f, struct GlobalInfo *g) } } - /* Assign information to a SockInfo structure */ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, struct GlobalInfo *g) @@ -261,7 +256,6 @@ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, ev_io_start(g->loop, &f->ev); } - /* Initialize a new SockInfo structure */ static void addsock(curl_socket_t s, CURL *easy, int action, struct GlobalInfo *g) @@ -304,7 +298,6 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) return 0; } - /* CURLOPT_WRITEFUNCTION */ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) { @@ -328,7 +321,6 @@ static int xferinfo_cb(void *p, curl_off_t dltotal, curl_off_t dlnow, return 0; } - /* Create a new easy handle, and add it to the global curl_multi */ static void new_conn(const char *url, struct GlobalInfo *g) { diff --git a/docs/examples/hiperfifo.c b/docs/examples/hiperfifo.c index 35a519b63e41..1af1eb0c72c3 100644 --- a/docs/examples/hiperfifo.c +++ b/docs/examples/hiperfifo.c @@ -88,7 +88,6 @@ struct GlobalInfo { int stopped; }; - /* Information associated with a specific easy handle */ struct ConnInfo { CURL *easy; @@ -97,7 +96,6 @@ struct ConnInfo { char error[CURL_ERROR_SIZE]; }; - /* Information associated with a specific socket */ struct SockInfo { curl_socket_t sockfd; @@ -134,7 +132,6 @@ static void mcode_or_die(const char *where, CURLMcode code) } } - /* Update the event timer after curl_multi library calls */ static int multi_timer_cb(CURLM *multi, long timeout_ms, struct GlobalInfo *g) { @@ -158,7 +155,6 @@ static int multi_timer_cb(CURLM *multi, long timeout_ms, struct GlobalInfo *g) return 0; } - /* Check for completed transfers, and remove their easy handles */ static void check_multi_info(struct GlobalInfo *g) { @@ -187,7 +183,6 @@ static void check_multi_info(struct GlobalInfo *g) event_base_loopbreak(g->evbase); } - /* Called by libevent when we get action on a multi socket */ static void event_cb(int fd, short kind, void *userp) { @@ -210,7 +205,6 @@ static void event_cb(int fd, short kind, void *userp) } } - /* Called by libevent when our timeout expires */ static void timer_cb(int fd, short kind, void *userp) { @@ -225,7 +219,6 @@ static void timer_cb(int fd, short kind, void *userp) check_multi_info(g); } - /* Clean up the SockInfo structure */ static void remsock(struct SockInfo *f) { @@ -237,7 +230,6 @@ static void remsock(struct SockInfo *f) } } - /* Assign information to a SockInfo structure */ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, struct GlobalInfo *g) @@ -256,7 +248,6 @@ static void setsock(struct SockInfo *f, curl_socket_t s, CURL *e, int act, event_add(&f->ev, NULL); } - /* Initialize a new SockInfo structure */ static void addsock(curl_socket_t s, CURL *easy, int action, struct GlobalInfo *g) @@ -296,7 +287,6 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) return 0; } - /* CURLOPT_WRITEFUNCTION */ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) { @@ -305,7 +295,6 @@ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) return size * nmemb; } - /* CURLOPT_PROGRESSFUNCTION */ static int xferinfo_cb(void *p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ult, curl_off_t uln) @@ -319,7 +308,6 @@ static int xferinfo_cb(void *p, curl_off_t dltotal, curl_off_t dlnow, return 0; } - /* Create a new easy handle, and add it to the global curl_multi */ static void new_conn(const char *url, struct GlobalInfo *g) { diff --git a/lib/ftp.c b/lib/ftp.c index 29c2f789a3e9..6c710dceb962 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -430,6 +430,7 @@ static const struct Curl_cwtype ftp_cw_lc = { }; #endif /* CURL_PREFER_LF_LINEENDS */ + /*********************************************************************** * * ftp_check_ctrl_on_data_wait() @@ -629,7 +630,6 @@ static CURLcode ftp_readresp(struct Curl_easy *data, * from a server after a command. * */ - CURLcode Curl_GetFTPResponse(struct Curl_easy *data, ssize_t *nreadp, /* return number of bytes read */ int *ftpcodep) /* return the ftp-code */ @@ -3494,7 +3494,6 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, * * BLOCKING */ - static CURLcode ftp_sendquote(struct Curl_easy *data, struct ftp_conn *ftpc, @@ -3617,7 +3616,6 @@ ftp_pasv_verbose(struct Curl_easy *data, * (which basically is only for when PASV is being sent to retry a failed * EPSV). */ - static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) { struct connectdata *conn = data->conn; @@ -3781,7 +3779,6 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) * This is the actual DO function for FTP. Get a file/directory according to * the options previously setup. */ - static CURLcode ftp_perform(struct Curl_easy *data, struct ftp_conn *ftpc, diff --git a/lib/md4.c b/lib/md4.c index b9c98d6c4aea..b30881213e95 100644 --- a/lib/md4.c +++ b/lib/md4.c @@ -342,7 +342,7 @@ static const void *my_md4_body(MD4_CTX *ctx, saved_c = c; saved_d = d; -/* Round 1 */ + /* Round 1 */ MD4_STEP(MD4_F, a, b, c, d, MD4_SET(0), 3) MD4_STEP(MD4_F, d, a, b, c, MD4_SET(1), 7) MD4_STEP(MD4_F, c, d, a, b, MD4_SET(2), 11) @@ -360,7 +360,7 @@ static const void *my_md4_body(MD4_CTX *ctx, MD4_STEP(MD4_F, c, d, a, b, MD4_SET(14), 11) MD4_STEP(MD4_F, b, c, d, a, MD4_SET(15), 19) -/* Round 2 */ + /* Round 2 */ MD4_STEP(MD4_G, a, b, c, d, MD4_GET(0) + 0x5a827999, 3) MD4_STEP(MD4_G, d, a, b, c, MD4_GET(4) + 0x5a827999, 5) MD4_STEP(MD4_G, c, d, a, b, MD4_GET(8) + 0x5a827999, 9) @@ -378,7 +378,7 @@ static const void *my_md4_body(MD4_CTX *ctx, MD4_STEP(MD4_G, c, d, a, b, MD4_GET(11) + 0x5a827999, 9) MD4_STEP(MD4_G, b, c, d, a, MD4_GET(15) + 0x5a827999, 13) -/* Round 3 */ + /* Round 3 */ MD4_STEP(MD4_H, a, b, c, d, MD4_GET(0) + 0x6ed9eba1, 3) MD4_STEP(MD4_H, d, a, b, c, MD4_GET(8) + 0x6ed9eba1, 9) MD4_STEP(MD4_H, c, d, a, b, MD4_GET(4) + 0x6ed9eba1, 11) diff --git a/lib/md5.c b/lib/md5.c index 625670965a1c..e5cc4088dac6 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -382,7 +382,7 @@ static const void *my_md5_body(my_md5_ctx *ctx, saved_c = c; saved_d = d; -/* Round 1 */ + /* Round 1 */ MD5_STEP(MD5_F, a, b, c, d, MD5_SET(0), 0xd76aa478, 7) MD5_STEP(MD5_F, d, a, b, c, MD5_SET(1), 0xe8c7b756, 12) MD5_STEP(MD5_F, c, d, a, b, MD5_SET(2), 0x242070db, 17) @@ -400,7 +400,7 @@ static const void *my_md5_body(my_md5_ctx *ctx, MD5_STEP(MD5_F, c, d, a, b, MD5_SET(14), 0xa679438e, 17) MD5_STEP(MD5_F, b, c, d, a, MD5_SET(15), 0x49b40821, 22) -/* Round 2 */ + /* Round 2 */ MD5_STEP(MD5_G, a, b, c, d, MD5_GET(1), 0xf61e2562, 5) MD5_STEP(MD5_G, d, a, b, c, MD5_GET(6), 0xc040b340, 9) MD5_STEP(MD5_G, c, d, a, b, MD5_GET(11), 0x265e5a51, 14) @@ -418,7 +418,7 @@ static const void *my_md5_body(my_md5_ctx *ctx, MD5_STEP(MD5_G, c, d, a, b, MD5_GET(7), 0x676f02d9, 14) MD5_STEP(MD5_G, b, c, d, a, MD5_GET(12), 0x8d2a4c8a, 20) -/* Round 3 */ + /* Round 3 */ MD5_STEP(MD5_H, a, b, c, d, MD5_GET(5), 0xfffa3942, 4) MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(8), 0x8771f681, 11) MD5_STEP(MD5_H, c, d, a, b, MD5_GET(11), 0x6d9d6122, 16) @@ -436,7 +436,7 @@ static const void *my_md5_body(my_md5_ctx *ctx, MD5_STEP(MD5_H, c, d, a, b, MD5_GET(15), 0x1fa27cf8, 16) MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(2), 0xc4ac5665, 23) -/* Round 4 */ + /* Round 4 */ MD5_STEP(MD5_I, a, b, c, d, MD5_GET(0), 0xf4292244, 6) MD5_STEP(MD5_I, d, a, b, c, MD5_GET(7), 0x432aff97, 10) MD5_STEP(MD5_I, c, d, a, b, MD5_GET(14), 0xab9423a7, 15) diff --git a/lib/memdebug.c b/lib/memdebug.c index c1121713ea34..0d8d39603c4d 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -321,9 +321,9 @@ curl_socket_t curl_dbg_socket(int domain, int type, int protocol, } SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, - SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf, - SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line, - const char *source) + SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf, + SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, + int line, const char *source) { SEND_TYPE_RETV rc; if(countcheck("send", line, source)) @@ -336,8 +336,8 @@ SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, } RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf, - RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line, - const char *source) + RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, + int line, const char *source) { RECV_TYPE_RETV rc; if(countcheck("recv", line, source)) diff --git a/lib/url.c b/lib/url.c index 283da6d68b50..29702296a98d 100644 --- a/lib/url.c +++ b/lib/url.c @@ -361,9 +361,9 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) struct UserDefined *set = &data->set; CURLcode result = CURLE_OK; - set->out = stdout; /* default output to stdout */ + set->out = stdout; /* default output to stdout */ set->in_set = stdin; /* default input from stdin */ - set->err = stderr; /* default stderr to stderr */ + set->err = stderr; /* default stderr to stderr */ /* use fwrite as default function to store output */ set->fwrite_func = (curl_write_callback)fwrite; diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index c74b8f865397..861c4e1cb91b 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -195,9 +195,9 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, /* Generate our response message */ status = Curl_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, - 0, 0, 0, &chlg_desc, 0, - &context, &resp_desc, &attrs, - &expiry); + 0, 0, 0, &chlg_desc, 0, + &context, &resp_desc, &attrs, + &expiry); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) @@ -591,11 +591,11 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, /* Generate our response message */ status = Curl_pSecFn->InitializeSecurityContext(&credentials, NULL, - spn, - ISC_REQ_USE_HTTP_STYLE, 0, 0, - &chlg_desc, 0, - digest->http_context, - &resp_desc, &attrs, &expiry); + spn, + ISC_REQ_USE_HTTP_STYLE, 0, 0, + &chlg_desc, 0, + digest->http_context, + &resp_desc, &attrs, &expiry); curlx_unicodefree(spn); if(status == SEC_I_COMPLETE_NEEDED || diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c index ea26f82750a6..6595ab977a79 100644 --- a/lib/vauth/krb5_sspi.c +++ b/lib/vauth/krb5_sspi.c @@ -282,8 +282,8 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, /* Get our response size information */ status = Curl_pSecFn->QueryContextAttributes(krb5->context, - SECPKG_ATTR_SIZES, - &sizes); + SECPKG_ATTR_SIZES, + &sizes); if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; @@ -392,7 +392,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, /* Encrypt the data */ status = Curl_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, - &wrap_desc, 0); + &wrap_desc, 0); if(status != SEC_E_OK) { free(padding); free(message); diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index d45e2db38e1f..101eb8abd305 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -170,11 +170,11 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, /* Generate our type-1 message */ status = Curl_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, - ntlm->spn, - 0, 0, SECURITY_NETWORK_DREP, - NULL, 0, - ntlm->context, &type_1_desc, - &attrs, &expiry); + ntlm->spn, + 0, 0, SECURITY_NETWORK_DREP, + NULL, 0, + ntlm->context, &type_1_desc, + &attrs, &expiry); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) Curl_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); @@ -308,13 +308,13 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, /* Generate our type-3 message */ status = Curl_pSecFn->InitializeSecurityContext(ntlm->credentials, - ntlm->context, - ntlm->spn, - 0, 0, SECURITY_NETWORK_DREP, - &type_2_desc, - 0, ntlm->context, - &type_3_desc, - &attrs, &expiry); + ntlm->context, + ntlm->spn, + 0, 0, SECURITY_NETWORK_DREP, + &type_2_desc, + 0, ntlm->context, + &type_3_desc, + &attrs, &expiry); if(status != SEC_E_OK) { infof(data, "NTLM handshake failure (type-3 message): Status=%lx", status); diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c index 9c4812526121..af3a9c9798c2 100644 --- a/lib/vauth/spnego_sspi.c +++ b/lib/vauth/spnego_sspi.c @@ -270,7 +270,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, if(nego->status == SEC_I_COMPLETE_NEEDED || nego->status == SEC_I_COMPLETE_AND_CONTINUE) { nego->status = (DWORD)Curl_pSecFn->CompleteAuthToken(nego->context, - &resp_desc); + &resp_desc); if(GSS_ERROR(nego->status)) { char buffer[STRERROR_LEN]; failf(data, "CompleteAuthToken failed: %s", @@ -308,7 +308,7 @@ CURLcode Curl_auth_create_spnego_message(struct negotiatedata *nego, char **outptr, size_t *outlen) { /* Base64 encode the already generated response */ - CURLcode result = curlx_base64_encode((const char *) nego->output_token, + CURLcode result = curlx_base64_encode((const char *)nego->output_token, nego->output_token_length, outptr, outlen); if(!result && (!*outptr || !*outlen)) { diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 3f7c58d08af2..4191924b5ab9 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2433,9 +2433,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, CURLcode result; const struct Curl_sockaddr_ex *sockaddr = NULL; int qfd; -static const struct alpn_spec ALPN_SPEC_H3 = { - { "h3", "h3-29" }, 2 -}; + static const struct alpn_spec ALPN_SPEC_H3 = {{ "h3", "h3-29" }, 2}; DEBUGASSERT(ctx->initialized); ctx->dcid.datalen = NGTCP2_MAX_CIDLEN; diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 3586ad0d556a..e82cbf2a3eaa 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -1161,9 +1161,7 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, const struct Curl_sockaddr_ex *peer_addr = NULL; BIO *bio = NULL; BIO_ADDR *baddr = NULL; -static const struct alpn_spec ALPN_SPEC_H3 = { - { "h3" }, 1 -}; + static const struct alpn_spec ALPN_SPEC_H3 = {{ "h3" }, 1}; DEBUGASSERT(ctx->initialized); diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 179ccf8aa1ac..8f0535d65d2a 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1256,9 +1256,7 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf, int rv; CURLcode result; const struct Curl_sockaddr_ex *sockaddr; -static const struct alpn_spec ALPN_SPEC_H3 = { - { "h3" }, 1 -}; + static const struct alpn_spec ALPN_SPEC_H3 = {{ "h3" }, 1}; DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD); DEBUGASSERT(ctx->initialized); diff --git a/lib/ws.c b/lib/ws.c index 3b654281604b..00fdeb3e97f8 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -1876,7 +1876,7 @@ CURL_EXTERN CURLcode curl_ws_start_frame(CURL *d, result = ws_enc_write_head(data, ws, &ws->enc, flags, frame_len, &ws->sendbuf); if(result) - CURL_TRC_WS(data, "curl_start_frame(), error adding frame head %d", + CURL_TRC_WS(data, "curl_start_frame(), error adding frame head %d", result); out: diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 43b819553791..574e03c13b24 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -936,7 +936,6 @@ sub scanfile { my $diff = $second - $first; checkwarn("INDENTATION", $line, length($1), $file, $ol, "not indented $indent steps (uses $diff)"); - } } } diff --git a/src/terminal.c b/src/terminal.c index 0150cd4a56ca..014e2df8c00b 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -66,7 +66,7 @@ unsigned int get_terminal_columns(void) cols = (int)ts.ws_col; #elif defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) { - HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE); + HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE); CONSOLE_SCREEN_BUFFER_INFO console_info; if((stderr_hnd != INVALID_HANDLE_VALUE) && diff --git a/tests/data/test1634 b/tests/data/test1634 index ad256348400b..ee7a50871aa7 100644 --- a/tests/data/test1634 +++ b/tests/data/test1634 @@ -48,7 +48,7 @@ http --retry with a 429 response and Retry-After: and --fail -http://%HOSTIP:%HTTPPORT/%TESTNUMBER --retry 1 --fail +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --retry 1 --fail diff --git a/tests/data/test1635 b/tests/data/test1635 index 399846c004fe..751d46232c8b 100644 --- a/tests/data/test1635 +++ b/tests/data/test1635 @@ -37,7 +37,7 @@ http --retry with a 429 response and Retry-After: and --fail-with-body -http://%HOSTIP:%HTTPPORT/%TESTNUMBER --retry 1 --fail-with-body +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --retry 1 --fail-with-body diff --git a/tests/data/test612 b/tests/data/test612 index 7ab5c80d65b3..899496146683 100644 --- a/tests/data/test612 +++ b/tests/data/test612 @@ -24,7 +24,7 @@ sftp SFTP post-quote remove file ---key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -T %LOGDIR/file%TESTNUMBER.txt -Q "-rm %SFTP_PWD/%LOGDIR/upload.%TESTNUMBER" sftp://%HOSTIP:%SSHPORT%SFTP_PWD/%LOGDIR/upload.%TESTNUMBER --insecure +--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -T %LOGDIR/file%TESTNUMBER.txt -Q "-rm %SFTP_PWD/%LOGDIR/upload.%TESTNUMBER" sftp://%HOSTIP:%SSHPORT%SFTP_PWD/%LOGDIR/upload.%TESTNUMBER --insecure Dummy test file for remove test diff --git a/tests/unit/unit1304.c b/tests/unit/unit1304.c index 250a2ee3f61c..041ce42691dd 100644 --- a/tests/unit/unit1304.c +++ b/tests/unit/unit1304.c @@ -159,8 +159,8 @@ static CURLcode test_unit1304(const char *arg) * with login[0] != 0. */ free(password); - free(login); password = NULL; + free(login); login = NULL; Curl_netrc_init(&store); result = Curl_parsenetrc(&store, From ac24e0a80e80f7a5f06aacd4696b185856fdb3ec Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 15 Sep 2025 15:21:30 +0200 Subject: [PATCH 029/465] GHA/codeql: tidy up config names Before this patch there was a single C config detected, named `build:`. Closes #18555 --- .github/workflows/codeql.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e33540959543..8d23d6bac272 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ concurrency: permissions: {} jobs: - codeql: + gha_python: name: 'GHA and Python' runs-on: ubuntu-latest permissions: @@ -61,23 +61,19 @@ jobs: uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 c: - name: 'C (${{ matrix.build.name }})' - runs-on: ${{ matrix.build.image }} + name: 'C' + runs-on: ${{ matrix.platform == 'Linux' && 'ubuntu-latest' || 'windows-2022' }} permissions: security-events: write # To create/update security events strategy: fail-fast: false matrix: - build: - - name: 'Linux' - image: ubuntu-latest - - name: 'Windows' - image: windows-2022 + platform: [Linux, Windows] env: - MATRIX_IMAGE: '${{ matrix.build.image }}' + MATRIX_PLATFORM: '${{ matrix.platform }}' steps: - name: 'install prereqs' - if: ${{ contains(matrix.build.image, 'ubuntu') }} + if: ${{ matrix.platform == 'Linux' }} timeout-minutes: 5 run: | sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list @@ -99,7 +95,7 @@ jobs: timeout-minutes: 10 shell: bash run: | - if [[ "${MATRIX_IMAGE}" = *'windows'* ]]; then + if [ "${MATRIX_PLATFORM}" = 'Windows' ]; then cmake -B . -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_VS_GLOBALS=TrackFileAccess=false \ -DCURL_USE_SCHANNEL=ON -DCURL_USE_LIBPSL=OFF -DUSE_WIN32_IDN=ON From 56d3bb78bedf200ac093b0ec8f75845b3f7cbb7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:56:28 +0000 Subject: [PATCH 030/465] GHA: bump actions/checkout from 4.2.2 to 5.0.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 5.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.2.2...08c6903cd8c0fde910a37f88322edcfb5dd907a8) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Closes #18556 --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8d23d6bac272..9993d92cacf1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -47,7 +47,7 @@ jobs: permissions: security-events: write # To create/update security events steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 with: persist-credentials: false @@ -81,7 +81,7 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 with: persist-credentials: false From 98d5321530e498d66756c1e2b2ef449b8cfc762c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 12:00:44 +0000 Subject: [PATCH 031/465] GHA: Update nghttp2/nghttp2 to v1.67.1 Closes #18552 --- .github/workflows/http3-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 195437182f11..2fe8b8cdbba6 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -60,7 +60,7 @@ env: # renovate: datasource=github-tags depName=ngtcp2/ngtcp2 versioning=semver registryUrl=https://github.com NGTCP2_VERSION: 1.15.1 # renovate: datasource=github-tags depName=nghttp2/nghttp2 versioning=semver registryUrl=https://github.com - NGHTTP2_VERSION: 1.67.0 + NGHTTP2_VERSION: 1.67.1 # renovate: datasource=github-tags depName=cloudflare/quiche versioning=semver registryUrl=https://github.com QUICHE_VERSION: 0.24.6 From af7d67d3c03329116e593d999851d2cc3ebbf119 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 16 Sep 2025 10:27:42 +0200 Subject: [PATCH 032/465] krb5: return appropriate error on send failures Closes #18561 --- lib/krb5.c | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/lib/krb5.c b/lib/krb5.c index 563d724bbbc8..b041d2f2277e 100644 --- a/lib/krb5.c +++ b/lib/krb5.c @@ -620,16 +620,16 @@ static CURLcode sec_recv(struct Curl_easy *data, int sockindex, /* Send |length| bytes from |from| to the |sockindex| socket taking care of encoding and negotiating with the server. |from| can be NULL. */ -static void do_sec_send(struct Curl_easy *data, struct connectdata *conn, - int sockindex, const char *from, size_t length) +static CURLcode do_sec_send(struct Curl_easy *data, struct connectdata *conn, + int sockindex, const char *from, size_t length) { int bytes, htonl_bytes; /* 32-bit integers for htonl */ char *buffer = NULL; char *cmd_buffer; size_t cmd_size = 0; - CURLcode error; enum protection_level prot_level = conn->data_prot; bool iscmd = (prot_level == PROT_CMD); + CURLcode result = CURLE_OK; DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST); @@ -642,36 +642,40 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn, bytes = conn->mech->encode(conn->app_data, from, (int)length, (int)prot_level, (void **)&buffer); if(!buffer || bytes <= 0) - return; /* error */ + return CURLE_OUT_OF_MEMORY; /* error */ if(iscmd) { - error = curlx_base64_encode(buffer, curlx_sitouz(bytes), - &cmd_buffer, &cmd_size); - if(error) { + result = curlx_base64_encode(buffer, curlx_sitouz(bytes), + &cmd_buffer, &cmd_size); + if(result) { free(buffer); - return; /* error */ + return result; /* error */ } if(cmd_size > 0) { static const char *enc = "ENC "; static const char *mic = "MIC "; if(prot_level == PROT_PRIVATE) - socket_write(data, sockindex, enc, 4); + result = socket_write(data, sockindex, enc, 4); else - socket_write(data, sockindex, mic, 4); - - socket_write(data, sockindex, cmd_buffer, cmd_size); - socket_write(data, sockindex, "\r\n", 2); - infof(data, "Send: %s%s", prot_level == PROT_PRIVATE ? enc : mic, - cmd_buffer); - free(cmd_buffer); + result = socket_write(data, sockindex, mic, 4); + if(!result) + result = socket_write(data, sockindex, cmd_buffer, cmd_size); + if(!result) + result = socket_write(data, sockindex, "\r\n", 2); + if(!result) + infof(data, "Send: %s%s", prot_level == PROT_PRIVATE ? enc : mic, + cmd_buffer); } + free(cmd_buffer); } else { htonl_bytes = (int)htonl((OM_uint32)bytes); - socket_write(data, sockindex, &htonl_bytes, sizeof(htonl_bytes)); - socket_write(data, sockindex, buffer, curlx_sitouz(bytes)); + result = socket_write(data, sockindex, &htonl_bytes, sizeof(htonl_bytes)); + if(!result) + result = socket_write(data, sockindex, buffer, curlx_sitouz(bytes)); } free(buffer); + return result; } static CURLcode sec_write(struct Curl_easy *data, int sockindex, @@ -685,11 +689,13 @@ static CURLcode sec_write(struct Curl_easy *data, int sockindex, if(len <= 0) len = length; while(length) { + CURLcode result; if(length < len) len = length; - /* WTF: this ignores all errors writing to the socket */ - do_sec_send(data, conn, sockindex, buffer, len); + result = do_sec_send(data, conn, sockindex, buffer, len); + if(result) + return result; length -= len; buffer += len; *pnwritten += len; From a333fd4411b95fc0c3061b2d675de9287b6123e0 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 15 Sep 2025 21:03:52 +0200 Subject: [PATCH 033/465] GHA/codeql: enable more build options, build servers and tunits - add HTTP/3 build with OpenSSL 3.5, nghttp3 and ngtcp2. - enable GSASL, Heimdal, rtmp, SSLS-export. - make one build MultiSSL with GnuTLS, mbedTLS, Rustls, wolfSSL. - build servers (also on Windows), and tunits. - use Linuxbrew to install build dependencies missing from Ubuntu. Coverage is now 466 C files. (was: 446) Closes #18557 --- .github/workflows/codeql.yml | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9993d92cacf1..5ff3434442f8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -79,7 +79,9 @@ jobs: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get -o Dpkg::Use-Pty=0 update sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev + sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev \ + libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev + /home/linuxbrew/.linuxbrew/bin/brew install gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 with: @@ -102,9 +104,27 @@ jobs: cmake --build . --verbose src/Debug/curl.exe --disable --version else - cmake -B . -G Ninja - cmake --build . --verbose - src/curl --disable --version + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + + # MultiSSL + export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix mbedtls)/lib/pkgconfig:$(brew --prefix rustls-ffi)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" + cmake -B _bld1 -G Ninja \ + -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DCURL_USE_WOLFSSL=ON \ + -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON + cmake --build _bld1 --verbose + cmake --build _bld1 --verbose --target servers + cmake --build _bld1 --verbose --target tunits + + # HTTP/3 + export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix libnghttp3)/lib/pkgconfig:$(brew --prefix libngtcp2)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" + cmake -B _bld2 -G Ninja \ + -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR="$(brew --prefix openssl)" -DUSE_NGTCP2=ON \ + -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON + cmake --build _bld2 --verbose + cmake --build _bld2 --verbose --target servers + + _bld1/src/curl --disable --version + _bld2/src/curl --disable --version fi - name: 'perform analysis' From f6ddc1fc1e25ff8ea866f90942719af898d0ef0c Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 15 Sep 2025 15:01:54 +0200 Subject: [PATCH 034/465] Makefile.example: simplify and make it configurable - build in a single step. - allow overriding all variables: source, target, compiler, libpaths, libs, flags. Example: ```shell LIBS= LDFLAGS= SRC=altsvc.c make -f Makefile.example ``` Closes #18554 --- docs/examples/Makefile.example | 37 +++++++++++++++------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/docs/examples/Makefile.example b/docs/examples/Makefile.example index 9738e94bb82d..f2994e73e1e4 100644 --- a/docs/examples/Makefile.example +++ b/docs/examples/Makefile.example @@ -22,34 +22,29 @@ # ########################################################################### -# What to call the final executable -TARGET = example +SRC ?= ftpget.c -# Which object files that the executable consists of -OBJS = ftpget.o +# What to call the final executable +TARGET ?= example # What compiler to use -CC = gcc +CC ?= gcc -# Compiler flags, -g for debug, -c to make an object file -CFLAGS = -c -g +# Compiler flags, -g for debug +CFLAGS ?= -g -# This should point to a directory that holds libcurl, if it is not -# in the system's standard lib dir -# We also set a -L to include the directory where we have the OpenSSL -# libraries -LDFLAGS = -L/home/dast/lib -L/usr/local/ssl/lib +# This should point to a directory that holds libcurl, if it is not in the +# system's standard lib dir +# We also set a -L to include the directory where we have the OpenSSL libraries +LDFLAGS ?= -L/home/dast/lib -L/usr/local/ssl/lib -# We need -lcurl for the curl stuff # We need -lsocket and -lnsl when on Solaris -# We need -lssl and -lcrypto when using libcurl with SSL support +# We need -lssl and -lcrypto when using libcurl with TLS support # We need -lpthread for the pthread example -LIBS = -lcurl -lsocket -lnsl -lssl -lcrypto +LIBS ?= -lsocket -lnsl -lssl -lcrypto +# We need -lcurl for the curl stuff +LIBS := -lcurl $(LIBS) # Link the target with all objects and libraries -$(TARGET) : $(OBJS) - $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS) - -# Compile the source files into object files -ftpget.o : ftpget.c - $(CC) $(CFLAGS) $< +$(TARGET) : $(SRC) + $(CC) -o $(TARGET) $(CFLAGS) $(LDFLAGS) $(LIBS) $< From 619307feb09fb48feb9a24bbe5655dfcc8f17a3a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 16 Sep 2025 10:49:14 +0200 Subject: [PATCH 035/465] cmake: fix building docs when the base directory contains `.3` Fixing: ``` ninja: error: '<...>/basedir.md/_bld/docs/libcurl/libcurl-symbols.md', needed by 'docs/libcurl/curl_easy_cleanup.3', missing and no known rule to make it ``` Reported-by: Nir Azkiel Fixes #18560 Follow-up to 898b012a9bf388590c4be7f526815b5ab74feca1 #1288 Closes #18563 --- docs/libcurl/CMakeLists.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/libcurl/CMakeLists.txt b/docs/libcurl/CMakeLists.txt index 2102dd8ee3b5..bee1021f7256 100644 --- a/docs/libcurl/CMakeLists.txt +++ b/docs/libcurl/CMakeLists.txt @@ -52,11 +52,9 @@ function(curl_add_manual_pages _listname) endif() list(APPEND _rofffiles "${CMAKE_CURRENT_BINARY_DIR}/${_file}") - if(_file STREQUAL "libcurl-symbols.3") - # Special case, an auto-generated file. - string(REPLACE ".3" ".md" _mdfile "${CMAKE_CURRENT_BINARY_DIR}/${_file}") - else() - string(REPLACE ".3" ".md" _mdfile "${_file}") + string(REPLACE ".3" ".md" _mdfile "${_file}") + if(_file STREQUAL "libcurl-symbols.3") # Special case for auto-generated file + set(_mdfile "${CMAKE_CURRENT_BINARY_DIR}/${_mdfile}") endif() list(APPEND _mdfiles "${_mdfile}") endforeach() From ea752b575c6ee984fb2a4d16a9dbf0d4f1e26282 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 16 Sep 2025 12:47:27 +0200 Subject: [PATCH 036/465] sws: fix checking `sscanf()` return value Closes #18565 --- tests/server/sws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/server/sws.c b/tests/server/sws.c index 2b94e529383f..a512a7a31e26 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -330,7 +330,7 @@ static int sws_ProcessRequest(struct sws_httprequest *req) size_t npath = 0; /* httppath length */ if(sscanf(line, - "%" REQUEST_KEYWORD_SIZE_TXT"s ", request)) { + "%" REQUEST_KEYWORD_SIZE_TXT"s ", request) == 1) { http = strstr(line + strlen(request), "HTTP/"); if(http && sscanf(http, "HTTP/%d.%d", From ff8dfd315c155960836105ad719185c3b4d547bd Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 16 Sep 2025 15:49:58 +0200 Subject: [PATCH 037/465] aws-lc: re-enable large read-ahead with v1.61.0 again AWS-LC fixed a bug with large read ahead buffers in v1.61.0. Check a define introduced in that version to enable the large read ahead again. AWS-LC issue: https://github.com/aws/aws-lc/issues/2650 Closes #18568 --- lib/vtls/openssl.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 5c22ad25dc94..af890b6c5795 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -121,14 +121,11 @@ static void ossl_provider_cleanup(struct Curl_easy *data); #endif -/* - * AWS-LC has `SSL_CTX_set_default_read_buffer_len()?` but runs into - * decryption failures with large buffers. Sporadic failures in - * test_10_08 with h2 proxy uploads, increased frequency - * with CURL_DBG_SOCK_RBLOCK=50. Looks like a bug on their part. - */ +/* AWS-LC fixed a bug with large buffers in v1.61.0 which also introduced + * X509_V_ERR_EC_KEY_EXPLICIT_PARAMS. */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !defined(LIBRESSL_VERSION_NUMBER) && !defined(HAVE_BORINGSSL_LIKE) + !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) && \ + (!defined(OPENSSL_IS_AWSLC) || (defined(X509_V_ERR_EC_KEY_EXPLICIT_PARAMS))) #define HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN 1 #endif From cdb56c6666e79fff211d91ee88b0c0e9a5a0dd23 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 16 Sep 2025 16:30:08 +0200 Subject: [PATCH 038/465] docs/libcurl: clarify some timeout option behavior Closes #18569 --- docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md | 9 +++++++-- docs/libcurl/opts/CURLOPT_FTPPORT.md | 1 + .../libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md | 13 ++++++------- .../opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md | 10 +++++----- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md index 8fdbc9663247..5dd19a708b13 100644 --- a/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md +++ b/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md @@ -8,6 +8,7 @@ See-also: - CURLOPT_CONNECTTIMEOUT_MS (3) - CURLOPT_DEBUGFUNCTION (3) - CURLOPT_STDERR (3) + - CURLOPT_FTPPORT (3) Protocol: - FTP Added-in: 7.24.0 @@ -28,7 +29,11 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ACCEPTTIMEOUT_MS, long ms); # DESCRIPTION Pass a long telling libcurl the maximum number of milliseconds to wait for a -server to connect back to libcurl when an active FTP connection is used. +server to connect back to libcurl when an active FTP connection is used. When +active FTP is used, the client (libcurl) tells the server to do a TCP connect +back to the client, instead of vice versa for passive FTP. + +This option has no purpose for passive FTP. # DEFAULT @@ -45,7 +50,7 @@ int main(void) if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/path/file"); - /* wait no more than 5 seconds for FTP server responses */ + /* wait no more than 5 seconds for the FTP server to connect */ curl_easy_setopt(curl, CURLOPT_ACCEPTTIMEOUT_MS, 5000L); curl_easy_perform(curl); diff --git a/docs/libcurl/opts/CURLOPT_FTPPORT.md b/docs/libcurl/opts/CURLOPT_FTPPORT.md index c5eee3c0ac73..59e4419512c5 100644 --- a/docs/libcurl/opts/CURLOPT_FTPPORT.md +++ b/docs/libcurl/opts/CURLOPT_FTPPORT.md @@ -9,6 +9,7 @@ Protocol: See-also: - CURLOPT_FTP_USE_EPRT (3) - CURLOPT_FTP_USE_EPSV (3) + - CURLOPT_ACCEPTTIMEOUT_MS (3) Added-in: 7.1 --- diff --git a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md index 3d6ba1f9aad4..30ae25b42ac5 100644 --- a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md +++ b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md @@ -33,13 +33,12 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SERVER_RESPONSE_TIMEOUT, # DESCRIPTION -Pass a long. Causes libcurl to set a *timeout* period (in seconds) on the -amount of time that the server is allowed to take in order to send a response -message for a command before the session is considered dead. While libcurl is -waiting for a response, this value overrides CURLOPT_TIMEOUT(3). It is -recommended that if used in conjunction with CURLOPT_TIMEOUT(3), you set -CURLOPT_SERVER_RESPONSE_TIMEOUT(3) to a value smaller than -CURLOPT_TIMEOUT(3). +Pass a long. It tells libcurl to wait no longer than *timeout* seconds for +responses on sent commands. If no response is received within this period, the +connection is considered dead and the transfer fails. + +It is recommended that if used in conjunction with CURLOPT_TIMEOUT(3), you set +CURLOPT_SERVER_RESPONSE_TIMEOUT(3) to a value smaller than CURLOPT_TIMEOUT(3). This option was formerly known as CURLOPT_FTP_RESPONSE_TIMEOUT. diff --git a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md index 7acbd105ec87..267659cde2db 100644 --- a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md +++ b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md @@ -33,11 +33,11 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, # DESCRIPTION -Pass a long. Causes libcurl to set a *timeout* period (in milliseconds) on the -amount of time that the server is allowed to take in order to send a response -message for a command before the session is considered dead. While libcurl is -waiting for a response, this value overrides CURLOPT_TIMEOUT(3). It is -recommended that if used in conjunction with CURLOPT_TIMEOUT(3), you set +Pass a long. It tells libcurl to wait no longer than *timeout* milliseconds +for responses on sent commands. If no response is received within this period, +the connection is considered dead and the transfer fails. + +It is recommended that if used in conjunction with CURLOPT_TIMEOUT(3), you set CURLOPT_SERVER_RESPONSE_TIMEOUT_MS(3) to a value smaller than CURLOPT_TIMEOUT(3). From 22ac7f30ad1075295234a8f74f59f9ce9b173b1c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 12:13:10 +0000 Subject: [PATCH 039/465] GHA: update openssl/openssl to v3.5.3 Closes #18566 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 2fe8b8cdbba6..4ad880ddf6dc 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -42,7 +42,7 @@ env: MAKEFLAGS: -j 5 CURL_CI: github # handled in renovate.json - OPENSSL_VERSION: 3.5.2 + OPENSSL_VERSION: 3.5.3 # handled in renovate.json QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index ed206ec03c42..70a6a259ab8d 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -52,7 +52,7 @@ env: # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # handled in renovate.json - OPENSSL_VERSION: 3.5.2 + OPENSSL_VERSION: 3.5.3 # handled in renovate.json QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=rustls/rustls-ffi versioning=semver registryUrl=https://github.com From 3053a3e90f696dc1cfb481c61a2032dcc3b6c15c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 16 Sep 2025 16:49:54 +0200 Subject: [PATCH 040/465] docs/libcurl: use lowercase must To shout less. Use bold in some places. Closes #18570 --- docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md | 4 ++-- docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md | 6 +++--- docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md | 6 +++--- docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md | 6 +++--- docs/libcurl/opts/CURLINFO_LOCAL_IP.md | 6 +++--- docs/libcurl/opts/CURLINFO_PRIMARY_IP.md | 6 +++--- docs/libcurl/opts/CURLINFO_REFERER.md | 6 +++--- docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md | 6 +++--- docs/libcurl/opts/CURLINFO_SCHEME.md | 6 +++--- docs/libcurl/opts/CURLOPT_HEADERDATA.md | 6 +++--- docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md | 12 ++++++------ docs/libcurl/opts/CURLOPT_SHARE.md | 13 ++++++------- docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md | 2 +- docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md | 2 +- docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md | 4 ++-- docs/libcurl/opts/CURLOPT_WRITEDATA.md | 2 +- 16 files changed, 46 insertions(+), 47 deletions(-) diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md b/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md index 71e9c5122cf7..8a9093ced2ff 100644 --- a/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md +++ b/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md @@ -33,8 +33,8 @@ object. This is the value read from the Content-Type: field. If you get NULL, it means that the server did not send a valid Content-Type header or that the protocol used does not support this. -The **ct** pointer is set to NULL or pointing to private memory. You MUST -NOT free it - it gets freed when you call curl_easy_cleanup(3) on the +The **ct** pointer is NULL or points to private memory. You **must not** free +it. It gets freed automatically when you call curl_easy_cleanup(3) on the corresponding curl handle. The modern way to get this header from a response is to instead use the diff --git a/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md b/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md index 0a748063c642..5299dab8c16e 100644 --- a/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md +++ b/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md @@ -35,9 +35,9 @@ method. In cases when you have asked libcurl to follow redirects, the method may not be the same method the first request would use. -The **methodp** pointer is NULL or points to private memory. You MUST NOT -free - it gets freed when you call curl_easy_cleanup(3) on the -corresponding curl handle. +The **methodp** pointer is NULL or points to private memory. You +**must not** free it. The memory gets freed automatically when you call +curl_easy_cleanup(3) on the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md b/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md index aa5090183464..172f6de3d46b 100644 --- a/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md +++ b/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md @@ -32,9 +32,9 @@ Pass in a pointer to a char pointer and get the last used effective URL. In cases when you have asked libcurl to follow redirects, it may not be the same value you set with CURLOPT_URL(3). -The **urlp** pointer is NULL or points to private memory. You MUST NOT free -- it gets freed when you call curl_easy_cleanup(3) on the corresponding curl -handle. +The **urlp** pointer is NULL or points to private memory. You **must not** +free it. It memory gets freed automatically when you call curl_easy_cleanup(3) +on the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md index 08b5a6d336ba..db053e311e75 100644 --- a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md +++ b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md @@ -32,9 +32,9 @@ path of the entry path. That is the initial path libcurl ended up in when logging on to the remote FTP or SFTP server. This stores a NULL as pointer if something is wrong. -The **path** pointer is NULL or points to private memory. You MUST NOT free -- it gets freed when you call curl_easy_cleanup(3) on the corresponding curl -handle. +The **path** pointer is NULL or points to private memory. You **must not** +free it. The memory gets freed automatically when you call +curl_easy_cleanup(3) on the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_LOCAL_IP.md b/docs/libcurl/opts/CURLINFO_LOCAL_IP.md index a8b89914a0bc..c626815c9003 100644 --- a/docs/libcurl/opts/CURLINFO_LOCAL_IP.md +++ b/docs/libcurl/opts/CURLINFO_LOCAL_IP.md @@ -35,9 +35,9 @@ with this **curl** handle. This string may be IPv6 when that is enabled. Note that you get a pointer to a memory area that is reused at next request so you need to copy the string if you want to keep the information. -The **ip** pointer is NULL or points to private memory. You MUST NOT free - it -gets freed when you call curl_easy_cleanup(3) on the corresponding CURL -handle. +The **ip** pointer is NULL or points to private memory. You **must not** free +it. The memory gets freed automatically when you call curl_easy_cleanup(3) on +the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md b/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md index e87be53e3c73..1fdb130711e4 100644 --- a/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md +++ b/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md @@ -35,9 +35,9 @@ string holding the IP address of the most recent connection done with this get a pointer to a memory area that is reused at next request so you need to copy the string if you want to keep the information. -The **ip** pointer is NULL or points to private memory. You MUST NOT free - it -gets freed when you call curl_easy_cleanup(3) on the corresponding curl -handle. +The **ip** pointer is NULL or points to private memory. You **must not** free +it. The memory gets freed automatically when you call curl_easy_cleanup(3) on +the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_REFERER.md b/docs/libcurl/opts/CURLINFO_REFERER.md index bd278dd60348..17b9db1a18a3 100644 --- a/docs/libcurl/opts/CURLINFO_REFERER.md +++ b/docs/libcurl/opts/CURLINFO_REFERER.md @@ -31,9 +31,9 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REFERER, char **hdrp); Pass in a pointer to a char pointer and get the referrer header used in the most recent request. -The **hdrp** pointer is NULL or points to private memory you MUST NOT free - -it gets freed when you call curl_easy_cleanup(3) on the corresponding curl -handle. +The **hdrp** pointer is NULL or points to private memory. You **must not** +free it. The memory gets freed automatically when you call +curl_easy_cleanup(3) on the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md b/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md index c24f42b24d13..121642677b78 100644 --- a/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md +++ b/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md @@ -33,9 +33,9 @@ most recent RTSP Session ID. Applications wishing to resume an RTSP session on another connection should retrieve this info before closing the active connection. -The **id** pointer is NULL or points to private memory. You MUST NOT free - it -gets freed when you call curl_easy_cleanup(3) on the corresponding curl -handle. +The **id** pointer is NULL or points to private memory. You **must not** free +it. The memory gets freed automatically when you call curl_easy_cleanup(3) on +the corresponding curl handle. # %PROTOCOLS% diff --git a/docs/libcurl/opts/CURLINFO_SCHEME.md b/docs/libcurl/opts/CURLINFO_SCHEME.md index 0089531d012b..1c61849829af 100644 --- a/docs/libcurl/opts/CURLINFO_SCHEME.md +++ b/docs/libcurl/opts/CURLINFO_SCHEME.md @@ -33,9 +33,9 @@ Pass a pointer to a char pointer to receive the pointer to a null-terminated string holding the URL scheme used for the most recent connection done with this CURL **handle**. -The **scheme** pointer is NULL or points to private memory. You MUST NOT -free - it gets freed when you call curl_easy_cleanup(3) on the corresponding -curl handle. +The **scheme** pointer is NULL or points to private memory. You **must not** +free it. The memory gets freed automatically when you call +curl_easy_cleanup(3) on the corresponding curl handle. The returned scheme might be upper or lowercase. Do comparisons case insensitively. diff --git a/docs/libcurl/opts/CURLOPT_HEADERDATA.md b/docs/libcurl/opts/CURLOPT_HEADERDATA.md index bb3f2ed83474..f767961cdc37 100644 --- a/docs/libcurl/opts/CURLOPT_HEADERDATA.md +++ b/docs/libcurl/opts/CURLOPT_HEADERDATA.md @@ -36,9 +36,9 @@ If CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) is used, If neither of those options are set, *pointer* must be a valid FILE * and it is used by a plain fwrite() to write headers to. -If you are using libcurl as a Windows DLL, you **MUST** use a -CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) if you set -this option or you might experience crashes. +If you are using libcurl as a Windows DLL, you **must** use a +CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) if you set this option +or you might experience crashes. # DEFAULT diff --git a/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md b/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md index 29dc8bb4ff75..d2dda82dd8e3 100644 --- a/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md @@ -50,15 +50,15 @@ rewinding the read data stream is the only action it can request. The rewinding of the read data stream may be necessary when doing an HTTP PUT or POST with a multi-pass authentication method. -The callback MUST return *CURLIOE_UNKNOWNCMD* if the input *cmd* is -not *CURLIOCMD_RESTARTREAD*. +The callback **must** return *CURLIOE_UNKNOWNCMD* if the input *cmd* is not +*CURLIOCMD_RESTARTREAD*. -The *clientp* argument to the callback is set with the -CURLOPT_IOCTLDATA(3) option. +The *clientp* argument to the callback is set with the CURLOPT_IOCTLDATA(3) +option. **This option is deprecated**. Do not use it. Use CURLOPT_SEEKFUNCTION(3) -instead to provide seeking. If CURLOPT_SEEKFUNCTION(3) is set, this -parameter is ignored when seeking. +instead to provide seeking. If CURLOPT_SEEKFUNCTION(3) is set, this parameter +is ignored when seeking. # DEFAULT diff --git a/docs/libcurl/opts/CURLOPT_SHARE.md b/docs/libcurl/opts/CURLOPT_SHARE.md index c4488086a7e5..9b9a281e00be 100644 --- a/docs/libcurl/opts/CURLOPT_SHARE.md +++ b/docs/libcurl/opts/CURLOPT_SHARE.md @@ -26,13 +26,12 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SHARE, CURLSH *share); # DESCRIPTION -Pass a *share* handle as a parameter. The share handle must have been -created by a previous call to curl_share_init(3). Setting this option, -makes this curl handle use the data from the shared handle instead of keeping -the data to itself. This enables several curl handles to share data. If the -curl handles are used simultaneously in multiple threads, you **MUST** use -the locking methods in the share handle. See curl_share_setopt(3) for -details. +Pass a *share* handle as a parameter. The share handle must have been created +by a previous call to curl_share_init(3). Setting this option, makes this curl +handle use the data from the shared handle instead of keeping the data to +itself. This enables several curl handles to share data. If the curl handles +are used simultaneously in multiple threads, you **must** use the locking +methods in the share handle. See curl_share_setopt(3) for details. If you add a share that is set to share cookies, your easy handle uses that cookie cache and get the cookie engine enabled. If you stop sharing an object diff --git a/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md index 89422e4ef65d..0f7e9996bd57 100644 --- a/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md @@ -44,7 +44,7 @@ says what type it is, from the **CURLKHTYPE_*** series in the **clientp** is a custom pointer set with CURLOPT_SSH_HOSTKEYDATA(3). -The callback MUST return one of the following return codes to tell libcurl how +The callback must return one of the following return codes to tell libcurl how to act: ## CURLKHMATCH_OK diff --git a/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md b/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md index 636b7a3609cc..1e21b614f136 100644 --- a/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md @@ -68,7 +68,7 @@ called if CURLOPT_SSH_KNOWNHOSTS(3) is also set. This callback function gets passed the curl handle, the key from the known_hosts file *knownkey*, the key from the remote site *foundkey*, info from libcurl on the matching status and a custom pointer (set with -CURLOPT_SSH_KEYDATA(3)). It MUST return one of the following return codes to +CURLOPT_SSH_KEYDATA(3)). It must return one of the following return codes to tell libcurl how to act: ## CURLKHSTAT_FINE_REPLACE diff --git a/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md b/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md index 262c0897942e..07e7266da5c7 100644 --- a/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md +++ b/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md @@ -35,8 +35,8 @@ HTTP response sent using a compressed Transfer-Encoding that is automatically uncompressed by libcurl on reception. Transfer-Encoding differs slightly from the Content-Encoding you ask for with -CURLOPT_ACCEPT_ENCODING(3) in that a Transfer-Encoding is strictly meant -to be for the transfer and thus MUST be decoded before the data arrives in the +CURLOPT_ACCEPT_ENCODING(3) in that a Transfer-Encoding is strictly meant to be +for the transfer and thus must be decoded before the data arrives in the client. Traditionally, Transfer-Encoding has been much less used and supported by both HTTP clients and HTTP servers. diff --git a/docs/libcurl/opts/CURLOPT_WRITEDATA.md b/docs/libcurl/opts/CURLOPT_WRITEDATA.md index 5983de5d27fc..f6c6a2eeb9f1 100644 --- a/docs/libcurl/opts/CURLOPT_WRITEDATA.md +++ b/docs/libcurl/opts/CURLOPT_WRITEDATA.md @@ -36,7 +36,7 @@ to *fwrite(3)* when writing data. The internal CURLOPT_WRITEFUNCTION(3) writes the data to the FILE * given with this option, or to stdout if this option has not been set. -If you are using libcurl as a Windows DLL, you **MUST** use a +If you are using libcurl as a Windows DLL, you must also use CURLOPT_WRITEFUNCTION(3) if you set this option or you might experience crashes. From 92361999086712c7ae6ca59930cdac204e0db2a2 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 08:25:42 +0200 Subject: [PATCH 041/465] setopt: make CURLOPT_MAXREDIRS accept -1 (again) Regression from b059f7d (shipped in 8.16.0) Reported-by: Adam Light Fixes #18571 Closes #18576 --- lib/setopt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/setopt.c b/lib/setopt.c index 6f98e7dce4e3..d7a7f6c52d89 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -955,7 +955,7 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, break; case CURLOPT_MAXREDIRS: - result = value_range(&arg, -1, 0, 0x7fff); + result = value_range(&arg, -1, -1, 0x7fff); if(result) return result; s->maxredirs = (short)arg; From 04e08664a8e392b05a79cd710ef43fe0de7c1797 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 10:30:31 +0200 Subject: [PATCH 042/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 58d8fe6d02d4..c6fb253c75f3 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,24 +4,39 @@ curl and libcurl 8.16.1 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3500 + Contributors: 3502 This release includes the following changes: This release includes the following bugfixes: + o asyn-thrdd: drop pthread_cancel [30] + o aws-lc: re-enable large read-ahead with v1.61.0 again [16] + o cmake: fix building docs when the base directory contains `.3` [18] + o cmdline-docs: extended, clarified, refreshed [28] o curl_easy_getinfo: error code on NULL arg [2] o curl_mem_undef.h: limit to `CURLDEBUG` for non-memalloc overrides [19] o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] o CURLOPT_MAXLIFETIME_CONN: make default 24 hours [10] + o CURLOPT_SSL_VERIFYHOST.md: add see-also to two other VERIFYHOST options [32] + o CURLOPT_TIMECONDITION.md: works for FILE and FTP as well [27] + o dist: do not distribute `CI.md` [29] + o docs/libcurl: clarify some timeout option behavior [15] o docs/libcurl: remove ancient version references [7] + o docs/libcurl: use lowercase must [5] o easy_getinfo: check magic, Curl_close safety [3] + o krb5: return appropriate error on send failures [22] o libcurl-security.md: mention long-running connections [6] + o Makefile.example: simplify and make it configurable [20] o ngtcp2: check error code on connect failure [13] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o setopt: accept *_SSL_VERIFYHOST set to 2L [31] + o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] o ssl-sessions.md: mark option experimental [12] + o sws: fix checking `sscanf()` return value [17] + o TODO: remove already implemented or bad items [36] o urldata: FILE is not a list-only protocol [9] This release includes the following known bugs: @@ -46,16 +61,19 @@ Planned upcoming removals include: This release would not have looked like this without help, code, reports and advice from friends like these: - Andrew Kirillov, Dan Fandrich, Daniel Stenberg, Emilio Pozuelo Monfort, - Ethan Everett, fds242 on github, renovate[bot], Stefan Eissing, + Adam Light, Andrew Kirillov, Dan Fandrich, Daniel Stenberg, dependabot[bot], + Emilio Pozuelo Monfort, Ethan Everett, fds242 on github, Javier Blazquez, + Jicea, Nir Azkiel, renovate[bot], Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats - (9 contributors) + (15 contributors) References to bug reports and discussions on issues: + [1] = https://curl.se/bug/?i=18571 [2] = https://curl.se/bug/?i=18512 [3] = https://curl.se/bug/?i=18511 [4] = https://curl.se/bug/?i=18505 + [5] = https://curl.se/bug/?i=18570 [6] = https://curl.se/bug/?i=18533 [7] = https://curl.se/bug/?i=18530 [8] = https://curl.se/bug/?i=18531 @@ -64,4 +82,17 @@ References to bug reports and discussions on issues: [12] = https://curl.se/bug/?i=18523 [13] = https://curl.se/bug/?i=18521 [14] = https://curl.se/bug/?i=18518 + [15] = https://curl.se/bug/?i=18569 + [16] = https://curl.se/bug/?i=18568 + [17] = https://curl.se/bug/?i=18565 + [18] = https://curl.se/bug/?i=18560 [19] = https://curl.se/bug/?i=18510 + [20] = https://curl.se/bug/?i=18554 + [22] = https://curl.se/bug/?i=18561 + [27] = https://curl.se/bug/?i=18551 + [28] = https://curl.se/bug/?i=18550 + [29] = https://curl.se/bug/?i=18549 + [30] = https://curl.se/bug/?i=18532 + [31] = https://curl.se/mail/lib-2025-09/0031.html + [32] = https://curl.se/bug/?i=18548 + [36] = https://curl.se/bug/?i=18542 From 0a27a506b1f1ff926dd94766434dcc8ff4c12bb4 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 13:02:01 +0200 Subject: [PATCH 043/465] managen: ignore version mentions < 7.66.0 Only mention version specific details for versions from within the last six years. Closes #18583 --- scripts/managen | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/managen b/scripts/managen index 1eb536a0e6d7..768c632d4bdf 100755 --- a/scripts/managen +++ b/scripts/managen @@ -265,8 +265,8 @@ sub too_old { elsif($version =~ /^(\d+)\.(\d+)/) { $a = $1 * 1000 + $2 * 10; } - if($a < 7600) { - # we consider everything before 7.60.0 to be too old to mention + if($a < 7660) { + # we consider everything before 7.66.0 to be too old to mention # specific changes for return 1; } From dbe4e28d57f76b5ad96241bc5865d043679575d8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 11:53:33 +0200 Subject: [PATCH 044/465] managen: render better manpage references/links - When an option name is used in text, this script no longer outputs the short plus long version in the manpage output. It makes the text much more readable. This always showing both verions was previously done primarily to make sure roffit would linkify it correctly, but since roffit 0.17 it should link both long or short names correctly. - When managen outputs generic text about options at the end of the description it now highlights them properly so that they too get linkified correctly in the HTML version. For consistency. Closes #18580 --- scripts/managen | 55 ++++++++++++++++++++++++--------------------- tests/data/test1705 | 8 +++---- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/scripts/managen b/scripts/managen index 768c632d4bdf..929068067099 100755 --- a/scripts/managen +++ b/scripts/managen @@ -66,8 +66,7 @@ my $indent = 4; # get the long name version, return the manpage string sub manpageify { - my ($k)=@_; - my $l; + my ($k, $manpage)=@_; my $trail = ''; # the matching pattern might include a trailing dot that cannot be part of # the option name @@ -75,18 +74,15 @@ sub manpageify { # cut off trailing dot $trail = "."; } - my $klong = $k; - # quote "bare" minuses in the long name - $klong =~ s/-/\\-/g; - if($optlong{$k}) { - # both short + long - $l = "\\fI-".$optlong{$k}.", \\-\\-$klong\\fP$trail"; - } - else { + if($manpage) { + my $klong = $k; + # quote "bare" minuses in the long name + $klong =~ s/-/\\-/g; + # only long - $l = "\\fI\\-\\-$klong\\fP$trail"; + return "\\fI\\-\\-$klong\\fP$trail"; } - return $l; + return "--$k$trail"; } @@ -477,7 +473,7 @@ sub render { if($manpage) { if(!$quote && $d =~ /--/) { - $d =~ s/--([a-z0-9.-]+)/manpageify($1)/ge; + $d =~ s/--([a-z0-9.-]+)/manpageify($1, 1)/ge; } # quote minuses in the output @@ -741,7 +737,9 @@ sub single { } if($scope eq "global") { push @desc, "\n" if(!$manpage); - push @desc, "${pre}This option is global and does not need to be specified for each use of --next.\n"; + push @desc, + sprintf("${pre}This option is global and does not need to be specified for each use of %s.\n", + manpageify("next", $manpage)); } else { print STDERR "$f:$line:1:ERROR: unrecognized scope: '$scope'\n"; @@ -751,11 +749,15 @@ sub single { my @extra; if($multi eq "single") { - push @extra, "${pre}If --$long is provided several times, the last set ". - "value is used.\n"; + push @extra, + sprintf("${pre}If %s is provided several times, the last set ". + "value is used.\n", + manpageify($long, $manpage)); } elsif($multi eq "append") { - push @extra, "${pre}--$long can be used several times in a command line\n"; + push @extra, + sprintf("${pre}%s can be used several times in a command line\n", + manpageify($long, $manpage)); } elsif($multi eq "boolean") { my $rev = "no-$long"; @@ -767,20 +769,23 @@ sub single { } my $dashes = $manpage ? "\\-\\-" : "--"; push @extra, - "${pre}Providing --$long multiple times has no extra effect.\n". - "Disable it again with $dashes$rev.\n"; + sprintf("${pre}Providing %s multiple times has no extra effect.\n". + "Disable it again with $dashes$rev.\n", + manpageify($long, $manpage)); } elsif($multi eq "mutex") { push @extra, - "${pre}Providing --$long multiple times has no extra effect.\n"; + sprintf("${pre}Providing %s multiple times has no extra effect.\n", + manpageify($long, $manpage)); } elsif($multi eq "custom") { ; # left for the text to describe } elsif($multi eq "per-URL") { push @extra, - "${pre}--$long is associated with a single URL. Use it once per URL ". - "when you use several URLs in a command line.\n"; + sprintf("${pre}%s is associated with a single URL. Use it once per URL ". + "when you use several URLs in a command line.\n", + manpageify($long, $manpage)); } else { print STDERR "$f:$line:1:ERROR: unrecognized Multi: '$multi'\n"; @@ -804,7 +809,7 @@ sub single { if(!$helplong{$k}) { print STDERR "$f:$line:1:WARN: see-also a non-existing option: $k\n"; } - my $l = $manpage ? manpageify($k) : "--$k"; + my $l = manpageify($k, $manpage); my $sep = " and"; if($and && ($i < $and)) { $sep = ","; @@ -814,7 +819,7 @@ sub single { } if($requires) { - my $l = $manpage ? manpageify($long) : "--$long"; + my $l = manpageify($long, $manpage); push @foot, "$l requires that libcurl". " is built to support $requires.\n"; } @@ -827,7 +832,7 @@ sub single { if(!$helplong{$k}) { print STDERR "WARN: $f mutexes a non-existing option: $k\n"; } - my $l = $manpage ? manpageify($k) : "--$k"; + my $l = manpageify($k, $manpage); my $sep = ", "; if($count == ($num -1)) { $sep = " and "; diff --git a/tests/data/test1705 b/tests/data/test1705 index b56982ae40f5..7c21ffa34939 100644 --- a/tests/data/test1705 +++ b/tests/data/test1705 @@ -224,9 +224,9 @@ End with a quote hello .fi -This option is global and does not need to be specified for each use of --next. +This option is global and does not need to be specified for each use of \fI\-\-next\fP. -Providing --fakeitreal multiple times has no extra effect. +Providing \fI\-\-fakeitreal\fP multiple times has no extra effect. Disable it again with \-\-no-fakeitreal. Example: @@ -265,14 +265,14 @@ relying upon support for that protocol being built into curl to avoid an error. This option can be used multiple times, in which case the effect is the same as concatenating the protocols into one instance of the option. -If --proto is provided several times, the last set value is used. +If \fI\-\-proto\fP is provided several times, the last set value is used. Example: .nf curl --proto =http,https,sftp https://example.com .fi -See also \fI-v, \-\-fakeitreal\fP and \fI\-\-proto\-default\fP. +See also \fI\-\-fakeitreal\fP and \fI\-\-proto\-default\fP. .SH PROXY PROTOCOL PREFIXES The proxy string may be specified with a protocol:// prefix to specify alternative proxy protocols. From 0f067ba4aa30b681a0e92761e003936470340fd5 Mon Sep 17 00:00:00 2001 From: Christian Schmitz Date: Wed, 17 Sep 2025 11:04:47 +0200 Subject: [PATCH 045/465] libcurl-multi.md: added curl_multi_get_offt mention The multi interface page didn't mention the new curl_multi_get_offt function. Closes #18579 --- docs/libcurl/libcurl-multi.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/libcurl/libcurl-multi.md b/docs/libcurl/libcurl-multi.md index 3becb648defd..27f153b8ade3 100644 --- a/docs/libcurl/libcurl-multi.md +++ b/docs/libcurl/libcurl-multi.md @@ -166,7 +166,9 @@ get activity on the sockets you have been asked to wait on, or if the timeout timer expires. You can poll curl_multi_info_read(3) to see if any transfer has -completed, as it then has a message saying so. +completed, as it then has a message saying so. To know how many transfers are +currently queued, running, pending or done, you can use the +curl_multi_get_offt(3) function. # BLOCKING From 74fdc1185f40c2fe2253043ff3f563fbbd4b43ed Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Wed, 17 Sep 2025 20:33:25 +0200 Subject: [PATCH 046/465] configure: add "-mt" for pthread support on HP-UX HP-UX requires this compiler and linker flag to pass proper macros and add required libraries. Closes #18585 --- configure.ac | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index af005beffd12..3f02d037ef3d 100644 --- a/configure.ac +++ b/configure.ac @@ -4340,11 +4340,9 @@ if test "$want_threaded_resolver" = "yes" && test "$USE_THREADS_WIN32" != "1"; t AC_CHECK_FUNC(pthread_create, [USE_THREADS_POSIX=1] ) LIBS="$save_LIBS" - dnl on HP-UX, life is more complicated... case $host in *-hp-hpux*) - dnl it doesn't actually work without -lpthread - USE_THREADS_POSIX="" + CFLAGS="$CFLAGS -mt" ;; *) ;; From 3031fae3bd5135853133b95cd5396e93925a23bf Mon Sep 17 00:00:00 2001 From: Christian Schmitz Date: Wed, 17 Sep 2025 10:11:59 +0200 Subject: [PATCH 047/465] multi.h: add CURLMINFO_LASTENTRY For multiple enums, we use LASTENTRY values to do range checks when receiving an option as integer. So I added LASTENTRY, so the check will work, even if you add more options later. Closes #18578 --- include/curl/multi.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/curl/multi.h b/include/curl/multi.h index 782541f1abbd..99e4413c9fe9 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -464,7 +464,9 @@ typedef enum { * be read via `curl_multi_info_read()`. */ CURLMINFO_XFERS_DONE = 4, /* The total number of easy handles added to the multi handle, ever. */ - CURLMINFO_XFERS_ADDED = 5 + CURLMINFO_XFERS_ADDED = 5, + + CURLMINFO_LASTENTRY /* the last unused */ } CURLMinfo_offt; /* From a827e4294cee78e2169555d4d99c6c5d583d51bc Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 23:22:36 +0200 Subject: [PATCH 048/465] smtp: check EHLO responses case insensitively Adjust test 980 to announce starttls in lowercase. Fixes #18588 Reported-by: Joshua Rogers Closes #18589 --- lib/smtp.c | 8 ++++---- tests/data/test980 | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/smtp.c b/lib/smtp.c index 5dba1f9ea8c2..84ff693a3c4e 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -989,19 +989,19 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data, len -= 4; /* Does the server support the STARTTLS capability? */ - if(len >= 8 && !memcmp(line, "STARTTLS", 8)) + if(len >= 8 && curl_strnequal(line, "STARTTLS", 8)) smtpc->tls_supported = TRUE; /* Does the server support the SIZE capability? */ - else if(len >= 4 && !memcmp(line, "SIZE", 4)) + else if(len >= 4 && curl_strnequal(line, "SIZE", 4)) smtpc->size_supported = TRUE; /* Does the server support the UTF-8 capability? */ - else if(len >= 8 && !memcmp(line, "SMTPUTF8", 8)) + else if(len >= 8 && curl_strnequal(line, "SMTPUTF8", 8)) smtpc->utf8_supported = TRUE; /* Does the server support authentication? */ - else if(len >= 5 && !memcmp(line, "AUTH ", 5)) { + else if(len >= 5 && curl_strnequal(line, "AUTH ", 5)) { smtpc->auth_supported = TRUE; /* Advance past the AUTH keyword */ diff --git a/tests/data/test980 b/tests/data/test980 index 5811b437d411..8a52559472ba 100644 --- a/tests/data/test980 +++ b/tests/data/test980 @@ -10,7 +10,7 @@ STARTTLS # Server-side -CAPA STARTTLS +CAPA starttls AUTH PLAIN REPLY STARTTLS 454 currently unavailable\r\n235 Authenticated\r\n250 2.1.0 Sender ok\r\n250 2.1.5 Recipient ok\r\n354 Enter mail\r\n250 2.0.0 Accepted REPLY AUTH 535 5.7.8 Authentication credentials invalid From 20f757ef140a8466e888e6f395461a3ea73daf41 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Thu, 18 Sep 2025 06:45:12 +0500 Subject: [PATCH 049/465] tool_cb_hdr: fix fwrite check in header callback Compare fwrite result to nmemb (items), not cb (bytes). Closes #18593 --- src/tool_cb_hdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c index 6af9d1947e1e..3bb3c12dc806 100644 --- a/src/tool_cb_hdr.c +++ b/src/tool_cb_hdr.c @@ -116,7 +116,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) if(per->config->headerfile && heads->stream) { size_t rc = fwrite(ptr, size, nmemb, heads->stream); - if(rc != cb) + if(rc != nmemb) return rc; /* flush the stream to send off what we got earlier */ if(fflush(heads->stream)) { From 4e74b9f592b7e0775800f212052c18c44128f89b Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Thu, 18 Sep 2025 03:43:11 +0500 Subject: [PATCH 050/465] socks_sspi: restore non-blocking socket on error paths Closes #18592 --- lib/socks_sspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 49210585b0f0..c106fec0c8fb 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -559,6 +559,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, */ return CURLE_OK; error: + (void)curlx_nonblock(sock, TRUE); free(service_name); Curl_pSecFn->FreeCredentialsHandle(&cred_handle); Curl_pSecFn->DeleteSecurityContext(&sspi_context); From ca034e839c92570b6cece09b63624af41f39e77b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Sep 2025 08:49:22 +0200 Subject: [PATCH 051/465] tool: fix exponential retry delay Also, show retry delay with decimals since it might be not be integer seconds. Regression from da27db068fc888d7091d347080 (shipped in 8.16.0) Reported-by: Andrew Olsen Fixes #18591 Assisted-by: Jay Satiro Closes #18595 --- src/tool_cfgable.c | 1 - src/tool_cfgable.h | 3 ++- src/tool_operate.c | 21 ++++++++++++++------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index 0321848b0d5a..675f4d2d9da9 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -52,7 +52,6 @@ struct OperationConfig *config_alloc(void) config->ftp_skip_ip = TRUE; config->file_clobber_mode = CLOBBER_DEFAULT; config->upload_flags = CURLULFLAG_SEEN; - config->retry_delay_ms = RETRY_SLEEP_DEFAULT; curlx_dyn_init(&config->postdata, MAX_FILE2MEMORY); return config; } diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 5e7222a8a86d..3b2ac93a74de 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -209,7 +209,8 @@ struct OperationConfig { long httpversion; unsigned long socks5_auth;/* auth bitmask for socks5 proxies */ long req_retry; /* number of retries */ - long retry_delay_ms; /* delay between retries (in milliseconds) */ + long retry_delay_ms; /* delay between retries (in milliseconds), + 0 means increase exponentially */ long retry_maxtime_ms; /* maximum time to keep retrying */ unsigned long mime_options; /* Mime option flags. */ diff --git a/src/tool_operate.c b/src/tool_operate.c index 2c3030096f6a..4337cdee6006 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -437,7 +437,6 @@ static CURLcode retrycheck(struct OperationConfig *config, ": FTP error" }; - sleeptime = per->retry_sleep; if(RETRY_HTTP == retry) { curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after); if(retry_after) { @@ -464,20 +463,28 @@ static CURLcode retrycheck(struct OperationConfig *config, } } } + if(!sleeptime && !config->retry_delay_ms) { + if(!per->retry_sleep) + per->retry_sleep = RETRY_SLEEP_DEFAULT; + else + per->retry_sleep *= 2; + if(per->retry_sleep > RETRY_SLEEP_MAX) + per->retry_sleep = RETRY_SLEEP_MAX; + } + if(!sleeptime) + sleeptime = per->retry_sleep; warnf("Problem %s. " - "Will retry in %ld second%s. " + "Will retry in %ld%s%.*ld second%s. " "%ld retr%s left.", m[retry], sleeptime/1000L, + (sleeptime%1000L ? "." : ""), + (sleeptime%1000L ? 3 : 0), + sleeptime%1000L, (sleeptime/1000L == 1 ? "" : "s"), per->retry_remaining, (per->retry_remaining > 1 ? "ies" : "y")); per->retry_remaining--; - if(!config->retry_delay_ms) { - per->retry_sleep *= 2; - if(per->retry_sleep > RETRY_SLEEP_MAX) - per->retry_sleep = RETRY_SLEEP_MAX; - } if(outs->bytes && outs->filename && outs->stream) { #ifndef __MINGW32CE__ From 0f0821133095cf8b6efdfd98c71a09fccb34ac78 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 18 Sep 2025 11:10:45 +0200 Subject: [PATCH 052/465] cfilter: unlink and discard Rewrite the code that removes a filter from the connection and discards it. Always look at the connection, otherwise it will not work of the filter is at the top of the chain. Change QUIC filter setup code to always tear down the chain in construction when an error occured. HTTP proxy, do not remove the h1/h2 sub filter on close. Leave it to be discarded with the connection. Avoids keeping an additional pointer that might become dangling. Triggered by a reported on a code bug in discard method. Reported-by: Joshua Rogers Closes #18596 --- lib/cfilters.c | 37 +++++++++++++++++-------------------- lib/cfilters.h | 16 ++++++---------- lib/http_proxy.c | 28 ++++------------------------ lib/vquic/curl_ngtcp2.c | 20 +++++++++----------- lib/vquic/curl_osslq.c | 19 +++++++++---------- lib/vquic/curl_quiche.c | 19 +++++++++---------- lib/vtls/vtls.c | 2 +- 7 files changed, 55 insertions(+), 86 deletions(-) diff --git a/lib/cfilters.c b/lib/cfilters.c index efd2ac6f63d4..07f3c5f7b462 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -383,29 +383,26 @@ void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at, *pnext = tail; } -bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf, - struct Curl_cfilter *discard, - struct Curl_easy *data, - bool destroy_always) +bool Curl_conn_cf_discard(struct Curl_cfilter **pcf, + struct Curl_easy *data) { - struct Curl_cfilter **pprev = &cf->next; + struct Curl_cfilter *cf = pcf ? *pcf : NULL; bool found = FALSE; - - /* remove from sub-chain and destroy */ - DEBUGASSERT(cf); - while(*pprev) { - if(*pprev == cf) { - *pprev = discard->next; - discard->next = NULL; - found = TRUE; - break; + if(cf) { + if(cf->conn) { + /* unlink if present in connection filter chain */ + struct Curl_cfilter **pprev = &cf->conn->cfilter[cf->sockindex]; + while(*pprev) { + if(*pprev == *pcf) { + *pprev = (*pcf)->next; + cf->next = NULL; + found = TRUE; + break; + } + pprev = &((*pprev)->next); + } } - pprev = &((*pprev)->next); - } - if(found || destroy_always) { - discard->next = NULL; - discard->cft->destroy(discard, data); - free(discard); + Curl_conn_cf_discard_chain(pcf, data); } return found; } diff --git a/lib/cfilters.h b/lib/cfilters.h index 815b72a6e801..af38191a931d 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -297,16 +297,12 @@ void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at, struct Curl_cfilter *cf_new); /** - * Discard, e.g. remove and destroy `discard` iff - * it still is in the filter chain below `cf`. If `discard` - * is no longer found beneath `cf` return FALSE. - * if `destroy_always` is TRUE, will call `discard`s destroy - * function and free it even if not found in the subchain. - */ -bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf, - struct Curl_cfilter *discard, - struct Curl_easy *data, - bool destroy_always); + * Extract filter `*pcf` from its connection filter chain. + * Destroy `*pcf`, even if it was not part of the chain and NULL it. + * Returns TRUE of cf has been part of chain. + */ +bool Curl_conn_cf_discard(struct Curl_cfilter **pcf, + struct Curl_easy *data); /** * Discard all cfilters starting with `*pcf` and clearing it afterwards. diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 2d742856ce81..b756efe711b4 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -215,9 +215,8 @@ CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf, } struct cf_proxy_ctx { - /* the protocol specific sub-filter we install during connect */ - struct Curl_cfilter *cf_protocol; int httpversion; /* HTTP version used to CONNECT */ + BIT(sub_filter_installed); }; CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq, @@ -317,8 +316,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, return result; *done = FALSE; - if(!ctx->cf_protocol) { - struct Curl_cfilter *cf_protocol = NULL; + if(!ctx->sub_filter_installed) { int httpversion = 0; const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data); @@ -332,7 +330,6 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, result = Curl_cf_h1_proxy_insert_after(cf, data); if(result) goto out; - cf_protocol = cf->next; httpversion = 10; } else if(!alpn || !strcmp(alpn, "http/1.1")) { @@ -340,7 +337,6 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, result = Curl_cf_h1_proxy_insert_after(cf, data); if(result) goto out; - cf_protocol = cf->next; /* Assume that without an ALPN, we are talking to an ancient one */ httpversion = 11; } @@ -350,7 +346,6 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, result = Curl_cf_h2_proxy_insert_after(cf, data); if(result) goto out; - cf_protocol = cf->next; httpversion = 20; } #endif @@ -360,7 +355,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, goto out; } - ctx->cf_protocol = cf_protocol; + ctx->sub_filter_installed = TRUE; ctx->httpversion = httpversion; /* after we installed the filter "below" us, we call connect * on out sub-chain again. @@ -371,7 +366,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, /* subchain connected and we had already installed the protocol filter. * This means the protocol tunnel is established, we are done. */ - DEBUGASSERT(ctx->cf_protocol); + DEBUGASSERT(ctx->sub_filter_installed); result = CURLE_OK; } @@ -419,23 +414,8 @@ static void http_proxy_cf_destroy(struct Curl_cfilter *cf, static void http_proxy_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct cf_proxy_ctx *ctx = cf->ctx; - CURL_TRC_CF(data, cf, "close"); cf->connected = FALSE; - if(ctx->cf_protocol) { - struct Curl_cfilter *f; - /* if someone already removed it, we assume he also - * took care of destroying it. */ - for(f = cf->next; f; f = f->next) { - if(f == ctx->cf_protocol) { - /* still in our sub-chain */ - Curl_conn_cf_discard_sub(cf, ctx->cf_protocol, data, FALSE); - break; - } - } - ctx->cf_protocol = NULL; - } if(cf->next) cf->next->cft->do_close(cf->next, data); } diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 4191924b5ab9..6cadc8fc58d1 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2767,7 +2767,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, const struct Curl_addrinfo *ai) { struct cf_ngtcp2_ctx *ctx = NULL; - struct Curl_cfilter *cf = NULL, *udp_cf = NULL; + struct Curl_cfilter *cf = NULL; CURLcode result; (void)data; @@ -2781,23 +2781,21 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); if(result) goto out; + cf->conn = conn; - result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); + result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC); if(result) goto out; - - cf->conn = conn; - udp_cf->conn = cf->conn; - udp_cf->sockindex = cf->sockindex; - cf->next = udp_cf; + cf->next->conn = cf->conn; + cf->next->sockindex = cf->sockindex; out: *pcf = (!result) ? cf : NULL; if(result) { - if(udp_cf) - Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); - Curl_safefree(cf); - cf_ngtcp2_ctx_free(ctx); + if(cf) + Curl_conn_cf_discard_chain(&cf, data); + else if(ctx) + cf_ngtcp2_ctx_free(ctx); } return result; } diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index e82cbf2a3eaa..c292072a65b6 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -2398,7 +2398,7 @@ CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf, const struct Curl_addrinfo *ai) { struct cf_osslq_ctx *ctx = NULL; - struct Curl_cfilter *cf = NULL, *udp_cf = NULL; + struct Curl_cfilter *cf = NULL; CURLcode result; (void)data; @@ -2412,23 +2412,22 @@ CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf, result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); if(result) goto out; + cf->conn = conn; - result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); + result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC); if(result) goto out; - cf->conn = conn; - udp_cf->conn = cf->conn; - udp_cf->sockindex = cf->sockindex; - cf->next = udp_cf; + cf->next->conn = cf->conn; + cf->next->sockindex = cf->sockindex; out: *pcf = (!result) ? cf : NULL; if(result) { - if(udp_cf) - Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); - Curl_safefree(cf); - cf_osslq_ctx_free(ctx); + if(cf) + Curl_conn_cf_discard_chain(&cf, data); + else if(ctx) + cf_osslq_ctx_free(ctx); } return result; } diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 8f0535d65d2a..c1563c4e6309 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1636,7 +1636,7 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf, const struct Curl_addrinfo *ai) { struct cf_quiche_ctx *ctx = NULL; - struct Curl_cfilter *cf = NULL, *udp_cf = NULL; + struct Curl_cfilter *cf = NULL; CURLcode result; (void)data; @@ -1651,22 +1651,21 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf, result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); if(result) goto out; + cf->conn = conn; - result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); + result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC); if(result) goto out; - - udp_cf->conn = cf->conn; - udp_cf->sockindex = cf->sockindex; - cf->next = udp_cf; + cf->next->conn = cf->conn; + cf->next->sockindex = cf->sockindex; out: *pcf = (!result) ? cf : NULL; if(result) { - if(udp_cf) - Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); - Curl_safefree(cf); - cf_quiche_ctx_free(ctx); + if(cf) + Curl_conn_cf_discard_chain(&cf, data); + else if(ctx) + cf_quiche_ctx_free(ctx); } return result; diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index f17f9142bed1..bfec585ce210 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1862,7 +1862,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, Curl_shutdown_clear(data, sockindex); if(!result && !done) /* blocking failed? */ result = CURLE_SSL_SHUTDOWN_FAILED; - Curl_conn_cf_discard_sub(head, cf, data, FALSE); + Curl_conn_cf_discard(&cf, data); CURL_TRC_CF(data, cf, "shutdown and remove SSL, done -> %d", result); break; } From 5cc2b8344675140efc660d7a67958274c9caf590 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Sep 2025 14:49:09 +0200 Subject: [PATCH 053/465] smb: adjust buffer size checks The checks did not account for the **two byte** 16bit read so risked reading one more byte than what actually was received. Reported-by: Joshua Rogers Closes #18599 --- lib/smb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/smb.c b/lib/smb.c index 81cf6e7cc1f4..bf02119ea1db 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -1104,7 +1104,7 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done) break; case SMB_DOWNLOAD: - if(h->status || smbc->got < sizeof(struct smb_header) + 14) { + if(h->status || smbc->got < sizeof(struct smb_header) + 15) { req->result = CURLE_RECV_ERROR; next_state = SMB_CLOSE; break; @@ -1133,7 +1133,7 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done) break; case SMB_UPLOAD: - if(h->status || smbc->got < sizeof(struct smb_header) + 6) { + if(h->status || smbc->got < sizeof(struct smb_header) + 7) { req->result = CURLE_UPLOAD_FAILED; next_state = SMB_CLOSE; break; From 232d5a2ed9c091c88e3b724a1e7d6d6e6cac0079 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Sep 2025 15:02:03 +0200 Subject: [PATCH 054/465] openldap: avoid indexing the result at -1 for blank responses Reported-by: Joshua Rogers Closes #18600 --- lib/openldap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/openldap.c b/lib/openldap.c index da26d4a78d06..1f8737f5243a 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -1172,7 +1172,8 @@ static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf, if(!binary) { /* check for leading or trailing whitespace */ if(ISBLANK(bvals[i].bv_val[0]) || - ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1])) + (bvals[i].bv_len && + ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))) binval = TRUE; else { /* check for unprintable characters */ From b4922b1295333dc6679eb1d588ddc2fb6b7fd5b7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 16 Sep 2025 11:47:38 +0200 Subject: [PATCH 055/465] GHA/codeql: enable cares, debug, build curlinfo, examples Also build examples, out of curiousity, as an experiment, possibly temporary. It needs around 40 seconds. Closes #18564 --- .github/workflows/codeql.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5ff3434442f8..2344f1d16fa9 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -79,7 +79,7 @@ jobs: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get -o Dpkg::Use-Pty=0 update sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev \ + sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libc-ares-dev \ libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev /home/linuxbrew/.linuxbrew/bin/brew install gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi @@ -108,12 +108,14 @@ jobs: # MultiSSL export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix mbedtls)/lib/pkgconfig:$(brew --prefix rustls-ffi)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" - cmake -B _bld1 -G Ninja \ + cmake -B _bld1 -G Ninja -DENABLE_DEBUG=ON \ -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DCURL_USE_WOLFSSL=ON \ - -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON + -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON -DENABLE_ARES=ON cmake --build _bld1 --verbose + cmake --build _bld1 --verbose --target curlinfo cmake --build _bld1 --verbose --target servers cmake --build _bld1 --verbose --target tunits + cmake --build _bld1 --verbose --target curl-examples-build # HTTP/3 export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix libnghttp3)/lib/pkgconfig:$(brew --prefix libngtcp2)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" From 44a586472b42a288836f730b4b3b7dd5490057f6 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Sep 2025 15:50:17 +0200 Subject: [PATCH 056/465] ldap: do not base64 encode zero length string Reported-by: Joshua Rogers Closes #18602 --- lib/ldap.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/ldap.c b/lib/ldap.c index c66a56d7bb24..4b232e2bb676 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -634,22 +634,9 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) if((attr_len > 7) && (strcmp(";binary", attr + (attr_len - 7)) == 0)) { /* Binary attribute, encode to base64. */ - result = curlx_base64_encode(vals[i]->bv_val, vals[i]->bv_len, - &val_b64, &val_b64_sz); - if(result) { - ldap_value_free_len(vals); - FREE_ON_WINLDAP(attr); - ldap_memfree(attribute); - if(ber) - ber_free(ber, 0); - - goto quit; - } - - if(val_b64_sz > 0) { - result = Curl_client_write(data, CLIENTWRITE_BODY, val_b64, - val_b64_sz); - free(val_b64); + if(vals[i]->bv_len) { + result = curlx_base64_encode(vals[i]->bv_val, vals[i]->bv_len, + &val_b64, &val_b64_sz); if(result) { ldap_value_free_len(vals); FREE_ON_WINLDAP(attr); @@ -659,6 +646,21 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) goto quit; } + + if(val_b64_sz > 0) { + result = Curl_client_write(data, CLIENTWRITE_BODY, val_b64, + val_b64_sz); + free(val_b64); + if(result) { + ldap_value_free_len(vals); + FREE_ON_WINLDAP(attr); + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + } } } else { From a80abc45a572132b7f425e526cd60c0cf49f28e2 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Tue, 16 Sep 2025 23:27:23 +0500 Subject: [PATCH 057/465] sasl: clear canceled mechanism instead of toggling it Use &= ~authused in SASL_CANCEL (was ^=) to actually remove the offending mechanism and avoid re-enabling a disabled mech on retry. Closes #18573 --- lib/curl_sasl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 8eb63fb94954..9c86f3ea086e 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -812,7 +812,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, case SASL_CANCEL: /* Remove the offending mechanism from the supported list */ - sasl->authmechs ^= sasl->authused; + sasl->authmechs &= (unsigned short)~sasl->authused; + sasl->authused = SASL_AUTH_NONE; + sasl->curmech = NULL; /* Start an alternative SASL authentication */ return Curl_sasl_start(sasl, data, sasl->force_ir, progress); From f8175b1536610ec60a9d2dce5a055d59287af4d5 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Thu, 18 Sep 2025 02:07:17 -0400 Subject: [PATCH 058/465] socks_sspi: Fix some memory cleanup calls - Ensure memory allocated by malloc() is freed by free(). Prior to this change SSPI's FreeContextBuffer() was sometimes used to free malloc'd memory. I can only assume the reason we have no crash reports about this is because the underlying heap free is probably the same for both. Reported-by: Joshua Rogers Fixes https://github.com/curl/curl/issues/18587 Closes https://github.com/curl/curl/pull/18594 --- lib/socks_sspi.c | 102 +++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index c106fec0c8fb..3ff3b723f9a2 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -90,6 +90,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, unsigned char socksreq[4]; /* room for GSS-API exchange header only */ const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; + char *etbuf; + size_t etbuf_size; /* GSS-API request looks like * +----+------+-----+----------------+ @@ -131,11 +133,14 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, wrap_desc.pBuffers = sspi_w_token; wrap_desc.ulVersion = SECBUFFER_VERSION; - cred_handle.dwLower = 0; - cred_handle.dwUpper = 0; + memset(&cred_handle, 0, sizeof(cred_handle)); + memset(&sspi_context, 0, sizeof(sspi_context)); names.sUserName = NULL; + etbuf = NULL; + etbuf_size = 0; + status = Curl_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)CURL_UNCONST(TEXT("Kerberos")), @@ -178,11 +183,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, curlx_unicodefree(sname); - if(sspi_recv_token.pvBuffer) { - Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - sspi_recv_token.pvBuffer = NULL; - sspi_recv_token.cbBuffer = 0; - } + Curl_safefree(sspi_recv_token.pvBuffer); + sspi_recv_token.cbBuffer = 0; if(check_sspi_err(data, status, "InitializeSecurityContext")) { failf(data, "Failed to initialise security context."); @@ -220,10 +222,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } sspi_send_token.cbBuffer = 0; - if(sspi_recv_token.pvBuffer) { - Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - sspi_recv_token.pvBuffer = NULL; - } + Curl_safefree(sspi_recv_token.pvBuffer); sspi_recv_token.cbBuffer = 0; if(status != SEC_I_CONTINUE_NEEDED) @@ -289,7 +288,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, status = Curl_pSecFn->QueryCredentialsAttributes(&cred_handle, SECPKG_CRED_ATTR_NAMES, &names); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); if(check_sspi_err(data, status, "QueryCredentialAttributes")) { failf(data, "Failed to determine username."); result = CURLE_COULDNT_CONNECT; @@ -303,6 +301,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, curlx_unicodefree(user_utf8); #endif Curl_pSecFn->FreeContextBuffer(names.sUserName); + names.sUserName = NULL; } /* Do encryption */ @@ -399,35 +398,30 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, result = CURLE_COULDNT_CONNECT; goto error; } - sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer + - sspi_w_token[1].cbBuffer + - sspi_w_token[2].cbBuffer; - sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); - if(!sspi_send_token.pvBuffer) { + + etbuf_size = sspi_w_token[0].cbBuffer + + sspi_w_token[1].cbBuffer + + sspi_w_token[2].cbBuffer; + etbuf = malloc(etbuf_size); + if(!etbuf) { result = CURLE_OUT_OF_MEMORY; goto error; } - memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer); - memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, + memcpy(etbuf, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); + memcpy(etbuf + sspi_w_token[0].cbBuffer, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); - memcpy((PUCHAR) sspi_send_token.pvBuffer + - sspi_w_token[0].cbBuffer + - sspi_w_token[1].cbBuffer, + memcpy(etbuf + sspi_w_token[0].cbBuffer + sspi_w_token[1].cbBuffer, sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - sspi_w_token[0].pvBuffer = NULL; + Curl_safefree(sspi_w_token[0].pvBuffer); sspi_w_token[0].cbBuffer = 0; - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - sspi_w_token[1].pvBuffer = NULL; + Curl_safefree(sspi_w_token[1].pvBuffer); sspi_w_token[1].cbBuffer = 0; - Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); - sspi_w_token[2].pvBuffer = NULL; + Curl_safefree(sspi_w_token[2].pvBuffer); sspi_w_token[2].cbBuffer = 0; - us_length = htons((unsigned short)sspi_send_token.cbBuffer); + us_length = htons((unsigned short)etbuf_size); memcpy(socksreq + 2, &us_length, sizeof(short)); } @@ -450,16 +444,14 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } } else { - code = Curl_conn_cf_send(cf->next, data, - (char *)sspi_send_token.pvBuffer, - sspi_send_token.cbBuffer, FALSE, &written); - if(code || (sspi_send_token.cbBuffer != (size_t)written)) { + code = Curl_conn_cf_send(cf->next, data, etbuf, etbuf_size, + FALSE, &written); + if(code || (etbuf_size != written)) { failf(data, "Failed to send SSPI encryption type."); result = CURLE_COULDNT_CONNECT; goto error; } - if(sspi_send_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + Curl_safefree(etbuf); } result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); @@ -514,8 +506,16 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, status = Curl_pSecFn->DecryptMessage(&sspi_context, &wrap_desc, 0, &qop); + /* since sspi_w_token[1].pvBuffer is allocated by the SSPI in this case, it + must be freed in this block using FreeContextBuffer() instead of + potentially in error cleanup using free(). */ + if(check_sspi_err(data, status, "DecryptMessage")) { failf(data, "Failed to query security context attributes."); + if(sspi_w_token[1].pvBuffer) { + Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + sspi_w_token[1].pvBuffer = NULL; + } result = CURLE_COULDNT_CONNECT; goto error; } @@ -523,13 +523,20 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(sspi_w_token[1].cbBuffer != 1) { failf(data, "Invalid SSPI encryption response length (%lu).", (unsigned long)sspi_w_token[1].cbBuffer); + if(sspi_w_token[1].pvBuffer) { + Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + sspi_w_token[1].pvBuffer = NULL; + } result = CURLE_COULDNT_CONNECT; goto error; } memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + Curl_safefree(sspi_w_token[0].pvBuffer); + sspi_w_token[0].cbBuffer = 0; Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + sspi_w_token[1].pvBuffer = NULL; + sspi_w_token[1].cbBuffer = 0; } else { if(sspi_w_token[0].cbBuffer != 1) { @@ -539,7 +546,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, goto error; } memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + Curl_safefree(sspi_w_token[0].pvBuffer); + sspi_w_token[0].cbBuffer = 0; } (void)curlx_nonblock(sock, TRUE); @@ -557,24 +565,24 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, conn->socks5_sspi_context = sspi_context; } */ + + Curl_pSecFn->DeleteSecurityContext(&sspi_context); + Curl_pSecFn->FreeCredentialsHandle(&cred_handle); return CURLE_OK; error: (void)curlx_nonblock(sock, TRUE); free(service_name); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); Curl_pSecFn->DeleteSecurityContext(&sspi_context); - if(sspi_recv_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + Curl_pSecFn->FreeCredentialsHandle(&cred_handle); + free(sspi_recv_token.pvBuffer); if(sspi_send_token.pvBuffer) Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); if(names.sUserName) Curl_pSecFn->FreeContextBuffer(names.sUserName); - if(sspi_w_token[0].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - if(sspi_w_token[1].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - if(sspi_w_token[2].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); + free(sspi_w_token[0].pvBuffer); + free(sspi_w_token[1].pvBuffer); + free(sspi_w_token[2].pvBuffer); + free(etbuf); return result; } #endif From ad147ec53de822a18b5dec63b72f43688ae53869 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Wed, 17 Sep 2025 00:52:28 +0500 Subject: [PATCH 059/465] tftp: propagate expired timer from tftp_state_timeout() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Curl_timeleft() < 0 we used to return 0, masking the expiry and skipping the caller’s (timeout_ms < 0) path. Now we set FIN and return the negative value so tftp_multi_statemach() aborts with CURLE_OPERATION_TIMEDOUT as intended. Closes #18574 --- lib/tftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tftp.c b/lib/tftp.c index 4c2fadc2caf8..620ab1e70df8 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -1184,7 +1184,7 @@ static timediff_t tftp_state_timeout(struct tftp_conn *state, if(timeout_ms < 0) { state->error = TFTP_ERR_TIMEOUT; state->state = TFTP_STATE_FIN; - return 0; + return timeout_ms; } current = time(NULL); if(current > state->rx_time + state->retry_time) { From 54aff4db3c620fd1fcd7c7a7f949fd8ca3773eb8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Sep 2025 17:32:39 +0200 Subject: [PATCH 060/465] tftp: check and act on tftp_set_timeouts() returning error Reported-by: Joshua Rogers Ref: https://github.com/curl/curl/pull/18574#issuecomment-3300183302 Closes #18603 --- lib/tftp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/tftp.c b/lib/tftp.c index 620ab1e70df8..84b92ee48827 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -962,6 +962,7 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done) int need_blksize; struct connectdata *conn = data->conn; const struct Curl_sockaddr_ex *remote_addr = NULL; + CURLcode result; blksize = TFTP_BLKSIZE_DEFAULT; @@ -1013,7 +1014,9 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done) ((struct sockaddr *)&state->local_addr)->sa_family = (CURL_SA_FAMILY_T)(remote_addr->family); - tftp_set_timeouts(state); + result = tftp_set_timeouts(state); + if(result) + return result; if(!conn->bits.bound) { /* If not already bound, bind to any interface, random UDP port. If it is From ce354d0f4d251371f65f1770d95bba1d926de421 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Thu, 18 Sep 2025 11:38:20 -0400 Subject: [PATCH 061/465] tool_operate: Improve wording in retry message - Use the plural 'seconds' for anything other than exactly 1 second. Before: Will retry in 1.250 second. After: Will retry in 1.250 seconds. Follow-up to ca034e83. Closes https://github.com/curl/curl/pull/18604 --- src/tool_operate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tool_operate.c b/src/tool_operate.c index 4337cdee6006..75926d704ba4 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -480,7 +480,7 @@ static CURLcode retrycheck(struct OperationConfig *config, (sleeptime%1000L ? "." : ""), (sleeptime%1000L ? 3 : 0), sleeptime%1000L, - (sleeptime/1000L == 1 ? "" : "s"), + (sleeptime == 1000L ? "" : "s"), per->retry_remaining, (per->retry_remaining > 1 ? "ies" : "y")); From f13250edf11312ab8c0425cf39b182a31b53c6f7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 18 Sep 2025 18:50:09 +0200 Subject: [PATCH 062/465] examples: fix two issues found by CodeQL - http2-upload: use `fstat()` to query file length to fix TOCTOU. - ftpuploadresume: fix checking `sscanf()` return value. Follow-up to b4922b1295333dc6679eb1d588ddc2fb6b7fd5b7 #18564 Closes #18605 --- docs/examples/ftpuploadresume.c | 2 +- docs/examples/http2-upload.c | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/examples/ftpuploadresume.c b/docs/examples/ftpuploadresume.c index b02ad928a6dc..67495aec6870 100644 --- a/docs/examples/ftpuploadresume.c +++ b/docs/examples/ftpuploadresume.c @@ -38,7 +38,7 @@ static size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, long len = 0; r = sscanf(ptr, "Content-Length: %ld\n", &len); - if(r) + if(r == 1) *((long *) stream) = len; return size * nmemb; diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index 482889ea1857..31f4ed56e1ba 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -45,6 +45,9 @@ #ifdef _WIN32 #undef stat #define stat _stat +#undef fstat +#define fstat _fstat +#define fileno _fileno #endif /* curl stuff */ @@ -223,24 +226,27 @@ static int setup(struct input *i, int num, const char *upload) curl_msnprintf(url, 256, "https://localhost:8443/upload-%d", num); - /* get the file size of the local file */ - if(stat(upload, &file_info)) { - fprintf(stderr, "error: could not stat file %s: %s\n", upload, + i->in = fopen(upload, "rb"); + if(!i->in) { + fprintf(stderr, "error: could not open file %s for reading: %s\n", upload, strerror(errno)); fclose(out); return 1; } - uploadsize = file_info.st_size; - - i->in = fopen(upload, "rb"); - if(!i->in) { - fprintf(stderr, "error: could not open file %s for reading: %s\n", upload, +#ifdef UNDER_CE + if(stat(upload, &file_info) != 0) { +#else + if(fstat(fileno(i->in), &file_info) != 0) { +#endif + fprintf(stderr, "error: could not stat file %s: %s\n", upload, strerror(errno)); fclose(out); return 1; } + uploadsize = file_info.st_size; + hnd = i->hnd = curl_easy_init(); /* write to this file */ From cec6c1cd9c3923e2b583ba2f0756a733ad25293e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 18 Sep 2025 20:26:15 +0200 Subject: [PATCH 063/465] GHA/codeql: make it run on docs updates, to verify examples Follow-up to b4922b1295333dc6679eb1d588ddc2fb6b7fd5b7 #18564 --- .github/workflows/codeql.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2344f1d16fa9..7b2922e2bbdb 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,7 +13,6 @@ name: 'CodeQL' - '**/*.md' - '.circleci/**' - 'appveyor.*' - - 'docs/**' - 'packages/**' - 'plan9/**' - 'projects/**' @@ -26,7 +25,6 @@ name: 'CodeQL' - '**/*.md' - '.circleci/**' - 'appveyor.*' - - 'docs/**' - 'packages/**' - 'plan9/**' - 'projects/**' From 9f18cb6544bbf47e2e2fad6564bc03098273c7bc Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 18 Sep 2025 14:02:51 +0200 Subject: [PATCH 064/465] libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() - null-terminate the result to match the other getter `libssh2_sftp_symlink_ex()` call. - check negative result and bail out early. Reported-by: Joshua Rogers Closes #18598 --- lib/vssh/libssh2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 5dfc377ec14e..73d48077b535 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -2405,6 +2405,12 @@ static CURLcode ssh_state_sftp_readdir_link(struct Curl_easy *data, curlx_dyn_free(&sshp->readdir_link); + if(rc < 0) + return CURLE_OUT_OF_MEMORY; + + /* It seems that this string is not always null-terminated */ + sshp->readdir_filename[rc] = '\0'; + /* append filename and extra output */ result = curlx_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename); if(result) From 9fb8d567ca96659dc0d35cc82f160a721adf6edd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 08:47:15 +0200 Subject: [PATCH 065/465] tool_operate: keep the progress meter for --out-null Fixes #18607 Closes #18609 --- src/tool_operate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tool_operate.c b/src/tool_operate.c index 75926d704ba4..8ca3c14e8f12 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1277,8 +1277,8 @@ static CURLcode single_transfer(struct OperationConfig *config, config->resume_from = -1; /* -1 will then force get-it-yourself */ } - if(output_expected(per->url, per->uploadfile) && outs->stream && - isatty(fileno(outs->stream))) + if(!outs->out_null && output_expected(per->url, per->uploadfile) && + outs->stream && isatty(fileno(outs->stream))) /* we send the output to a tty, therefore we switch off the progress meter */ per->noprogress = global->noprogress = global->isatty = TRUE; From 0d9a07abb731cc52a220f48430f66b546965594f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 18 Sep 2025 23:25:28 +0200 Subject: [PATCH 066/465] libssh2: drop two redundant null-terminations The null-termination was first added in the initial SFTP commit in 2006: a634f644005cbe2b3dea2b84328d605ec3474054 At that time this was a reasonable concern because libssh2 started null-terminating this string just one year prior, in 2005: https://github.com/libssh2/libssh2/commit/efc3841fd2c2c945e96492e9089e4d1810709d53 This fix was released in libssh2 v0.13 (2006-03-02). curl requires libssh2 v1.2.8, making this workaround no longer necessary. Follow-up to 9f18cb6544bbf47e2e2fad6564bc03098273c7bc #18598 Closes #18606 --- lib/vssh/libssh2.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 73d48077b535..69284407ab98 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1995,8 +1995,6 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data, return CURLE_AGAIN; if(rc > 0) { - /* It seems that this string is not always null-terminated */ - sshp->readdir_filename[rc] = '\0'; free(sshc->homedir); sshc->homedir = strdup(sshp->readdir_filename); if(!sshc->homedir) { @@ -2408,9 +2406,6 @@ static CURLcode ssh_state_sftp_readdir_link(struct Curl_easy *data, if(rc < 0) return CURLE_OUT_OF_MEMORY; - /* It seems that this string is not always null-terminated */ - sshp->readdir_filename[rc] = '\0'; - /* append filename and extra output */ result = curlx_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename); if(result) From 9618c337d1c876df04599462fbdb73d370162dbf Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 19 Sep 2025 10:19:29 +0200 Subject: [PATCH 067/465] GHA/codeql: try disabling the TRAP cache The `cpp` CodeQL job is adding a cache entry for each run on the master branch. One for Linux, another for Windows. Size: 68MB + 180MB = 248MB. In one week we got 50+ such entries, almost filling the available cache space. Following the recommendation in an open issue thread, this patch tries to disable this cache. Since it only affects master, the effect can only be verified after merging. The latest cache is picked up in PRs. The performance impact is also to be seen after merge. Bug: https://github.com/curl/curl/pull/18528#issuecomment-3288950880 Ref: https://github.com/github/codeql-action/pull/1172 Ref: https://github.com/github/codeql-action/issues/2030 Ref: https://github.com/github/codeql-action/issues/2885#issuecomment-2879069087 Follow-up to cc50f05370981e4933504e8aaec6b15880ff847f #18528 Closes #18613 --- .github/workflows/codeql.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 7b2922e2bbdb..ec41fcf6267e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -90,6 +90,7 @@ jobs: with: languages: cpp build-mode: manual + trap-caching: false - name: 'build' timeout-minutes: 10 From b2356a31974e137e304c35f2c0f7c7a4a988eeb6 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 19 Sep 2025 14:20:14 +0200 Subject: [PATCH 068/465] GHA: tidy up actions/checkout version in comments [ci skip] --- .github/workflows/checkdocs.yml | 2 +- .github/workflows/codeql.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index 36a4ff999e3a..f236ebc85013 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -39,7 +39,7 @@ jobs: # name: 'proselint' # runs-on: ubuntu-latest # steps: - # - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4 + # - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 # with: # persist-credentials: false # diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ec41fcf6267e..b5e05efe4655 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -45,7 +45,7 @@ jobs: permissions: security-events: write # To create/update security events steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: persist-credentials: false @@ -81,7 +81,7 @@ jobs: libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev /home/linuxbrew/.linuxbrew/bin/brew install gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: persist-credentials: false From 4f5528675a1bc1008748c3c0f636ab4c1ec6d9c0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 13:35:23 +0200 Subject: [PATCH 069/465] libssh: react on errors from ssh_scp_read Reported in Joshua's sarif data Closes #18616 --- lib/vssh/libssh.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 695532ff8514..2554468c4bf3 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -2889,7 +2889,7 @@ static CURLcode scp_recv(struct Curl_easy *data, int sockindex, { struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - ssize_t nread; + int nread; (void)sockindex; /* we only support SCP on the fixed known primary socket */ *pnread = 0; @@ -2899,7 +2899,8 @@ static CURLcode scp_recv(struct Curl_easy *data, int sockindex, /* libssh returns int */ nread = ssh_scp_read(sshc->scp_session, mem, len); - + if(nread == SSH_ERROR) + return CURLE_SSH; #if 0 /* The following code is misleading, mostly added as wishful thinking * that libssh at some point will implement non-blocking ssh_scp_write/read. From df60e8fe701e189e7629fd08b61950a0fb1b697a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 13:23:14 +0200 Subject: [PATCH 070/465] cf_socket_recv: don't count reading zero bytes as first byte Reported in Joshua's sarif data Closes #18615 --- lib/cf-socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cf-socket.c b/lib/cf-socket.c index f449ca36caf7..308325ccdc15 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1578,7 +1578,7 @@ static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, *pnread = (size_t)nread; CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread); - if(!result && !ctx->got_first_byte) { + if(!result && !ctx->got_first_byte && nread) { ctx->first_byte_at = curlx_now(); ctx->got_first_byte = TRUE; } From 1055864b03beee1615c04421854e5e927a0cdb5d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 14:19:26 +0200 Subject: [PATCH 071/465] telnet: make printsub require another byte input Reported in Joshua's sarif data Closes #18618 --- lib/telnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/telnet.c b/lib/telnet.c index cc827c1b3e8a..05e5ebe60cc7 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -713,7 +713,7 @@ static void printsub(struct Curl_easy *data, else /* bad input */ return; } - if(length < 1) { + if(length <= 1) { infof(data, "(Empty suboption?)"); return; } From fd6eb8d6e77d95e71c0c55678b46173b21edd1e9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 15:59:57 +0200 Subject: [PATCH 072/465] cookie: avoid saving a cookie file if no transfer was done Because parts of the cookie loading happens on transfer start the in-memory cookie jar risks being incomplete and then a save might wrongly truncate the target file. Added test 1902 to verify. Reported-by: divinity76 on github Fixes #18621 Closes #18622 --- lib/cookie.c | 12 +++++----- tests/data/Makefile.am | 2 +- tests/data/test1902 | 43 ++++++++++++++++++++++++++++++++++ tests/libtest/Makefile.inc | 2 +- tests/libtest/lib1902.c | 48 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 tests/data/test1902 create mode 100644 tests/libtest/lib1902.c diff --git a/lib/cookie.c b/lib/cookie.c index 35d33268f966..90d375a7611b 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -1658,18 +1658,18 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup) { CURLcode res; - if(data->set.str[STRING_COOKIEJAR]) { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + /* only save the cookie file if a transfer was started (data->state.url is + set), as otherwise the cookies were not completely initialized and there + might be cookie files that weren't loaded so saving the file is the wrong + thing. */ + if(data->set.str[STRING_COOKIEJAR] && data->state.url) { /* if we have a destination file for all the cookies to get dumped to */ res = cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]); if(res) infof(data, "WARNING: failed to save cookies in %s: %s", data->set.str[STRING_COOKIEJAR], curl_easy_strerror(res)); } - else { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - } if(cleanup && (!data->share || (data->cookies != data->share->cookies))) { Curl_cookie_cleanup(data->cookies); diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 4523de48864f..dfff0122575c 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -232,7 +232,7 @@ test1708 test1709 test1710 \ \ test1800 test1801 \ \ -test1900 test1901 test1903 test1904 test1905 test1906 test1907 \ +test1900 test1901 test1902 test1903 test1904 test1905 test1906 test1907 \ test1908 test1909 test1910 test1911 test1912 test1913 test1914 test1915 \ test1916 test1917 test1918 test1919 \ \ diff --git a/tests/data/test1902 b/tests/data/test1902 new file mode 100644 index 000000000000..7bf70e9068fe --- /dev/null +++ b/tests/data/test1902 @@ -0,0 +1,43 @@ + + + +cookies + + + +# Client-side + + + +set COOKIEFILE and COOKIEJAR but make no transfer + + +cookies + + +lib%TESTNUMBER + + + +%LOGDIR/cookie%TESTNUMBER + + +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +example.com FALSE / FALSE 0 has_js 1 + + + +# Verify data after the test has been "shot" + + +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +example.com FALSE / FALSE 0 has_js 1 + + + diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index 40ec0d1559d5..00273f9e9d6a 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -90,7 +90,7 @@ TESTS_C = \ lib1591.c lib1592.c lib1593.c lib1594.c lib1597.c \ lib1598.c lib1599.c \ lib1662.c \ - lib1900.c lib1901.c lib1903.c lib1905.c lib1906.c lib1907.c \ + lib1900.c lib1901.c lib1902.c lib1903.c lib1905.c lib1906.c lib1907.c \ lib1908.c lib1910.c lib1911.c lib1912.c lib1913.c \ lib1915.c lib1916.c lib1918.c lib1919.c \ lib1933.c lib1934.c lib1935.c lib1936.c lib1937.c lib1938.c lib1939.c \ diff --git a/tests/libtest/lib1902.c b/tests/libtest/lib1902.c new file mode 100644 index 000000000000..8e5929e33827 --- /dev/null +++ b/tests/libtest/lib1902.c @@ -0,0 +1,48 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "first.h" + +#include "memdebug.h" + +static CURLcode test_lib1902(const char *URL) +{ + CURLcode res = CURLE_OK; + CURL *curl; + + curl_global_init(CURL_GLOBAL_ALL); + + curl = curl_easy_init(); + if(curl) { + easy_setopt(curl, CURLOPT_COOKIEFILE, URL); + easy_setopt(curl, CURLOPT_COOKIEJAR, URL); + + /* Do not perform any actual network operation, + the issue occur when not calling curl.*perform */ + } + +test_cleanup: + curl_easy_cleanup(curl); + curl_global_cleanup(); + return res; +} From b0c823b86fa00e6a41a61614b45999e94b573eaf Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 16:47:01 +0200 Subject: [PATCH 073/465] RELEASE-NOTES: synced and bump to 8.17.0 --- RELEASE-NOTES | 65 ++++++++++++++++++++++++++++++++++++++---- include/curl/curlver.h | 8 +++--- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index c6fb253c75f3..69b05b895a9f 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -1,10 +1,10 @@ -curl and libcurl 8.16.1 +curl and libcurl 8.17.0 Public curl releases: 271 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3502 + Contributors: 3504 This release includes the following changes: @@ -13,8 +13,12 @@ This release includes the following bugfixes: o asyn-thrdd: drop pthread_cancel [30] o aws-lc: re-enable large read-ahead with v1.61.0 again [16] + o cf_socket_recv: don't count reading zero bytes as first byte [23] + o cfilter: unlink and discard [46] o cmake: fix building docs when the base directory contains `.3` [18] o cmdline-docs: extended, clarified, refreshed [28] + o configure: add "-mt" for pthread support on HP-UX [52] + o cookie: avoid saving a cookie file if no transfer was done [11] o curl_easy_getinfo: error code on NULL arg [2] o curl_mem_undef.h: limit to `CURLDEBUG` for non-memalloc overrides [19] o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] @@ -26,17 +30,39 @@ This release includes the following bugfixes: o docs/libcurl: remove ancient version references [7] o docs/libcurl: use lowercase must [5] o easy_getinfo: check magic, Curl_close safety [3] + o examples: fix two issues found by CodeQL [35] o krb5: return appropriate error on send failures [22] + o ldap: do not base64 encode zero length string [42] + o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] + o libssh2: drop two redundant null-terminations [26] + o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] + o libssh: react on errors from ssh_scp_read [24] o Makefile.example: simplify and make it configurable [20] + o managen: ignore version mentions < 7.66.0 [55] + o managen: render better manpage references/links [54] + o multi.h: add CURLMINFO_LASTENTRY [51] o ngtcp2: check error code on connect failure [13] + o openldap: avoid indexing the result at -1 for blank responses [44] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o sasl: clear canceled mechanism instead of toggling it [41] o setopt: accept *_SSL_VERIFYHOST set to 2L [31] o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] + o smb: adjust buffer size checks [45] + o smtp: check EHLO responses case insensitively [50] + o socks_sspi: fix memory cleanup calls [40] + o socks_sspi: restore non-blocking socket on error paths [48] o ssl-sessions.md: mark option experimental [12] o sws: fix checking `sscanf()` return value [17] + o telnet: make printsub require another byte input [21] + o tftp: check and act on tftp_set_timeouts() returning error [38] + o tftp: propagate expired timer from tftp_state_timeout() [39] o TODO: remove already implemented or bad items [36] + o tool: fix exponential retry delay [47] + o tool_cb_hdr: fix fwrite check in header callback [49] + o tool_operate: improve wording in retry message [37] + o tool_operate: keep the progress meter for --out-null [33] o urldata: FILE is not a list-only protocol [9] This release includes the following known bugs: @@ -61,11 +87,12 @@ Planned upcoming removals include: This release would not have looked like this without help, code, reports and advice from friends like these: - Adam Light, Andrew Kirillov, Dan Fandrich, Daniel Stenberg, dependabot[bot], + Adam Light, Andrew Kirillov, Andrew Olsen, Christian Schmitz, Dan Fandrich, + Daniel Stenberg, dependabot[bot], divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, fds242 on github, Javier Blazquez, - Jicea, Nir Azkiel, renovate[bot], Samuel Dionne-Riel, Stefan Eissing, - Viktor Szakats - (15 contributors) + Jicea, Joshua Rogers, Michael Osipov, Nir Azkiel, Ray Satiro, renovate[bot], + Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats + (21 contributors) References to bug reports and discussions on issues: @@ -79,6 +106,7 @@ References to bug reports and discussions on issues: [8] = https://curl.se/bug/?i=18531 [9] = https://curl.se/bug/?i=18525 [10] = https://curl.se/bug/?i=18527 + [11] = https://curl.se/bug/?i=18621 [12] = https://curl.se/bug/?i=18523 [13] = https://curl.se/bug/?i=18521 [14] = https://curl.se/bug/?i=18518 @@ -88,11 +116,36 @@ References to bug reports and discussions on issues: [18] = https://curl.se/bug/?i=18560 [19] = https://curl.se/bug/?i=18510 [20] = https://curl.se/bug/?i=18554 + [21] = https://curl.se/bug/?i=18618 [22] = https://curl.se/bug/?i=18561 + [23] = https://curl.se/bug/?i=18615 + [24] = https://curl.se/bug/?i=18616 + [26] = https://curl.se/bug/?i=18606 [27] = https://curl.se/bug/?i=18551 [28] = https://curl.se/bug/?i=18550 [29] = https://curl.se/bug/?i=18549 [30] = https://curl.se/bug/?i=18532 [31] = https://curl.se/mail/lib-2025-09/0031.html [32] = https://curl.se/bug/?i=18548 + [33] = https://curl.se/bug/?i=18607 + [34] = https://curl.se/bug/?i=18598 + [35] = https://curl.se/bug/?i=18605 [36] = https://curl.se/bug/?i=18542 + [37] = https://curl.se/bug/?i=18604 + [38] = https://curl.se/bug/?i=18603 + [39] = https://curl.se/bug/?i=18574 + [40] = https://curl.se/bug/?i=18587 + [41] = https://curl.se/bug/?i=18573 + [42] = https://curl.se/bug/?i=18602 + [44] = https://curl.se/bug/?i=18600 + [45] = https://curl.se/bug/?i=18599 + [46] = https://curl.se/bug/?i=18596 + [47] = https://curl.se/bug/?i=18591 + [48] = https://curl.se/bug/?i=18592 + [49] = https://curl.se/bug/?i=18593 + [50] = https://curl.se/bug/?i=18588 + [51] = https://curl.se/bug/?i=18578 + [52] = https://curl.se/bug/?i=18585 + [53] = https://curl.se/bug/?i=18579 + [54] = https://curl.se/bug/?i=18580 + [55] = https://curl.se/bug/?i=18583 diff --git a/include/curl/curlver.h b/include/curl/curlver.h index 03baeb4ae1d6..19b2bf87521b 100644 --- a/include/curl/curlver.h +++ b/include/curl/curlver.h @@ -32,13 +32,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "8.16.1-DEV" +#define LIBCURL_VERSION "8.17.0-DEV" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 8 -#define LIBCURL_VERSION_MINOR 16 -#define LIBCURL_VERSION_PATCH 1 +#define LIBCURL_VERSION_MINOR 17 +#define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will always follow this syntax: @@ -58,7 +58,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x081001 +#define LIBCURL_VERSION_NUM 0x081100 /* * This is the date and time when the full source package was created. The From 58f071dbe4be8dfc95dad4ac4c9574502966d1dd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 17:36:29 +0200 Subject: [PATCH 074/465] tool_getparam/set_rate: skip the multiplication on overflow The code detected the problem but didn't avoid the calculation correctly. Fixes #18624 Reported-by: BobodevMm on github Closes #18625 --- src/tool_getparam.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tool_getparam.c b/src/tool_getparam.c index f2ad6daf2ef9..b8fec5f7ab3b 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -1012,8 +1012,9 @@ static ParameterError set_rate(const char *nextarg) errorf("too large --rate unit"); err = PARAM_NUMBER_TOO_LARGE; } - /* this typecast is okay based on the check above */ - numerator *= (long)numunits; + else + /* this typecast is okay based on the check above */ + numerator *= (long)numunits; } if(err) From a0369e1705b536279313c11dd54d490cf6f9ea3d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 14:59:17 +0200 Subject: [PATCH 075/465] gtls: avoid potential use of uninitialized variable in trace output Reported in Joshua's sarif data Closes #18620 --- lib/vtls/gtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index f38c90e66c34..eef64886e1e3 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -2195,7 +2195,7 @@ static CURLcode gtls_recv(struct Curl_cfilter *cf, } out: - CURL_TRC_CF(data, cf, "gtls_recv(len=%zu) -> 0, %zu", blen, *pnread); + CURL_TRC_CF(data, cf, "gtls_recv(len=%zu) -> 0, %zd", blen, nread); return result; } From 5e2d4d790575d4ad0381c4862f5e435a3b6532d1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 13:47:16 +0200 Subject: [PATCH 076/465] base64: accept zero length argument to base64_encode We used to treat 0 as "call strlen() to get the length" for curlx_base64_encode, but it turns out this is rather fragile as we easily do the mistake of passing in zero when the data is actually not there and then calling strlen() is wrong. Force the caller to pass in the correct size. A zero length input string now returns a zero length output and a NULL pointer. Closes #18617 --- lib/curlx/base64.c | 4 +--- tests/unit/unit1302.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/curlx/base64.c b/lib/curlx/base64.c index dc6e9c001ce0..5f6887bd5c4c 100644 --- a/lib/curlx/base64.c +++ b/lib/curlx/base64.c @@ -182,7 +182,7 @@ static CURLcode base64_encode(const char *table64, *outlen = 0; if(!insize) - insize = strlen(inputbuff); + return CURLE_OK; #if SIZEOF_SIZE_T == 4 if(insize > UINT_MAX/4) @@ -240,8 +240,6 @@ static CURLcode base64_encode(const char *table64, * encoded data. Size of encoded data is returned in variable pointed by * outlen. * - * Input length of 0 indicates input buffer holds a null-terminated string. - * * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. * diff --git a/tests/unit/unit1302.c b/tests/unit/unit1302.c index 54693631ff54..a1676699f27d 100644 --- a/tests/unit/unit1302.c +++ b/tests/unit/unit1302.c @@ -172,7 +172,7 @@ static CURLcode test_unit1302(const char *arg) fprintf(stderr, "Test %u URL encoded output length %d instead of %d\n", i, (int)olen, (int)e->olen); } - if(memcmp(out, e->output, e->olen)) { + if(out && memcmp(out, e->output, e->olen)) { fprintf(stderr, "Test %u URL encoded badly. Got '%s', expected '%s'\n", i, out, e->output); unitfail++; From 8d004781a577fc2fae72873c4a45b2fb3f366d98 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 27 Jul 2025 13:50:03 +0200 Subject: [PATCH 077/465] build: drop the winbuild build system In favor of CMake. Closes #18040 --- .github/labeler.yml | 2 - .github/scripts/codespell.sh | 1 - .github/scripts/spacecheck.pl | 3 +- .github/scripts/typos.toml | 1 - .github/workflows/checksrc.yml | 2 - .github/workflows/curl-for-win.yml | 2 - .github/workflows/fuzz.yml | 2 - .github/workflows/http3-linux.yml | 2 - .github/workflows/linux-old.yml | 2 - .github/workflows/linux.yml | 2 - .github/workflows/macos.yml | 2 - .github/workflows/non-native.yml | 2 - .github/workflows/windows.yml | 2 - .gitignore | 1 - Makefile.am | 5 +- appveyor.sh | 23 - appveyor.yml | 51 -- docs/DEPRECATE.md | 8 +- docs/INSTALL-CMAKE.md | 60 +-- docs/INSTALL.md | 2 - projects/README.md | 3 - winbuild/.gitignore | 6 - winbuild/Makefile.vc | 308 ------------ winbuild/MakefileBuild.vc | 732 ----------------------------- winbuild/README.md | 207 -------- winbuild/makedebug.bat | 33 -- 26 files changed, 4 insertions(+), 1460 deletions(-) delete mode 100644 winbuild/.gitignore delete mode 100644 winbuild/Makefile.vc delete mode 100644 winbuild/MakefileBuild.vc delete mode 100644 winbuild/README.md delete mode 100644 winbuild/makedebug.bat diff --git a/.github/labeler.yml b/.github/labeler.yml index 42a891e62386..982055f16a3b 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -75,7 +75,6 @@ build: packages/**,\ plan9/**,\ projects/**,\ - winbuild/**,\ lib/libcurl.def,\ tests/cmake/**\ }" @@ -520,6 +519,5 @@ Windows: m4/curl-schannel.m4,\ projects/**,\ src/tool_doswin.c,\ - winbuild/**,\ lib/libcurl.def\ }" diff --git a/.github/scripts/codespell.sh b/.github/scripts/codespell.sh index 766eeeb87c6f..b373a7d210cc 100755 --- a/.github/scripts/codespell.sh +++ b/.github/scripts/codespell.sh @@ -14,7 +14,6 @@ codespell \ --skip 'docs/THANKS' \ --skip 'packages/*' \ --skip 'scripts/wcurl' \ - --skip 'winbuild/*' \ --ignore-regex '.*spellchecker:disable-line' \ --ignore-words '.github/scripts/codespell-ignore.txt' \ $(git ls-files) diff --git a/.github/scripts/spacecheck.pl b/.github/scripts/spacecheck.pl index e61d30b5b0c9..7caf52632761 100755 --- a/.github/scripts/spacecheck.pl +++ b/.github/scripts/spacecheck.pl @@ -30,7 +30,7 @@ "^m4/zz40-xc-ovr.m4", "Makefile\\.(am|example)\$", "/mkfile", - "\\.(sln|vc)\$", + "\\.sln\$", "^tests/data/test", ); @@ -40,7 +40,6 @@ my @need_crlf = ( "\\.(bat|sln)\$", - "^winbuild/.+\\.md\$", ); my @space_at_eol = ( diff --git a/.github/scripts/typos.toml b/.github/scripts/typos.toml index 46301615cd4f..73ecac136aca 100644 --- a/.github/scripts/typos.toml +++ b/.github/scripts/typos.toml @@ -25,5 +25,4 @@ extend-exclude = [ "docs/THANKS", "packages/*", "scripts/wcurl", - "winbuild/*", ] diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 061a192297d9..a0ff120becb3 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -18,7 +18,6 @@ name: 'Source' - 'Dockerfile' - 'plan9/**' - 'tests/data/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'Source' - 'Dockerfile' - 'plan9/**' - 'tests/data/**' - - 'winbuild/**' permissions: {} diff --git a/.github/workflows/curl-for-win.yml b/.github/workflows/curl-for-win.yml index 704a78d2cd28..0090c7d6e22e 100644 --- a/.github/workflows/curl-for-win.yml +++ b/.github/workflows/curl-for-win.yml @@ -17,7 +17,6 @@ name: 'curl-for-win' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'curl-for-win' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index d9cc43169e7a..1c466160fc77 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -20,7 +20,6 @@ name: 'Fuzzer' - 'plan9/**' - 'projects/**' - 'tests/data/**' - - 'winbuild/**' pull_request: branches: - master @@ -35,7 +34,6 @@ name: 'Fuzzer' - 'plan9/**' - 'projects/**' - 'tests/data/**' - - 'winbuild/**' permissions: {} diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 4ad880ddf6dc..3d3b35dee093 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -17,7 +17,6 @@ name: 'Linux HTTP/3' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'Linux HTTP/3' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: # Hardcoded workflow filename as workflow name above is just Linux again diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index 352986eb0473..e572c1745fb9 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -31,7 +31,6 @@ name: 'Old Linux' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -43,7 +42,6 @@ name: 'Old Linux' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' permissions: {} diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 70a6a259ab8d..af2edf0e092b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -16,7 +16,6 @@ name: 'Linux' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -27,7 +26,6 @@ name: 'Linux' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 5e817dd4bdd1..be8565303eb8 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -17,7 +17,6 @@ name: 'macOS' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'macOS' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.github/workflows/non-native.yml b/.github/workflows/non-native.yml index 3c76ed9de852..2670c39078fd 100644 --- a/.github/workflows/non-native.yml +++ b/.github/workflows/non-native.yml @@ -17,7 +17,6 @@ name: 'non-native' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'non-native' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index b519af47d66c..d45979c05ac2 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -17,7 +17,6 @@ name: 'Windows' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'Windows' - 'packages/**' - 'plan9/**' - 'projects/**' - - 'winbuild/**' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.gitignore b/.gitignore index 9c901f9fffef..0ac100295697 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,6 @@ /.vs /bld/ /build/ -/builds/ /stats/ __pycache__ Debug diff --git a/Makefile.am b/Makefile.am index b5ab0442a81d..fd97e61d9df3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -66,9 +66,6 @@ CMAKE_DIST = \ VC_DIST = projects/README.md projects/generate.bat -WINBUILD_DIST = winbuild/README.md \ - winbuild/MakefileBuild.vc winbuild/Makefile.vc winbuild/makedebug.bat - PLAN9_DIST = plan9/include/mkfile \ plan9/include/mkfile \ plan9/mkfile.proto \ @@ -80,7 +77,7 @@ PLAN9_DIST = plan9/include/mkfile \ plan9/src/mkfile EXTRA_DIST = CHANGES.md COPYING RELEASE-NOTES Dockerfile .editorconfig \ - $(CMAKE_DIST) $(VC_DIST) $(WINBUILD_DIST) $(PLAN9_DIST) + $(CMAKE_DIST) $(VC_DIST) $(PLAN9_DIST) DISTCLEANFILES = buildinfo.txt diff --git a/appveyor.sh b/appveyor.sh index dea58c954542..4be76095ee4a 100644 --- a/appveyor.sh +++ b/appveyor.sh @@ -96,29 +96,6 @@ elif [ "${BUILD_SYSTEM}" = 'VisualStudioSolution' ]; then msbuild.exe -maxcpucount "-property:Configuration=${PRJ_CFG}" "Windows/${VC_VERSION}/curl-all.sln" ) curl="build/Win32/${VC_VERSION}/${PRJ_CFG}/curld.exe" -elif [ "${BUILD_SYSTEM}" = 'winbuild_vs2015' ]; then - ( - cd winbuild - cat << EOF > _make.bat - call "C:/Program Files/Microsoft SDKs/Windows/v7.1/Bin/SetEnv.cmd" /x64 - call "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/vcvarsall.bat" x86_amd64 - nmake -f Makefile.vc mode=dll VC=14 "SSL_PATH=${openssl_root_win}" WITH_SSL=dll MACHINE=x64 DEBUG=${DEBUG} ENABLE_UNICODE=${ENABLE_UNICODE} WINBUILD_ACKNOWLEDGE_DEPRECATED=yes -EOF - ./_make.bat - rm _make.bat - ) - curl="builds/libcurl-vc14-x64-${PATHPART}-dll-ssl-dll-ipv6-sspi/bin/curl.exe" -elif [ "${BUILD_SYSTEM}" = 'winbuild_vs2017' ]; then - ( - cd winbuild - cat << EOF > _make.bat - call "C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvars64.bat" - nmake -f Makefile.vc mode=dll VC=14.10 "SSL_PATH=${openssl_root_win}" WITH_SSL=dll MACHINE=x64 DEBUG=${DEBUG} ENABLE_UNICODE=${ENABLE_UNICODE} WINBUILD_ACKNOWLEDGE_DEPRECATED=yes -EOF - ./_make.bat - rm _make.bat - ) - curl="builds/libcurl-vc14.10-x64-${PATHPART}-dll-ssl-dll-ipv6-sspi/bin/curl.exe" fi find . \( -name '*.exe' -o -name '*.dll' -o -name '*.lib' -o -name '*.pdb' \) -exec file '{}' \; diff --git a/appveyor.yml b/appveyor.yml index 42b580883c3b..af6ecd2c159b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -147,57 +147,6 @@ environment: PRJ_CFG: Debug HTTP_ONLY: 'ON' - # winbuild-based builds - - - job_name: 'winbuild, VS2015, Debug, x64, OpenSSL 1.1.1, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' - BUILD_SYSTEM: winbuild_vs2015 - DEBUG: 'yes' - PATHPART: debug - ENABLE_UNICODE: 'no' - - job_name: 'winbuild, VS2015, Release, x64, OpenSSL 1.1.1, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' - BUILD_SYSTEM: winbuild_vs2015 - DEBUG: 'no' - PATHPART: release - ENABLE_UNICODE: 'no' - - job_name: 'winbuild, VS2017, Debug, x64, OpenSSL 1.1.1, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' - BUILD_SYSTEM: winbuild_vs2017 - DEBUG: 'yes' - PATHPART: debug - ENABLE_UNICODE: 'no' - - job_name: 'winbuild, VS2017, Release, x64, OpenSSL 1.1.1, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' - BUILD_SYSTEM: winbuild_vs2017 - DEBUG: 'no' - PATHPART: release - ENABLE_UNICODE: 'no' - - job_name: 'winbuild, VS2015, Debug, x64, OpenSSL 1.1.1, Unicode, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' - BUILD_SYSTEM: winbuild_vs2015 - DEBUG: 'yes' - PATHPART: debug - ENABLE_UNICODE: 'yes' - - job_name: 'winbuild, VS2015, Release, x64, OpenSSL 1.1.1, Unicode, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' - BUILD_SYSTEM: winbuild_vs2015 - DEBUG: 'no' - PATHPART: release - ENABLE_UNICODE: 'yes' - - job_name: 'winbuild, VS2017, Debug, x64, OpenSSL 1.1.1, Unicode, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' - BUILD_SYSTEM: winbuild_vs2017 - DEBUG: 'yes' - PATHPART: debug - ENABLE_UNICODE: 'yes' - - job_name: 'winbuild, VS2017, Release, x64, OpenSSL 1.1.1, Unicode, Build-only' - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' - BUILD_SYSTEM: winbuild_vs2017 - DEBUG: 'no' - PATHPART: release - ENABLE_UNICODE: 'yes' - # generated VisualStudioSolution-based builds - job_name: 'VisualStudioSolution, VS2013, Debug, x86, Schannel, Build-only' diff --git a/docs/DEPRECATE.md b/docs/DEPRECATE.md index 65c630cbeebe..786b6a92c7e0 100644 --- a/docs/DEPRECATE.md +++ b/docs/DEPRECATE.md @@ -12,13 +12,6 @@ email the as soon as possible and explain to us why this is a problem for you and how your use case cannot be satisfied properly using a workaround. -## winbuild build system - -curl drops support for the winbuild build method after September 2025. - -We recommend migrating to CMake. See the migration guide in -`docs/INSTALL-CMAKE.md`. - ## Windows CE Windows CE "mainstream support" ended on October 9, 2018, and "Extended @@ -79,3 +72,4 @@ We remove support for this OpenSSL version from curl in June 2026. - Secure Transport (removed in 8.15.0) - BearSSL (removed in 8.15.0) - msh3 (removed in 8.16.0) + - winbuild build system (removed in 8.17.0) diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index ea761fa99a0e..b112e1f8b435 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -23,9 +23,7 @@ It consists of the following steps after you have unpacked the source. We recommend building with CMake on Windows. For instructions on migrating from the `projects/Windows` Visual Studio solution files, see -[this section](#migrating-from-visual-studio-ide-project-files). For -instructions on migrating from the winbuild builds, see -[the following section](#migrating-from-winbuild-builds). +[this section](#migrating-from-visual-studio-ide-project-files). ## Using `cmake` @@ -546,59 +544,3 @@ We do *not* specify `-DCMAKE_BUILD_TYPE=Debug` here as we might do for the `"NMake Makefiles"` generator because the Visual Studio generators are [multi-config generators](https://cmake.org/cmake/help/latest/prop_gbl/GENERATOR_IS_MULTI_CONFIG.html) and therefore ignore the value of `CMAKE_BUILD_TYPE`. - -# Migrating from winbuild builds - -We recommend CMake to build curl with MSVC. The winbuild build system is -deprecated and is going to be removed in September 2025 in favor of the CMake -build system. - -In CMake you can customize the path of dependencies by passing the absolute -header path and the full path of the library via `*_INCLUDE_DIR` and -`*_LIBRARY` options (see the complete list in the option listing above). -The full path to the library can point to a static library or an import -library, which defines if the dependency is linked as a dll or statically. -For OpenSSL this works -[differently](https://cmake.org/cmake/help/latest/module/FindOpenSSL.html): -You can pass the root directory of the OpenSSL installation via -`OPENSSL_ROOT_DIR`, then pass `OPENSSL_USE_STATIC_LIBS=ON` to select static -libs. - -winbuild options | Equivalent CMake options -:-------------------------------- | :-------------------------------- -`DEBUG` | `CMAKE_BUILD_TYPE=Debug` -`GEN_PDB` | `CMAKE_EXE_LINKER_FLAGS=/Fd`, `CMAKE_SHARED_LINKER_FLAGS=/Fd` -`LIB_NAME_DLL`, `LIB_NAME_STATIC` | `IMPORT_LIB_SUFFIX`, `LIBCURL_OUTPUT_NAME`, `STATIC_LIB_SUFFIX` -`VC`: `` | see the CMake [Visual Studio generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) -`MACHINE`: `x64`, `x86` | `-A x64`, `-A Win32` -`MODE`: `dll`, `static` | `BUILD_SHARED_LIBS=ON/OFF`, `BUILD_STATIC_LIBS=ON/OFF`, `BUILD_STATIC_CURL=ON/OFF` (default: dll) -`RTLIBCFG`: `static` | `CURL_STATIC_CRT=ON` -`ENABLE_IDN` | `USE_WIN32_IDN=ON` -`ENABLE_IPV6` | `ENABLE_IPV6=ON` -`ENABLE_NGHTTP2` | `USE_NGHTTP2=ON` -`ENABLE_OPENSSL_AUTO_LOAD_CONFIG` | `CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG=OFF` (default) -`ENABLE_SCHANNEL` | `CURL_USE_SCHANNEL=ON` -`ENABLE_SSPI` | `CURL_WINDOWS_SSPI=ON` (default with Schannel) -`ENABLE_UNICODE` | `ENABLE_UNICODE=ON` -`WITH_PREFIX` | `CMAKE_INSTALL_PREFIX=` -`WITH_DEVEL` | see individual `*_INCLUDE_DIR` and `*_LIBRARY` options and `OPENSSL_ROOT_DIR` -`WITH_CARES`, `CARES_PATH` | `ENABLE_ARES=ON`, optional: `CARES_INCLUDE_DIR`, `CARES_LIBRARY` -`WITH_MBEDTLS`, `MBEDTLS_PATH` | `CURL_USE_MBEDTLS=ON`, optional: `MBEDTLS_INCLUDE_DIR`, `MBEDTLS_LIBRARY`, `MBEDX509_LIBRARY`, `MBEDCRYPTO_LIBRARY` -`WITH_NGHTTP2`, `NGHTTP2_PATH` | `USE_NGHTTP2=ON`, optional: `NGHTTP2_INCLUDE_DIR`, `NGHTTP2_LIBRARY` -`WITH_SSH`, `SSH_PATH` | `CURL_USE_LIBSSH=ON`, optional: `LIBSSH_INCLUDE_DIR`, `LIBSSH_LIBRARY` -`WITH_SSH2`, `SSH2_PATH` | `CURL_USE_LIBSSH2=ON`, optional: `LIBSSH2_INCLUDE_DIR`, `LIBSSH2_LIBRARY` -`WITH_SSL`, `SSL_PATH` | `CURL_USE_OPENSSL=ON`, optional: `OPENSSL_ROOT_DIR`, `OPENSSL_USE_STATIC_LIBS=ON` -`WITH_WOLFSSL`, `WOLFSSL_PATH` | `CURL_USE_WOLFSSL=ON`, optional: `WOLFSSL_INCLUDE_DIR`, `WOLFSSL_LIBRARY` -`WITH_ZLIB`, `ZLIB_PATH` | `CURL_ZLIB=ON`, optional: `ZLIB_INCLUDE_DIR`, `ZLIB_LIBRARY` - -For example this command-line: - - > nmake -f Makefile.vc VC=17 MACHINE=x64 DEBUG=ON mode=dll SSL_PATH=C:\OpenSSL WITH_SSL=dll ENABLE_UNICODE=ON - -translates to: - - > cmake . -G "Visual Studio 17 2022" -A x64 -DBUILD_SHARED_LIBS=ON -DOPENSSL_ROOT_DIR=C:\OpenSSL -DCURL_USE_OPENSSL=ON -DENABLE_UNICODE=ON -DCURL_USE_LIBPSL=OFF - > cmake --build . --config Debug - -We use `--config` with `cmake --build` because the Visual Studio CMake -generators are multi-config and therefore ignore `CMAKE_BUILD_TYPE`. diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 0c53731710f1..ab20e9fde1df 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -347,7 +347,6 @@ If you want to set any of these defines you have the following options: - Modify `lib/config-win32.h` - Modify `lib/curl_setup.h` - - Modify `winbuild/Makefile.vc` - Modify the "Preprocessor Definitions" in the libcurl project Note: The pre-processor settings can be found using the Visual Studio IDE @@ -362,7 +361,6 @@ visible to libcurl and curl compilation processes. To set this definition you have the following alternatives: - Modify `lib/config-win32.h` - - Modify `winbuild/Makefile.vc` - Modify the "Preprocessor Definitions" in the libcurl project Note: The pre-processor settings can be found using the Visual Studio IDE diff --git a/projects/README.md b/projects/README.md index e587249dbb84..1777074c6d05 100644 --- a/projects/README.md +++ b/projects/README.md @@ -16,9 +16,6 @@ You need to generate the project files before using them. Please run "generate To generate project files for recent versions of Visual Studio instead, use cmake. Refer to INSTALL-CMAKE.md in the docs directory. -Another way to build curl using Visual Studio is without project files. Refer -to README in the winbuild directory. - ## Directory Structure The following directory structure is used for the legacy project files: diff --git a/winbuild/.gitignore b/winbuild/.gitignore deleted file mode 100644 index 0d7f2b276f76..000000000000 --- a/winbuild/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (C) Daniel Stenberg, , et al. -# -# SPDX-License-Identifier: curl - -*.idb -*.inc diff --git a/winbuild/Makefile.vc b/winbuild/Makefile.vc deleted file mode 100644 index 1a202cb559c6..000000000000 --- a/winbuild/Makefile.vc +++ /dev/null @@ -1,308 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# 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 -# -#*************************************************************************** - -!MESSAGE -!MESSAGE WARNING: -!MESSAGE -!MESSAGE The winbuild build system is deprecated and will be removed in -!MESSAGE September 2025 in favor of the CMake build system. -!MESSAGE -!MESSAGE Please see docs/INSTALL-CMAKE.md : "Migrating from winbuild builds" -!MESSAGE -!MESSAGE To use the winbuild build system you must acknowledge this warning by -!MESSAGE setting command line option WINBUILD_ACKNOWLEDGE_DEPRECATED=yes -!MESSAGE -!IF "$(WINBUILD_ACKNOWLEDGE_DEPRECATED)"!="yes" -!ERROR The user must acknowledge the deprecation warning to continue. -!ENDIF - -!IF "$(MODE)"=="static" -TARGET = $(LIB_NAME_STATIC) -AS_DLL = false -CFGSET=true -!ELSEIF "$(MODE)"=="dll" -TARGET = $(LIB_NAME_DLL) -AS_DLL = true -CFGSET=true -!ELSE -!MESSAGE Invalid mode: $(MODE) - -####################### -# Usage -# - -!MESSAGE See winbuild/README.md for usage -!ERROR please choose a valid mode - -!ENDIF - -!INCLUDE "../lib/Makefile.inc" -CSOURCES=$(CSOURCES: = ) -LIBCURL_OBJS=$(CSOURCES:.c=.obj) - -!INCLUDE "../src/Makefile.inc" -CURL_CFILES=$(CURL_CFILES: = ) -CURL_OBJS=$(CURL_CFILES:.c=.obj) - - -# backwards compatible check for USE_SSPI -!IFDEF USE_SSPI -ENABLE_SSPI = $(USE_SSPI) -!ENDIF - -# default options - -!IFNDEF MACHINE -# Note: nmake magically changes the value of PROCESSOR_ARCHITECTURE from "AMD64" -# to "x86" when building in a 32 bit build environment on a 64 bit machine. -!IF "$(PROCESSOR_ARCHITECTURE)"=="AMD64" -MACHINE = x64 -!ELSE -MACHINE = x86 -!ENDIF -!ENDIF - -!IFNDEF ENABLE_IDN -USE_IDN = true -!ELSEIF "$(ENABLE_IDN)"=="yes" -USE_IDN = true -!ELSEIF "$(ENABLE_IDN)"=="no" -USE_IDN = false -!ENDIF - -!IFNDEF ENABLE_IPV6 -USE_IPV6 = true -!ELSEIF "$(ENABLE_IPV6)"=="yes" -USE_IPV6 = true -!ELSEIF "$(ENABLE_IPV6)"=="no" -USE_IPV6 = false -!ENDIF - -!IFNDEF ENABLE_SSPI -USE_SSPI = true -!ELSEIF "$(ENABLE_SSPI)"=="yes" -USE_SSPI = true -!ELSEIF "$(ENABLE_SSPI)"=="no" -USE_SSPI = false -!ENDIF - -!IFNDEF ENABLE_SCHANNEL -!IF DEFINED(WITH_SSL) || DEFINED(WITH_MBEDTLS) || DEFINED(WITH_WOLFSSL) -USE_SCHANNEL = false -!ELSE -USE_SCHANNEL = $(USE_SSPI) -!ENDIF -!ELSEIF "$(ENABLE_SCHANNEL)"=="yes" -USE_SCHANNEL = true -!ELSEIF "$(ENABLE_SCHANNEL)"=="no" -USE_SCHANNEL = false -!ENDIF - -!IFNDEF ENABLE_OPENSSL_AUTO_LOAD_CONFIG -ENABLE_OPENSSL_AUTO_LOAD_CONFIG = true -!ELSEIF "$(ENABLE_OPENSSL_AUTO_LOAD_CONFIG)"=="yes" -!UNDEF ENABLE_OPENSSL_AUTO_LOAD_CONFIG -ENABLE_OPENSSL_AUTO_LOAD_CONFIG = true -!ELSEIF "$(ENABLE_OPENSSL_AUTO_LOAD_CONFIG)"=="no" -!UNDEF ENABLE_OPENSSL_AUTO_LOAD_CONFIG -ENABLE_OPENSSL_AUTO_LOAD_CONFIG = false -!ENDIF - -!IFNDEF ENABLE_UNICODE -USE_UNICODE = false -!ELSEIF "$(ENABLE_UNICODE)"=="yes" -USE_UNICODE = true -!ELSEIF "$(ENABLE_UNICODE)"=="no" -USE_UNICODE = false -!ENDIF - -CONFIG_NAME_LIB = libcurl - -!IF "$(WITH_SSL)"=="dll" -USE_SSL = true -SSL = dll -!ELSEIF "$(WITH_SSL)"=="static" -USE_SSL = true -SSL = static -!ENDIF - -!IF "$(ENABLE_NGHTTP2)"=="yes" -# compatibility bit, WITH_NGHTTP2 is the correct flag -WITH_NGHTTP2 = dll -USE_NGHTTP2 = true -NGHTTP2 = dll -!ELSEIF "$(WITH_NGHTTP2)"=="dll" -USE_NGHTTP2 = true -NGHTTP2 = dll -!ELSEIF "$(WITH_NGHTTP2)"=="static" -USE_NGHTTP2 = true -NGHTTP2 = static -!ENDIF - -!IFNDEF USE_NGHTTP2 -USE_NGHTTP2 = false -!ENDIF - -!IF "$(WITH_MBEDTLS)"=="dll" || "$(WITH_MBEDTLS)"=="static" -USE_MBEDTLS = true -MBEDTLS = $(WITH_MBEDTLS) -!ENDIF - -!IF "$(WITH_WOLFSSL)"=="dll" || "$(WITH_WOLFSSL)"=="static" -USE_WOLFSSL = true -WOLFSSL = $(WITH_WOLFSSL) -!ENDIF - -!IF "$(WITH_CARES)"=="dll" -USE_CARES = true -CARES = dll -!ELSEIF "$(WITH_CARES)"=="static" -USE_CARES = true -CARES = static -!ENDIF - -!IF "$(WITH_ZLIB)"=="dll" -USE_ZLIB = true -ZLIB = dll -!ELSEIF "$(WITH_ZLIB)"=="static" -USE_ZLIB = true -ZLIB = static -!ENDIF - -!IF "$(WITH_SSH2)"=="dll" -USE_SSH2 = true -SSH2 = dll -!ELSEIF "$(WITH_SSH2)"=="static" -USE_SSH2 = true -SSH2 = static -!ENDIF - -!IF "$(WITH_SSH)"=="dll" -USE_SSH = true -SSH = dll -!ELSEIF "$(WITH_SSH)"=="static" -USE_SSH = true -SSH = static -!ENDIF - -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-vc$(VC)-$(MACHINE) - -!IF "$(DEBUG)"=="yes" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-debug -!ELSE -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-release -!ENDIF - -!IF "$(AS_DLL)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-dll -!ELSE -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-static -!ENDIF - -!IF "$(USE_SSL)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ssl-$(SSL) -!ENDIF - -!IF "$(USE_MBEDTLS)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-mbedtls-$(MBEDTLS) -!ENDIF - -!IF "$(USE_WOLFSSL)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-wolfssl-$(WOLFSSL) -!ENDIF - -!IF "$(USE_CARES)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-cares-$(CARES) -!ENDIF - -!IF "$(USE_ZLIB)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-zlib-$(ZLIB) -!ENDIF - -!IF "$(USE_SSH2)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ssh2-$(SSH2) -!ENDIF - -!IF "$(USE_SSH)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ssh-$(SSH) -!ENDIF - -!IF "$(USE_IPV6)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-ipv6 -!ENDIF - -!IF "$(USE_SSPI)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-sspi -!ENDIF - -!IF "$(USE_SCHANNEL)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-schannel -!ENDIF - -!IF "$(USE_NGHTTP2)"=="true" -CONFIG_NAME_LIB = $(CONFIG_NAME_LIB)-nghttp2-$(NGHTTP2) -!ENDIF - -!MESSAGE configuration name: $(CONFIG_NAME_LIB) - -# Note these directories are removed by this makefile's 'clean' so they should -# not be changed to point to user-specified directories that may contain other -# data. MakefileBuild.vc uses the same variable names but allows some user -# changes and therefore does not remove the directories. -BUILD_DIR=../builds/$(CONFIG_NAME_LIB) -LIBCURL_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-lib -CURL_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-curl -DIRDIST = ..\builds\$(CONFIG_NAME_LIB)\ - -$(MODE): - @echo LIBCURL_OBJS = \> LIBCURL_OBJS.inc - @for %%i in ($(LIBCURL_OBJS)) do @echo $(LIBCURL_DIROBJ)/%%i \>> LIBCURL_OBJS.inc - @echo. >> LIBCURL_OBJS.inc - - @echo CURL_OBJS = \> CURL_OBJS.inc - @for %%i in ($(CURL_OBJS)) do @echo $(CURL_DIROBJ)/%%i \>> CURL_OBJS.inc - @echo. >> CURL_OBJS.inc - - @SET CONFIG_NAME_LIB=$(CONFIG_NAME_LIB) - @SET MACHINE=$(MACHINE) - @SET USE_NGHTTP2=$(USE_NGHTTP2) - @SET USE_IDN=$(USE_IDN) - @SET USE_IPV6=$(USE_IPV6) - @SET USE_SSPI=$(USE_SSPI) - @SET USE_SCHANNEL=$(USE_SCHANNEL) - @SET USE_UNICODE=$(USE_UNICODE) -# compatibility bit - @SET WITH_NGHTTP2=$(WITH_NGHTTP2) - - @$(MAKE) /NOLOGO /F MakefileBuild.vc - -copy_from_lib: - echo copying .c... - FOR %%i IN ($(CURLX_CFILES:/=\)) DO copy %%i ..\src\ - -clean: - @if exist $(LIBCURL_DIROBJ) rd /s /q $(LIBCURL_DIROBJ) - @if exist $(CURL_DIROBJ) rd /s /q $(CURL_DIROBJ) - @if exist $(DIRDIST) rd /s /q $(DIRDIST) - $(MAKE) /NOLOGO /F MakefileBuild.vc $@ diff --git a/winbuild/MakefileBuild.vc b/winbuild/MakefileBuild.vc deleted file mode 100644 index 509e43e263d7..000000000000 --- a/winbuild/MakefileBuild.vc +++ /dev/null @@ -1,732 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# 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 -# -#*************************************************************************** - -########################################################################### -# -# Makefile for building libcurl with MSVC -# -# Usage: see README.md -# -############################################################## - -CFGSET=FALSE -WINBUILD_DIR=`cd` - -# Utilities. -# If a path is required that contains characters such as space, quote the path. -MT = mt.exe -RC = rc.exe -ZIP = zip.exe - -# Allow changing C compiler via environment variable CC (default cl.exe) -# This command macro is not set by default: https://msdn.microsoft.com/en-us/library/ms933742.aspx -!If "$(CC)" == "" -CC = cl.exe -!Endif - -!IF "$(VC)"=="6" -CC_NODEBUG = $(CC) /O2 /DNDEBUG -CC_DEBUG = $(CC) /Od /Gm /Zi /D_DEBUG /GZ -CFLAGS = /I. /I../lib /I../include /nologo /W4 /GX /YX /FD /c /DBUILDING_LIBCURL -!ELSE -CC_NODEBUG = $(CC) /O2 /DNDEBUG -CC_DEBUG = $(CC) /Od /D_DEBUG /RTC1 /Z7 /LDd -CFLAGS = /I. /I../lib /I../include /nologo /W4 /EHsc /FD /c /DBUILDING_LIBCURL -!ENDIF - -LFLAGS = /nologo /machine:$(MACHINE) -LNKDLL = link.exe /DLL -# Use lib.exe instead of link.exe as link.exe /lib has the following bad habits: -# - optimizing options like /opt:ref raises warnings (at least in Visual Studio 2015) -# - all (including Windows) dependencies are aggregated (as static parts) -# - link.exe /lib is not documented (anymore) at MSDN -# Instead of id: just create an archive, that contains all objects -LNKLIB = lib.exe - -CFLAGS_PDB = /Zi -LFLAGS_PDB = /incremental:no /opt:ref,icf /DEBUG - -CFLAGS_LIBCURL_STATIC = /DCURL_STATICLIB - -WIN_LIBS = ws2_32.lib wldap32.lib advapi32.lib crypt32.lib secur32.lib - -BASE_NAME = libcurl -BASE_NAME_DEBUG = $(BASE_NAME)_debug -BASE_NAME_STATIC = $(BASE_NAME)_a -BASE_NAME_STATIC_DEBUG = $(BASE_NAME_STATIC)_debug - -LIB_NAME_STATIC = $(BASE_NAME_STATIC).lib -LIB_NAME_STATIC_DEBUG = $(BASE_NAME_STATIC_DEBUG).lib -LIB_NAME_DLL = $(BASE_NAME).dll -LIB_NAME_IMP = $(BASE_NAME).lib -LIB_NAME_DLL_DEBUG = $(BASE_NAME_DEBUG).dll -LIB_NAME_IMP_DEBUG = $(BASE_NAME_DEBUG).lib - -PDB_NAME_STATIC = $(BASE_NAME_STATIC).pdb -PDB_NAME_STATIC_DEBUG = $(BASE_NAME_STATIC_DEBUG).pdb -PDB_NAME_DLL = $(BASE_NAME).pdb -PDB_NAME_DLL_DEBUG = $(BASE_NAME_DEBUG).pdb - -# CURL Command section -PROGRAM_NAME = curl.exe -CURL_CFLAGS = /I../lib /I../lib/curlx /I../include /nologo /W4 /EHsc /FD /c -CURL_LFLAGS = /out:$(DIRDIST)\bin\$(PROGRAM_NAME) /subsystem:console $(LFLAGS) -CURL_RESFLAGS = /i../include - -############################################################# -## Nothing more to do below this line! -LIBCURL_SRC_DIR = ..\lib -CURL_SRC_DIR = ..\src - -!IF EXISTS($(CURL_SRC_DIR)\tool_hugehelp.c) -USE_MANUAL = true -CFLAGS = $(CFLAGS) /DUSE_MANUAL -!ENDIF - -!IFNDEF WITH_DEVEL -WITH_DEVEL = ../../deps -!ENDIF -DEVEL_INCLUDE= $(WITH_DEVEL)/include -DEVEL_LIB = $(WITH_DEVEL)/lib - -!IF EXISTS("$(DEVEL_INCLUDE)") -CFLAGS = $(CFLAGS) /I"$(DEVEL_INCLUDE)" -!ENDIF -!IF EXISTS("$(DEVEL_LIB)") -LFLAGS = $(LFLAGS) "/LIBPATH:$(DEVEL_LIB)" -!ENDIF - -!IFDEF SSL_PATH -SSL_INC_DIR = $(SSL_PATH)\include -SSL_LIB_DIR = $(SSL_PATH)\lib -SSL_LFLAGS = $(SSL_LFLAGS) "/LIBPATH:$(SSL_LIB_DIR)" -!ELSE -SSL_INC_DIR=$(DEVEL_INCLUDE)\openssl -SSL_LIB_DIR=$(DEVEL_LIB) -!ENDIF - -!IF "$(WITH_SSL)"=="dll" || "$(WITH_SSL)"=="static" -!IF EXISTS("$(SSL_LIB_DIR)\libssl.lib") -SSL_LIBS = libssl.lib libcrypto.lib -!ELSE -SSL_LIBS = libeay32.lib ssleay32.lib -!ENDIF -USE_SSL = true -SSL = $(WITH_SSL) -!IF "$(WITH_SSL)"=="static" -WIN_LIBS = $(WIN_LIBS) gdi32.lib user32.lib crypt32.lib -!ENDIF -!ENDIF - -!IFDEF USE_SSL -SSL_CFLAGS = /DUSE_OPENSSL /I"$(SSL_INC_DIR)" -!IF "$(ENABLE_OPENSSL_AUTO_LOAD_CONFIG)"=="false" -SSL_CFLAGS = $(SSL_CFLAGS) /DCURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG -!ENDIF -!ENDIF - -!IF "$(DISABLE_WEBSOCKETS)"=="true" -CFLAGS = $(CFLAGS) /DCURL_DISABLE_WEBSOCKETS=1 -!ENDIF - -!IFDEF NGHTTP2_PATH -NGHTTP2_INC_DIR = $(NGHTTP2_PATH)\include -NGHTTP2_LIB_DIR = $(NGHTTP2_PATH)\lib -NGHTTP2_LFLAGS = $(NGHTTP2_LFLAGS) "/LIBPATH:$(NGHTTP2_LIB_DIR)" -!ELSE -NGHTTP2_INC_DIR = $(DEVEL_INCLUDE) -NGHTTP2_LIB_DIR = $(DEVEL_LIB) -!ENDIF - -!IF "$(WITH_NGHTTP2)"=="dll" -NGHTTP2_CFLAGS = /DUSE_NGHTTP2 /I"$(NGHTTP2_INC_DIR)" -NGHTTP2_LIBS = nghttp2.lib -!ELSEIF "$(WITH_NGHTTP2)"=="static" -NGHTTP2_CFLAGS = /DUSE_NGHTTP2 /DNGHTTP2_STATICLIB /I"$(NGHTTP2_INC_DIR)" -!IF EXISTS("$(NGHTTP2_LIB_DIR)\nghttp2_static.lib") -NGHTTP2_LIBS = nghttp2_static.lib -!ELSE -NGHTTP2_LIBS = nghttp2.lib -!ENDIF -!ENDIF - -!IFDEF MBEDTLS_PATH -MBEDTLS_INC_DIR = $(MBEDTLS_PATH)\include -MBEDTLS_LIB_DIR = $(MBEDTLS_PATH)\lib -MBEDTLS_LFLAGS = $(MBEDTLS_LFLAGS) "/LIBPATH:$(MBEDTLS_LIB_DIR)" -!ELSE -MBEDTLS_INC_DIR = $(DEVEL_INCLUDE) -MBEDTLS_LIB_DIR = $(DEVEL_LIB) -!ENDIF - -!IF "$(WITH_MBEDTLS)"=="dll" || "$(WITH_MBEDTLS)"=="static" -USE_MBEDTLS = true -MBEDTLS = $(WITH_MBEDTLS) -MBEDTLS_CFLAGS = /DUSE_MBEDTLS /I"$(MBEDTLS_INC_DIR)" -MBEDTLS_LIBS = mbedtls.lib mbedcrypto.lib mbedx509.lib -!ENDIF - -!IFDEF WOLFSSL_PATH -WOLFSSL_INC_DIR = $(WOLFSSL_PATH)\include -WOLFSSL_LIB_DIR = $(WOLFSSL_PATH)\lib -WOLFSSL_LFLAGS = $(WOLFSSL_LFLAGS) "/LIBPATH:$(WOLFSSL_LIB_DIR)" -!ELSE -WOLFSSL_INC_DIR = $(DEVEL_INCLUDE) -WOLFSSL_LIB_DIR = $(DEVEL_LIB) -!ENDIF - -!IF "$(WITH_WOLFSSL)"=="dll" || "$(WITH_WOLFSSL)"=="static" -USE_WOLFSSL = true -WOLFSSL = $(WITH_WOLFSSL) -WOLFSSL_CFLAGS = /DUSE_WOLFSSL /I"$(WOLFSSL_INC_DIR)" -WOLFSSL_LIBS = wolfssl.lib -!ENDIF - - -!IFDEF CARES_PATH -CARES_INC_DIR = $(CARES_PATH)\include -CARES_LIB_DIR = $(CARES_PATH)\lib -CARES_LFLAGS = $(CARES_LFLAGS) "/LIBPATH:$(CARES_LIB_DIR)" -!ELSE -CARES_INC_DIR = $(DEVEL_INCLUDE)/cares -CARES_LIB_DIR = $(DEVEL_LIB) -!ENDIF - -!IF "$(WITH_CARES)"=="dll" -!IF "$(DEBUG)"=="yes" -CARES_LIBS = caresd.lib -!ELSE -CARES_LIBS = cares.lib -!ENDIF -USE_CARES = true -CARES = dll -!ELSEIF "$(WITH_CARES)"=="static" -!IF "$(DEBUG)"=="yes" -CARES_LIBS = libcaresd.lib -!ELSE -CARES_LIBS = libcares.lib -!ENDIF -USE_CARES = true -CARES = static -!ENDIF - -!IFDEF USE_CARES -CARES_CFLAGS = /DUSE_ARES /I"$(CARES_INC_DIR)" -!IF "$(CARES)"=="static" -CARES_CFLAGS = $(CARES_CFLAGS) /DCARES_STATICLIB -!ENDIF -!ENDIF - - -!IFDEF ZLIB_PATH -ZLIB_INC_DIR = $(ZLIB_PATH)\include -ZLIB_LIB_DIR = $(ZLIB_PATH)\lib -ZLIB_LFLAGS = $(ZLIB_LFLAGS) "/LIBPATH:$(ZLIB_LIB_DIR)" -!ELSE -ZLIB_INC_DIR = $(DEVEL_INCLUDE) -ZLIB_LIB_DIR = $(DEVEL_LIB) -!ENDIF - -# Depending on how zlib is built the libraries have different names, we -# try to handle them all. -!IF "$(WITH_ZLIB)"=="dll" -!IF EXISTS("$(ZLIB_LIB_DIR)\zlibwapi.lib") -ZLIB_LIBS = zlibwapi.lib -ADDITIONAL_ZLIB_CFLAGS = /DZLIB_WINAPI -!ELSEIF EXISTS("$(ZLIB_LIB_DIR)\zdll.lib") -ZLIB_LIBS = zdll.lib -!ELSE -ZLIB_LIBS = zlib.lib -!ENDIF -USE_ZLIB = true -ZLIB = dll -!ELSEIF "$(WITH_ZLIB)"=="static" -!IF EXISTS("$(ZLIB_LIB_DIR)\zlibstat.lib") -ZLIB_LIBS = zlibstat.lib -ADDITIONAL_ZLIB_CFLAGS = /DZLIB_WINAPI -!ELSEIF EXISTS("$(ZLIB_LIB_DIR)\zlibstatic.lib") -ZLIB_LIBS = zlibstatic.lib -!ELSEIF EXISTS("$(ZLIB_LIB_DIR)\zlib.lib") -ZLIB_LIBS = zlib.lib -!ELSE -ZLIB_LIBS = zlib_a.lib -!ENDIF -USE_ZLIB = true -ZLIB = static -!ENDIF - -!IFDEF USE_ZLIB -ZLIB_CFLAGS = /DHAVE_LIBZ $(ADDITIONAL_ZLIB_CFLAGS) /I"$(ZLIB_INC_DIR)" -!ENDIF - - -!IFDEF SSH2_PATH -SSH2_INC_DIR= $(SSH2_PATH)\include -SSH2_LIB_DIR= $(SSH2_PATH)\lib -SSH2_LFLAGS = $(SSH2_LFLAGS) "/LIBPATH:$(SSH2_LIB_DIR)" -!ELSE -SSH2_LIB_DIR= $(DEVEL_LIB) -SSH2_INC_DIR= $(DEVEL_INCLUDE)/libssh2 -!ENDIF - -!IF "$(WITH_SSH2)"=="dll" -SSH2_LIBS = libssh2.lib -USE_SSH2 = true -SSH2 = dll -!ELSEIF "$(WITH_SSH2)"=="static" -# libssh2 NMakefile on Windows at default creates a static library without _a suffix -!IF EXISTS("$(SSH2_LIB_DIR)\libssh2.lib") -SSH2_LIBS = libssh2.lib -!ELSE -SSH2_LIBS = libssh2_a.lib -!ENDIF -WIN_LIBS = $(WIN_LIBS) user32.lib -USE_SSH2 = true -SSH2 = static -!ENDIF - -!IFDEF USE_SSH2 -SSH2_CFLAGS = /DUSE_LIBSSH2 -SSH2_CFLAGS = $(SSH2_CFLAGS) /I"$(SSH2_INC_DIR)" -!ENDIF - - -!IFDEF SSH_PATH -SSH_INC_DIR= $(SSH_PATH)\include -SSH_LIB_DIR= $(SSH_PATH)\lib -SSH_LFLAGS = $(SSH_LFLAGS) "/LIBPATH:$(SSH_LIB_DIR)" -!ELSE -SSH_LIB_DIR= $(DEVEL_LIB) -SSH_INC_DIR= $(DEVEL_INCLUDE) -!ENDIF - -!IF "$(WITH_SSH)"=="dll" || "$(WITH_SSH)"=="static" -SSH_LIBS = ssh.lib -USE_SSH = true -SSH = $(WITH_SSH) -!ENDIF - -!IFDEF USE_SSH -SSH_CFLAGS = /DUSE_LIBSSH -SSH_CFLAGS = $(SSH_CFLAGS) /I"$(SSH_INC_DIR)" -!ENDIF - - -!IFNDEF USE_IDN -USE_IDN = true -!ELSEIF "$(USE_IDN)"=="yes" -USE_IDN = true -!ENDIF - -!IF "$(USE_IDN)"=="true" -IDN_CFLAGS = $(IDN_CFLAGS) /DUSE_WIN32_IDN -WIN_LIBS = $(WIN_LIBS) Normaliz.lib -!ENDIF - - -!IFNDEF USE_IPV6 -USE_IPV6 = true -!ELSEIF "$(USE_IPV6)"=="yes" -USE_IPV6 = true -!ENDIF - -!IF "$(USE_IPV6)"=="true" -IPV6_CFLAGS = $(IPV6_CFLAGS) /DUSE_IPV6 -!ENDIF - - -!IFNDEF USE_SSPI -USE_SSPI = true -!ELSEIF "$(USE_SSPI)"=="yes" -USE_SSPI = true -!ENDIF - -!IF "$(USE_SSPI)"=="true" -SSPI_CFLAGS = $(SSPI_CFLAGS) /DUSE_WINDOWS_SSPI -!ENDIF - - -!IFNDEF USE_SCHANNEL -!IF "$(USE_SSL)"=="true" -USE_SCHANNEL = false -!ELSE -USE_SCHANNEL = $(USE_SSPI) -!ENDIF -!ELSEIF "$(USE_SCHANNEL)"=="yes" -USE_SCHANNEL = true -!ENDIF - - -!IF "$(USE_SCHANNEL)"=="true" -!IF "$(USE_SSPI)"!="true" -!ERROR cannot build with Schannel without SSPI -!ENDIF -SSPI_CFLAGS = $(SSPI_CFLAGS) /DUSE_SCHANNEL -WIN_LIBS = $(WIN_LIBS) Crypt32.lib -!ENDIF - - -!IF "$(GEN_PDB)"=="yes" -GEN_PDB = true -!ENDIF - - -!IFDEF EMBED_MANIFEST -MANIFESTTOOL = $(MT) -manifest $(DIRDIST)\bin\$(PROGRAM_NAME).manifest -outputresource:$(DIRDIST)\bin\$(PROGRAM_NAME);1 -!ENDIF - -# Runtime library configuration -!IF "$(RTLIBCFG)"=="static" -RTLIB = /MT -RTLIB_DEBUG = /MTd -!ELSE -RTLIB = /MD -RTLIB_DEBUG = /MDd -!ENDIF - -!IF "$(MODE)"=="static" -TARGET = $(LIB_NAME_STATIC) -CURL_LIBCURL_LIBNAME=$(LIB_NAME_STATIC) -AS_DLL = false -CFGSET = true -!ELSEIF "$(MODE)"=="dll" -TARGET = $(LIB_NAME_DLL) -CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP) -AS_DLL = true -CFGSET = true -!ENDIF - -!IF "$(CFGSET)" == "FALSE" -!ERROR please choose a valid mode -!ENDIF - - -# CURL_XX macros are for the curl.exe command - -!IF "$(DEBUG)"=="yes" -RC_FLAGS = /d_DEBUG /Fo $@ $(LIBCURL_SRC_DIR)\libcurl.rc -CURL_CC = $(CC_DEBUG) $(RTLIB_DEBUG) -CURL_RC_FLAGS = $(CURL_RC_FLAGS) /i../include /d_DEBUG /Fo $@ $(CURL_SRC_DIR)\curl.rc -!ELSE -RC_FLAGS = /Fo $@ $(LIBCURL_SRC_DIR)\libcurl.rc -CURL_CC = $(CC_NODEBUG) $(RTLIB) -CURL_RC_FLAGS = $(CURL_RC_FLAGS) /i../include /Fo $@ $(CURL_SRC_DIR)\curl.rc -!ENDIF - -!IF "$(AS_DLL)" == "true" - -LNK = $(LNKDLL) $(LFLAGS) $(WIN_LIBS) /out:$(LIB_DIROBJ)\$(TARGET) -!IF "$(DEBUG)"=="yes" -TARGET = $(LIB_NAME_DLL_DEBUG) -LNK = $(LNK) /DEBUG /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) -PDB = $(PDB_NAME_DLL_DEBUG) -CURL_LIBS = /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) -!ELSE -TARGET = $(LIB_NAME_DLL) -LNK = $(LNK) /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP) -PDB = $(PDB_NAME_DLL) -CURL_LIBS = /IMPLIB:$(LIB_DIROBJ)\$(LIB_NAME_IMP) -!ENDIF -RESOURCE = $(LIB_DIROBJ)\libcurl.res - -# AS_DLL -!ELSE - -!IF "$(DEBUG)"=="yes" -TARGET = $(LIB_NAME_STATIC_DEBUG) -PDB = $(PDB_NAME_STATIC_DEBUG) -!ELSE -TARGET = $(LIB_NAME_STATIC) -PDB = $(PDB_NAME_STATIC) -!ENDIF -LNK = $(LNKLIB) /out:$(LIB_DIROBJ)\$(TARGET) -CURL_CC = $(CURL_CC) $(CFLAGS_LIBCURL_STATIC) - -# AS_DLL -!ENDIF - -!IF "$(USE_SSL)"=="true" -CFLAGS = $(CFLAGS) $(SSL_CFLAGS) -LFLAGS = $(LFLAGS) $(SSL_LFLAGS) $(SSL_LIBS) -!ENDIF - -!IF "$(USE_MBEDTLS)"=="true" -CFLAGS = $(CFLAGS) $(MBEDTLS_CFLAGS) -LFLAGS = $(LFLAGS) $(MBEDTLS_LFLAGS) $(MBEDTLS_LIBS) -!ENDIF - -!IF "$(USE_WOLFSSL)"=="true" -CFLAGS = $(CFLAGS) $(WOLFSSL_CFLAGS) -LFLAGS = $(LFLAGS) $(WOLFSSL_LFLAGS) $(WOLFSSL_LIBS) -!ENDIF - -!IF "$(USE_CARES)"=="true" -CFLAGS = $(CFLAGS) $(CARES_CFLAGS) -LFLAGS = $(LFLAGS) $(CARES_LFLAGS) $(CARES_LIBS) -!ENDIF - -!IF "$(USE_ZLIB)"=="true" -CFLAGS = $(CFLAGS) $(ZLIB_CFLAGS) -LFLAGS = $(LFLAGS) $(ZLIB_LFLAGS) $(ZLIB_LIBS) -!ENDIF - -!IF "$(USE_SSH2)"=="true" -CFLAGS = $(CFLAGS) $(SSH2_CFLAGS) -LFLAGS = $(LFLAGS) $(SSH2_LFLAGS) $(SSH2_LIBS) -!ENDIF - -!IF "$(USE_SSH)"=="true" -CFLAGS = $(CFLAGS) $(SSH_CFLAGS) -LFLAGS = $(LFLAGS) $(SSH_LFLAGS) $(SSH_LIBS) -!ENDIF - -!IF "$(USE_IDN)"=="true" -CFLAGS = $(CFLAGS) $(IDN_CFLAGS) -!ENDIF - -!IF "$(USE_IPV6)"=="true" -CFLAGS = $(CFLAGS) $(IPV6_CFLAGS) -!ENDIF - -!IF "$(USE_SSPI)"=="true" -CFLAGS = $(CFLAGS) $(SSPI_CFLAGS) -!ENDIF - -!IF "$(USE_NGHTTP2)"=="true" -CFLAGS = $(CFLAGS) $(NGHTTP2_CFLAGS) -LFLAGS = $(LFLAGS) $(NGHTTP2_LFLAGS) $(NGHTTP2_LIBS) -!ENDIF - -!IF "$(GEN_PDB)"=="true" -CFLAGS = $(CFLAGS) $(CFLAGS_PDB) /Fd"$(LIB_DIROBJ)\$(PDB)" -LFLAGS = $(LFLAGS) $(LFLAGS_PDB) -!ENDIF - -!IF ( "$(USE_SSL)"=="true" && "$(USE_SCHANNEL)"=="true" ) \ - || ( "$(USE_SSL)"=="true" && "$(USE_MBEDTLS)"=="true" ) \ - || ( "$(USE_SSL)"=="true" && "$(USE_WOLFSSL)"=="true" ) \ - || ( "$(USE_MBEDTLS)"=="true" && "$(USE_WOLFSSL)"=="true" ) \ - || ( "$(USE_MBEDTLS)"=="true" && "$(USE_SCHANNEL)"=="true" ) \ - || ( "$(USE_WOLFSSL)"=="true" && "$(USE_SCHANNEL)"=="true" ) -CFLAGS = $(CFLAGS) /DCURL_WITH_MULTI_SSL -!ENDIF - -!IF "$(USE_UNICODE)"=="true" -CFLAGS = $(CFLAGS) /DUNICODE /D_UNICODE -!ENDIF - -LIB_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-lib -CURL_DIROBJ = ..\builds\$(CONFIG_NAME_LIB)-obj-curl - -!IFDEF WITH_PREFIX -DIRDIST = $(WITH_PREFIX) -!ELSE -DIRDIST = ..\builds\$(CONFIG_NAME_LIB)\ -!ENDIF - -# -# curl.exe -# -CURL_LINK = link.exe /incremental:no /libpath:"$(DIRDIST)\lib" - -!IF "$(CFGSET)" != "FALSE" -# A mode was provided, so the library can be built. -# -!include CURL_OBJS.inc -!include LIBCURL_OBJS.inc - -!IF "$(AS_DLL)" == "true" -LIB_OBJS = $(LIBCURL_OBJS) $(RESOURCE) -!ELSE -LIB_OBJS = $(LIBCURL_OBJS) -!ENDIF - -EXE_OBJS = $(CURL_OBJS) $(CURL_DIROBJ)\curl.res - -all : $(TARGET) $(PROGRAM_NAME) - -package: $(TARGET) - @cd $(DIRDIST) - @-$(ZIP) -9 -q -r ..\$(CONFIG_NAME_LIB).zip .>nul 2<&1 - @cd $(MAKEDIR) - -$(TARGET): $(LIB_OBJS) $(LIB_DIROBJ) $(DIRDIST) - @echo Using SSL: $(USE_SSL) - @echo Using NGHTTP2: $(USE_NGHTTP2) - @echo Using c-ares: $(USE_CARES) - @echo Using SSH2: $(USE_SSH2) - @echo Using SSH: $(USE_SSH) - @echo Using ZLIB: $(USE_ZLIB) - @echo Using IDN: $(USE_IDN) - @echo Using IPv6: $(USE_IPV6) - @echo Using SSPI: $(USE_SSPI) - @echo Using Schannel: $(USE_SCHANNEL) - @echo CFLAGS: $(CFLAGS) - @echo LFLAGS: $(LFLAGS) - @echo GenPDB: $(GEN_PDB) - @echo Debug: $(DEBUG) - @echo Machine: $(MACHINE) - $(LNK) $(LIB_OBJS) - @echo Copying libs... - @if exist $(LIB_DIROBJ)\$(LIB_NAME_DLL) copy $(LIB_DIROBJ)\$(LIB_NAME_DLL) $(DIRDIST)\bin\ /y >nul 2<&1 - @if exist $(LIB_DIROBJ)\$(LIB_NAME_STATIC) copy $(LIB_DIROBJ)\$(LIB_NAME_STATIC) $(DIRDIST)\lib\ /y >nul 2<&1 - @if exist $(LIB_DIROBJ)\$(LIB_NAME_DLL_DEBUG) copy $(LIB_DIROBJ)\$(LIB_NAME_DLL_DEBUG) $(DIRDIST)\bin\ /y >nul 2<&1 - @if exist $(LIB_DIROBJ)\$(LIB_NAME_STATIC_DEBUG) copy $(LIB_DIROBJ)\$(LIB_NAME_STATIC_DEBUG) $(DIRDIST)\lib\ /y >nul 2<&1 - @if exist $(LIB_DIROBJ)\$(LIB_NAME_IMP) copy $(LIB_DIROBJ)\$(LIB_NAME_IMP) $(DIRDIST)\lib\ /y >nul 2<&1 - @if exist $(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) copy $(LIB_DIROBJ)\$(LIB_NAME_IMP_DEBUG) $(DIRDIST)\lib >nul 2<&1 - @-copy $(LIB_DIROBJ)\*.exp $(DIRDIST)\lib /y >nul 2<&1 - @-copy $(LIB_DIROBJ)\*.pdb $(DIRDIST)\lib /y >nul 2<&1 - @-copy ..\include\curl\*.h $(DIRDIST)\include\curl\ /y >nul 2<&1 - -$(LIB_OBJS): $(LIB_DIROBJ) $(DIRDIST) - -$(DIRDIST): - @if not exist "$(DIRDIST)\bin" mkdir $(DIRDIST)\bin - @if not exist "$(DIRDIST)\include" mkdir $(DIRDIST)\include - @if not exist "$(DIRDIST)\include\curl" mkdir $(DIRDIST)\include\curl - @if not exist "$(DIRDIST)\lib" mkdir $(DIRDIST)\lib - -$(LIB_DIROBJ): - @if not exist "$(LIB_DIROBJ)" mkdir $(LIB_DIROBJ) - @if not exist "$(LIB_DIROBJ)\vauth" mkdir $(LIB_DIROBJ)\vauth - @if not exist "$(LIB_DIROBJ)\vtls" mkdir $(LIB_DIROBJ)\vtls - @if not exist "$(LIB_DIROBJ)\vssh" mkdir $(LIB_DIROBJ)\vssh - @if not exist "$(LIB_DIROBJ)\vquic" mkdir $(LIB_DIROBJ)\vquic - @if not exist "$(LIB_DIROBJ)\curlx" mkdir $(LIB_DIROBJ)\curlx - -$(CURL_DIROBJ): - @if not exist "$(CURL_DIROBJ)" mkdir $(CURL_DIROBJ) -# we need a lib dir for the portability functions from libcurl -# we use the .c directly here - @if not exist "$(CURL_DIROBJ)" mkdir $(CURL_DIROBJ)\lib - -.SUFFIXES: .c .obj .res - -{$(LIBCURL_SRC_DIR)\}.c{$(LIB_DIROBJ)\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\\" $< - -{$(LIBCURL_SRC_DIR)\vauth\}.c{$(LIB_DIROBJ)\vauth\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\vauth\\" $< - -{$(LIBCURL_SRC_DIR)\vtls\}.c{$(LIB_DIROBJ)\vtls\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\vtls\\" $< - -{$(LIBCURL_SRC_DIR)\vssh\}.c{$(LIB_DIROBJ)\vssh\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\vssh\\" $< - -{$(LIBCURL_SRC_DIR)\vquic\}.c{$(LIB_DIROBJ)\vquic\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\vquic\\" $< - -{$(LIBCURL_SRC_DIR)\curlx\}.c{$(LIB_DIROBJ)\curlx\}.obj:: - $(CURL_CC) $(CFLAGS) /Fo"$(LIB_DIROBJ)\curlx\\" $< - -$(LIB_DIROBJ)\libcurl.res: $(LIBCURL_SRC_DIR)\libcurl.rc - $(RC) $(RC_FLAGS) - -# -# curl.exe -# - - -!IF "$(MODE)"=="static" -!IF "$(DEBUG)"=="yes" -CURL_LIBCURL_LIBNAME=$(LIB_NAME_STATIC_DEBUG) -!ELSE -CURL_LIBCURL_LIBNAME=$(LIB_NAME_STATIC) -!ENDIF -!ELSEIF "$(MODE)"=="dll" -!IF "$(DEBUG)"=="yes" -CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP_DEBUG) -!ELSE -CURL_LIBCURL_LIBNAME=$(LIB_NAME_IMP) -!ENDIF -!ENDIF - -CURL_FROM_LIBCURL=\ - $(CURL_DIROBJ)\nonblock.obj \ - $(CURL_DIROBJ)\strparse.obj \ - $(CURL_DIROBJ)\strcase.obj \ - $(CURL_DIROBJ)\timeval.obj \ - $(CURL_DIROBJ)\wait.obj \ - $(CURL_DIROBJ)\warnless.obj \ - $(CURL_DIROBJ)\multibyte.obj \ - $(CURL_DIROBJ)\version_win32.obj \ - $(CURL_DIROBJ)\dynbuf.obj \ - $(CURL_DIROBJ)\base64.obj - -!IFDEF USE_MANUAL -CURL_FROM_LIBCURL = $(CURL_FROM_LIBCURL) $(CURL_DIROBJ)\tool_hugehelp.obj -!ENDIF - -$(PROGRAM_NAME): $(CURL_DIROBJ) $(CURL_FROM_LIBCURL) $(EXE_OBJS) - $(CURL_LINK) $(CURL_LFLAGS) $(CURL_LIBCURL_LIBNAME) $(WIN_LIBS) $(CURL_FROM_LIBCURL) $(EXE_OBJS) - $(MANIFESTTOOL) - -{$(CURL_SRC_DIR)\}.c{$(CURL_DIROBJ)\}.obj:: - $(CURL_CC) $(CURL_CFLAGS) /Fo"$(CURL_DIROBJ)\\" $< - -!IFDEF USE_MANUAL -$(CURL_DIROBJ)\tool_hugehelp.obj: $(CURL_SRC_DIR)\tool_hugehelp.c - $(CURL_CC) $(CURL_CFLAGS) /Zm200 /Fo"$@" $(CURL_SRC_DIR)\tool_hugehelp.c -!ENDIF -$(CURL_DIROBJ)\nonblock.obj: ../lib/curlx/nonblock.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/nonblock.c -$(CURL_DIROBJ)\strparse.obj: ../lib/curlx/strparse.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/strparse.c -$(CURL_DIROBJ)\strcase.obj: ../lib/strcase.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/strcase.c -$(CURL_DIROBJ)\timeval.obj: ../lib/curlx/timeval.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/timeval.c -$(CURL_DIROBJ)\multibyte.obj: ../lib/curlx/multibyte.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/multibyte.c -$(CURL_DIROBJ)\version_win32.obj: ../lib/curlx/version_win32.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/version_win32.c -$(CURL_DIROBJ)\wait.obj: ../lib/curlx/wait.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/wait.c -$(CURL_DIROBJ)\warnless.obj: ../lib/curlx/warnless.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/warnless.c -$(CURL_DIROBJ)\dynbuf.obj: ../lib/curlx/dynbuf.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/dynbuf.c -$(CURL_DIROBJ)\base64.obj: ../lib/curlx/base64.c - $(CURL_CC) $(CURL_CFLAGS) /Fo"$@" ../lib/curlx/base64.c -$(CURL_DIROBJ)\curl.res: $(CURL_SRC_DIR)\curl.rc - $(RC) $(CURL_RC_FLAGS) - -!ENDIF # End of case where a config was provided. - -# Makefile.vc's clean removes (LIB)CURL_DIROBJ and DIRDIST dirs then calls -# this clean. Note those are the original directories we control and not the -# directories possibly modified by this makefile to point to user-specified -# directories. -# For example, don't remove DIRDIST here since it may contain user files if it -# has been changed by WITH_PREFIX to a different output dir (eg C:\usr\local). -clean: - @-erase /s *.dll 2> NUL - @-erase /s *.exp 2> NUL - @-erase /s *.idb 2> NUL - @-erase /s *.lib 2> NUL - @-erase /s *.obj 2> NUL - @-erase /s *.pch 2> NUL - @-erase /s *.pdb 2> NUL - @-erase /s *.res 2> NUL diff --git a/winbuild/README.md b/winbuild/README.md deleted file mode 100644 index 691e2dbc8d6b..000000000000 --- a/winbuild/README.md +++ /dev/null @@ -1,207 +0,0 @@ - - -# Deprecation warning - - This winbuild build system is deprecated and is going to be removed in - September 2025 in favor of the CMake build system. - - Please see docs/INSTALL-CMAKE.md : "Migrating from winbuild builds" - -# Building curl with Visual C++ - - This document describes how to compile, build and install curl and libcurl - from sources using the Visual C++ build tool. To build with VC++, you have to - first install VC++. The minimum required version of VC is 9 (part of Visual - Studio 2008). However using a more recent version is strongly recommended. - - VC++ is also part of the Windows Platform SDK. You do not have to install the - full Visual Studio or Visual C++ if all you want is to build curl. - - The latest Platform SDK can be downloaded freely from [Windows SDK and - emulator - archive](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive) - -## Prerequisites - - If you wish to support zlib, OpenSSL, c-ares, ssh2, you have to download them - separately and copy them to the `deps` directory as shown below: - - somedirectory\ - |_curl-src - | |_winbuild - | - |_deps - |_ lib - |_ include - |_ bin - - It is also possible to create the `deps` directory in some other random places - and tell the `Makefile` its location using the `WITH_DEVEL` option. - -## Open a command prompt - -Open a Visual Studio Command prompt: - - Using the **'VS [version] [platform] [type] Command Prompt'** menu entry: - where [version] is the Visual Studio version, [platform] is e.g. x64 and - [type] Native or Cross platform build. This type of command prompt may not - exist in all Visual Studio versions. For example, to build a 64-bit curl open - the x64 Native Tools prompt. - - See also: - - [How to: Enable a 64-Bit, x64 hosted MSVC toolset on the command line](https://docs.microsoft.com/en-us/cpp/build/how-to-enable-a-64-bit-visual-cpp-toolset-on-the-command-line) - - [Set the Path and Environment Variables for Command-Line Builds](https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line) - - [Developer Command Prompt for Visual Studio](https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs) - -## Build in the console - - Once you are in the console, go to the winbuild directory in the curl - sources: - - cd curl-src\winbuild - - Then you can call `nmake /f Makefile.vc` with the desired options (see - below). The builds are in the top src directory, `builds\` directory, in a - directory named using the options given to the nmake call. - - nmake /f Makefile.vc mode= - -where `` is one or many of: - - - `VC=` - VC version. 6 or later. - - `WITH_DEVEL=` - Paths for the development files (SSL, zlib, etc.) - Defaults to sibling directory: `../deps` - - `WITH_SSL=` - Enable OpenSSL support, DLL or static - - `WITH_NGHTTP2=` - Enable HTTP/2 support, DLL or static - - `WITH_MBEDTLS=` - Enable mbedTLS support, DLL or static - - `WITH_WOLFSSL=` - Enable wolfSSL support, DLL or static - - `WITH_CARES=` - Enable c-ares support, DLL or static - - `WITH_ZLIB=` - Enable zlib support, DLL or static - - `WITH_SSH=` - Enable libssh support, DLL or static - - `WITH_SSH2=` - Enable libssh2 support, DLL or static - - `WITH_PREFIX=` - Where to install the build - - `ENABLE_SSPI=` - Enable SSPI support, defaults to yes - - `ENABLE_IPV6=` - Enable IPv6, defaults to yes - - `ENABLE_IDN=` - Enable use of Windows IDN APIs, defaults to yes - Requires Windows Vista or later - - `ENABLE_SCHANNEL=` - Enable native Windows SSL support, defaults - to yes if SSPI and no other SSL library - - `ENABLE_OPENSSL_AUTO_LOAD_CONFIG=` - - Enable loading OpenSSL configuration - automatically, defaults to yes - - `ENABLE_UNICODE=` - Enable Unicode support, defaults to no - - `GEN_PDB=` - Generate External Program Database - (debug symbols for release build) - - `DEBUG=` - Debug builds - - `MACHINE=` - Target architecture (default is x86) - - `CARES_PATH=` - Custom path for c-ares - - `MBEDTLS_PATH=` - Custom path for mbedTLS - - `WOLFSSL_PATH=` - Custom path for wolfSSL - - `NGHTTP2_PATH=` - Custom path for nghttp2 - - `SSH_PATH=` - Custom path for libssh - - `SSH2_PATH=` - Custom path for libssh2 - - `SSL_PATH=` - Custom path for OpenSSL - - `ZLIB_PATH=` - Custom path for zlib - -## Cleaning a build - - For most build configurations you can remove a bad build by using the same - options with the added keyword "clean". For example: - - nmake /f Makefile.vc mode=static clean - - Build errors due to switching Visual Studio platform tools or mistakenly - specifying the wrong machine platform for the tools can usually be solved by - first cleaning the bad build. - -## Static linking of Microsoft's C runtime (CRT): - - If you are using mode=static, nmake creates and links to the static build of - libcurl but *not* the static CRT. If you must you can force nmake to link in - the static CRT by passing `RTLIBCFG=static`. Typically you shouldn't use that - option, and nmake defaults to the DLL CRT. `RTLIBCFG` is rarely used and - therefore rarely tested. When passing `RTLIBCFG` for a configuration that was - already built but not with that option, or if the option was specified - differently, you must destroy the build directory containing the - configuration so that nmake can build it from scratch. - - This option is not recommended unless you have enough development experience - to know how to match the runtime library for linking (that is, the CRT). If - `RTLIBCFG=static` then release builds use `/MT` and debug builds use `/MTd`. - -## Building your own application with libcurl (Visual Studio example) - - When you build curl and libcurl, nmake shows the relative path where the - output directory is. The output directory is named from the options nmake - used when building. You may also see temp directories of the same name but - with suffixes -obj-curl and -obj-lib. - - For example let's say you have built curl.exe and libcurl.dll from the Visual - Studio 2010 x64 Win64 Command Prompt: - - nmake /f Makefile.vc mode=dll VC=10 - - The output directory has a name similar to - `..\builds\libcurl-vc10-x64-release-dll-ipv6-sspi-schannel`. - - The output directory contains subdirectories bin, lib and include. Those are - the directories to set in your Visual Studio project. You can either copy the - output directory to your project or leave it in place. Following the example, - let's assume you leave it in place and your curl top source directory is - `C:\curl-7.82.0`. You would set these options for configurations using the - x64 platform: - -~~~ - - Configuration Properties > Debugging > Environment - PATH=C:\curl-7.82.0\builds\libcurl-vc10-x64-release-dll-ipv6-sspi-schannel\bin;%PATH% - - - C/C++ > General > Additional Include Directories - C:\curl-7.82.0\builds\libcurl-vc10-x64-release-dll-ipv6-sspi-schannel\include; - - - Linker > General > Additional Library Directories - C:\curl-7.82.0\builds\libcurl-vc10-x64-release-dll-ipv6-sspi-schannel\lib; - - - Linker > Input > Additional Dependencies - libcurl.lib; -~~~ - - For configurations using the x86 platform (aka Win32 platform) you would - need to make a separate x86 build of libcurl. - - If you build libcurl static (`mode=static`) or debug (`DEBUG=yes`) then the - library name varies and separate builds may be necessary for separate - configurations of your project within the same platform. This is discussed in - the next section. - -## Building your own application with a static libcurl - - When building an application that uses the static libcurl library on Windows, - you must define `CURL_STATICLIB`. Otherwise the linker looks for dynamic - import symbols. - - The static library name has an `_a` suffix in the basename and the debug - library name has a `_debug` suffix in the basename. For example, - `libcurl_a_debug.lib` is a static debug build of libcurl. - - You may need a separate build of libcurl for each VC configuration combination - (for example: Debug|Win32, Debug|x64, Release|Win32, Release|x64). - - You must specify any additional dependencies needed by your build of static - libcurl (for example: - `advapi32.lib;crypt32.lib;normaliz.lib;ws2_32.lib;wldap32.lib`). - -## Legacy Windows and SSL - - When you build curl using the build files in this directory the default SSL - backend is Schannel (Windows SSPI), the native SSL library that comes with - the Windows OS. Schannel in Windows 8 and earlier is not able to connect to - servers that no longer support the legacy handshakes and algorithms used by - those versions. If you are using curl in one of those earlier versions of - Windows you should choose another SSL backend like OpenSSL. diff --git a/winbuild/makedebug.bat b/winbuild/makedebug.bat deleted file mode 100644 index 6305537e3ded..000000000000 --- a/winbuild/makedebug.bat +++ /dev/null @@ -1,33 +0,0 @@ -@echo off -rem *************************************************************************** -rem * _ _ ____ _ -rem * Project ___| | | | _ \| | -rem * / __| | | | |_) | | -rem * | (__| |_| | _ <| |___ -rem * \___|\___/|_| \_\_____| -rem * -rem * Copyright (C) Daniel Stenberg, , et al. -rem * -rem * This software is licensed as described in the file COPYING, which -rem * you should have received as part of this distribution. The terms -rem * are also available at https://curl.se/docs/copyright.html. -rem * -rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell -rem * copies of the Software, and permit persons to whom the Software is -rem * furnished to do so, under the terms of the COPYING file. -rem * -rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -rem * KIND, either express or implied. -rem * -rem * SPDX-License-Identifier: curl -rem * -rem *************************************************************************** - -where.exe nmake.exe >nul 2>&1 - -if %ERRORLEVEL% EQU 1 ( - echo Error: Cannot find nmake.exe - be sure to run this script from within a Developer Command-Prompt -) else ( - nmake.exe /f Makefile.vc MODE=static DEBUG=yes GEN_PDB=yes - if %ERRORLEVEL% NEQ 0 echo Error: Build Failed -) From 1c49f2f26d0f200bb9de61f795f06a1bc56845e9 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 1 Aug 2025 21:09:52 +0200 Subject: [PATCH 078/465] windows: replace `_beginthreadex()` with `CreateThread()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace `_beginthreadex()` C runtime calls with native win32 API `CreateThread()`. The latter was already used in `src/tool_doswin.c` and in UWP and Windows CE builds before this patch. After this patch all Windows flavors use it. To drop PP logic and simplify code. While working on this it turned out that `src/tool_doswin.c` calls `TerminateThread()`, which isn't recommended by the documentation, except for "the most extreme cases". This patch makes no attempt to change that code. Ref: 9a2663322c330ff11275abafd612e9c99407a94a #17572 Ref: https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminatethread Also: - use `WaitForSingleObjectEx()` on all desktop Windows. Ref: 4be80d5109a340973dc6ce0221ec5c5761587df0 Ref: https://sourceforge.net/p/curl/feature-requests/82/ Ref: https://learn.microsoft.com/windows/win32/api/synchapi/nf-synchapi-waitforsingleobjectex - tests: drop redundant casts. - lib3207: fix to not rely on thread macros when building without thread support. Assisted-by: Jay Satiro Assisted-by: Marcel Raad Assisted-by: Michał Petryka Follow-up to 38029101e2d78ba125732b3bab6ec267b80a0e72 #11625 Closes #18451 --- lib/curl_threads.c | 26 +++++--------------------- lib/curl_threads.h | 12 +++--------- tests/libtest/lib3026.c | 24 +++++------------------- tests/libtest/lib3207.c | 4 ++++ tests/server/sockfilt.c | 11 +++++------ tests/server/util.c | 20 +++++++------------- 6 files changed, 29 insertions(+), 68 deletions(-) diff --git a/lib/curl_threads.c b/lib/curl_threads.c index 96fd0f8a7af9..94425d19fe8a 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -26,12 +26,8 @@ #include -#ifdef USE_THREADS_POSIX -# ifdef HAVE_PTHREAD_H -# include -# endif -#elif defined(USE_THREADS_WIN32) -# include +#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) +#include #endif #include "curl_threads.h" @@ -105,20 +101,8 @@ int Curl_thread_join(curl_thread_t *hnd) curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T (CURL_STDCALL *func) (void *), void *arg) { -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) - typedef HANDLE curl_win_thread_handle_t; -#else - typedef uintptr_t curl_win_thread_handle_t; -#endif - curl_thread_t t; - curl_win_thread_handle_t thread_handle; -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) - thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL); -#else - thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL); -#endif - t = (curl_thread_t)thread_handle; - if((t == 0) || (t == LongToHandle(-1L))) { + curl_thread_t t = CreateThread(NULL, 0, func, arg, 0, NULL); + if(!t) { #ifdef UNDER_CE DWORD gle = GetLastError(); /* !checksrc! disable ERRNOVAR 1 */ @@ -142,7 +126,7 @@ void Curl_thread_destroy(curl_thread_t *hnd) int Curl_thread_join(curl_thread_t *hnd) { -#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < _WIN32_WINNT_VISTA) +#ifdef UNDER_CE int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0); #else int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0); diff --git a/lib/curl_threads.h b/lib/curl_threads.h index 82f08c5fbb56..241014cc6acb 100644 --- a/lib/curl_threads.h +++ b/lib/curl_threads.h @@ -26,6 +26,7 @@ #include "curl_setup.h" #ifdef USE_THREADS_POSIX +# define CURL_THREAD_RETURN_T unsigned int # define CURL_STDCALL # define curl_mutex_t pthread_mutex_t # define curl_thread_t pthread_t * @@ -35,7 +36,8 @@ # define Curl_mutex_release(m) pthread_mutex_unlock(m) # define Curl_mutex_destroy(m) pthread_mutex_destroy(m) #elif defined(USE_THREADS_WIN32) -# define CURL_STDCALL __stdcall +# define CURL_THREAD_RETURN_T DWORD +# define CURL_STDCALL WINAPI # define curl_mutex_t CRITICAL_SECTION # define curl_thread_t HANDLE # define curl_thread_t_null (HANDLE)0 @@ -47,14 +49,6 @@ # define Curl_mutex_acquire(m) EnterCriticalSection(m) # define Curl_mutex_release(m) LeaveCriticalSection(m) # define Curl_mutex_destroy(m) DeleteCriticalSection(m) -#else -# define CURL_STDCALL -#endif - -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) -#define CURL_THREAD_RETURN_T DWORD -#else -#define CURL_THREAD_RETURN_T unsigned int #endif #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) diff --git a/tests/libtest/lib3026.c b/tests/libtest/lib3026.c index 2b35a258417a..167fdd4d332f 100644 --- a/tests/libtest/lib3026.c +++ b/tests/libtest/lib3026.c @@ -26,12 +26,7 @@ #define NUM_THREADS 100 #ifdef _WIN32 -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) -static DWORD WINAPI t3026_run_thread(LPVOID ptr) -#else -#include -static unsigned int WINAPI t3026_run_thread(void *ptr) -#endif +static DWORD WINAPI t3026_run_thread(void *ptr) { CURLcode *result = ptr; @@ -44,13 +39,8 @@ static unsigned int WINAPI t3026_run_thread(void *ptr) static CURLcode test_lib3026(const char *URL) { -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) - typedef HANDLE curl_win_thread_handle_t; -#else - typedef uintptr_t curl_win_thread_handle_t; -#endif CURLcode results[NUM_THREADS]; - curl_win_thread_handle_t thread_handles[NUM_THREADS]; + HANDLE thread_handles[NUM_THREADS]; unsigned tid_count = NUM_THREADS, i; CURLcode test_failure = CURLE_OK; curl_version_info_data *ver; @@ -65,13 +55,9 @@ static CURLcode test_lib3026(const char *URL) } for(i = 0; i < tid_count; i++) { - curl_win_thread_handle_t th; + HANDLE th; results[i] = CURL_LAST; /* initialize with invalid value */ -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) th = CreateThread(NULL, 0, t3026_run_thread, &results[i], 0, NULL); -#else - th = _beginthreadex(NULL, 0, t3026_run_thread, &results[i], 0, NULL); -#endif if(!th) { curl_mfprintf(stderr, "%s:%d Couldn't create thread, errno %lu\n", __FILE__, __LINE__, GetLastError()); @@ -84,8 +70,8 @@ static CURLcode test_lib3026(const char *URL) cleanup: for(i = 0; i < tid_count; i++) { - WaitForSingleObject((HANDLE)thread_handles[i], INFINITE); - CloseHandle((HANDLE)thread_handles[i]); + WaitForSingleObject(thread_handles[i], INFINITE); + CloseHandle(thread_handles[i]); if(results[i] != CURLE_OK) { curl_mfprintf(stderr, "%s:%d thread[%u]: curl_global_init() failed," "with code %d (%s)\n", __FILE__, __LINE__, diff --git a/tests/libtest/lib3207.c b/tests/libtest/lib3207.c index 446d98a00083..e3b50ff40ff2 100644 --- a/tests/libtest/lib3207.c +++ b/tests/libtest/lib3207.c @@ -68,7 +68,11 @@ static size_t write_memory_callback(char *contents, size_t size, return realsize; } +#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) static CURL_THREAD_RETURN_T CURL_STDCALL test_thread(void *ptr) +#else +static unsigned int test_thread(void *ptr) +#endif { struct Ctx *ctx = (struct Ctx *)ptr; CURLcode res = CURLE_OK; diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index c8b21beee90c..2785b751340e 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -412,8 +412,7 @@ struct select_ws_wait_data { HANDLE signal; /* internal event to signal handle trigger */ HANDLE abort; /* internal event to abort waiting threads */ }; -#include -static unsigned int WINAPI select_ws_wait_thread(void *lpParameter) +static DWORD WINAPI select_ws_wait_thread(void *lpParameter) { struct select_ws_wait_data *data; HANDLE signal, handle, handles[2]; @@ -557,25 +556,25 @@ static unsigned int WINAPI select_ws_wait_thread(void *lpParameter) static HANDLE select_ws_wait(HANDLE handle, HANDLE signal, HANDLE abort) { - typedef uintptr_t curl_win_thread_handle_t; struct select_ws_wait_data *data; - curl_win_thread_handle_t thread; /* allocate internal waiting data structure */ data = malloc(sizeof(struct select_ws_wait_data)); if(data) { + HANDLE thread; + data->handle = handle; data->signal = signal; data->abort = abort; /* launch waiting thread */ - thread = _beginthreadex(NULL, 0, &select_ws_wait_thread, data, 0, NULL); + thread = CreateThread(NULL, 0, &select_ws_wait_thread, data, 0, NULL); /* free data if thread failed to launch */ if(!thread) { free(data); } - return (HANDLE)thread; + return thread; } return NULL; } diff --git a/tests/server/util.c b/tests/server/util.c index 26a5dd17f708..02f91083e4f4 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -350,7 +350,7 @@ static SIGHANDLER_T old_sigbreak_handler = SIG_ERR; #endif #if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) -static unsigned int thread_main_id = 0; +static DWORD thread_main_id = 0; static HANDLE thread_main_window = NULL; static HWND hidden_main_window = NULL; #endif @@ -487,8 +487,7 @@ static LRESULT CALLBACK main_window_proc(HWND hwnd, UINT uMsg, } /* Window message queue loop for hidden main window, details see above. */ -#include -static unsigned int WINAPI main_window_loop(void *lpParameter) +static DWORD WINAPI main_window_loop(void *lpParameter) { WNDCLASS wc; BOOL ret; @@ -509,7 +508,7 @@ static unsigned int WINAPI main_window_loop(void *lpParameter) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, (HWND)NULL, (HMENU)NULL, - wc.hInstance, (LPVOID)NULL); + wc.hInstance, NULL); if(!hidden_main_window) { win32_perror("CreateWindowEx failed"); return (DWORD)-1; @@ -623,15 +622,10 @@ void install_signal_handlers(bool keep_sigalrm) #endif #if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) - { - typedef uintptr_t curl_win_thread_handle_t; - curl_win_thread_handle_t thread; - thread = _beginthreadex(NULL, 0, &main_window_loop, - (void *)GetModuleHandle(NULL), 0, &thread_main_id); - thread_main_window = (HANDLE)thread; - if(!thread_main_window || !thread_main_id) - logmsg("cannot start main window loop"); - } + thread_main_window = CreateThread(NULL, 0, &main_window_loop, + GetModuleHandle(NULL), 0, &thread_main_id); + if(!thread_main_window || !thread_main_id) + logmsg("cannot start main window loop"); #endif #endif } From dc3f4fd89b7700a920597630d43e6c2702c6cc46 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 3 Sep 2025 16:48:49 +0200 Subject: [PATCH 079/465] autotools: make `--enable-code-coverage` support llvm/clang Cherry-picked from #18468 Closes #18473 --- configure.ac | 5 ++--- m4/curl-functions.m4 | 32 +++++++++++++++++++------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index 3f02d037ef3d..6c33b561be37 100644 --- a/configure.ac +++ b/configure.ac @@ -128,9 +128,6 @@ CURLVERSION=`$SED -ne 's/^#define LIBCURL_VERSION "\(.*\)".*/\1/p' ${srcdir}/inc XC_CHECK_PROG_CC CURL_ATOMIC -dnl for --enable-code-coverage -CURL_COVERAGE - XC_AUTOMAKE AC_MSG_CHECKING([curl version]) AC_MSG_RESULT($CURLVERSION) @@ -523,6 +520,8 @@ dnl platform/compiler/architecture specific checks/flags dnl ********************************************************************** CURL_CHECK_COMPILER +dnl for --enable-code-coverage +CURL_COVERAGE CURL_CHECK_NATIVE_WINDOWS curl_cv_wince='no' diff --git a/m4/curl-functions.m4 b/m4/curl-functions.m4 index 83206dbc82f6..3640f0c84ebb 100644 --- a/m4/curl-functions.m4 +++ b/m4/curl-functions.m4 @@ -4290,25 +4290,31 @@ AC_DEFUN([CURL_COVERAGE],[ AS_HELP_STRING([--enable-code-coverage], [Provide code coverage]), coverage="$enableval") - dnl if not gcc switch off again - AS_IF([ test "$GCC" != "yes" ], coverage="no" ) + dnl if not gcc or clang switch off again + AS_IF([test "$compiler_id" != "GNU_C" -a "$compiler_id" != "CLANG" -a "$compiler_id" != "APPLECLANG"], coverage="no" ) AC_MSG_RESULT($coverage) if test "x$coverage" = "xyes"; then curl_coverage_msg="enabled" - AC_CHECK_TOOL([GCOV], [gcov], [gcov]) - if test -z "$GCOV"; then - AC_MSG_ERROR([needs gcov for code coverage]) - fi - AC_CHECK_PROG([LCOV], [lcov], [lcov]) - if test -z "$LCOV"; then - AC_MSG_ERROR([needs lcov for code coverage]) - fi - CPPFLAGS="$CPPFLAGS -DNDEBUG" - CFLAGS="$CFLAGS -O0 -g -fprofile-arcs -ftest-coverage" - LIBS="$LIBS -lgcov" + CFLAGS="$CFLAGS -O0 -g" + + if test "$compiler_id" = "GNU_C"; then + AC_CHECK_TOOL([GCOV], [gcov], [gcov]) + if test -z "$GCOV"; then + AC_MSG_ERROR([needs gcov for code coverage]) + fi + AC_CHECK_PROG([LCOV], [lcov], [lcov]) + if test -z "$LCOV"; then + AC_MSG_ERROR([needs lcov for code coverage]) + fi + CFLAGS="$CFLAGS -ftest-coverage -fprofile-arcs" + LIBS="$LIBS -lgcov" + else + CFLAGS="$CFLAGS -fprofile-instr-generate -fcoverage-mapping" + LDFLAGS="$LDFLAGS -fprofile-instr-generate -fcoverage-mapping" + fi fi ]) From 91720b620e802748d2e1629f43e29b76736542f9 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 3 Sep 2025 14:32:29 +0200 Subject: [PATCH 080/465] cmake: add `CURL_CODE_COVERAGE` option To sync up with the `--enable-code-coverage` `./configure` option. Ref: https://gcc.gnu.org/onlinedocs/gcc/Invoking-Gcov.html Ref: https://gcc.gnu.org/onlinedocs/gcc/Cross-profiling.html Ref: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html Closes #18468 --- CMakeLists.txt | 23 +++++++++++++++++++++++ docs/INSTALL-CMAKE.md | 1 + lib/CMakeLists.txt | 17 +++++++++++++++++ src/CMakeLists.txt | 10 ++++++++++ 4 files changed, 51 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0265162e74d3..ad78c58ed1db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -311,6 +311,26 @@ if(CURL_CLANG_TIDY) endif() endif() +option(CURL_CODE_COVERAGE "Enable code coverage build options" OFF) +if(CURL_CODE_COVERAGE) + if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + set(CURL_COVERAGE_MACROS "NDEBUG") + set(CURL_COVERAGE_CFLAGS "-O0" "-g" "-fprofile-arcs") + if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.1) + list(APPEND CURL_COVERAGE_CFLAGS "--coverage") + else() + list(APPEND CURL_COVERAGE_CFLAGS "-ftest-coverage") + endif() + set(CURL_COVERAGE_LIBS "gcov") + elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(CURL_COVERAGE_MACROS "NDEBUG") + set(CURL_COVERAGE_CFLAGS "-O0" "-g" "-fprofile-instr-generate" "-fcoverage-mapping") + set(CURL_COVERAGE_LDFLAGS "-fprofile-instr-generate" "-fcoverage-mapping") + else() + set(CURL_CODE_COVERAGE OFF) + endif() +endif() + # For debug libs and exes, add "-d" postfix if(NOT DEFINED CMAKE_DEBUG_POSTFIX) set(CMAKE_DEBUG_POSTFIX "-d") @@ -1984,6 +2004,9 @@ if(WIN32) endif() list(APPEND CURL_LIBS ${CURL_NETWORK_AND_TIME_LIBS}) +if(CURL_CODE_COVERAGE) + list(APPEND CURL_LIBS ${CURL_COVERAGE_LIBS}) +endif() if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") # MSVC but exclude clang-cl set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-MP") # Parallel compilation diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index b112e1f8b435..94a19c71c749 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -227,6 +227,7 @@ target_link_libraries(my_target PRIVATE CURL::libcurl) - `BUILD_TESTING`: Build tests. Default: `ON` - `CURL_CLANG_TIDY`: Run the build through `clang-tidy`. Default: `OFF` - `CURL_CLANG_TIDYFLAGS`: Custom options to pass to `clang-tidy`. Default: (empty) +- `CURL_CODE_COVERAGE`: Enable code coverage build options. Default: `OFF` - `CURL_COMPLETION_FISH`: Install fish completions. Default: `OFF` - `CURL_COMPLETION_FISH_DIR`: Custom fish completion install directory. - `CURL_COMPLETION_ZSH`: Install zsh completions. Default: `OFF` diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 3476d55b096a..7dce3aea8770 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -124,6 +124,10 @@ if(SHARE_LIB_OBJECT AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) set_target_properties(${LIB_OBJECT} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() endif() + if(CURL_CODE_COVERAGE) + set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) + set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) + endif() target_include_directories(${LIB_OBJECT} INTERFACE "$" @@ -162,6 +166,10 @@ if(BUILD_STATIC_LIBS) set_target_properties(${LIB_STATIC} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() endif() + if(CURL_CODE_COVERAGE) + set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) + set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) + endif() target_include_directories(${LIB_STATIC} INTERFACE "$" @@ -198,6 +206,15 @@ if(BUILD_SHARED_LIBS) set_target_properties(${LIB_SHARED} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() endif() + if(CURL_CODE_COVERAGE) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) + target_link_options(${LIB_SHARED} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + else() + target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + endif() + endif() target_include_directories(${LIB_SHARED} INTERFACE "$" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 37ca979bab99..c4b8ebb9346d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -129,6 +129,16 @@ if(ENABLE_UNICODE AND MINGW AND NOT MINGW32CE) endif() endif() +if(CURL_CODE_COVERAGE) + set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) + set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) + target_link_options(${EXE_NAME} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + else() + target_link_libraries(${EXE_NAME} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + endif() +endif() + ################################################################################ install(TARGETS ${EXE_NAME} EXPORT ${TARGETS_EXPORT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) From 096fc4325b895b507defd387aed0d021a3ea0a02 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 7 Sep 2025 17:30:05 +0200 Subject: [PATCH 081/465] digest_sspi: fix two memory leaks in error branches Closes #18488 --- lib/vauth/digest_sspi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index 861c4e1cb91b..cf297ff84dca 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -521,6 +521,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, if(!digest->user) { free(output_token); + Curl_sspi_free_identity(p_identity); return CURLE_OUT_OF_MEMORY; } } @@ -530,6 +531,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, if(!digest->passwd) { free(output_token); + Curl_sspi_free_identity(p_identity); Curl_safefree(digest->user); return CURLE_OUT_OF_MEMORY; } From ad26a6cb99b6a5a98cfb3856743f0cea14657895 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 5 Sep 2025 10:44:06 +0200 Subject: [PATCH 082/465] tidy-up: avoid using the reserved macro namespace To avoid hitting `-Wreserved-macro-identifier` where possible. - amigaos: introduce local macro instead of reusing `__request()`. - easy_lock: avoid redefining `__has_builtin()`. Follow-up to 33fd57b8fff8c0d873da2316a2a7f911caac2bae #9062 - rand: drop interim macro `_random()`. - windows: rename local macro `_tcsdup()` to `Curl_tcsdup()`. To avoid using the reserved macro namespace and to avoid colliding with `_tcsdup()` as defined by Windows headers. - checksrc: ban `_tcsdup()` in favor of `Curl_tcsdup()`. - tool_doswin: avoid redefining `_use_lfn()` (MS-DOS). - tool_findfile: limit `__NO_NET_API` hack to AmigaOS. Syncing this pattern with `lib/netrc.c`. Follow-up to 784a8ec2c1a3cc4bd676077a28a0d5f6ee7786a5 #16279 - examples/http2-upload: avoid reserved namespace for local macro. More cases will be removed when dropping WinCE support via #17927. Cases remain when defining external macros out of curl's control. Ref: #18477 Closes #18482 --- docs/examples/http2-upload.c | 4 ++-- docs/internals/CODE_STYLE.md | 1 + lib/amigaos.c | 7 ++++--- lib/curl_mem_undef.h | 2 +- lib/curl_memory.h | 6 +++--- lib/curl_setup.h | 2 +- lib/curl_sspi.c | 4 ++-- lib/easy_lock.h | 14 ++++++-------- lib/memdebug.h | 6 +++--- lib/rand.c | 12 +++++------- lib/vauth/digest_sspi.c | 2 +- lib/vauth/vauth.c | 2 +- lib/vtls/schannel.c | 2 +- scripts/checksrc.pl | 1 + src/tool_doswin.c | 7 ++++--- src/tool_findfile.c | 4 ++++ 16 files changed, 40 insertions(+), 36 deletions(-) diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index 31f4ed56e1ba..128a4b0beda1 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -71,14 +71,14 @@ int my_gettimeofday(struct timeval *tp, void *tzp) (void)tzp; if(tp) { /* Offset between 1601-01-01 and 1970-01-01 in 100 nanosec units */ - #define _WIN32_FT_OFFSET (116444736000000000) + #define WIN32_FT_OFFSET (116444736000000000) union { CURL_TYPEOF_CURL_OFF_T ns100; /* time since 1 Jan 1601 in 100ns units */ FILETIME ft; } _now; GetSystemTimeAsFileTime(&_now.ft); tp->tv_usec = (long)((_now.ns100 / 10) % 1000000); - tp->tv_sec = (long)((_now.ns100 - _WIN32_FT_OFFSET) / 10000000); + tp->tv_sec = (long)((_now.ns100 - WIN32_FT_OFFSET) / 10000000); } return 0; } diff --git a/docs/internals/CODE_STYLE.md b/docs/internals/CODE_STYLE.md index dadec934ddc4..aef5103fed6f 100644 --- a/docs/internals/CODE_STYLE.md +++ b/docs/internals/CODE_STYLE.md @@ -335,6 +335,7 @@ This is the full list of functions generally banned. _mbscat _mbsncat _tcscat + _tcsdup _tcsncat _waccess _wcscat diff --git a/lib/amigaos.c b/lib/amigaos.c index ac6d6b41937d..cc5d49f9b8e7 100644 --- a/lib/amigaos.c +++ b/lib/amigaos.c @@ -199,8 +199,9 @@ struct Library *SocketBase = NULL; #ifdef __libnix__ void __request(const char *msg); +#define CURL_AMIGA_REQUEST(msg) __request(msg) #else -# define __request(msg) Printf((const unsigned char *)(msg "\n\a"), 0) +#define CURL_AMIGA_REQUEST(msg) Printf((const unsigned char *)(msg "\n\a"), 0) #endif void Curl_amiga_cleanup(void) @@ -217,14 +218,14 @@ CURLcode Curl_amiga_init(void) SocketBase = OpenLibrary((const unsigned char *)"bsdsocket.library", 4); if(!SocketBase) { - __request("No TCP/IP Stack running!"); + CURL_AMIGA_REQUEST("No TCP/IP Stack running!"); return CURLE_FAILED_INIT; } if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl", TAG_DONE)) { - __request("SocketBaseTags ERROR"); + CURL_AMIGA_REQUEST("SocketBaseTags ERROR"); return CURLE_FAILED_INIT; } diff --git a/lib/curl_mem_undef.h b/lib/curl_mem_undef.h index acc3a9226aef..f3cca294e9a5 100644 --- a/lib/curl_mem_undef.h +++ b/lib/curl_mem_undef.h @@ -30,7 +30,7 @@ #undef realloc #undef free #ifdef _WIN32 -#undef _tcsdup +#undef Curl_tcsdup #endif #ifdef CURLDEBUG diff --git a/lib/curl_memory.h b/lib/curl_memory.h index 07ef111ce78e..7793bb63a389 100644 --- a/lib/curl_memory.h +++ b/lib/curl_memory.h @@ -77,11 +77,11 @@ #define free(ptr) Curl_cfree(ptr) #ifdef _WIN32 -#undef _tcsdup +#undef Curl_tcsdup #ifdef UNICODE -#define _tcsdup(ptr) Curl_wcsdup(ptr) +#define Curl_tcsdup(ptr) Curl_wcsdup(ptr) #else -#define _tcsdup(ptr) Curl_cstrdup(ptr) +#define Curl_tcsdup(ptr) Curl_cstrdup(ptr) #endif #endif /* _WIN32 */ diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 72c118affcc0..93cbb570568d 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -46,7 +46,7 @@ fail. Fixed in 14.2.0_1. Disable the workaround if the fix is detected. */ #if defined(__APPLE__) && !defined(__clang__) && defined(__GNUC__) && \ defined(__has_attribute) -# if !defined(__has_feature) +# if !defined(__has_feature) /* Keep this PP check separate from others */ # define availability curl_pp_attribute_disabled # elif !__has_feature(attribute_availability) # define availability curl_pp_attribute_disabled diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c index 635f560b68a3..c819b1c22ea5 100644 --- a/lib/curl_sspi.c +++ b/lib/curl_sspi.c @@ -138,7 +138,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, } /* Setup the identity's user and length */ - dup_user.tchar_ptr = _tcsdup(user.tchar_ptr); + dup_user.tchar_ptr = Curl_tcsdup(user.tchar_ptr); if(!dup_user.tchar_ptr) { curlx_unicodefree(useranddomain.tchar_ptr); return CURLE_OUT_OF_MEMORY; @@ -165,7 +165,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, passwd.tchar_ptr = curlx_convert_UTF8_to_tchar(passwdp); if(!passwd.tchar_ptr) return CURLE_OUT_OF_MEMORY; - dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr); + dup_passwd.tchar_ptr = Curl_tcsdup(passwd.tchar_ptr); if(!dup_passwd.tchar_ptr) { curlx_unicodefree(passwd.tchar_ptr); return CURLE_OUT_OF_MEMORY; diff --git a/lib/easy_lock.h b/lib/easy_lock.h index 909753f43aa3..f8998cc5472c 100644 --- a/lib/easy_lock.h +++ b/lib/easy_lock.h @@ -45,20 +45,18 @@ #define curl_simple_lock atomic_int #define CURL_SIMPLE_LOCK_INIT 0 -/* a clang-thing */ -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - #ifndef __INTEL_COMPILER /* The Intel compiler tries to look like GCC *and* clang *and* lies in its __has_builtin() function, so override it. */ /* if GCC on i386/x86_64 or if the built-in is present */ -#if ( (defined(__GNUC__) && !defined(__clang__)) && \ - (defined(__i386__) || defined(__x86_64__))) || \ - __has_builtin(__builtin_ia32_pause) +#if (defined(__GNUC__) && !defined(__clang__)) && \ + (defined(__i386__) || defined(__x86_64__)) #define HAVE_BUILTIN_IA32_PAUSE +#elif defined(__has_builtin) /* Keep this PP check separate from others */ +#if __has_builtin(__builtin_ia32_pause) +#define HAVE_BUILTIN_IA32_PAUSE +#endif #endif #endif diff --git a/lib/memdebug.h b/lib/memdebug.h index 30469b99a503..eabdd9c258cf 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -48,11 +48,11 @@ #define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__) #ifdef _WIN32 -#undef _tcsdup +#undef Curl_tcsdup #ifdef UNICODE -#define _tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) +#define Curl_tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) #else -#define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) +#define Curl_tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) #endif #endif /* _WIN32 */ diff --git a/lib/rand.c b/lib/rand.c index a1a5e42c2bb0..f30f3de7c34d 100644 --- a/lib/rand.c +++ b/lib/rand.c @@ -149,12 +149,6 @@ static CURLcode weak_random(struct Curl_easy *data, } #endif -#ifdef USE_SSL -#define _random(x,y,z) Curl_ssl_random(x,y,z) -#else -#define _random(x,y,z) weak_random(x,y,z) -#endif - static CURLcode randit(struct Curl_easy *data, unsigned int *rnd, bool env_override) { @@ -185,7 +179,11 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd, #endif /* data may be NULL! */ - return _random(data, (unsigned char *)rnd, sizeof(*rnd)); +#ifdef USE_SSL + return Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd)); +#else + return weak_random(data, (unsigned char *)rnd, sizeof(*rnd)); +#endif } /* diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index cf297ff84dca..0a1fe84ddf41 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -277,7 +277,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, if(!domain.tchar_ptr) return CURLE_OUT_OF_MEMORY; - dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); + dup_domain.tchar_ptr = Curl_tcsdup(domain.tchar_ptr); if(!dup_domain.tchar_ptr) { curlx_unicodefree(domain.tchar_ptr); return CURLE_OUT_OF_MEMORY; diff --git a/lib/vauth/vauth.c b/lib/vauth/vauth.c index 1b44aa6de1ad..c6cf4285725a 100644 --- a/lib/vauth/vauth.c +++ b/lib/vauth/vauth.c @@ -100,7 +100,7 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, free(utf8_spn); if(!tchar_spn) return NULL; - dupe_tchar_spn = _tcsdup(tchar_spn); + dupe_tchar_spn = Curl_tcsdup(tchar_spn); curlx_unicodefree(tchar_spn); return dupe_tchar_spn; } diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 1afc6790cc51..21dcf1371b32 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -433,7 +433,7 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path, return CURLE_SSL_CERTPROBLEM; *sep = TEXT('\0'); - *store_path = _tcsdup(store_path_start); + *store_path = Curl_tcsdup(store_path_start); *sep = TEXT('\\'); if(!*store_path) return CURLE_OUT_OF_MEMORY; diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 574e03c13b24..c52b8258d7f0 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -62,6 +62,7 @@ "_mbscat" => 1, "_mbsncat" => 1, "_tcscat" => 1, + "_tcsdup" => 1, "_tcsncat" => 1, "_wcscat" => 1, "_wcsncat" => 1, diff --git a/src/tool_doswin.c b/src/tool_doswin.c index 4ed90ba8c50f..c0dcfed04e37 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -46,9 +46,10 @@ # undef PATH_MAX # define PATH_MAX MAX_PATH #elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */ -# define _use_lfn(f) (0) /* long filenames never available */ +# define CURL_USE_LFN(f) 0 /* long filenames never available */ #elif defined(__DJGPP__) -# include /* _use_lfn(f) prototype */ +# include /* for _use_lfn(f) prototype */ +# define CURL_USE_LFN(f) _use_lfn(f) #endif #ifdef MSDOS @@ -314,7 +315,7 @@ static SANITIZEcode msdosify(char **const sanitized, const char *file_name, return SANITIZE_ERR_INVALID_PATH; /* Support for Windows 9X VFAT systems, when available. */ - if(_use_lfn(file_name)) { + if(CURL_USE_LFN(file_name)) { illegal_aliens = illegal_chars_w95; len -= (illegal_chars_w95 - illegal_chars_dos); } diff --git a/src/tool_findfile.c b/src/tool_findfile.c index 72868f4b4f73..8b2be8414214 100644 --- a/src/tool_findfile.c +++ b/src/tool_findfile.c @@ -24,10 +24,14 @@ #include "tool_setup.h" #ifdef HAVE_PWD_H +#ifdef __AMIGA__ #undef __NO_NET_API /* required for AmigaOS to declare getpwuid() */ +#endif #include +#ifdef __AMIGA__ #define __NO_NET_API #endif +#endif #ifdef HAVE_FCNTL_H #include From 87cbeecee4118fa3dcc8a0179b1c3b43e4775cb4 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 7 Sep 2025 21:42:41 +0200 Subject: [PATCH 083/465] windows: stop passing unused, optional argument for Win9x compatibility Expiry timestamp in `AcquireCredentialsHandle()` (SSPI) and `InitializeSecurityContext()` (Schannel) calls. The argument is optional in both. The returned value was never used in curl. The reason for passing it was Windows 95 compatibility, according to comments in the SSPI code. curl no longer supports Windows 95. Ref: https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-acquirecredentialshandlea Ref: https://learn.microsoft.com/windows/win32/secauthn/initializesecuritycontext--schannel Ref: 3fe531196771c8e81f917eebca4a06e062ab3a19 Ref: aaa42aa0d594b95c6c670a373ba30c507aa0a5ed Closes #18490 --- lib/socks_sspi.c | 6 ++---- lib/vauth/digest_sspi.c | 10 ++++------ lib/vauth/krb5_sspi.c | 6 ++---- lib/vauth/ntlm_sspi.c | 8 +++----- lib/vauth/spnego_sspi.c | 6 ++---- lib/vtls/schannel.c | 13 +++++-------- lib/vtls/schannel_int.h | 2 -- 7 files changed, 18 insertions(+), 33 deletions(-) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 3ff3b723f9a2..cdc9ef864a9a 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -83,7 +83,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, CtxtHandle sspi_context; PCtxtHandle context_handle = NULL; SecPkgCredentials_Names names; - TimeStamp expiry; char *service_name = NULL; unsigned short us_length; unsigned long qop; @@ -146,7 +145,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, (TCHAR *)CURL_UNCONST(TEXT("Kerberos")), SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, - &cred_handle, &expiry); + &cred_handle, NULL); if(check_sspi_err(data, status, "AcquireCredentialsHandle")) { failf(data, "Failed to acquire credentials."); @@ -178,8 +177,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, &input_desc, 0, &sspi_context, &output_desc, - &sspi_ret_flags, - &expiry); + &sspi_ret_flags, NULL); curlx_unicodefree(sname); diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index 0a1fe84ddf41..2f4b8d4a1dca 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -112,7 +112,6 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, SecBufferDesc resp_desc; SECURITY_STATUS status; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ /* Ensure we have a valid challenge message */ if(!Curl_bufref_len(chlg)) { @@ -168,7 +167,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_DIGEST)), SECPKG_CRED_OUTBOUND, NULL, p_identity, NULL, NULL, - &credentials, &expiry); + &credentials, NULL); if(status != SEC_E_OK) { Curl_sspi_free_identity(p_identity); @@ -197,7 +196,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, status = Curl_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, 0, 0, 0, &chlg_desc, 0, &context, &resp_desc, &attrs, - &expiry); + NULL); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) @@ -488,7 +487,6 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, SecBuffer resp_buf; SecBufferDesc resp_desc; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ TCHAR *spn; /* free the copy of user/passwd used to make the previous identity */ @@ -542,7 +540,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_DIGEST)), SECPKG_CRED_OUTBOUND, NULL, p_identity, NULL, NULL, - &credentials, &expiry); + &credentials, NULL); if(status != SEC_E_OK) { Curl_sspi_free_identity(p_identity); free(output_token); @@ -597,7 +595,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, ISC_REQ_USE_HTTP_STYLE, 0, 0, &chlg_desc, 0, digest->http_context, - &resp_desc, &attrs, &expiry); + &resp_desc, &attrs, NULL); curlx_unicodefree(spn); if(status == SEC_I_COMPLETE_NEEDED || diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c index 6595ab977a79..985f1c38fc63 100644 --- a/lib/vauth/krb5_sspi.c +++ b/lib/vauth/krb5_sspi.c @@ -107,7 +107,6 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, SecBufferDesc resp_desc; SECURITY_STATUS status; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ if(!krb5->spn) { /* Generate our SPN */ @@ -162,7 +161,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_KERBEROS)), SECPKG_CRED_OUTBOUND, NULL, krb5->p_identity, NULL, NULL, - krb5->credentials, &expiry); + krb5->credentials, NULL); if(status != SEC_E_OK) return CURLE_LOGIN_DENIED; @@ -204,8 +203,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, 0, SECURITY_NATIVE_DREP, chlg ? &chlg_desc : NULL, 0, &context, - &resp_desc, &attrs, - &expiry); + &resp_desc, &attrs, NULL); if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index 101eb8abd305..9127a9bb277d 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -98,7 +98,6 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, SecBufferDesc type_1_desc; SECURITY_STATUS status; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ /* Clean up any former leftovers and initialise to defaults */ Curl_auth_cleanup_ntlm(ntlm); @@ -147,7 +146,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NTLM)), SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity, NULL, NULL, - ntlm->credentials, &expiry); + ntlm->credentials, NULL); if(status != SEC_E_OK) return CURLE_LOGIN_DENIED; @@ -174,7 +173,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, 0, 0, SECURITY_NETWORK_DREP, NULL, 0, ntlm->context, &type_1_desc, - &attrs, &expiry); + &attrs, NULL); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) Curl_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); @@ -255,7 +254,6 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, SecBufferDesc type_3_desc; SECURITY_STATUS status; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; @@ -314,7 +312,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, &type_2_desc, 0, ntlm->context, &type_3_desc, - &attrs, &expiry); + &attrs, NULL); if(status != SEC_E_OK) { infof(data, "NTLM handshake failure (type-3 message): Status=%lx", status); diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c index af3a9c9798c2..f21c66796f91 100644 --- a/lib/vauth/spnego_sspi.c +++ b/lib/vauth/spnego_sspi.c @@ -105,7 +105,6 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, SecBufferDesc chlg_desc; SecBufferDesc resp_desc; unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; @@ -173,7 +172,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NEGOTIATE)), SECPKG_CRED_OUTBOUND, NULL, nego->p_identity, NULL, NULL, - nego->credentials, &expiry); + nego->credentials, NULL); if(nego->status != SEC_E_OK) return CURLE_AUTH_ERROR; @@ -250,8 +249,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, 0, SECURITY_NATIVE_DREP, chlg ? &chlg_desc : NULL, 0, nego->context, - &resp_desc, &attrs, - &expiry); + &resp_desc, &attrs, NULL); /* Free the decoded challenge as it is not required anymore */ free(chlg); diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 21dcf1371b32..fb9ef108226b 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -796,8 +796,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, (TCHAR *)CURL_UNCONST(UNISP_NAME), SECPKG_CRED_OUTBOUND, NULL, &credentials, NULL, NULL, - &backend->cred->cred_handle, - &backend->cred->time_stamp); + &backend->cred->cred_handle, NULL); } else { /* Pre-Windows 10 1809 or the user set a legacy algorithm list. @@ -835,8 +834,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, (TCHAR *)CURL_UNCONST(UNISP_NAME), SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL, - &backend->cred->cred_handle, - &backend->cred->time_stamp); + &backend->cred->cred_handle, NULL); } if(client_certs[0]) @@ -1050,7 +1048,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) backend->req_flags, 0, 0, (backend->use_alpn ? &inbuf_desc : NULL), 0, &backend->ctxt->ctxt_handle, - &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp); + &outbuf_desc, &backend->ret_flags, NULL); if(sspi_status != SEC_I_CONTINUE_NEEDED) { char buffer[STRERROR_LEN]; @@ -1259,7 +1257,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) &backend->cred->cred_handle, &backend->ctxt->ctxt_handle, backend->cred->sni_hostname, backend->req_flags, 0, 0, &inbuf_desc, 0, NULL, - &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp); + &outbuf_desc, &backend->ret_flags, NULL); /* free buffer for received handshake data */ Curl_safefree(inbuf[0].pvBuffer); @@ -2440,8 +2438,7 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, 0, &backend->ctxt->ctxt_handle, &outbuf_desc, - &backend->ret_flags, - &backend->ctxt->time_stamp); + &backend->ret_flags, NULL); if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { /* send close message which is in output buffer */ diff --git a/lib/vtls/schannel_int.h b/lib/vtls/schannel_int.h index 5483d12b5bb7..f9adb5829440 100644 --- a/lib/vtls/schannel_int.h +++ b/lib/vtls/schannel_int.h @@ -99,7 +99,6 @@ typedef struct _SCH_CREDENTIALS { struct Curl_schannel_cred { CredHandle cred_handle; - TimeStamp time_stamp; TCHAR *sni_hostname; HCERTSTORE client_cert_store; int refcount; @@ -107,7 +106,6 @@ struct Curl_schannel_cred { struct Curl_schannel_ctxt { CtxtHandle ctxt_handle; - TimeStamp time_stamp; }; struct schannel_ssl_backend_data { From 92f215fea1aa8bd5b1709d38f42aab77ab3fc662 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 4 Sep 2025 11:56:33 +0200 Subject: [PATCH 084/465] build: address some `-Weverything` warnings, update picky warnings `-Weverything` is not enabled by curl, and not recommended by LLVM, because it may enable experimental options, and will result in new fallouts after toolchain upgrades. This patch aims to fix/silence as much as possible as found with llvm/clang 21.1.0. It also permanently enables warnings that were fixed in source and deemed manageable in the future. `-Wformat` warnings are addressed separately via #18343. Fix/silence warnings in the source: - typecheck-gcc.h: fix `-Wreserved-identifier`. - lib: silence `-Wcast-function-type-strict`. For llvm 16+ or Apple clang 16+. - asyn-ares: limit `HAPPY_EYEBALLS_DNS_TIMEOUT` to old c-ares versions. - curl_trc: fix `-Wc++-hidden-decl`. - doh: fix `-Wc++-keyword`. - ftp: fix `-Wreserved-identifier`. - ldap: fix `-Wreserved-identifier`. - mqtt: comment unused macro to avoid warning. - multi_ev: drop unused macros to avoid warnings. - setopt: fix useless `break;` after `return;`. - gtls, mbedtls, rustls: silence `-Wconditional-uninitialized`. - socks_sspi, schannel, x509asn1: fix `-Wimplicit-int-enum-cast`. - x509asn1: fix `-Wc++-keyword`. - openssl: scope `OSSL_UI_METHOD_CAST` to avoid unused macro warning. - libssh2, wolfssl: drop unused macros. - curl_ngtcp2, curl_quiche, httpsrr, urlapi: drop/limit unused macros. - tool_getparam: fix useless `break;` after `return;` or `break;`. Not normally enabled because it doesn't work with unity. https://github.com/llvm/llvm-project/issues/71046 - tool_operate: fix `-Wc++-keyword`. - curlinfo: fix a `-Wunsafe-buffer-usage`. - tests: silence `-Wformat-non-iso`. - lib557: fix `-Wreserved-identifier`. - lib1565: silence `-Wconditional-uninitialized`. Enable the above clang warnings permanently in picky mode: - `-Wc++-hidden-decl` - `-Wc++-keyword` (except for Windows, where it collides with `wchar_t`) - `-Wcast-function-type-strict` - `-Wcast-function-type` - `-Wconditional-uninitialized` - `-Wformat-non-iso` (except for clang-cl) - `-Wreserved-identifier` - `-Wtentative-definition-compat` Silence problematic `-Weverything` warnings globally (in picky mode): - `-Wused-but-marked-unused` (88000+ hits) and `-Wdisabled-macro-expansion` (2600+ hits). Triggered by `typecheck-gcc.h` when building with clang 14+. Maybe there exists a way to fix within that header? Ref: https://discourse.llvm.org/t/removing-wused-but-marked-unused/55310 - `-Wunsafe-buffer-usage`. clang 16+. 7000+ hits. May be useful in theory, but such high volume of hits makes it impractical to review and possibly address. Meant for C++. Ref: https://clang.llvm.org/docs/SafeBuffers.html Ref: https://stackoverflow.com/questions/77017567/how-to-fix-code-to-avoid-warning-wunsafe-buffer-usage Ref: https://discourse.llvm.org/t/rfc-c-buffer-hardening/65734 Ref: https://github.com/llvm/llvm-project/pull/111624 - `-Wimplicit-void-ptr-cast`. clang 21+. 1700+ hits. C++ warning, deemed pure noise. Ref: https://github.com/curl/curl/issues/18470#issuecomment-3253506266 - `-Wswitch-default` (180+ hits), `-Wswitch-enum` (190+ hits), `-Wcovered-switch-default` (20+ hits). Next to impossible to fix cleanly, esp. when the covered `case` branches depend on compile-time options. - `-Wdocumentation-unknown-command` (8+ hits). Triggered in a few sources. Seems arbitrary and bogus. - `-Wpadded` (550+ hits). - `-Wc++-keyword` on Windows, where it collides with `wchar_t`. (100+ hits) Ref: https://github.com/llvm/llvm-project/issues/155988 - `-Wreserved-macro-identifier`. clang 13+. 5+ hits. Sometimes it's necessary to set external macros that use the reserved namespace. E.g. `_CRT_NONSTDC_NO_DEPRECATE`, `__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__`, `__NO_NET_API`, possibly `_REENTRANT`, and more. It's not worth trying to silence them individually. - `-Wnonportable-system-include-path` with `clang-cl`. It'd be broken by doing what the warning suggests. - `-Wformat-non-iso` for clang-cl. CMake `PICKY_COMPILER=ON` (the default) or `./configure` `--enable-warnings` (not the default) is required to enable these silencing rules. Also: - autotools, cmake: fix Apple clang and mainline llvm version translations. Ref: https://en.wikipedia.org/wiki/Xcode#Toolchain_versions - autotools, cmake: enable `-Warray-compare` for clang 20+. Follow-up to 4b7accda5ae3f2e663aa3f3853805241ef87c2fe #17196 - cmake: fix to enable `-Wmissing-variable-declarations` at an earlier clang version. - cmake: update internal logic to handle warning options with `+` in them. - cmake: fix internal logic to match the whole option when looking into `CMAKE_C_FLAGS` for custom-disabled warnings. Follow-up to b85cb8cb4e143d1615d4fcc1ce8f2f7b66453995 #18485 Closes #18477 --- CMake/PickyWarnings.cmake | 120 ++++++++-- include/curl/typecheck-gcc.h | 418 +++++++++++++++++------------------ lib/asyn-ares.c | 22 +- lib/curl_trc.c | 2 - lib/curl_trc.h | 10 +- lib/curlx/version_win32.c | 7 + lib/doh.c | 10 +- lib/formdata.c | 7 + lib/ftp.c | 12 +- lib/httpsrr.c | 2 - lib/ldap.c | 43 ++-- lib/mqtt.c | 2 +- lib/multi_ev.c | 4 - lib/sendf.c | 7 + lib/setopt.c | 16 +- lib/socks_sspi.c | 23 +- lib/url.c | 7 + lib/urlapi.c | 2 + lib/vquic/curl_ngtcp2.c | 7 - lib/vquic/curl_quiche.c | 6 - lib/vssh/libssh2.c | 10 +- lib/vtls/gtls.c | 2 +- lib/vtls/mbedtls.c | 2 +- lib/vtls/openssl.c | 16 +- lib/vtls/rustls.c | 4 +- lib/vtls/schannel.c | 11 +- lib/vtls/wolfssl.c | 3 - lib/vtls/x509asn1.c | 4 +- lib/vtls/x509asn1.h | 2 +- m4/curl-compilers.m4 | 73 ++++-- src/curlinfo.c | 6 +- src/tool_getparam.c | 3 - src/tool_operate.c | 4 +- tests/libtest/lib1565.c | 2 +- tests/libtest/lib557.c | 13 +- tests/unit/unit1398.c | 9 + 36 files changed, 532 insertions(+), 359 deletions(-) diff --git a/CMake/PickyWarnings.cmake b/CMake/PickyWarnings.cmake index f67576d68123..bdd226e9246e 100644 --- a/CMake/PickyWarnings.cmake +++ b/CMake/PickyWarnings.cmake @@ -47,8 +47,8 @@ endif() if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.6) OR - (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.3)) - list(APPEND _picky "-Werror=partial-availability") # clang 3.6 appleclang 6.3 + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.1)) + list(APPEND _picky "-Werror=partial-availability") # clang 3.6 appleclang 6.1 endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") @@ -87,6 +87,9 @@ if(PICKY_COMPILER) set(_picky_detect ) + # Notes: -Wno-* options should ideally be disabled at their precise cutoff versions, + # to suppress undesired warnings in case -Weverything is passed as a custom option. + # Assume these options always exist with both clang and gcc. # Require clang 3.0 / gcc 2.95 or later. list(APPEND _picky_enable @@ -121,13 +124,14 @@ if(PICKY_COMPILER) -Wmissing-field-initializers # clang 2.7 gcc 4.1 -Wmissing-noreturn # clang 2.7 gcc 4.1 -Wno-format-nonliteral # clang 1.0 gcc 2.96 (3.0) + -Wno-padded # clang 2.9 gcc 4.1 # Not used: We cannot change public structs -Wno-sign-conversion # clang 2.9 gcc 4.3 + -Wno-switch-default # clang 2.7 gcc 4.1 # Not used: Annoying to fix or silence + -Wno-switch-enum # clang 2.7 gcc 4.1 # Not used: It basically disallows default case -Wno-system-headers # clang 1.0 gcc 3.0 - # -Wpadded # clang 2.9 gcc 4.1 # Not used: We cannot change public structs -Wold-style-definition # clang 2.7 gcc 3.4 -Wredundant-decls # clang 2.7 gcc 4.1 -Wstrict-prototypes # clang 1.0 gcc 3.3 - # -Wswitch-enum # clang 2.7 gcc 4.1 # Not used: It basically disallows default case -Wtype-limits # clang 2.7 gcc 4.3 -Wunreachable-code # clang 2.7 gcc 4.1 # -Wunused-macros # clang 2.7 gcc 4.1 # Not practical @@ -139,6 +143,8 @@ if(PICKY_COMPILER) if(CMAKE_C_COMPILER_ID MATCHES "Clang") list(APPEND _picky_enable ${_picky_common_old} + -Wconditional-uninitialized # clang 3.0 + -Wno-used-but-marked-unused # clang 3.0 # Triggered by typecheck-gcc.h (with clang 14+) -Wshift-sign-overflow # clang 2.9 -Wshorten-64-to-32 # clang 1.0 -Wformat=2 # clang 3.0 gcc 4.8 @@ -149,39 +155,102 @@ if(PICKY_COMPILER) ) endif() # Enable based on compiler version + if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.1) + list(APPEND _picky_enable + -Wno-covered-switch-default # clang 3.1 appleclang 3.1 # Annoying to fix or silence + -Wno-disabled-macro-expansion # clang 3.1 appleclang 3.1 # Triggered by typecheck-gcc.h (with clang 14+) + ) + if(MSVC) + list(APPEND _picky_enable + -Wno-format-non-iso # clang 3.1 appleclang 3.1 # 'q' length modifier is not supported by ISO C + ) + else() + list(APPEND _picky_enable + -Wformat-non-iso # clang 3.1 appleclang 3.1 + ) + endif() + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.3) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0)) + list(APPEND _picky_enable + -Wenum-conversion # clang 3.2 gcc 10.0 appleclang 4.2 g++ 11.0 + -Wmissing-variable-declarations # clang 3.2 appleclang 4.2 + -Wno-documentation-unknown-command # clang 3.3 appleclang 5.0 + -Wsometimes-uninitialized # clang 3.2 appleclang 4.2 + ) + endif() if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.6) OR - (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.3)) + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.1)) list(APPEND _picky_enable - -Wdouble-promotion # clang 3.6 gcc 4.6 appleclang 6.3 - -Wenum-conversion # clang 3.2 gcc 10.0 appleclang 4.6 g++ 11.0 + -Wdouble-promotion # clang 3.6 gcc 4.6 appleclang 6.1 -Wheader-guard # clang 3.4 appleclang 5.1 -Wpragmas # clang 3.5 gcc 4.1 appleclang 6.0 - -Wsometimes-uninitialized # clang 3.2 appleclang 4.6 # -Wunreachable-code-break # clang 3.5 appleclang 6.0 # Not used: Silent in "unity" builds -Wunused-const-variable # clang 3.4 gcc 6.0 appleclang 5.1 ) endif() if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.9) OR - (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.3)) + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)) list(APPEND _picky_enable - -Wcomma # clang 3.9 appleclang 8.3 - -Wmissing-variable-declarations # clang 3.2 appleclang 4.6 + -Wcomma # clang 3.9 appleclang 8.1 ) + if(MSVC) + list(APPEND _picky_enable + -Wno-nonportable-system-include-path # clang 3.9 appleclang 8.1 # No truly portable solution to this + ) + endif() endif() if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0) OR - (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.3)) + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 11)) list(APPEND _picky_enable - -Wassign-enum # clang 7.0 appleclang 10.3 - -Wextra-semi-stmt # clang 7.0 appleclang 10.3 + -Wassign-enum # clang 7.0 appleclang 11.0 + -Wextra-semi-stmt # clang 7.0 appleclang 11.0 ) endif() if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0) OR - (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.4)) + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12)) + list(APPEND _picky_enable + -Wimplicit-fallthrough # clang 4.0 gcc 7.0 appleclang 9.0 # We do silencing for clang 10.0 and above only + -Wxor-used-as-pow # clang 10.0 gcc 13.0 appleclang 12.0 + ) + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1)) + list(APPEND _picky_enable + -Wcast-function-type # clang 13.0 appleclang 13.1 + -Wreserved-identifier # clang 13.0 appleclang 13.1 # Keep it before -Wno-reserved-macro-identifier + -Wno-reserved-macro-identifier # clang 13.0 appleclang 13.1 # External macros have to be set sometimes + ) + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0)) + list(APPEND _picky_enable + -Wno-unsafe-buffer-usage # clang 16.0 appleclang 15.0 + ) + endif() + if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) OR + (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)) list(APPEND _picky_enable - -Wimplicit-fallthrough # clang 4.0 gcc 7.0 appleclang 12.4 # We do silencing for clang 10.0 and above only - -Wxor-used-as-pow # clang 10.0 gcc 13.0 + -Wcast-function-type-strict # clang 16.0 appleclang 16.0 ) endif() + if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 21.0) + list(APPEND _picky_enable + -Warray-compare # clang 20.0 gcc 12.0 appleclang ? + -Wc++-hidden-decl # clang 21.0 appleclang ? + -Wno-implicit-void-ptr-cast # clang 21.0 appleclang ? + -Wtentative-definition-compat # clang 21.0 appleclang ? + ) + if(WIN32) + list(APPEND _picky_enable + -Wno-c++-keyword # clang 21.0 appleclang ? # `wchar_t` triggers it on Windows + ) + else() + list(APPEND _picky_enable + -Wc++-keyword # clang 21.0 appleclang ? + ) + endif() + endif() else() # gcc # Enable based on compiler version if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.3) @@ -207,7 +276,7 @@ if(PICKY_COMPILER) endif() if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4.8) list(APPEND _picky_enable - -Wdouble-promotion # clang 3.6 gcc 4.6 appleclang 6.3 + -Wdouble-promotion # clang 3.6 gcc 4.6 appleclang 6.1 -Wformat=2 # clang 3.0 gcc 4.8 -Wtrampolines # gcc 4.6 ) @@ -232,21 +301,21 @@ if(PICKY_COMPILER) -Walloc-zero # gcc 7.0 -Wduplicated-branches # gcc 7.0 -Wformat-truncation=2 # gcc 7.0 - -Wimplicit-fallthrough # clang 4.0 gcc 7.0 + -Wimplicit-fallthrough # clang 4.0 gcc 7.0 appleclang 9.0 -Wrestrict # gcc 7.0 ) endif() if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0) list(APPEND _picky_enable -Warith-conversion # gcc 10.0 - -Wenum-conversion # clang 3.2 gcc 10.0 appleclang 4.6 g++ 11.0 + -Wenum-conversion # clang 3.2 gcc 10.0 appleclang 4.2 g++ 11.0 ) endif() if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0) list(APPEND _picky_enable - -Warray-compare # clang 20.0 gcc 12.0 + -Warray-compare # clang 20.0 gcc 12.0 appleclang ? -Wenum-int-mismatch # gcc 13.0 - -Wxor-used-as-pow # clang 10.0 gcc 13.0 + -Wxor-used-as-pow # clang 10.0 gcc 13.0 appleclang 12.0 ) endif() if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0) @@ -262,8 +331,11 @@ if(PICKY_COMPILER) set(_picky_skipped "") foreach(_ccopt IN LISTS _picky_enable) - string(REGEX MATCH "-W([a-z0-9-]+)" _ccmatch "${_ccopt}") - if(_ccmatch AND CMAKE_C_FLAGS MATCHES "-Wno-${CMAKE_MATCH_1}" AND NOT _ccopt STREQUAL "-Wall" AND NOT _ccopt MATCHES "^-Wno-") + string(REGEX MATCH "-W([a-z0-9+-]+)" _ccmatch "${_ccopt}") + string(REPLACE "+" "\\+" _cmake_match_1 "${CMAKE_MATCH_1}") # escape '+' to make it a valid regex + if(_ccmatch AND "${CMAKE_C_FLAGS} " MATCHES "-Wno-${_cmake_match_1} " AND + NOT _ccopt STREQUAL "-Wall" AND + NOT _ccopt MATCHES "^-Wno-") string(APPEND _picky_skipped " ${_ccopt}") else() list(APPEND _picky "${_ccopt}") diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index a0b41aeb2473..07fba246d4c4 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -29,9 +29,9 @@ /* To add a new kind of warning, add an * if(curlcheck_sometype_option(_curl_opt)) * if(!curlcheck_sometype(value)) - * _curl_easy_setopt_err_sometype(); + * Wcurl_easy_setopt_err_sometype(); * block and define curlcheck_sometype_option, curlcheck_sometype and - * _curl_easy_setopt_err_sometype below + * Wcurl_easy_setopt_err_sometype below * * NOTE: We use two nested 'if' statements here instead of the && operator, in * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x @@ -47,113 +47,113 @@ CURL_IGNORE_DEPRECATION( \ if(curlcheck_long_option(option)) \ if(!curlcheck_long(value)) \ - _curl_easy_setopt_err_long(); \ + Wcurl_easy_setopt_err_long(); \ if(curlcheck_off_t_option(option)) \ if(!curlcheck_off_t(value)) \ - _curl_easy_setopt_err_curl_off_t(); \ + Wcurl_easy_setopt_err_curl_off_t(); \ if(curlcheck_string_option(option)) \ if(!curlcheck_string(value)) \ - _curl_easy_setopt_err_string(); \ + Wcurl_easy_setopt_err_string(); \ if((option) == CURLOPT_PRIVATE) { } \ if(curlcheck_write_cb_option(option)) \ if(!curlcheck_write_cb(value)) \ - _curl_easy_setopt_err_write_callback(); \ + Wcurl_easy_setopt_err_write_callback(); \ if(curlcheck_curl_option(option)) \ if(!curlcheck_curl(value)) \ - _curl_easy_setopt_err_curl(); \ + Wcurl_easy_setopt_err_curl(); \ if((option) == CURLOPT_RESOLVER_START_FUNCTION) \ if(!curlcheck_resolver_start_callback(value)) \ - _curl_easy_setopt_err_resolver_start_callback(); \ + Wcurl_easy_setopt_err_resolver_start_callback(); \ if((option) == CURLOPT_READFUNCTION) \ if(!curlcheck_read_cb(value)) \ - _curl_easy_setopt_err_read_cb(); \ + Wcurl_easy_setopt_err_read_cb(); \ if((option) == CURLOPT_IOCTLFUNCTION) \ if(!curlcheck_ioctl_cb(value)) \ - _curl_easy_setopt_err_ioctl_cb(); \ + Wcurl_easy_setopt_err_ioctl_cb(); \ if((option) == CURLOPT_SOCKOPTFUNCTION) \ if(!curlcheck_sockopt_cb(value)) \ - _curl_easy_setopt_err_sockopt_cb(); \ + Wcurl_easy_setopt_err_sockopt_cb(); \ if((option) == CURLOPT_OPENSOCKETFUNCTION) \ if(!curlcheck_opensocket_cb(value)) \ - _curl_easy_setopt_err_opensocket_cb(); \ + Wcurl_easy_setopt_err_opensocket_cb(); \ if((option) == CURLOPT_PROGRESSFUNCTION) \ if(!curlcheck_progress_cb(value)) \ - _curl_easy_setopt_err_progress_cb(); \ + Wcurl_easy_setopt_err_progress_cb(); \ if((option) == CURLOPT_XFERINFOFUNCTION) \ if(!curlcheck_xferinfo_cb(value)) \ - _curl_easy_setopt_err_xferinfo_cb(); \ + Wcurl_easy_setopt_err_xferinfo_cb(); \ if((option) == CURLOPT_DEBUGFUNCTION) \ if(!curlcheck_debug_cb(value)) \ - _curl_easy_setopt_err_debug_cb(); \ + Wcurl_easy_setopt_err_debug_cb(); \ if((option) == CURLOPT_SSL_CTX_FUNCTION) \ if(!curlcheck_ssl_ctx_cb(value)) \ - _curl_easy_setopt_err_ssl_ctx_cb(); \ + Wcurl_easy_setopt_err_ssl_ctx_cb(); \ if(curlcheck_conv_cb_option(option)) \ if(!curlcheck_conv_cb(value)) \ - _curl_easy_setopt_err_conv_cb(); \ + Wcurl_easy_setopt_err_conv_cb(); \ if((option) == CURLOPT_SEEKFUNCTION) \ if(!curlcheck_seek_cb(value)) \ - _curl_easy_setopt_err_seek_cb(); \ + Wcurl_easy_setopt_err_seek_cb(); \ if((option) == CURLOPT_CHUNK_BGN_FUNCTION) \ if(!curlcheck_chunk_bgn_cb(value)) \ - _curl_easy_setopt_err_chunk_bgn_cb(); \ + Wcurl_easy_setopt_err_chunk_bgn_cb(); \ if((option) == CURLOPT_CHUNK_END_FUNCTION) \ if(!curlcheck_chunk_end_cb(value)) \ - _curl_easy_setopt_err_chunk_end_cb(); \ + Wcurl_easy_setopt_err_chunk_end_cb(); \ if((option) == CURLOPT_CLOSESOCKETFUNCTION) \ if(!curlcheck_close_socket_cb(value)) \ - _curl_easy_setopt_err_close_socket_cb(); \ + Wcurl_easy_setopt_err_close_socket_cb(); \ if((option) == CURLOPT_FNMATCH_FUNCTION) \ if(!curlcheck_fnmatch_cb(value)) \ - _curl_easy_setopt_err_fnmatch_cb(); \ + Wcurl_easy_setopt_err_fnmatch_cb(); \ if((option) == CURLOPT_HSTSREADFUNCTION) \ if(!curlcheck_hstsread_cb(value)) \ - _curl_easy_setopt_err_hstsread_cb(); \ + Wcurl_easy_setopt_err_hstsread_cb(); \ if((option) == CURLOPT_HSTSWRITEFUNCTION) \ if(!curlcheck_hstswrite_cb(value)) \ - _curl_easy_setopt_err_hstswrite_cb(); \ + Wcurl_easy_setopt_err_hstswrite_cb(); \ if((option) == CURLOPT_SSH_HOSTKEYFUNCTION) \ if(!curlcheck_ssh_hostkey_cb(value)) \ - _curl_easy_setopt_err_ssh_hostkey_cb(); \ + Wcurl_easy_setopt_err_ssh_hostkey_cb(); \ if((option) == CURLOPT_SSH_KEYFUNCTION) \ if(!curlcheck_ssh_key_cb(value)) \ - _curl_easy_setopt_err_ssh_key_cb(); \ + Wcurl_easy_setopt_err_ssh_key_cb(); \ if((option) == CURLOPT_INTERLEAVEFUNCTION) \ if(!curlcheck_interleave_cb(value)) \ - _curl_easy_setopt_err_interleave_cb(); \ + Wcurl_easy_setopt_err_interleave_cb(); \ if((option) == CURLOPT_PREREQFUNCTION) \ if(!curlcheck_prereq_cb(value)) \ - _curl_easy_setopt_err_prereq_cb(); \ + Wcurl_easy_setopt_err_prereq_cb(); \ if((option) == CURLOPT_TRAILERFUNCTION) \ if(!curlcheck_trailer_cb(value)) \ - _curl_easy_setopt_err_trailer_cb(); \ + Wcurl_easy_setopt_err_trailer_cb(); \ if(curlcheck_cb_data_option(option)) \ if(!curlcheck_cb_data(value)) \ - _curl_easy_setopt_err_cb_data(); \ + Wcurl_easy_setopt_err_cb_data(); \ if((option) == CURLOPT_ERRORBUFFER) \ if(!curlcheck_error_buffer(value)) \ - _curl_easy_setopt_err_error_buffer(); \ + Wcurl_easy_setopt_err_error_buffer(); \ if((option) == CURLOPT_CURLU) \ if(!curlcheck_ptr((value), CURLU)) \ - _curl_easy_setopt_err_curlu(); \ + Wcurl_easy_setopt_err_curlu(); \ if((option) == CURLOPT_STDERR) \ if(!curlcheck_FILE(value)) \ - _curl_easy_setopt_err_FILE(); \ + Wcurl_easy_setopt_err_FILE(); \ if(curlcheck_postfields_option(option)) \ if(!curlcheck_postfields(value)) \ - _curl_easy_setopt_err_postfields(); \ + Wcurl_easy_setopt_err_postfields(); \ if((option) == CURLOPT_HTTPPOST) \ if(!curlcheck_arr((value), struct curl_httppost)) \ - _curl_easy_setopt_err_curl_httpost(); \ + Wcurl_easy_setopt_err_curl_httpost(); \ if((option) == CURLOPT_MIMEPOST) \ if(!curlcheck_ptr((value), curl_mime)) \ - _curl_easy_setopt_err_curl_mimepost(); \ + Wcurl_easy_setopt_err_curl_mimepost(); \ if(curlcheck_slist_option(option)) \ if(!curlcheck_arr((value), struct curl_slist)) \ - _curl_easy_setopt_err_curl_slist(); \ + Wcurl_easy_setopt_err_curl_slist(); \ if((option) == CURLOPT_SHARE) \ if(!curlcheck_ptr((value), CURLSH)) \ - _curl_easy_setopt_err_CURLSH(); \ + Wcurl_easy_setopt_err_CURLSH(); \ ) \ } \ curl_easy_setopt(handle, option, value); \ @@ -166,28 +166,28 @@ CURL_IGNORE_DEPRECATION( \ if(curlcheck_string_info(info)) \ if(!curlcheck_arr((arg), char *)) \ - _curl_easy_getinfo_err_string(); \ + Wcurl_easy_getinfo_err_string(); \ if(curlcheck_long_info(info)) \ if(!curlcheck_arr((arg), long)) \ - _curl_easy_getinfo_err_long(); \ + Wcurl_easy_getinfo_err_long(); \ if(curlcheck_double_info(info)) \ if(!curlcheck_arr((arg), double)) \ - _curl_easy_getinfo_err_double(); \ + Wcurl_easy_getinfo_err_double(); \ if(curlcheck_slist_info(info)) \ if(!curlcheck_arr((arg), struct curl_slist *)) \ - _curl_easy_getinfo_err_curl_slist(); \ + Wcurl_easy_getinfo_err_curl_slist(); \ if(curlcheck_tlssessioninfo_info(info)) \ if(!curlcheck_arr((arg), struct curl_tlssessioninfo *)) \ - _curl_easy_getinfo_err_curl_tlssessioninfo(); \ + Wcurl_easy_getinfo_err_curl_tlssessioninfo(); \ if(curlcheck_certinfo_info(info)) \ if(!curlcheck_arr((arg), struct curl_certinfo *)) \ - _curl_easy_getinfo_err_curl_certinfo(); \ + Wcurl_easy_getinfo_err_curl_certinfo(); \ if(curlcheck_socket_info(info)) \ if(!curlcheck_arr((arg), curl_socket_t)) \ - _curl_easy_getinfo_err_curl_socket(); \ + Wcurl_easy_getinfo_err_curl_socket(); \ if(curlcheck_off_t_info(info)) \ if(!curlcheck_arr((arg), curl_off_t)) \ - _curl_easy_getinfo_err_curl_off_t(); \ + Wcurl_easy_getinfo_err_curl_off_t(); \ ) \ } \ curl_easy_getinfo(handle, info, arg); \ @@ -198,25 +198,25 @@ if(__builtin_constant_p(option)) { \ if(curlcheck_long_option(option)) \ if(!curlcheck_long(value)) \ - _curl_multi_setopt_err_long(); \ + Wcurl_multi_setopt_err_long(); \ if(curlcheck_off_t_option(option)) \ if(!curlcheck_off_t(value)) \ - _curl_multi_setopt_err_curl_off_t(); \ + Wcurl_multi_setopt_err_curl_off_t(); \ if(curlcheck_multicb_data_option(option)) \ if(!curlcheck_cb_data(value)) \ - _curl_multi_setopt_err_cb_data(); \ + Wcurl_multi_setopt_err_cb_data(); \ if(curlcheck_charpp_option(option)) \ if(!curlcheck_ptrptr(value, char)) \ - _curl_multi_setopt_err_charpp(); \ + Wcurl_multi_setopt_err_charpp(); \ if((option) == CURLMOPT_PUSHFUNCTION) \ if(!curlcheck_multipush_cb(value)) \ - _curl_multi_setopt_err_pushcb(); \ + Wcurl_multi_setopt_err_pushcb(); \ if((option) == CURLMOPT_SOCKETFUNCTION) \ if(!curlcheck_multisocket_cb(value)) \ - _curl_multi_setopt_err_socketcb(); \ + Wcurl_multi_setopt_err_socketcb(); \ if((option) == CURLMOPT_TIMERFUNCTION) \ if(!curlcheck_multitimer_cb(value)) \ - _curl_multi_setopt_err_timercb(); \ + Wcurl_multi_setopt_err_timercb(); \ } \ curl_multi_setopt(handle, option, value); \ }) @@ -256,7 +256,7 @@ #define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) -/* the actual warnings, triggered by calling the _curl_easy_setopt_err* +/* the actual warnings, triggered by calling the Wcurl_easy_setopt_err* * functions */ /* To define a new warning, use _CURL_WARNING(identifier, "message") */ @@ -265,117 +265,117 @@ __attribute__((__unused__)) __attribute__((__noinline__)) \ id(void) { __asm__(""); } -CURLWARNING(_curl_multi_setopt_err_long, +CURLWARNING(Wcurl_multi_setopt_err_long, "curl_multi_setopt expects a long argument") -CURLWARNING(_curl_multi_setopt_err_curl_off_t, +CURLWARNING(Wcurl_multi_setopt_err_curl_off_t, "curl_multi_setopt expects a curl_off_t argument") -CURLWARNING(_curl_multi_setopt_err_cb_data, +CURLWARNING(Wcurl_multi_setopt_err_cb_data, "curl_multi_setopt expects a 'void *' argument") -CURLWARNING(_curl_multi_setopt_err_charpp, +CURLWARNING(Wcurl_multi_setopt_err_charpp, "curl_multi_setopt expects a 'char **' argument") -CURLWARNING(_curl_multi_setopt_err_pushcb, +CURLWARNING(Wcurl_multi_setopt_err_pushcb, "curl_multi_setopt expects a curl_push_callback argument") -CURLWARNING(_curl_multi_setopt_err_socketcb, +CURLWARNING(Wcurl_multi_setopt_err_socketcb, "curl_multi_setopt expects a curl_socket_callback argument") -CURLWARNING(_curl_multi_setopt_err_timercb, +CURLWARNING(Wcurl_multi_setopt_err_timercb, "curl_multi_setopt expects a curl_multi_timer_callback argument") -CURLWARNING(_curl_easy_setopt_err_long, +CURLWARNING(Wcurl_easy_setopt_err_long, "curl_easy_setopt expects a long argument") -CURLWARNING(_curl_easy_setopt_err_curl_off_t, +CURLWARNING(Wcurl_easy_setopt_err_curl_off_t, "curl_easy_setopt expects a curl_off_t argument") -CURLWARNING(_curl_easy_setopt_err_string, +CURLWARNING(Wcurl_easy_setopt_err_string, "curl_easy_setopt expects a " "string ('char *' or char[]) argument") -CURLWARNING(_curl_easy_setopt_err_write_callback, +CURLWARNING(Wcurl_easy_setopt_err_write_callback, "curl_easy_setopt expects a curl_write_callback argument") -CURLWARNING(_curl_easy_setopt_err_resolver_start_callback, +CURLWARNING(Wcurl_easy_setopt_err_resolver_start_callback, "curl_easy_setopt expects a " "curl_resolver_start_callback argument") -CURLWARNING(_curl_easy_setopt_err_read_cb, +CURLWARNING(Wcurl_easy_setopt_err_read_cb, "curl_easy_setopt expects a curl_read_callback argument") -CURLWARNING(_curl_easy_setopt_err_ioctl_cb, +CURLWARNING(Wcurl_easy_setopt_err_ioctl_cb, "curl_easy_setopt expects a curl_ioctl_callback argument") -CURLWARNING(_curl_easy_setopt_err_sockopt_cb, +CURLWARNING(Wcurl_easy_setopt_err_sockopt_cb, "curl_easy_setopt expects a curl_sockopt_callback argument") -CURLWARNING(_curl_easy_setopt_err_opensocket_cb, +CURLWARNING(Wcurl_easy_setopt_err_opensocket_cb, "curl_easy_setopt expects a " "curl_opensocket_callback argument") -CURLWARNING(_curl_easy_setopt_err_progress_cb, +CURLWARNING(Wcurl_easy_setopt_err_progress_cb, "curl_easy_setopt expects a curl_progress_callback argument") -CURLWARNING(_curl_easy_setopt_err_xferinfo_cb, +CURLWARNING(Wcurl_easy_setopt_err_xferinfo_cb, "curl_easy_setopt expects a curl_xferinfo_callback argument") -CURLWARNING(_curl_easy_setopt_err_debug_cb, +CURLWARNING(Wcurl_easy_setopt_err_debug_cb, "curl_easy_setopt expects a curl_debug_callback argument") -CURLWARNING(_curl_easy_setopt_err_ssl_ctx_cb, +CURLWARNING(Wcurl_easy_setopt_err_ssl_ctx_cb, "curl_easy_setopt expects a curl_ssl_ctx_callback argument") -CURLWARNING(_curl_easy_setopt_err_conv_cb, +CURLWARNING(Wcurl_easy_setopt_err_conv_cb, "curl_easy_setopt expects a curl_conv_callback argument") -CURLWARNING(_curl_easy_setopt_err_seek_cb, +CURLWARNING(Wcurl_easy_setopt_err_seek_cb, "curl_easy_setopt expects a curl_seek_callback argument") -CURLWARNING(_curl_easy_setopt_err_cb_data, +CURLWARNING(Wcurl_easy_setopt_err_cb_data, "curl_easy_setopt expects a " "private data pointer as argument") -CURLWARNING(_curl_easy_setopt_err_chunk_bgn_cb, +CURLWARNING(Wcurl_easy_setopt_err_chunk_bgn_cb, "curl_easy_setopt expects a curl_chunk_bgn_callback argument") -CURLWARNING(_curl_easy_setopt_err_chunk_end_cb, +CURLWARNING(Wcurl_easy_setopt_err_chunk_end_cb, "curl_easy_setopt expects a curl_chunk_end_callback argument") -CURLWARNING(_curl_easy_setopt_err_close_socket_cb, +CURLWARNING(Wcurl_easy_setopt_err_close_socket_cb, "curl_easy_setopt expects a curl_closesocket_callback argument") -CURLWARNING(_curl_easy_setopt_err_fnmatch_cb, +CURLWARNING(Wcurl_easy_setopt_err_fnmatch_cb, "curl_easy_setopt expects a curl_fnmatch_callback argument") -CURLWARNING(_curl_easy_setopt_err_hstsread_cb, +CURLWARNING(Wcurl_easy_setopt_err_hstsread_cb, "curl_easy_setopt expects a curl_hstsread_callback argument") -CURLWARNING(_curl_easy_setopt_err_hstswrite_cb, +CURLWARNING(Wcurl_easy_setopt_err_hstswrite_cb, "curl_easy_setopt expects a curl_hstswrite_callback argument") -CURLWARNING(_curl_easy_setopt_err_ssh_key_cb, +CURLWARNING(Wcurl_easy_setopt_err_ssh_key_cb, "curl_easy_setopt expects a curl_sshkeycallback argument") -CURLWARNING(_curl_easy_setopt_err_ssh_hostkey_cb, +CURLWARNING(Wcurl_easy_setopt_err_ssh_hostkey_cb, "curl_easy_setopt expects a curl_sshhostkeycallback argument") -CURLWARNING(_curl_easy_setopt_err_interleave_cb, +CURLWARNING(Wcurl_easy_setopt_err_interleave_cb, "curl_easy_setopt expects a curl_interleave_callback argument") -CURLWARNING(_curl_easy_setopt_err_prereq_cb, +CURLWARNING(Wcurl_easy_setopt_err_prereq_cb, "curl_easy_setopt expects a curl_prereq_callback argument") -CURLWARNING(_curl_easy_setopt_err_trailer_cb, +CURLWARNING(Wcurl_easy_setopt_err_trailer_cb, "curl_easy_setopt expects a curl_trailerfunc_ok argument") -CURLWARNING(_curl_easy_setopt_err_error_buffer, +CURLWARNING(Wcurl_easy_setopt_err_error_buffer, "curl_easy_setopt expects a " "char buffer of CURL_ERROR_SIZE as argument") -CURLWARNING(_curl_easy_setopt_err_curlu, +CURLWARNING(Wcurl_easy_setopt_err_curlu, "curl_easy_setopt expects a 'CURLU *' argument") -CURLWARNING(_curl_easy_setopt_err_curl, +CURLWARNING(Wcurl_easy_setopt_err_curl, "curl_easy_setopt expects a 'CURL *' argument") -CURLWARNING(_curl_easy_setopt_err_FILE, +CURLWARNING(Wcurl_easy_setopt_err_FILE, "curl_easy_setopt expects a 'FILE *' argument") -CURLWARNING(_curl_easy_setopt_err_postfields, +CURLWARNING(Wcurl_easy_setopt_err_postfields, "curl_easy_setopt expects a 'void *' or 'char *' argument") -CURLWARNING(_curl_easy_setopt_err_curl_httpost, +CURLWARNING(Wcurl_easy_setopt_err_curl_httpost, "curl_easy_setopt expects a 'struct curl_httppost *' " "argument") -CURLWARNING(_curl_easy_setopt_err_curl_mimepost, +CURLWARNING(Wcurl_easy_setopt_err_curl_mimepost, "curl_easy_setopt expects a 'curl_mime *' " "argument") -CURLWARNING(_curl_easy_setopt_err_curl_slist, +CURLWARNING(Wcurl_easy_setopt_err_curl_slist, "curl_easy_setopt expects a 'struct curl_slist *' argument") -CURLWARNING(_curl_easy_setopt_err_CURLSH, +CURLWARNING(Wcurl_easy_setopt_err_CURLSH, "curl_easy_setopt expects a CURLSH* argument") -CURLWARNING(_curl_easy_getinfo_err_string, +CURLWARNING(Wcurl_easy_getinfo_err_string, "curl_easy_getinfo expects a pointer to 'char *'") -CURLWARNING(_curl_easy_getinfo_err_long, +CURLWARNING(Wcurl_easy_getinfo_err_long, "curl_easy_getinfo expects a pointer to long") -CURLWARNING(_curl_easy_getinfo_err_double, +CURLWARNING(Wcurl_easy_getinfo_err_double, "curl_easy_getinfo expects a pointer to double") -CURLWARNING(_curl_easy_getinfo_err_curl_slist, +CURLWARNING(Wcurl_easy_getinfo_err_curl_slist, "curl_easy_getinfo expects a pointer to 'struct curl_slist *'") -CURLWARNING(_curl_easy_getinfo_err_curl_tlssessioninfo, +CURLWARNING(Wcurl_easy_getinfo_err_curl_tlssessioninfo, "curl_easy_getinfo expects a pointer to " "'struct curl_tlssessioninfo *'") -CURLWARNING(_curl_easy_getinfo_err_curl_certinfo, +CURLWARNING(Wcurl_easy_getinfo_err_curl_certinfo, "curl_easy_getinfo expects a pointer to " "'struct curl_certinfo *'") -CURLWARNING(_curl_easy_getinfo_err_curl_socket, +CURLWARNING(Wcurl_easy_getinfo_err_curl_socket, "curl_easy_getinfo expects a pointer to curl_socket_t") -CURLWARNING(_curl_easy_getinfo_err_curl_off_t, +CURLWARNING(Wcurl_easy_getinfo_err_curl_off_t, "curl_easy_getinfo expects a pointer to curl_off_t") /* groups of curl_easy_setops options that take the same type of argument */ @@ -704,60 +704,60 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), __typeof__(fread) *) || \ curlcheck_cb_compatible((expr), curl_read_callback) || \ - curlcheck_cb_compatible((expr), _curl_read_callback1) || \ - curlcheck_cb_compatible((expr), _curl_read_callback2) || \ - curlcheck_cb_compatible((expr), _curl_read_callback3) || \ - curlcheck_cb_compatible((expr), _curl_read_callback4) || \ - curlcheck_cb_compatible((expr), _curl_read_callback5) || \ - curlcheck_cb_compatible((expr), _curl_read_callback6)) -typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); -typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); -typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); -typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); -typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); -typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); + curlcheck_cb_compatible((expr), Wcurl_read_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_read_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_read_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_read_callback4) || \ + curlcheck_cb_compatible((expr), Wcurl_read_callback5) || \ + curlcheck_cb_compatible((expr), Wcurl_read_callback6)) +typedef size_t (*Wcurl_read_callback1)(char *, size_t, size_t, void *); +typedef size_t (*Wcurl_read_callback2)(char *, size_t, size_t, const void *); +typedef size_t (*Wcurl_read_callback3)(char *, size_t, size_t, FILE *); +typedef size_t (*Wcurl_read_callback4)(void *, size_t, size_t, void *); +typedef size_t (*Wcurl_read_callback5)(void *, size_t, size_t, const void *); +typedef size_t (*Wcurl_read_callback6)(void *, size_t, size_t, FILE *); /* evaluates to true if expr is of type curl_write_callback or "similar" */ #define curlcheck_write_cb(expr) \ (curlcheck_read_cb(expr) || \ curlcheck_cb_compatible((expr), __typeof__(fwrite) *) || \ curlcheck_cb_compatible((expr), curl_write_callback) || \ - curlcheck_cb_compatible((expr), _curl_write_callback1) || \ - curlcheck_cb_compatible((expr), _curl_write_callback2) || \ - curlcheck_cb_compatible((expr), _curl_write_callback3) || \ - curlcheck_cb_compatible((expr), _curl_write_callback4) || \ - curlcheck_cb_compatible((expr), _curl_write_callback5) || \ - curlcheck_cb_compatible((expr), _curl_write_callback6)) -typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); -typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, + curlcheck_cb_compatible((expr), Wcurl_write_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_write_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_write_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_write_callback4) || \ + curlcheck_cb_compatible((expr), Wcurl_write_callback5) || \ + curlcheck_cb_compatible((expr), Wcurl_write_callback6)) +typedef size_t (*Wcurl_write_callback1)(const char *, size_t, size_t, void *); +typedef size_t (*Wcurl_write_callback2)(const char *, size_t, size_t, const void *); -typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); -typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); -typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, +typedef size_t (*Wcurl_write_callback3)(const char *, size_t, size_t, FILE *); +typedef size_t (*Wcurl_write_callback4)(const void *, size_t, size_t, void *); +typedef size_t (*Wcurl_write_callback5)(const void *, size_t, size_t, const void *); -typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); +typedef size_t (*Wcurl_write_callback6)(const void *, size_t, size_t, FILE *); /* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ #define curlcheck_ioctl_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_ioctl_callback) || \ - curlcheck_cb_compatible((expr), _curl_ioctl_callback1) || \ - curlcheck_cb_compatible((expr), _curl_ioctl_callback2) || \ - curlcheck_cb_compatible((expr), _curl_ioctl_callback3) || \ - curlcheck_cb_compatible((expr), _curl_ioctl_callback4)) -typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); -typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); -typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); -typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); + curlcheck_cb_compatible((expr), Wcurl_ioctl_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_ioctl_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_ioctl_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_ioctl_callback4)) +typedef curlioerr (*Wcurl_ioctl_callback1)(CURL *, int, void *); +typedef curlioerr (*Wcurl_ioctl_callback2)(CURL *, int, const void *); +typedef curlioerr (*Wcurl_ioctl_callback3)(CURL *, curliocmd, void *); +typedef curlioerr (*Wcurl_ioctl_callback4)(CURL *, curliocmd, const void *); /* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ #define curlcheck_sockopt_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_sockopt_callback) || \ - curlcheck_cb_compatible((expr), _curl_sockopt_callback1) || \ - curlcheck_cb_compatible((expr), _curl_sockopt_callback2)) -typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); -typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, + curlcheck_cb_compatible((expr), Wcurl_sockopt_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_sockopt_callback2)) +typedef int (*Wcurl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (*Wcurl_sockopt_callback2)(const void *, curl_socket_t, curlsocktype); /* evaluates to true if expr is of type curl_opensocket_callback or @@ -765,28 +765,28 @@ typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, #define curlcheck_opensocket_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_opensocket_callback) || \ - curlcheck_cb_compatible((expr), _curl_opensocket_callback1) || \ - curlcheck_cb_compatible((expr), _curl_opensocket_callback2) || \ - curlcheck_cb_compatible((expr), _curl_opensocket_callback3) || \ - curlcheck_cb_compatible((expr), _curl_opensocket_callback4)) -typedef curl_socket_t (*_curl_opensocket_callback1) + curlcheck_cb_compatible((expr), Wcurl_opensocket_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_opensocket_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_opensocket_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_opensocket_callback4)) +typedef curl_socket_t (*Wcurl_opensocket_callback1) (void *, curlsocktype, struct curl_sockaddr *); -typedef curl_socket_t (*_curl_opensocket_callback2) +typedef curl_socket_t (*Wcurl_opensocket_callback2) (void *, curlsocktype, const struct curl_sockaddr *); -typedef curl_socket_t (*_curl_opensocket_callback3) +typedef curl_socket_t (*Wcurl_opensocket_callback3) (const void *, curlsocktype, struct curl_sockaddr *); -typedef curl_socket_t (*_curl_opensocket_callback4) +typedef curl_socket_t (*Wcurl_opensocket_callback4) (const void *, curlsocktype, const struct curl_sockaddr *); /* evaluates to true if expr is of type curl_progress_callback or "similar" */ #define curlcheck_progress_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_progress_callback) || \ - curlcheck_cb_compatible((expr), _curl_progress_callback1) || \ - curlcheck_cb_compatible((expr), _curl_progress_callback2)) -typedef int (*_curl_progress_callback1)(void *, + curlcheck_cb_compatible((expr), Wcurl_progress_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_progress_callback2)) +typedef int (*Wcurl_progress_callback1)(void *, double, double, double, double); -typedef int (*_curl_progress_callback2)(const void *, +typedef int (*Wcurl_progress_callback2)(const void *, double, double, double, double); /* evaluates to true if expr is of type curl_xferinfo_callback */ @@ -798,29 +798,29 @@ typedef int (*_curl_progress_callback2)(const void *, #define curlcheck_debug_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_debug_callback) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback1) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback2) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback3) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback4) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback5) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback6) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback7) || \ - curlcheck_cb_compatible((expr), _curl_debug_callback8)) -typedef int (*_curl_debug_callback1) (CURL *, + curlcheck_cb_compatible((expr), Wcurl_debug_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback4) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback5) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback6) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback7) || \ + curlcheck_cb_compatible((expr), Wcurl_debug_callback8)) +typedef int (*Wcurl_debug_callback1) (CURL *, curl_infotype, char *, size_t, void *); -typedef int (*_curl_debug_callback2) (CURL *, +typedef int (*Wcurl_debug_callback2) (CURL *, curl_infotype, char *, size_t, const void *); -typedef int (*_curl_debug_callback3) (CURL *, +typedef int (*Wcurl_debug_callback3) (CURL *, curl_infotype, const char *, size_t, void *); -typedef int (*_curl_debug_callback4) (CURL *, +typedef int (*Wcurl_debug_callback4) (CURL *, curl_infotype, const char *, size_t, const void *); -typedef int (*_curl_debug_callback5) (CURL *, +typedef int (*Wcurl_debug_callback5) (CURL *, curl_infotype, unsigned char *, size_t, void *); -typedef int (*_curl_debug_callback6) (CURL *, +typedef int (*Wcurl_debug_callback6) (CURL *, curl_infotype, unsigned char *, size_t, const void *); -typedef int (*_curl_debug_callback7) (CURL *, +typedef int (*Wcurl_debug_callback7) (CURL *, curl_infotype, const unsigned char *, size_t, void *); -typedef int (*_curl_debug_callback8) (CURL *, +typedef int (*Wcurl_debug_callback8) (CURL *, curl_infotype, const unsigned char *, size_t, const void *); /* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ @@ -828,66 +828,66 @@ typedef int (*_curl_debug_callback8) (CURL *, #define curlcheck_ssl_ctx_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_ssl_ctx_callback) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback1) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback2) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback3) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback4) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback5) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback6) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback7) || \ - curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback8)) -typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); -typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); -typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); -typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback4) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback5) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback6) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback7) || \ + curlcheck_cb_compatible((expr), Wcurl_ssl_ctx_callback8)) +typedef CURLcode (*Wcurl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback4)(CURL *, const void *, const void *); #ifdef HEADER_SSL_H /* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX * this will of course break if we are included before OpenSSL headers... */ -typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *); -typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *); -typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *); -typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX *, +typedef CURLcode (*Wcurl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *); +typedef CURLcode (*Wcurl_ssl_ctx_callback8)(CURL *, const SSL_CTX *, const void *); #else -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; -typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +typedef Wcurl_ssl_ctx_callback1 Wcurl_ssl_ctx_callback5; +typedef Wcurl_ssl_ctx_callback1 Wcurl_ssl_ctx_callback6; +typedef Wcurl_ssl_ctx_callback1 Wcurl_ssl_ctx_callback7; +typedef Wcurl_ssl_ctx_callback1 Wcurl_ssl_ctx_callback8; #endif /* evaluates to true if expr is of type curl_conv_callback or "similar" */ #define curlcheck_conv_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_conv_callback) || \ - curlcheck_cb_compatible((expr), _curl_conv_callback1) || \ - curlcheck_cb_compatible((expr), _curl_conv_callback2) || \ - curlcheck_cb_compatible((expr), _curl_conv_callback3) || \ - curlcheck_cb_compatible((expr), _curl_conv_callback4)) -typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); -typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); -typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); -typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + curlcheck_cb_compatible((expr), Wcurl_conv_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_conv_callback2) || \ + curlcheck_cb_compatible((expr), Wcurl_conv_callback3) || \ + curlcheck_cb_compatible((expr), Wcurl_conv_callback4)) +typedef CURLcode (*Wcurl_conv_callback1)(char *, size_t length); +typedef CURLcode (*Wcurl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*Wcurl_conv_callback3)(void *, size_t length); +typedef CURLcode (*Wcurl_conv_callback4)(const void *, size_t length); /* evaluates to true if expr is of type curl_seek_callback or "similar" */ #define curlcheck_seek_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_seek_callback) || \ - curlcheck_cb_compatible((expr), _curl_seek_callback1) || \ - curlcheck_cb_compatible((expr), _curl_seek_callback2)) -typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); -typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + curlcheck_cb_compatible((expr), Wcurl_seek_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_seek_callback2)) +typedef CURLcode (*Wcurl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*Wcurl_seek_callback2)(const void *, curl_off_t, int); /* evaluates to true if expr is of type curl_chunk_bgn_callback */ #define curlcheck_chunk_bgn_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_chunk_bgn_callback) || \ - curlcheck_cb_compatible((expr), _curl_chunk_bgn_callback1) || \ - curlcheck_cb_compatible((expr), _curl_chunk_bgn_callback2)) -typedef long (*_curl_chunk_bgn_callback1)(struct curl_fileinfo *, + curlcheck_cb_compatible((expr), Wcurl_chunk_bgn_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_chunk_bgn_callback2)) +typedef long (*Wcurl_chunk_bgn_callback1)(struct curl_fileinfo *, void *, int); -typedef long (*_curl_chunk_bgn_callback2)(void *, void *, int); +typedef long (*Wcurl_chunk_bgn_callback2)(void *, void *, int); /* evaluates to true if expr is of type curl_chunk_end_callback */ #define curlcheck_chunk_end_cb(expr) \ @@ -927,11 +927,11 @@ typedef long (*_curl_chunk_bgn_callback2)(void *, void *, int); /* evaluates to true if expr is of type curl_interleave_callback */ #define curlcheck_interleave_cb(expr) \ (curlcheck_NULL(expr) || \ - curlcheck_cb_compatible((expr), _curl_interleave_callback1) || \ - curlcheck_cb_compatible((expr), _curl_interleave_callback2)) -typedef size_t (*_curl_interleave_callback1)(void *p, size_t s, + curlcheck_cb_compatible((expr), Wcurl_interleave_callback1) || \ + curlcheck_cb_compatible((expr), Wcurl_interleave_callback2)) +typedef size_t (*Wcurl_interleave_callback1)(void *p, size_t s, size_t n, void *u); -typedef size_t (*_curl_interleave_callback2)(char *p, size_t s, +typedef size_t (*Wcurl_interleave_callback2)(char *p, size_t s, size_t n, void *u); /* evaluates to true if expr is of type curl_prereq_callback */ diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index e955990878ac..807ca5c0bd00 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -85,6 +85,17 @@ #if ARES_VERSION >= 0x011000 /* 1.16.0 or later has ares_getaddrinfo */ #define HAVE_CARES_GETADDRINFO 1 +#else +/* How long we are willing to wait for additional parallel responses after + obtaining a "definitive" one. For old c-ares without getaddrinfo. + + This is intended to equal the c-ares default timeout. cURL always uses that + default value. Unfortunately, c-ares does not expose its default timeout in + its API, but it is officially documented as 5 seconds. + + See query_completed_cb() for an explanation of how this is used. + */ +#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000 #endif #ifdef USE_HTTPSRR @@ -99,17 +110,6 @@ #include "curl_memory.h" #include "memdebug.h" -/* How long we are willing to wait for additional parallel responses after - obtaining a "definitive" one. For old c-ares without getaddrinfo. - - This is intended to equal the c-ares default timeout. cURL always uses that - default value. Unfortunately, c-ares does not expose its default timeout in - its API, but it is officially documented as 5 seconds. - - See query_completed_cb() for an explanation of how this is used. - */ -#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000 - #define CARES_TIMEOUT_PER_ATTEMPT 2000 static int ares_ver = 0; diff --git a/lib/curl_trc.c b/lib/curl_trc.c index 52671f4eaeb4..9426adcede4f 100644 --- a/lib/curl_trc.c +++ b/lib/curl_trc.c @@ -640,8 +640,6 @@ void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf, (void)data; (void)cf; (void)fmt; } -struct curl_trc_feat; - void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...) { (void)data; (void)fmt; diff --git a/lib/curl_trc.h b/lib/curl_trc.h index fa0999250fbe..2819abe2dd48 100644 --- a/lib/curl_trc.h +++ b/lib/curl_trc.h @@ -95,6 +95,11 @@ void Curl_trc_read(struct Curl_easy *data, void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...) CURL_PRINTF(2, 3); +struct curl_trc_feat { + const char *name; + int log_level; +}; + #ifndef CURL_DISABLE_FTP extern struct curl_trc_feat Curl_trc_feat_ftp; void Curl_trc_ftp(struct Curl_easy *data, @@ -184,11 +189,6 @@ void Curl_trc_ws(struct Curl_easy *data, #endif /* !CURL_HAVE_C99 */ -struct curl_trc_feat { - const char *name; - int log_level; -}; - #ifndef CURL_DISABLE_VERBOSE_STRINGS /* informational messages enabled */ diff --git a/lib/curlx/version_win32.c b/lib/curlx/version_win32.c index 8d0af68fcfe0..4efe62b111ca 100644 --- a/lib/curlx/version_win32.c +++ b/lib/curlx/version_win32.c @@ -134,8 +134,15 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, static bool onetime = TRUE; /* safe because first call is during init */ if(onetime) { +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN, (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo"))); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif onetime = FALSE; } diff --git a/lib/doh.c b/lib/doh.c index 030b026fe297..069d5387eaf0 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -759,7 +759,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh, ancount = doh_get16bit(doh, 6); while(ancount) { - unsigned short class; + unsigned short dnsclass; unsigned int ttl; rc = doh_skipqname(doh, dohlen, &index); @@ -779,8 +779,8 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh, if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; - class = doh_get16bit(doh, index); - if(DNS_CLASS_IN != class) + dnsclass = doh_get16bit(doh, index); + if(DNS_CLASS_IN != dnsclass) return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */ index += 2; @@ -816,7 +816,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh, if(dohlen < (index + 8)) return DOH_DNS_OUT_OF_RANGE; - index += 2 + 2 + 4; /* type, class and ttl */ + index += 2 + 2 + 4; /* type, dnsclass and ttl */ if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; @@ -838,7 +838,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh, if(dohlen < (index + 8)) return DOH_DNS_OUT_OF_RANGE; - index += 2 + 2 + 4; /* type, class and ttl */ + index += 2 + 2 + 4; /* type, dnsclass and ttl */ if(dohlen < (index + 2)) return DOH_DNS_OUT_OF_RANGE; diff --git a/lib/formdata.c b/lib/formdata.c index d8553e325694..475ca22fc864 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -868,10 +868,17 @@ CURLcode Curl_getformdata(CURL *data, particular, freopen(stdin) by the caller is not guaranteed to result as expected. This feature has been kept for backward compatibility: use of "-" pseudo filename should be avoided. */ +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif result = curl_mime_data_cb(part, (curl_off_t) -1, (curl_read_callback) fread, fseeko_wrapper, NULL, (void *) stdin); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif } else result = curl_mime_filedata(part, file->contents); diff --git a/lib/ftp.c b/lib/ftp.c index 6c710dceb962..6a33b6723cb8 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -142,11 +142,11 @@ static const char * const ftp_state_names[]={ #endif /* !CURL_DISABLE_VERBOSE_STRINGS */ /* This is the ONLY way to change FTP state! */ -static void _ftp_state(struct Curl_easy *data, - struct ftp_conn *ftpc, - ftpstate newstate +static void ftp_state_low(struct Curl_easy *data, + struct ftp_conn *ftpc, + ftpstate newstate #ifdef DEBUGBUILD - , int lineno + , int lineno #endif ) { @@ -172,9 +172,9 @@ static void _ftp_state(struct Curl_easy *data, /* Local API functions */ #ifndef DEBUGBUILD -#define ftp_state(x,y,z) _ftp_state(x,y,z) +#define ftp_state(x,y,z) ftp_state_low(x,y,z) #else /* !DEBUGBUILD */ -#define ftp_state(x,y,z) _ftp_state(x,y,z,__LINE__) +#define ftp_state(x,y,z) ftp_state_low(x,y,z,__LINE__) #endif /* DEBUGBUILD */ static CURLcode ftp_sendquote(struct Curl_easy *data, diff --git a/lib/httpsrr.c b/lib/httpsrr.c index df93ac34ac04..26b8522cc964 100644 --- a/lib/httpsrr.c +++ b/lib/httpsrr.c @@ -38,8 +38,6 @@ #include "curl_memory.h" #include "memdebug.h" -#define MAX_ALPN_LENGTH 255 - static CURLcode httpsrr_decode_alpn(const char *cp, size_t len, unsigned char *alpns) { diff --git a/lib/ldap.c b/lib/ldap.c index 4b232e2bb676..66cf8916d689 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -119,30 +119,30 @@ struct ldap_urldesc { char *lud_filter; #endif char **lud_exts; - size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the - "real" struct so can only be used in code - without HAVE_LDAP_URL_PARSE defined */ + size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the + "real" struct so can only be used in code + without HAVE_LDAP_URL_PARSE defined */ }; #undef LDAPURLDesc #define LDAPURLDesc struct ldap_urldesc -static int _ldap_url_parse(struct Curl_easy *data, - const struct connectdata *conn, - LDAPURLDesc **ludp); -static void _ldap_free_urldesc(LDAPURLDesc *ludp); +static int ldap_url_parse_low(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc **ludp); +static void ldap_free_urldesc_low(LDAPURLDesc *ludp); #undef ldap_free_urldesc -#define ldap_free_urldesc _ldap_free_urldesc +#define ldap_free_urldesc ldap_free_urldesc_low #endif #ifdef DEBUG_LDAP #define LDAP_TRACE(x) do { \ - _ldap_trace("%u: ", __LINE__); \ - _ldap_trace x; \ + ldap_trace_low("%u: ", __LINE__); \ + ldap_trace_low x; \ } while(0) - static void _ldap_trace(const char *fmt, ...) CURL_PRINTF(1, 2); + static void ldap_trace_low(const char *fmt, ...) CURL_PRINTF(1, 2); #else #define LDAP_TRACE(x) Curl_nop_stmt #endif @@ -346,7 +346,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #ifdef HAVE_LDAP_URL_PARSE rc = ldap_url_parse(data->state.url, &ludp); #else - rc = _ldap_url_parse(data, conn, &ludp); + rc = ldap_url_parse_low(data, conn, &ludp); #endif if(rc) { failf(data, "Bad LDAP URL: %s", ldap_err2string((curl_ldap_num_t)rc)); @@ -728,7 +728,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) } #ifdef DEBUG_LDAP -static void _ldap_trace(const char *fmt, ...) +static void ldap_trace_low(const char *fmt, ...) { static int do_trace = -1; va_list args; @@ -795,8 +795,9 @@ static size_t num_entries(const char *s) * * Defined in RFC4516 section 2. */ -static int _ldap_url_parse2(struct Curl_easy *data, - const struct connectdata *conn, LDAPURLDesc *ludp) +static int ldap_url_parse2_low(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc *ludp) { int rc = LDAP_SUCCESS; char *p; @@ -999,9 +1000,9 @@ static int _ldap_url_parse2(struct Curl_easy *data, return rc; } -static int _ldap_url_parse(struct Curl_easy *data, - const struct connectdata *conn, - LDAPURLDesc **ludpp) +static int ldap_url_parse_low(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc **ludpp) { LDAPURLDesc *ludp = calloc(1, sizeof(*ludp)); int rc; @@ -1010,16 +1011,16 @@ static int _ldap_url_parse(struct Curl_easy *data, if(!ludp) return LDAP_NO_MEMORY; - rc = _ldap_url_parse2(data, conn, ludp); + rc = ldap_url_parse2_low(data, conn, ludp); if(rc != LDAP_SUCCESS) { - _ldap_free_urldesc(ludp); + ldap_free_urldesc_low(ludp); ludp = NULL; } *ludpp = ludp; return rc; } -static void _ldap_free_urldesc(LDAPURLDesc *ludp) +static void ldap_free_urldesc_low(LDAPURLDesc *ludp) { if(!ludp) return; diff --git a/lib/mqtt.c b/lib/mqtt.c index 35afe012075f..01dd4e0a0d44 100644 --- a/lib/mqtt.c +++ b/lib/mqtt.c @@ -54,7 +54,7 @@ #define MQTT_MSG_SUBSCRIBE 0x82 #define MQTT_MSG_SUBACK 0x90 #define MQTT_MSG_DISCONNECT 0xe0 -#define MQTT_MSG_PINGREQ 0xC0 +/* #define MQTT_MSG_PINGREQ 0xC0 */ #define MQTT_MSG_PINGRESP 0xD0 #define MQTT_CONNACK_LEN 2 diff --git a/lib/multi_ev.c b/lib/multi_ev.c index 61c639d9e48d..49e6e673a040 100644 --- a/lib/multi_ev.c +++ b/lib/multi_ev.c @@ -51,8 +51,6 @@ static void mev_in_callback(struct Curl_multi *multi, bool value) multi->in_callback = value; } -#define CURL_MEV_CONN_HASH_SIZE 3 - /* Information about a socket for which we inform the libcurl application * what to supervise (CURL_POLL_IN/CURL_POLL_OUT/CURL_POLL_REMOVE) */ @@ -636,8 +634,6 @@ void Curl_multi_ev_conn_done(struct Curl_multi *multi, Curl_conn_meta_remove(conn, CURL_META_MEV_POLLSET); } -#define CURL_MEV_PS_HASH_SLOTS (991) /* nice prime */ - void Curl_multi_ev_init(struct Curl_multi *multi, size_t hashsize) { Curl_hash_init(&multi->ev.sh_entries, hashsize, mev_sh_entry_hash, diff --git a/lib/sendf.c b/lib/sendf.c index 551bb5ca81a6..f759fb61a4af 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -878,7 +878,14 @@ static CURLcode cr_in_rewind(struct Curl_easy *data, /* If no CURLOPT_READFUNCTION is used, we know that we operate on a given FILE * stream and we can actually attempt to rewind that ourselves with fseek() */ +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif if(data->state.fread_func == (curl_read_callback)fread) { +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif int err = fseek(data->state.in, 0, SEEK_SET); CURL_TRC_READ(data, "cr_in, rewind via fseek -> %d(%d)", (int)err, (int)errno); diff --git a/lib/setopt.c b/lib/setopt.c index d7a7f6c52d89..d958c5492a8d 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -818,10 +818,10 @@ static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, #if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \ defined(TCP_FASTOPEN_CONNECT) s->tcp_fastopen = enabled; + break; #else return CURLE_NOT_BUILT_IN; #endif - break; case CURLOPT_SSL_ENABLE_ALPN: s->ssl_enable_alpn = enabled; break; @@ -2637,8 +2637,15 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, */ s->fwrite_func = va_arg(param, curl_write_callback); if(!s->fwrite_func) +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif /* When set to NULL, reset to our internal default function */ s->fwrite_func = (curl_write_callback)fwrite; +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif break; case CURLOPT_READFUNCTION: /* @@ -2647,8 +2654,15 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, s->fread_func_set = va_arg(param, curl_read_callback); if(!s->fread_func_set) { s->is_fread_set = 0; +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif /* When set to NULL, reset to our internal default function */ s->fread_func_set = (curl_read_callback)fread; +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif } else s->is_fread_set = 1; diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index cdc9ef864a9a..7af0b081e28e 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -71,7 +71,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, CURLcode code; size_t actualread; size_t written; - int result; + CURLcode result; + int err; /* Needs GSS-API authentication */ SECURITY_STATUS status; unsigned long sspi_ret_flags = 0; @@ -236,8 +237,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, * +----+------+-----+----------------+ */ - result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); - if(result || (actualread != 4)) { + err = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(err || (actualread != 4)) { failf(data, "Failed to receive SSPI authentication response."); result = CURLE_COULDNT_CONNECT; goto error; @@ -268,10 +269,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, result = CURLE_OUT_OF_MEMORY; goto error; } - result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, - sspi_recv_token.cbBuffer, &actualread); + err = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, + sspi_recv_token.cbBuffer, &actualread); - if(result || (actualread != us_length)) { + if(err || (actualread != us_length)) { failf(data, "Failed to receive SSPI authentication token."); result = CURLE_COULDNT_CONNECT; goto error; @@ -452,8 +453,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, Curl_safefree(etbuf); } - result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); - if(result || (actualread != 4)) { + err = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(err || (actualread != 4)) { failf(data, "Failed to receive SSPI encryption response."); result = CURLE_COULDNT_CONNECT; goto error; @@ -484,10 +485,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, goto error; } - result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer, &actualread); + err = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, + sspi_w_token[0].cbBuffer, &actualread); - if(result || (actualread != us_length)) { + if(err || (actualread != us_length)) { failf(data, "Failed to receive SSPI encryption type."); result = CURLE_COULDNT_CONNECT; goto error; diff --git a/lib/url.c b/lib/url.c index 29702296a98d..3f792ec7655e 100644 --- a/lib/url.c +++ b/lib/url.c @@ -365,11 +365,18 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->in_set = stdin; /* default input from stdin */ set->err = stderr; /* default stderr to stderr */ +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif /* use fwrite as default function to store output */ set->fwrite_func = (curl_write_callback)fwrite; /* use fread as default function to read input */ set->fread_func_set = (curl_read_callback)fread; +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif set->is_fread_set = 0; set->seek_client = ZERO_NULL; diff --git a/lib/urlapi.c b/lib/urlapi.c index c89852794e05..7776645b4a0b 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -42,11 +42,13 @@ #include "curl_memory.h" #include "memdebug.h" +#ifdef _WIN32 /* MS-DOS/Windows style drive prefix, eg c: in c:foo */ #define STARTS_WITH_DRIVE_PREFIX(str) \ ((('a' <= str[0] && str[0] <= 'z') || \ ('A' <= str[0] && str[0] <= 'Z')) && \ (str[1] == ':')) +#endif /* MS-DOS/Windows style drive prefix, optionally with * a '|' instead of ':', followed by a slash or NUL */ diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 6cadc8fc58d1..246e0d51f661 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -80,7 +80,6 @@ #define QUIC_MAX_STREAMS (256*1024) -#define QUIC_MAX_DATA (1*1024*1024) #define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS) /* A stream window is the maximum amount we need to buffer for @@ -102,8 +101,6 @@ (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2 /* Receive and Send max number of chunks just follows from the * chunk size and window size */ -#define H3_STREAM_RECV_CHUNKS \ - (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) #define H3_STREAM_SEND_CHUNKS \ (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) @@ -1445,10 +1442,6 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id, return (nghttp3_ssize)nvecs; } -/* Index where :authority header field will appear in request header - field list. */ -#define AUTHORITY_DST_IDX 3 - static CURLcode h3_stream_open(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index c1563c4e6309..b88b4e97bd3d 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -75,8 +75,6 @@ * chunk size and window size */ #define H3_STREAM_RECV_CHUNKS \ (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) -#define H3_STREAM_SEND_CHUNKS \ - (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) /* * Store quiche version info in this buffer. @@ -955,10 +953,6 @@ static CURLcode cf_quiche_send_body(struct Curl_cfilter *cf, } } -/* Index where :authority header field will appear in request header - field list. */ -#define AUTHORITY_DST_IDX 3 - static CURLcode h3_open_stream(struct Curl_cfilter *cf, struct Curl_easy *data, const char *buf, size_t blen, bool eos, diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 69284407ab98..ebfd241e6c54 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1216,9 +1216,6 @@ sftp_upload_init(struct Curl_easy *data, return CURLE_OK; } -/* make sure that this does not collide with an actual libssh2 error code */ -#define ERROR_LIBBSH2 1 - static CURLcode ssh_state_pkey_init(struct Curl_easy *data, struct ssh_conn *sshc) { @@ -3411,12 +3408,19 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) */ #if LIBSSH2_VERSION_NUM >= 0x010b01 infof(data, "Uses HTTPS proxy"); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif libssh2_session_callback_set2(sshc->ssh_session, LIBSSH2_CALLBACK_RECV, (libssh2_cb_generic *)ssh_tls_recv); libssh2_session_callback_set2(sshc->ssh_session, LIBSSH2_CALLBACK_SEND, (libssh2_cb_generic *)ssh_tls_send); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif #else /* * This crazy union dance is here to avoid assigning a void pointer a diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index eef64886e1e3..e9252ec2a1d5 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -2064,7 +2064,7 @@ static CURLcode gtls_shutdown(struct Curl_cfilter *cf, (struct gtls_ssl_backend_data *)connssl->backend; char buf[1024]; CURLcode result = CURLE_OK; - ssize_t nread; + ssize_t nread = 0; size_t i; DEBUGASSERT(backend); diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 7b1a31e42f5b..a8abd0fe09a5 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -1160,7 +1160,7 @@ static CURLcode mbedtls_shutdown(struct Curl_cfilter *cf, (struct mbed_ssl_backend_data *)connssl->backend; unsigned char buf[1024]; CURLcode result = CURLE_OK; - int ret; + int ret = 0; size_t i; DEBUGASSERT(backend); diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index af890b6c5795..66084a27c3dc 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -137,13 +137,13 @@ static void ossl_provider_cleanup(struct Curl_easy *data); #if defined(USE_OPENSSL_ENGINE) || defined(OPENSSL_HAS_PROVIDERS) #include -#endif #if OPENSSL_VERSION_NUMBER >= 0x10100000L #define OSSL_UI_METHOD_CAST(x) (x) #else #define OSSL_UI_METHOD_CAST(x) CURL_UNCONST(x) #endif +#endif #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL 1.1.0+ and LibreSSL */ #define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ @@ -1631,7 +1631,14 @@ static int pkcs12load(struct Curl_easy *data, fail: EVP_PKEY_free(pri); X509_free(x509); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif sk_X509_pop_free(ca, X509_free); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif if(!cert_done) return 0; /* failure! */ return 1; @@ -3158,7 +3165,14 @@ static CURLcode load_cacert_from_memory(X509_STORE *store, } } +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif sk_X509_INFO_pop_free(inf, X509_INFO_free); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif BIO_free(cbio); /* if we did not end up importing anything, treat that as an error */ diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 221a7a6215ad..905d4f8a99e3 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -432,7 +432,7 @@ cr_get_selected_ciphers(struct Curl_easy *data, { const size_t supported_len = *selected_size; const size_t default_len = rustls_default_crypto_provider_ciphersuites_len(); - const struct rustls_supported_ciphersuite *entry; + const struct rustls_supported_ciphersuite *entry = NULL; const char *ciphers = ciphers12; size_t count = 0, default13_count = 0, i, j; const char *ptr, *end; @@ -1315,7 +1315,7 @@ cr_shutdown(struct Curl_cfilter *cf, struct rustls_ssl_backend_data *backend = (struct rustls_ssl_backend_data *)connssl->backend; CURLcode result = CURLE_OK; - size_t i, nread, nwritten; + size_t i, nread = 0, nwritten; DEBUGASSERT(backend); if(!backend->conn || cf->shutdown) { diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index fb9ef108226b..0cc34b138958 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -771,7 +771,9 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, SCH_CREDENTIALS credentials = { 0 }; TLS_PARAMETERS tls_parameters = { 0 }; - CRYPTO_SETTINGS crypto_settings[1] = { { 0 } }; + CRYPTO_SETTINGS crypto_settings[1]; + + memset(crypto_settings, 0, sizeof(crypto_settings)); tls_parameters.pDisabledCrypto = crypto_settings; @@ -2551,10 +2553,17 @@ static int schannel_init(void) { #if defined(HAS_ALPN_SCHANNEL) && !defined(UNDER_CE) typedef const char *(APIENTRY *WINE_GET_VERSION_FN)(void); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif WINE_GET_VERSION_FN p_wine_get_version = CURLX_FUNCTION_CAST(WINE_GET_VERSION_FN, (GetProcAddress(GetModuleHandleA("ntdll"), "wine_get_version"))); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif if(p_wine_get_version) { /* WINE detected */ const char *wine_version = p_wine_get_version(); /* e.g. "6.0.2" */ /* Assume ALPN support with WINE 6.0 or upper */ diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index afbb9b82182c..693cbdc92e21 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -1095,9 +1095,6 @@ static CURLcode ssl_version(struct Curl_easy *data, } -#define QUIC_CIPHERS \ - "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ - "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" #define QUIC_GROUPS "P-256:P-384:P-521" CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c index fe47e81a87d8..96b7f5bd630c 100644 --- a/lib/vtls/x509asn1.c +++ b/lib/vtls/x509asn1.c @@ -199,7 +199,7 @@ static const char *getASN1Element_(struct Curl_asn1Element *elem, elem->header = beg; b = (unsigned char) *beg++; elem->constructed = (b & 0x20) != 0; - elem->class = (b >> 6) & 3; + elem->eclass = (b >> 6) & 3; b &= 0x1F; if(b == 0x1F) return NULL; /* Long tag values not supported here. */ @@ -456,7 +456,7 @@ static CURLcode encodeOID(struct dynbuf *store, x = 0; do { if(x & 0xFF000000) - return 0; + return CURLE_OK; y = *(const unsigned char *) beg++; x = (x << 7) | (y & 0x7F); } while(y & 0x80); diff --git a/lib/vtls/x509asn1.h b/lib/vtls/x509asn1.h index f9bd455b704e..51ea0c2cd668 100644 --- a/lib/vtls/x509asn1.h +++ b/lib/vtls/x509asn1.h @@ -42,7 +42,7 @@ struct Curl_asn1Element { const char *header; /* Pointer to header byte. */ const char *beg; /* Pointer to element data. */ const char *end; /* Pointer to 1st byte after element. */ - unsigned char class; /* ASN.1 element class. */ + unsigned char eclass; /* ASN.1 element class. */ unsigned char tag; /* ASN.1 element tag. */ BIT(constructed); /* Element is constructed. */ }; diff --git a/m4/curl-compilers.m4 b/m4/curl-compilers.m4 index dc6d3aa4cfa3..0e4c4e2655b0 100644 --- a/m4/curl-compilers.m4 +++ b/m4/curl-compilers.m4 @@ -120,16 +120,18 @@ AC_DEFUN([CURL_CHECK_COMPILER_CLANG], [ compiler_num=`(expr $clangvhi "*" 100 + $clangvlo) 2>/dev/null` if test "$appleclang" = '1' && test "$oldapple" = '0'; then dnl Starting with Xcode 7 / clang 3.7, Apple clang won't tell its upstream version - if test "$compiler_num" -ge '1300'; then compiler_num='1200' - elif test "$compiler_num" -ge '1205'; then compiler_num='1101' - elif test "$compiler_num" -ge '1204'; then compiler_num='1000' - elif test "$compiler_num" -ge '1107'; then compiler_num='900' - elif test "$compiler_num" -ge '1103'; then compiler_num='800' - elif test "$compiler_num" -ge '1003'; then compiler_num='700' - elif test "$compiler_num" -ge '1001'; then compiler_num='600' - elif test "$compiler_num" -ge '904'; then compiler_num='500' - elif test "$compiler_num" -ge '902'; then compiler_num='400' - elif test "$compiler_num" -ge '803'; then compiler_num='309' + if test "$compiler_num" -ge '1700'; then compiler_num='1901' + elif test "$compiler_num" -ge '1600'; then compiler_num='1700' + elif test "$compiler_num" -ge '1500'; then compiler_num='1600' + elif test "$compiler_num" -ge '1400'; then compiler_num='1400' + elif test "$compiler_num" -ge '1301'; then compiler_num='1300' + elif test "$compiler_num" -ge '1300'; then compiler_num='1200' + elif test "$compiler_num" -ge '1200'; then compiler_num='1000' + elif test "$compiler_num" -ge '1100'; then compiler_num='800' + elif test "$compiler_num" -ge '1000'; then compiler_num='600' + elif test "$compiler_num" -ge '901'; then compiler_num='500' + elif test "$compiler_num" -ge '900'; then compiler_num='400' + elif test "$compiler_num" -ge '801'; then compiler_num='309' elif test "$compiler_num" -ge '703'; then compiler_num='308' else compiler_num='307' fi @@ -827,9 +829,10 @@ AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [empty-body]) CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-field-initializers]) CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [missing-noreturn]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-switch-default" + tmp_CFLAGS="$tmp_CFLAGS -Wno-switch-enum" # Not used because this basically disallows default case CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [old-style-definition]) CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [redundant-decls]) - # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [switch-enum]) # Not used because this basically disallows default case CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [type-limits]) # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused-macros]) # Not practical # tmp_CFLAGS="$tmp_CFLAGS -Wno-error=unused-macros" @@ -845,15 +848,23 @@ AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ dnl Only clang 2.9 or later if test "$compiler_num" -ge "209"; then tmp_CFLAGS="$tmp_CFLAGS -Wno-sign-conversion" + tmp_CFLAGS="$tmp_CFLAGS -Wno-padded" # Not used because we cannot change public structs CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [shift-sign-overflow]) - # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [padded]) # Not used because we cannot change public structs fi # dnl Only clang 3.0 or later if test "$compiler_num" -ge "300"; then CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [cast-qual]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [conditional-uninitialized]) CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [language-extension-token]) tmp_CFLAGS="$tmp_CFLAGS -Wformat=2" + tmp_CFLAGS="$tmp_CFLAGS -Wno-used-but-marked-unused" # Triggered by typecheck-gcc.h (with clang 14+) + fi + dnl Only clang 3.1 or later + if test "$compiler_num" -ge "301"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [format-non-iso]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-covered-switch-default" # Annoying to fix or silence + tmp_CFLAGS="$tmp_CFLAGS -Wno-disabled-macro-expansion" # Triggered by typecheck-gcc.h (with clang 14+) fi # dnl Only clang 3.2 or later @@ -870,6 +881,10 @@ AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ ;; esac fi + dnl Only clang 3.3 or later + if test "$compiler_num" -ge "303"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-documentation-unknown-command" + fi # dnl Only clang 3.4 or later if test "$compiler_num" -ge "304"; then @@ -907,6 +922,35 @@ AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough" # we have silencing markup for clang 10.0 and above only CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [xor-used-as-pow]) fi + dnl clang 13 or later + if test "$compiler_num" -ge "1300"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [cast-function-type]) + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [reserved-identifier]) # Keep it before -Wno-reserved-macro-identifier + tmp_CFLAGS="$tmp_CFLAGS -Wno-reserved-macro-identifier" # Sometimes such external macros need to be set + fi + dnl clang 16 or later + if test "$compiler_num" -ge "1600"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-unsafe-buffer-usage" + fi + dnl clang 17 or later + if test "$compiler_num" -ge "1700"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [cast-function-type-strict]) # with Apple clang it requires 16.0 or above + fi + dnl clang 20 or later + if test "$compiler_num" -ge "2000"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [array-compare]) + fi + dnl clang 21 or later + if test "$compiler_num" -ge "2100"; then + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [c++-hidden-decl]) + tmp_CFLAGS="$tmp_CFLAGS -Wno-implicit-void-ptr-cast" + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [tentative-definition-compat]) + if test "$curl_cv_native_windows" = "yes"; then + tmp_CFLAGS="$tmp_CFLAGS -Wno-c++-keyword" # `wchar_t` triggers it on Windows + else + CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [c++-keyword]) + fi + fi fi ;; # @@ -1015,10 +1059,11 @@ AC_DEFUN([CURL_SET_COMPILER_WARNING_OPTS], [ ;; esac CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unreachable-code unused-parameter]) - # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [padded]) # Not used because we cannot change public structs + tmp_CFLAGS="$tmp_CFLAGS -Wno-padded" # Not used because we cannot change public structs + tmp_CFLAGS="$tmp_CFLAGS -Wno-switch-default" + tmp_CFLAGS="$tmp_CFLAGS -Wno-switch-enum" # Not used because this basically disallows default case CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [pragmas]) CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [redundant-decls]) - # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [switch-enum]) # Not used because this basically disallows default case # CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [unused-macros]) # Not practical # tmp_CFLAGS="$tmp_CFLAGS -Wno-error=unused-macros" fi diff --git a/src/curlinfo.c b/src/curlinfo.c index d601904f3eef..14eb2f88c3d8 100644 --- a/src/curlinfo.c +++ b/src/curlinfo.c @@ -236,18 +236,16 @@ static const char *disabled[]={ #else "OFF" #endif - , - NULL }; int main(int argc, char **argv) { - int i; + size_t i; (void)argc; (void)argv; - for(i = 0; disabled[i]; i++) + for(i = 0; i < CURL_ARRAYSIZE(disabled); i++) printf("%s\n", disabled[i]); return 0; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index b8fec5f7ab3b..43d30778de64 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -2109,7 +2109,6 @@ static ParameterError opt_bool(struct OperationConfig *config, break; case C_REMOTE_NAME: /* --remote-name */ return parse_remote_name(config, toggle); - break; case C_PROXYTUNNEL: /* --proxytunnel */ config->proxytunnel = toggle; break; @@ -2131,7 +2130,6 @@ static ParameterError opt_bool(struct OperationConfig *config, break; case C_VERBOSE: /* --verbose */ return parse_verbose(toggle); - break; case C_VERSION: /* --version */ if(toggle) /* --no-version yields no output! */ return PARAM_VERSION_INFO_REQUESTED; @@ -2801,7 +2799,6 @@ static ParameterError opt_string(struct OperationConfig *config, else global->parallel_host = (unsigned short)val; break; - break; case C_PARALLEL_MAX: /* --parallel-max */ err = str2unum(&val, nextarg); if(err) diff --git a/src/tool_operate.c b/src/tool_operate.c index 8ca3c14e8f12..14eff06e0630 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1934,7 +1934,7 @@ static CURLcode serial_transfers(CURLSH *share) return result; } -static CURLcode is_using_schannel(int *using) +static CURLcode is_using_schannel(int *pusing) { CURLcode result = CURLE_OK; static int using_schannel = -1; /* -1 = not checked @@ -1958,7 +1958,7 @@ static CURLcode is_using_schannel(int *using) if(result) return result; } - *using = using_schannel; + *pusing = using_schannel; return result; } diff --git a/tests/libtest/lib1565.c b/tests/libtest/lib1565.c index 3fecdd84ce48..1b218d37a773 100644 --- a/tests/libtest/lib1565.c +++ b/tests/libtest/lib1565.c @@ -95,7 +95,7 @@ static CURLcode test_lib1565(const char *URL) CURL *started_handles[CONN_NUM]; int started_num = 0; int finished_num = 0; - pthread_t tid; + pthread_t tid = 0; bool tid_valid = false; struct CURLMsg *message; diff --git a/tests/libtest/lib557.c b/tests/libtest/lib557.c index 9742272a4409..f831c9bfc252 100644 --- a/tests/libtest/lib557.c +++ b/tests/libtest/lib557.c @@ -42,6 +42,10 @@ #if !defined(__clang__) && __GNUC__ >= 7 #pragma GCC diagnostic ignored "-Wformat-overflow" #endif +#if defined(__clang__) && \ + (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 1)) +#pragma clang diagnostic ignored "-Wformat-non-iso" +#endif #endif #define BUFSZ 256 @@ -1101,7 +1105,7 @@ static int test_curl_off_t_formatting(void) return failed; } -static int _string_check(int linenumber, char *buf, const char *buf2) +static int string_check_low(int linenumber, char *buf, const char *buf2) { if(strcmp(buf, buf2)) { /* they shouldn't differ */ @@ -1111,9 +1115,9 @@ static int _string_check(int linenumber, char *buf, const char *buf2) } return 0; } -#define string_check(x,y) _string_check(__LINE__, x, y) +#define string_check(x,y) string_check_low(__LINE__, x, y) -static int _strlen_check(int linenumber, char *buf, size_t len) +static int strlen_check_low(int linenumber, char *buf, size_t len) { size_t buflen = strlen(buf); if(len != buflen) { @@ -1124,8 +1128,7 @@ static int _strlen_check(int linenumber, char *buf, size_t len) } return 0; } - -#define strlen_check(x,y) _strlen_check(__LINE__, x, y) +#define strlen_check(x,y) strlen_check_low(__LINE__, x, y) /* * The output strings in this test need to have been verified with a system diff --git a/tests/unit/unit1398.c b/tests/unit/unit1398.c index fcdd3ec9bfd7..1b72bf1163b1 100644 --- a/tests/unit/unit1398.c +++ b/tests/unit/unit1398.c @@ -91,9 +91,18 @@ static CURLcode test_unit1398(const char *arg) fail_unless(rc == 15, "return code should be 15"); fail_unless(!strcmp(output, " 1234 567"), "wrong output"); +#if defined(__clang__) && \ + (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 1)) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-non-iso" +#endif /* double precision */ rc = curl_msnprintf(output, 24, "%2$.*1$.99d", 3, 5678); fail_unless(rc == 0, "return code should be 0"); +#if defined(__clang__) && \ + (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 1)) +#pragma clang diagnostic pop +#endif /* 129 input % flags */ rc = curl_msnprintf(output, 130, From 1429858bcea20a022ce7e21d0f6a9c826332b95e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 19 Sep 2025 22:22:14 +0200 Subject: [PATCH 085/465] tidy-up: update MS links, allow long URLs via `checksrc` - update Microsoft documentation links. (also drop language designator where present.) - checksrc: allow longer than 78 character lines if they contain a https URL. To make these links easier to use and parse. - merge links that were split into two lines. Closes #18626 --- docs/CIPHERS.md | 6 +++--- docs/INSTALL.md | 6 +++--- docs/TODO | 4 ++-- lib/cf-socket.c | 2 +- lib/cf-socket.h | 2 +- lib/curlx/multibyte.c | 2 +- lib/select.h | 2 +- lib/vauth/ntlm_sspi.c | 3 +-- lib/vauth/spnego_sspi.c | 3 +-- lib/vtls/openssl.c | 6 ++---- lib/vtls/schannel.c | 13 ++++++------- lib/vtls/schannel_verify.c | 2 +- scripts/checksrc.pl | 2 +- src/tool_doswin.c | 7 +++---- tests/server/sockfilt.c | 4 ++-- tests/server/util.c | 11 ++++------- 16 files changed, 33 insertions(+), 42 deletions(-) diff --git a/docs/CIPHERS.md b/docs/CIPHERS.md index 8ce938d9c2d9..7d9a1edf4762 100644 --- a/docs/CIPHERS.md +++ b/docs/CIPHERS.md @@ -163,11 +163,11 @@ for further information on that format. Schannel does not support setting individual TLS 1.2 cipher suites directly. It only allows the enabling and disabling of encryption algorithms. These are in the form of `CALG_xxx`, see the [Schannel `ALG_ID` -documentation](https://docs.microsoft.com/windows/desktop/SecCrypto/alg-id) +documentation](https://learn.microsoft.com/windows/win32/seccrypto/alg-id) for a list of these algorithms. Also, (since curl 7.77.0) `SCH_USE_STRONG_CRYPTO` can be given to pass that flag to Schannel, lookup the [documentation for the Windows version in -use](https://learn.microsoft.com/en-us/windows/win32/secauthn/cipher-suites-in-schannel) +use](https://learn.microsoft.com/windows/win32/secauthn/cipher-suites-in-schannel) to see how that affects the cipher suite selection. When not specifying the `--ciphers` and `--tls13-ciphers` options curl passes this flag by default. @@ -264,7 +264,7 @@ Restrict to only TLS 1.2 with the `CAMELLIA-128-GCM` cipher. - [OpenSSL cipher suite names documentation](https://docs.openssl.org/master/man1/openssl-ciphers/#cipher-suite-names) - [wolfSSL cipher support documentation](https://www.wolfssl.com/documentation/manuals/wolfssl/chapter04.html#cipher-support) - [mbedTLS cipher suites reference](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/ssl__ciphersuites_8h/) -- [Schannel cipher suites documentation](https://learn.microsoft.com/en-us/windows/win32/secauthn/cipher-suites-in-schannel) +- [Schannel cipher suites documentation](https://learn.microsoft.com/windows/win32/secauthn/cipher-suites-in-schannel) - [IANA cipher suites list](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4) - [Wikipedia cipher suite article](https://en.wikipedia.org/wiki/Cipher_suite) - [GnuTLS Priority Strings](https://gnutls.org/manual/html_node/Priority-Strings.html) diff --git a/docs/INSTALL.md b/docs/INSTALL.md index ab20e9fde1df..3972d242399f 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -193,9 +193,9 @@ You can build curl with: KB140584 is a must for any Windows developer. Especially important is full understanding if you are not going to follow the advice given above. - - [How To Use the C Runtime](https://support.microsoft.com/help/94248/how-to-use-the-c-run-time) - - [Runtime Library Compiler Options](https://docs.microsoft.com/cpp/build/reference/md-mt-ld-use-run-time-library) - - [Potential Errors Passing CRT Objects Across DLL Boundaries](https://docs.microsoft.com/cpp/c-runtime-library/potential-errors-passing-crt-objects-across-dll-boundaries) + - [How To Use the C Runtime](https://learn.microsoft.com/troubleshoot/developer/visualstudio/cpp/libraries/use-c-run-time) + - [Runtime Library Compiler Options](https://learn.microsoft.com/cpp/build/reference/md-mt-ld-use-run-time-library) + - [Potential Errors Passing CRT Objects Across DLL Boundaries](https://learn.microsoft.com/cpp/c-runtime-library/potential-errors-passing-crt-objects-across-dll-boundaries) If your app is misbehaving in some strange way, or it is suffering from memory corruption, before asking for further help, please try first to rebuild every diff --git a/docs/TODO b/docs/TODO index 6075577f318f..d7416f9c8e1b 100644 --- a/docs/TODO +++ b/docs/TODO @@ -860,14 +860,14 @@ The existing support for the -E/--cert and --key options could be extended by supplying a custom certificate and key in PEM format, see: - Getting a Certificate for Schannel - https://msdn.microsoft.com/en-us/library/windows/desktop/aa375447.aspx + https://learn.microsoft.com/windows/win32/secauthn/getting-a-certificate-for-schannel 15.2 Extend support for the --ciphers option The existing support for the --ciphers option could be extended by mapping the OpenSSL/GnuTLS cipher suites to the Schannel APIs, see - Specifying Schannel Ciphers and Cipher Strengths - https://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx + https://learn.microsoft.com/windows/win32/secauthn/specifying-schannel-ciphers-and-cipher-strengths 15.4 Add option to allow abrupt server closure diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 308325ccdc15..d7463345ad87 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -453,7 +453,7 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn, /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. - https://support.microsoft.com/kb/823764 + https://learn.microsoft.com/troubleshoot/windows-server/networking/slow-performance-copy-data-tcp-server-sockets-api Work-around: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size diff --git a/lib/cf-socket.h b/lib/cf-socket.h index 88c08fe7c0c0..083202fad900 100644 --- a/lib/cf-socket.h +++ b/lib/cf-socket.h @@ -80,7 +80,7 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn, /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. - https://support.microsoft.com/kb/823764 + https://learn.microsoft.com/troubleshoot/windows-server/networking/slow-performance-copy-data-tcp-server-sockets-api Work-around: Make the Socket Send Buffer Size Larger Than the Program Send Buffer Size diff --git a/lib/curlx/multibyte.c b/lib/curlx/multibyte.c index 30380275cc7e..1c81a71ec5b4 100644 --- a/lib/curlx/multibyte.c +++ b/lib/curlx/multibyte.c @@ -170,7 +170,7 @@ static bool fix_excessive_path(const TCHAR *in, TCHAR **out) * \\?\c:\longpath ---> \\?\c:\longpath (unchanged) * \\server\c$\longpath ---> \\?\UNC\server\c$\longpath * - * https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats + * https://learn.microsoft.com/dotnet/standard/io/file-path-formats */ if(!wcsncmp(fbuf, L"\\\\?\\", 4)) ; /* do nothing */ diff --git a/lib/select.h b/lib/select.h index 47cdd31267f2..a23921ceb999 100644 --- a/lib/select.h +++ b/lib/select.h @@ -85,7 +85,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms); /* With Winsock the valid range is [0..INVALID_SOCKET-1] according to - https://docs.microsoft.com/en-us/windows/win32/winsock/socket-data-type-2 + https://learn.microsoft.com/windows/win32/winsock/socket-data-type-2 */ #ifdef USE_WINSOCK #define VALID_SOCK(s) ((s) < INVALID_SOCKET) diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index 9127a9bb277d..dff5fe8747d8 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -275,8 +275,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, * we have to pass a second SecBuffer to the SecBufferDesc * otherwise IIS will not pass the authentication (401 response). * Minimum supported version is Windows 7. - * https://docs.microsoft.com/en-us/security-updates - * /SecurityAdvisories/2009/973811 + * https://learn.microsoft.com/security-updates/SecurityAdvisories/2009/973811 */ if(ntlm->sslContext) { SEC_CHANNEL_BINDINGS channelBindings; diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c index f21c66796f91..ae44523d328a 100644 --- a/lib/vauth/spnego_sspi.c +++ b/lib/vauth/spnego_sspi.c @@ -210,8 +210,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, * we have to pass a second SecBuffer to the SecBufferDesc * otherwise IIS will not pass the authentication (401 response). * Minimum supported version is Windows 7. - * https://docs.microsoft.com/en-us/security-updates - * /SecurityAdvisories/2009/973811 + * https://learn.microsoft.com/security-updates/SecurityAdvisories/2009/973811 */ if(nego->sslContext) { SEC_CHANNEL_BINDINGS channelBindings; diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 66084a27c3dc..49bc02230bea 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3462,8 +3462,7 @@ static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf, problems with server-sent legacy intermediates. Newer versions of OpenSSL do alternate chain checking by default but we do not know how to determine that in a reliable manner. - https://web.archive.org/web/20190422050538/ - rt.openssl.org/Ticket/Display.html?id=3621 + https://web.archive.org/web/20190422050538/rt.openssl.org/Ticket/Display.html?id=3621 */ X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST); if(!ssl_config->no_partialchain && !ssl_crlfile) { @@ -4733,8 +4732,7 @@ static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, /* Begin Gyrations to get the subjectPublicKeyInfo */ /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */ - /* https://groups.google.com/group/mailing.openssl.users/browse_thread - /thread/d61858dae102c6c7 */ + /* https://groups.google.com/group/mailing.openssl.users/browse_thread/thread/d61858dae102c6c7 */ len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); if(len1 < 1) break; /* failed */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 0cc34b138958..b511c43277e6 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -139,7 +139,7 @@ /* ALPN requires version 8.1 of the Windows SDK, which was shipped with Visual Studio 2013, aka _MSC_VER 1800: - https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx + https://learn.microsoft.com/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/hh831771 Or mingw-w64 9.0 or upper. */ #if (defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR >= 9) || \ @@ -585,8 +585,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, if(fInCert || blob) { /* Reading a .P12 or .pfx file, like the example at bottom of - https://social.msdn.microsoft.com/Forums/windowsdesktop/ - en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5 + https://learn.microsoft.com/archive/msdn-technet-forums/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5 */ CRYPT_DATA_BLOB datablob; WCHAR* pszPassword; @@ -1039,7 +1038,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) } /* Schannel InitializeSecurityContext: - https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx + https://learn.microsoft.com/windows/win32/api/rrascfg/nn-rrascfg-ieapproviderconfig At the moment we do not pass inbuf unless we are using ALPN since we only use it for that, and WINE (for which we currently disable ALPN) is giving @@ -1945,7 +1944,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, /* copy data into output buffer */ memcpy(outbuf[1].pvBuffer, buf, len); - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ + /* https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-encryptmessage */ sspi_status = Curl_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0, &outbuf_desc, 0); @@ -2164,7 +2163,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&inbuf_desc, inbuf, 4); - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx + /* https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-decryptmessage */ sspi_status = Curl_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); @@ -2373,7 +2372,7 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data, bool send_shutdown, bool *done) { - /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx + /* See https://learn.microsoft.com/windows/win32/secauthn/shutting-down-an-schannel-connection * Shutting Down an Schannel Connection */ struct ssl_connect_data *connssl = cf->ctx; diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index 17e42707631d..b19e1757d452 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -552,7 +552,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, * Right now we are only asking for the first preferred alternative name. * Instead we would need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG * (If Windows CE supports that?) and run this section in a loop for each. - * https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx + * https://learn.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-certgetnamestringa * curl: (51) schannel: CertGetNameString() certificate hostname * (.google.com) did not match connection (google.com) */ diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index c52b8258d7f0..28ad6315ba4c 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -516,7 +516,7 @@ sub scanfile { } # detect long lines - if(length($l) > $max_column) { + if(length($l) > $max_column && $l !~ / https:\/\//) { checkwarn("LONGLINE", $line, length($l), $file, $l, "Longer than $max_column columns"); } diff --git a/src/tool_doswin.c b/src/tool_doswin.c index c0dcfed04e37..bfe013d8e56e 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -84,7 +84,7 @@ f:\foo:bar => f:\foo:bar (flag SANITIZE_ALLOW_PATH) This function was implemented according to the guidelines in 'Naming Files, Paths, and Namespaces' section 'Naming Conventions'. -https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx +https://learn.microsoft.com/windows/win32/fileio/naming-a-file Flags ----- @@ -473,9 +473,8 @@ static SANITIZEcode rename_if_reserved_dos(char **const sanitized, /* Rename reserved device names that are known to be accessible without \\.\ Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS - https://web.archive.org/web/20160314141551/ - support.microsoft.com/en-us/kb/74496 - https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx + https://web.archive.org/web/20160314141551/support.microsoft.com/en-us/kb/74496 + https://learn.microsoft.com/windows/win32/fileio/naming-a-file */ for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) { size_t p_len; diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index 2785b751340e..a52efe0a1bf6 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -404,8 +404,8 @@ static bool read_data_block(unsigned char *buffer, ssize_t maxlen, * other handle types supported by WaitForMultipleObjectsEx() as * well as disk files, anonymous and names pipes, and character input. * - * https://msdn.microsoft.com/en-us/library/windows/desktop/ms687028.aspx - * https://msdn.microsoft.com/en-us/library/windows/desktop/ms741572.aspx + * https://learn.microsoft.com/windows/win32/api/synchapi/nf-synchapi-waitformultipleobjectsex + * https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-wsaenumnetworkevents */ struct select_ws_wait_data { HANDLE handle; /* actual handle to wait for during select */ diff --git a/tests/server/util.c b/tests/server/util.c index 02f91083e4f4..052effa89583 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -229,12 +229,9 @@ curl_off_t our_getpid(void) curl_off_t pid = (curl_off_t)t_getpid(); #ifdef _WIN32 /* store pid + MAX_PID to avoid conflict with Cygwin/msys PIDs, see also: - * - 2019-01-31: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; - * h=b5e1003722cb14235c4f166be72c09acdffc62ea - * - 2019-02-02: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; - * h=448cf5aa4b429d5a9cebf92a0da4ab4b5b6d23fe - * - 2024-12-19: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit; - * h=363357c023ce01e936bdaedf0f479292a8fa4e0f + * - 2019-01-31: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit;h=b5e1003722cb14235c4f166be72c09acdffc62ea + * - 2019-02-02: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit;h=448cf5aa4b429d5a9cebf92a0da4ab4b5b6d23fe + * - 2024-12-19: https://cygwin.com/git/?p=newlib-cygwin.git;a=commit;h=363357c023ce01e936bdaedf0f479292a8fa4e0f */ pid += 4194304; #endif @@ -422,7 +419,7 @@ static void exit_signal_handler(int signum) * They are included for ANSI compatibility. Therefore, you can set * signal handlers for these signals by using signal, and you can also * explicitly generate these signals by calling raise. Source: - * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/signal + * https://learn.microsoft.com/cpp/c-runtime-library/reference/signal */ static BOOL WINAPI ctrl_event_handler(DWORD dwCtrlType) { From 7a26304a95baecc32405099c0628f0a76a700a20 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 11:11:35 +0200 Subject: [PATCH 086/465] curl_slist_append.md: clarify that a NULL pointer is not acceptable Closes #18627 --- docs/libcurl/curl_slist_append.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/libcurl/curl_slist_append.md b/docs/libcurl/curl_slist_append.md index 75c6a57afd50..b2766f728db0 100644 --- a/docs/libcurl/curl_slist_append.md +++ b/docs/libcurl/curl_slist_append.md @@ -28,9 +28,10 @@ struct curl_slist *curl_slist_append(struct curl_slist *list, curl_slist_append(3) appends a string to a linked list of strings. The existing **list** should be passed as the first argument and the new list is -returned from this function. Pass in NULL in the **list** argument to create -a new list. The specified **string** has been appended when this function -returns. curl_slist_append(3) copies the string. +returned from this function. Pass in NULL in the **list** argument to create a +new list. The specified **string** has been appended when this function +returns. curl_slist_append(3) copies the string. The **string** argument must +be a valid string pointer and cannot be NULL. The list should be freed again (after usage) with curl_slist_free_all(3). From 335d16e944c86a0f7d9c52e3932e1f0ccca39feb Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 11:25:38 +0200 Subject: [PATCH 087/465] libssh: error on bad chgrp number To avoid it continuing with a zero gid. Reported in Joshua's sarif data Closes #18629 --- lib/vssh/libssh.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 2554468c4bf3..be8336ad0a1e 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1808,10 +1808,7 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, if(!strncmp(cmd, "chgrp", 5)) { const char *p = sshc->quote_path1; curl_off_t gid; - (void)curlx_str_number(&p, &gid, UINT_MAX); - sshc->quote_attrs->gid = (uint32_t)gid; - if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { + if(curlx_str_number(&p, &gid, UINT_MAX)) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chgrp gid not a number"); @@ -1820,6 +1817,7 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, sshc->actualcode = CURLE_QUOTE_ERROR; return SSH_NO_ERROR; } + sshc->quote_attrs->gid = (uint32_t)gid; sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; } else if(!strncmp(cmd, "chmod", 5)) { From 0209e087c6989d7b6df49d3e090414eeccdda8ef Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 11:31:54 +0200 Subject: [PATCH 088/465] tool_cb_hdr: size is always 1 - add comment in the header that the argument 'size' is always 1, as guaranteed by the libcurl API - then fix the call to fwrite() to avoid using "size, etag_length" which would be wrong if size was something else than 1, and use a fixed number there instead. Reported in Joshua's sarif data Closes #18630 --- src/tool_cb_hdr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c index 3bb3c12dc806..7781e4dc3ccc 100644 --- a/src/tool_cb_hdr.c +++ b/src/tool_cb_hdr.c @@ -81,6 +81,8 @@ int tool_write_headers(struct HdrCbData *hdrcbdata, FILE *stream) /* ** callback for CURLOPT_HEADERFUNCTION +* +* 'size' is always 1 */ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) { @@ -164,7 +166,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) } #endif - fwrite(etag_h, size, etag_length, etag_save->stream); + fwrite(etag_h, 1, etag_length, etag_save->stream); /* terminate with newline */ fputc('\n', etag_save->stream); (void)fflush(etag_save->stream); From 2fe95cb0e320db0c6034d154ab175002d23b936d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 11:17:48 +0200 Subject: [PATCH 089/465] rustls: typecast variable for safer trace output This is a variadic function call with a mismatched argument type; on platforms where uintptr_t and size_t differ, this invokes undefined behavior. Reported in Joshua's sarif data Closes #18628 --- lib/vtls/rustls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 905d4f8a99e3..e5d85aa38f38 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -121,7 +121,7 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n) connssl->peer_closed = TRUE; *out_n = (uintptr_t)nread; CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %d, %zu", - len, result, nread); + (size_t)len, result, nread); return ret; } From bf7375ecc50e857760b0d0a668c436e208a400bd Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 9 Sep 2025 15:29:12 +0200 Subject: [PATCH 090/465] build: avoid overriding system symbols for socket functions Before this patch `accept4()`, `socket()`, `socketpair()`, `send()` and `recv()` system symbols were remapped via macros, using the same name, to local curl debug wrappers. This patch replaces these overrides by introducing curl-namespaced macros that map either to the system symbols or to their curl debug wrappers in `CURLDEBUG` (TrackMemory) builds. This follows a patch that implemented the same for `accept()`. The old method required tricks to make these redefines work in unity builds, and avoid them interfering with system headers. These tricks did not work for system symbols implemented as macros. The new method allows to setup these mappings once, without interfering with system headers, upstream macros, or unity builds. It makes builds more robust. Also: - checksrc: ban all mapped functions. - docs/examples: tidy up checksrc rules. Follow-up to 9863599d69b79d290928a89bf9160f4e4e023d4e #18502 Follow-up to 3bb5e58c105d7be450b667858d1b8e7ae3ded555 #17827 Closes #18503 --- REUSE.toml | 1 + docs/examples/.checksrc | 3 +++ docs/examples/Makefile.am | 2 +- docs/examples/http2-upload.c | 1 - docs/examples/synctime.c | 2 -- lib/cf-socket.c | 6 +++--- lib/curl_addrinfo.c | 4 ++++ lib/curl_mem_undef.h | 11 ----------- lib/curl_setup.h | 24 ++++++++++++++++++++++-- lib/hostip.c | 2 +- lib/if2ip.c | 2 +- lib/memdebug.c | 16 +++++++++++----- lib/memdebug.h | 18 ------------------ lib/multi.c | 2 +- lib/socketpair.c | 6 +++--- lib/vquic/vquic.c | 4 ++-- packages/OS400/os400sys.c | 1 + scripts/checksrc.pl | 8 ++++++++ src/tool_cb_rea.c | 2 +- src/tool_cb_soc.c | 2 +- src/tool_doswin.c | 4 ++-- tests/libtest/lib1960.c | 2 +- tests/libtest/lib500.c | 2 +- tests/server/.checksrc | 6 ++++++ 24 files changed, 74 insertions(+), 57 deletions(-) create mode 100644 docs/examples/.checksrc diff --git a/REUSE.toml b/REUSE.toml index 81c214863fcd..6e8a272e795c 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -40,6 +40,7 @@ path = [ "tests/data/test**", "tests/valgrind.supp", # checksrc control files + "docs/examples/.checksrc", "lib/.checksrc", "lib/curlx/.checksrc", "lib/vauth/.checksrc", diff --git a/docs/examples/.checksrc b/docs/examples/.checksrc new file mode 100644 index 000000000000..0b626e65703d --- /dev/null +++ b/docs/examples/.checksrc @@ -0,0 +1,3 @@ +allowfunc gmtime +allowfunc localtime +allowfunc socket diff --git a/docs/examples/Makefile.am b/docs/examples/Makefile.am index 27d4ce741bd4..89ebcc9840f6 100644 --- a/docs/examples/Makefile.am +++ b/docs/examples/Makefile.am @@ -24,7 +24,7 @@ AUTOMAKE_OPTIONS = foreign nostdinc -EXTRA_DIST = CMakeLists.txt README.md Makefile.example $(COMPLICATED_EXAMPLES) +EXTRA_DIST = CMakeLists.txt .checksrc README.md Makefile.example $(COMPLICATED_EXAMPLES) # Specify our include paths here, and do it relative to $(top_srcdir) and # $(top_builddir), to ensure that these paths which belong to the library diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index 128a4b0beda1..d13c5e58063c 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -161,7 +161,6 @@ int my_trace(CURL *handle, curl_infotype type, known_offset = 1; } secs = epoch_offset + tv.tv_sec; - /* !checksrc! disable BANNEDFUNC 1 */ now = localtime(&secs); /* not thread safe but we do not care */ curl_msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld", now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec); diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c index ba5f09cb075a..8d7af7c8c4c3 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -298,10 +298,8 @@ int main(int argc, char *argv[]) /* Calculating time diff between GMT and localtime */ tt = time(0); - /* !checksrc! disable BANNEDFUNC 1 */ lt = localtime(&tt); tt_local = mktime(lt); - /* !checksrc! disable BANNEDFUNC 1 */ gmt = gmtime(&tt); tt_gmt = mktime(gmt); tzonediffFloat = difftime(tt_local, tt_gmt); diff --git a/lib/cf-socket.c b/lib/cf-socket.c index d7463345ad87..365ddb62a144 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -369,7 +369,7 @@ static CURLcode socket_open(struct Curl_easy *data, } else { /* opensocket callback not set, so simply create the socket now */ - *sockfd = socket(addr->family, addr->socktype, addr->protocol); + *sockfd = CURL_SOCKET(addr->family, addr->socktype, addr->protocol); } if(*sockfd == CURL_SOCKET_BAD) @@ -2113,8 +2113,8 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, if(!getsockname(ctx->sock, (struct sockaddr *) &add, &size)) { size = sizeof(add); #ifdef HAVE_ACCEPT4 - s_accepted = accept4(ctx->sock, (struct sockaddr *) &add, &size, - SOCK_NONBLOCK | SOCK_CLOEXEC); + s_accepted = CURL_ACCEPT4(ctx->sock, (struct sockaddr *) &add, &size, + SOCK_NONBLOCK | SOCK_CLOEXEC); #else s_accepted = CURL_ACCEPT(ctx->sock, (struct sockaddr *) &add, &size); #endif diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index 22212ac86f8e..c4ad71a02e1a 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -507,9 +507,11 @@ curl_dbg_freeaddrinfo(struct addrinfo *freethis, if(env) r_freeaddrinfo(freethis); else + /* !checksrc! disable BANNEDFUNC 1 */ freeaddrinfo(freethis); } #else + /* !checksrc! disable BANNEDFUNC 1 */ freeaddrinfo(freethis); #endif } @@ -540,8 +542,10 @@ curl_dbg_getaddrinfo(const char *hostname, if(env) res = r_getaddrinfo(hostname, service, hints, result); else + /* !checksrc! disable BANNEDFUNC 1 */ res = getaddrinfo(hostname, service, hints, result); #else + /* !checksrc! disable BANNEDFUNC 1 */ int res = getaddrinfo(hostname, service, hints, result); #endif if(res == 0) diff --git a/lib/curl_mem_undef.h b/lib/curl_mem_undef.h index f3cca294e9a5..a70a9fcf5379 100644 --- a/lib/curl_mem_undef.h +++ b/lib/curl_mem_undef.h @@ -35,17 +35,6 @@ #ifdef CURLDEBUG -#undef send -#undef recv - -#undef socket -#ifdef HAVE_ACCEPT4 -#undef accept4 -#endif -#ifdef HAVE_SOCKETPAIR -#undef socketpair -#endif - #undef fopen #ifdef CURL_FOPEN #define fopen(fname, mode) CURL_FOPEN(fname, mode) diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 93cbb570568d..e49c57231d2f 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -1083,9 +1083,21 @@ CURL_EXTERN ALLOC_FUNC curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__) #define CURL_FREEADDRINFO(data) \ curl_dbg_freeaddrinfo(data, __LINE__, __FILE__) - +#define CURL_SOCKET(domain,type,protocol) \ + curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__) +#ifdef HAVE_SOCKETPAIR +#define CURL_SOCKETPAIR(domain,type,protocol,socket_vector) \ + curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \ + __LINE__, __FILE__) +#endif #define CURL_ACCEPT(sock,addr,len) \ curl_dbg_accept(sock, addr, len, __LINE__, __FILE__) +#ifdef HAVE_ACCEPT4 +#define CURL_ACCEPT4(sock,addr,len,flags) \ + curl_dbg_accept4(sock, addr, len, flags, __LINE__, __FILE__) +#endif +#define CURL_SEND(a,b,c,d) curl_dbg_send(a,b,c,d, __LINE__, __FILE__) +#define CURL_RECV(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__) #else /* !CURLDEBUG */ @@ -1094,8 +1106,16 @@ CURL_EXTERN ALLOC_FUNC #define CURL_GETADDRINFO getaddrinfo #define CURL_FREEADDRINFO freeaddrinfo - +#define CURL_SOCKET socket +#ifdef HAVE_SOCKETPAIR +#define CURL_SOCKETPAIR socketpair +#endif #define CURL_ACCEPT accept +#ifdef HAVE_ACCEPT4 +#define CURL_ACCEPT4 accept4 +#endif +#define CURL_SEND send +#define CURL_RECV recv #endif /* CURLDEBUG */ diff --git a/lib/hostip.c b/lib/hostip.c index b6be2ca1f275..fd8f706e7f25 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -709,7 +709,7 @@ bool Curl_ipv6works(struct Curl_easy *data) else { int ipv6_works = -1; /* probe to see if we have a working IPv6 stack */ - curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); + curl_socket_t s = CURL_SOCKET(PF_INET6, SOCK_DGRAM, 0); if(s == CURL_SOCKET_BAD) /* an IPv6 address was requested but we cannot get/use one */ ipv6_works = 0; diff --git a/lib/if2ip.c b/lib/if2ip.c index 91ee59c02a72..e501921d067b 100644 --- a/lib/if2ip.c +++ b/lib/if2ip.c @@ -208,7 +208,7 @@ if2ip_result_t Curl_if2ip(int af, if(len >= sizeof(req.ifr_name)) return IF2IP_NOT_FOUND; - dummy = socket(AF_INET, SOCK_STREAM, 0); + dummy = CURL_SOCKET(AF_INET, SOCK_STREAM, 0); if(CURL_SOCKET_BAD == dummy) return IF2IP_NOT_FOUND; diff --git a/lib/memdebug.c b/lib/memdebug.c index 0d8d39603c4d..cffd4b2cf61b 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -311,7 +311,8 @@ curl_socket_t curl_dbg_socket(int domain, int type, int protocol, if(countcheck("socket", line, source)) return CURL_SOCKET_BAD; - sockfd = (socket)(domain, type, protocol); + /* !checksrc! disable BANNEDFUNC 1 */ + sockfd = socket(domain, type, protocol); if(source && (sockfd != CURL_SOCKET_BAD)) curl_dbg_log("FD %s:%d socket() = %" FMT_SOCKET_T "\n", @@ -328,7 +329,8 @@ SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, SEND_TYPE_RETV rc; if(countcheck("send", line, source)) return -1; - rc = (send)(sockfd, buf, len, flags); + /* !checksrc! disable BANNEDFUNC 1 */ + rc = send(sockfd, buf, len, flags); if(source) curl_dbg_log("SEND %s:%d send(%lu) = %ld\n", source, line, (unsigned long)len, (long)rc); @@ -342,7 +344,8 @@ RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf, RECV_TYPE_RETV rc; if(countcheck("recv", line, source)) return -1; - rc = (recv)(sockfd, buf, len, flags); + /* !checksrc! disable BANNEDFUNC 1 */ + rc = recv(sockfd, buf, len, flags); if(source) curl_dbg_log("RECV %s:%d recv(%lu) = %ld\n", source, line, (unsigned long)len, (long)rc); @@ -354,7 +357,8 @@ int curl_dbg_socketpair(int domain, int type, int protocol, curl_socket_t socket_vector[2], int line, const char *source) { - int res = (socketpair)(domain, type, protocol, socket_vector); + /* !checksrc! disable BANNEDFUNC 1 */ + int res = socketpair(domain, type, protocol, socket_vector); if(source && (res == 0)) curl_dbg_log("FD %s:%d socketpair() = " @@ -371,6 +375,7 @@ curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen, struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; + /* !checksrc! disable BANNEDFUNC 1 */ curl_socket_t sockfd = accept(s, addr, addrlen); if(source && (sockfd != CURL_SOCKET_BAD)) @@ -388,7 +393,8 @@ curl_socket_t curl_dbg_accept4(curl_socket_t s, void *saddr, void *saddrlen, struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; - curl_socket_t sockfd = (accept4)(s, addr, addrlen, flags); + /* !checksrc! disable BANNEDFUNC 1 */ + curl_socket_t sockfd = accept4(s, addr, addrlen, flags); if(source && (sockfd != CURL_SOCKET_BAD)) curl_dbg_log("FD %s:%d accept() = %" FMT_SOCKET_T "\n", diff --git a/lib/memdebug.h b/lib/memdebug.h index eabdd9c258cf..96ceb61759e5 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -42,10 +42,6 @@ #define realloc(ptr,size) curl_dbg_realloc(ptr, size, __LINE__, __FILE__) #undef free #define free(ptr) curl_dbg_free(ptr, __LINE__, __FILE__) -#undef send -#define send(a,b,c,d) curl_dbg_send(a,b,c,d, __LINE__, __FILE__) -#undef recv -#define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__) #ifdef _WIN32 #undef Curl_tcsdup @@ -56,20 +52,6 @@ #endif #endif /* _WIN32 */ -#undef socket -#define socket(domain,type,protocol) \ - curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__) -#ifdef HAVE_ACCEPT4 -#undef accept4 /* for those with accept4 as a macro */ -#define accept4(sock,addr,len,flags) \ - curl_dbg_accept4(sock, addr, len, flags, __LINE__, __FILE__) -#endif -#ifdef HAVE_SOCKETPAIR -#define socketpair(domain,type,protocol,socket_vector) \ - curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \ - __LINE__, __FILE__) -#endif - #undef fopen #define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) #undef fdopen diff --git a/lib/multi.c b/lib/multi.c index 918928d03cc5..442956f84416 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1277,7 +1277,7 @@ static void reset_socket_fdwrite(curl_socket_t s) int t; int l = (int)sizeof(t); if(!getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&t, &l) && t == SOCK_STREAM) - send(s, NULL, 0, 0); + CURL_SEND(s, NULL, 0, 0); } #endif diff --git a/lib/socketpair.c b/lib/socketpair.c index 4151a9bb979a..d2fd41141b24 100644 --- a/lib/socketpair.c +++ b/lib/socketpair.c @@ -91,7 +91,7 @@ int Curl_socketpair(int domain, int type, int protocol, #ifdef SOCK_NONBLOCK type = nonblocking ? type | SOCK_NONBLOCK : type; #endif - if(socketpair(domain, type, protocol, socks)) + if(CURL_SOCKETPAIR(domain, type, protocol, socks)) return -1; #ifndef SOCK_NONBLOCK if(nonblocking) { @@ -154,7 +154,7 @@ int Curl_socketpair(int domain, int type, int protocol, (void)type; (void)protocol; - listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + listener = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(listener == CURL_SOCKET_BAD) return -1; @@ -188,7 +188,7 @@ int Curl_socketpair(int domain, int type, int protocol, goto error; if(listen(listener, 1) == -1) goto error; - socks[0] = socket(AF_INET, SOCK_STREAM, 0); + socks[0] = CURL_SOCKET(AF_INET, SOCK_STREAM, 0); if(socks[0] == CURL_SOCKET_BAD) goto error; if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1) diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index 3a0ac872383f..47fbf63af05a 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -196,8 +196,8 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf, *psent = 0; - while((sent = send(qctx->sockfd, - (const char *)pkt, (SEND_TYPE_ARG3)pktlen, 0)) == -1 && + while((sent = CURL_SEND(qctx->sockfd, (const char *)pkt, + (SEND_TYPE_ARG3)pktlen, 0)) == -1 && SOCKERRNO == SOCKEINTR) ; diff --git a/packages/OS400/os400sys.c b/packages/OS400/os400sys.c index 7be72085498b..bc227a0e69fc 100644 --- a/packages/OS400/os400sys.c +++ b/packages/OS400/os400sys.c @@ -333,6 +333,7 @@ Curl_getaddrinfo_a(const char *nodename, const char *servname, eservname[i] = '\0'; } + /* !checksrc! disable BANNEDFUNC 1 */ status = getaddrinfo(enodename, eservname, hints, res); free(enodename); free(eservname); diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 28ad6315ba4c..0eeab72323f9 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -77,6 +77,14 @@ "_waccess" => 1, "_access" => 1, "access" => 1, + "accept" => 1, + "accept4" => 1, + "freeaddrinfo" => 1, + "getaddrinfo" => 1, + "recv" => 1, + "send" => 1, + "socket" => 1, + "socketpair" => 1, ); my %warnings_extended = ( diff --git a/src/tool_cb_rea.c b/src/tool_cb_rea.c index 0a3e9ef0ee2c..b7bd9a722732 100644 --- a/src/tool_cb_rea.c +++ b/src/tool_cb_rea.c @@ -92,7 +92,7 @@ size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) execute */ if(per->uploadfile && !strcmp(per->uploadfile, ".") && per->infd > 0) { #if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) - rc = recv(per->infd, buffer, curlx_uztosi(sz * nmemb), 0); + rc = CURL_RECV(per->infd, buffer, curlx_uztosi(sz * nmemb), 0); if(rc < 0) { if(SOCKERRNO == SOCKEWOULDBLOCK) { CURL_SETERRNO(0); diff --git a/src/tool_cb_soc.c b/src/tool_cb_soc.c index 22048ee6bbf9..d89870297cdb 100644 --- a/src/tool_cb_soc.c +++ b/src/tool_cb_soc.c @@ -54,5 +54,5 @@ curl_socket_t tool_socket_open_mptcp_cb(void *clientp, return CURL_SOCKET_BAD; #endif - return socket(addr->family, addr->socktype, protocol); + return CURL_SOCKET(addr->family, addr->socktype, protocol); } diff --git a/src/tool_doswin.c b/src/tool_doswin.c index bfe013d8e56e..0450e5707ba2 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -785,7 +785,7 @@ static DWORD WINAPI win_stdin_thread_func(void *thread_data) break; if(n == 0) break; - nwritten = send(socket_w, buffer, n, 0); + nwritten = CURL_SEND(socket_w, buffer, n, 0); if(nwritten == SOCKET_ERROR) break; if((DWORD)nwritten != n) @@ -889,7 +889,7 @@ curl_socket_t win32_stdin_read_thread(void) } /* Connect to the thread and rearrange our own STDIN handles */ - socket_r = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + socket_r = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(socket_r == CURL_SOCKET_BAD) { errorf("socket error: %08lx", GetLastError()); break; diff --git a/tests/libtest/lib1960.c b/tests/libtest/lib1960.c index 5cdc0224260c..1ee9277bef62 100644 --- a/tests/libtest/lib1960.c +++ b/tests/libtest/lib1960.c @@ -96,7 +96,7 @@ static CURLcode test_lib1960(const char *URL) * over this socket as "already connected" to libcurl and make sure that * this works. */ - client_fd = socket(AF_INET, SOCK_STREAM, 0); + client_fd = CURL_SOCKET(AF_INET, SOCK_STREAM, 0); if(client_fd == CURL_SOCKET_BAD) { curl_mfprintf(stderr, "socket creation error\n"); goto test_cleanup; diff --git a/tests/libtest/lib500.c b/tests/libtest/lib500.c index 0586c1407f9c..7081ec625d28 100644 --- a/tests/libtest/lib500.c +++ b/tests/libtest/lib500.c @@ -35,7 +35,7 @@ static curl_socket_t tst_opensocket(void *clientp, (void)clientp; (void)purpose; curl_mprintf("[OPEN] counter: %d\n", ++testcounter); - return socket(addr->family, addr->socktype, addr->protocol); + return CURL_SOCKET(addr->family, addr->socktype, addr->protocol); } static int tst_closesocket(void *clientp, curl_socket_t sock) diff --git a/tests/server/.checksrc b/tests/server/.checksrc index 8b1bcabe7789..be8f12cec014 100644 --- a/tests/server/.checksrc +++ b/tests/server/.checksrc @@ -1 +1,7 @@ +allowfunc accept +allowfunc freeaddrinfo +allowfunc getaddrinfo +allowfunc recv +allowfunc send +allowfunc socket allowfunc strtoul From ca75476a5c9ff3066cfcc3af0a2f33b936466501 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 20 Sep 2025 15:07:15 +0200 Subject: [PATCH 091/465] GHA/codeql: drop winbuild references [ci skip] Follow-up to 8d004781a577fc2fae72873c4a45b2fb3f366d98 #18040 --- .github/workflows/codeql.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b5e05efe4655..bb3c07482163 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -17,7 +17,6 @@ name: 'CodeQL' - 'plan9/**' - 'projects/**' - 'tests/data/**' - - 'winbuild/**' pull_request: branches: - master @@ -29,7 +28,6 @@ name: 'CodeQL' - 'plan9/**' - 'projects/**' - 'tests/data/**' - - 'winbuild/**' schedule: - cron: '0 0 * * 4' From 2a5da01e422f0853a2ea3764cde5fa08189d5b91 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 14:29:44 +0200 Subject: [PATCH 092/465] socks: make Curl_blockread_all return CURLcode Reported in Joshua's sarif data Closes #18635 --- lib/socks.c | 27 +++++++++++++-------------- lib/socks.h | 10 +++++----- lib/socks_sspi.c | 33 ++++++++++++++++++--------------- 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/lib/socks.c b/lib/socks.c index fc6c9730f875..4cb8619d7bd5 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -98,14 +98,14 @@ struct socks_state { * * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions. */ -int Curl_blockread_all(struct Curl_cfilter *cf, - struct Curl_easy *data, /* transfer */ - char *buf, /* store read data here */ - size_t blen, /* space in buf */ - size_t *pnread) /* amount bytes read */ +CURLcode Curl_blockread_all(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, /* store read data here */ + size_t blen, /* space in buf */ + size_t *pnread) /* amount bytes read */ { size_t nread = 0; - CURLcode err; + CURLcode result; *pnread = 0; for(;;) { @@ -116,21 +116,20 @@ int Curl_blockread_all(struct Curl_cfilter *cf, } if(!timeout_ms) timeout_ms = TIMEDIFF_T_MAX; - if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) { - return ~CURLE_OK; - } - err = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread); - if(CURLE_AGAIN == err) + if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) + return CURLE_OPERATION_TIMEDOUT; + result = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread); + if(CURLE_AGAIN == result) continue; - else if(err) - return (int)err; + else if(result) + return result; if(blen == nread) { *pnread += nread; return CURLE_OK; } if(!nread) /* EOF */ - return ~CURLE_OK; + return CURLE_RECV_ERROR; buf += nread; blen -= nread; diff --git a/lib/socks.h b/lib/socks.h index d60796316f75..f76bddc5f4e1 100644 --- a/lib/socks.h +++ b/lib/socks.h @@ -37,11 +37,11 @@ * * This is STUPID BLOCKING behavior */ -int Curl_blockread_all(struct Curl_cfilter *cf, - struct Curl_easy *data, - char *buf, - size_t blen, - size_t *pnread); +CURLcode Curl_blockread_all(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, + size_t blen, + size_t *pnread); #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 7af0b081e28e..6afc3eac3481 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -72,7 +72,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, size_t actualread; size_t written; CURLcode result; - int err; /* Needs GSS-API authentication */ SECURITY_STATUS status; unsigned long sspi_ret_flags = 0; @@ -237,10 +236,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, * +----+------+-----+----------------+ */ - err = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); - if(err || (actualread != 4)) { + result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI authentication response."); - result = CURLE_COULDNT_CONNECT; + if(!result) + result = CURLE_COULDNT_CONNECT; goto error; } @@ -269,12 +269,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, result = CURLE_OUT_OF_MEMORY; goto error; } - err = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, - sspi_recv_token.cbBuffer, &actualread); + result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, + sspi_recv_token.cbBuffer, &actualread); - if(err || (actualread != us_length)) { + if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI authentication token."); - result = CURLE_COULDNT_CONNECT; + if(!result) + result = CURLE_COULDNT_CONNECT; goto error; } @@ -453,10 +454,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, Curl_safefree(etbuf); } - err = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); - if(err || (actualread != 4)) { + result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); + if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI encryption response."); - result = CURLE_COULDNT_CONNECT; + if(!result) + result = CURLE_COULDNT_CONNECT; goto error; } @@ -485,12 +487,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, goto error; } - err = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer, &actualread); + result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, + sspi_w_token[0].cbBuffer, &actualread); - if(err || (actualread != us_length)) { + if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI encryption type."); - result = CURLE_COULDNT_CONNECT; + if(!result) + result = CURLE_COULDNT_CONNECT; goto error; } From 277ebca61009ac6618cd598aa81a9cf5f2b245f7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 14:45:47 +0200 Subject: [PATCH 093/465] ftp: fix port number range loop for PORT commands If the last port to test is 65535, the loop would previously wrongly wrap the counter and start over at 0, which was not intended. Reported in Joshua's sarif data Closes #18636 --- lib/ftp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/ftp.c b/lib/ftp.c index 6a33b6723cb8..1e2cd4d3cfeb 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -1121,14 +1121,16 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, else break; + /* check if port is the maximum value here, because it might be 0xffff and + then the increment below will wrap the 16 bit counter */ + if(port == port_max) { + /* maybe all ports were in use already */ + failf(data, "bind() failed, ran out of ports"); + goto out; + } port++; } - /* maybe all ports were in use already */ - if(port > port_max) { - failf(data, "bind() failed, we ran out of ports"); - goto out; - } /* get the name again after the bind() so that we can extract the port number it uses now */ From ca8ec6e033eb6b733d123495db18b5c99bf4208a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 14:56:03 +0200 Subject: [PATCH 094/465] tftp: handle tftp_multi_statemach() return code Previously just ignored. Reported in Joshua's sarif data Closes #18638 --- lib/tftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tftp.c b/lib/tftp.c index 84b92ee48827..7dc06261b2c4 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -1310,7 +1310,7 @@ static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done) if((state->state == TFTP_STATE_FIN) || result) return result; - tftp_multi_statemach(data, dophase_done); + result = tftp_multi_statemach(data, dophase_done); if(*dophase_done) DEBUGF(infof(data, "DO phase is complete")); From df8244c30fa80cc9310a096f9c4c024a76ad1bc6 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 15:00:37 +0200 Subject: [PATCH 095/465] libssh: error on bad chown number and store the value To avoid continuing with an unintended zero uid. Also actually use the value, which was omitted before! Reported in Joshua's sarif data Closes #18639 --- lib/vssh/libssh.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index be8336ad0a1e..56f21d85e99a 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1838,9 +1838,7 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, else if(!strncmp(cmd, "chown", 5)) { const char *p = sshc->quote_path1; curl_off_t uid; - (void)curlx_str_number(&p, &uid, UINT_MAX); - if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { + if(curlx_str_number(&p, &uid, UINT_MAX)) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); failf(data, "Syntax error: chown uid not a number"); @@ -1849,6 +1847,7 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, sshc->actualcode = CURLE_QUOTE_ERROR; return SSH_NO_ERROR; } + sshc->quote_attrs->uid = (uint32_t)uid; sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; } else if(!strncmp(cmd, "atime", 5) || From 82eeda104144b23de1bc89641d5a41f8a57eba6e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 16:47:16 +0200 Subject: [PATCH 096/465] CURLOPT_HEADER/WRITEFUNCTION.md: drop '* size' since size is always 1 Closes #18640 --- docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md | 4 ++-- docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md b/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md index 2f4c00a03ca5..8e16b78d5552 100644 --- a/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md @@ -109,9 +109,9 @@ Nothing. static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) { - /* received header is nitems * size long in 'buffer' NOT ZERO TERMINATED */ + /* received header is 'nitems' bytes in 'buffer' NOT ZERO TERMINATED */ /* 'userdata' is set with CURLOPT_HEADERDATA */ - return nitems * size; + return nitems; } int main(void) diff --git a/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md b/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md index 3ee11d8e476e..973a0aea754e 100644 --- a/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md @@ -40,13 +40,12 @@ delivered data, and the size of that data is *nmemb*; *size* is always 1. The data passed to this function is not null-terminated. The callback function is passed as much data as possible in all invokes, but -you must not make any assumptions. It may be one byte, it may be -thousands. The maximum amount of body data that is passed to the write -callback is defined in the curl.h header file: *CURL_MAX_WRITE_SIZE* (the -usual default is 16K). If CURLOPT_HEADER(3) is enabled, which makes header -data get passed to the write callback, you can get up to -*CURL_MAX_HTTP_HEADER* bytes of header data passed into it. This usually means -100K. +you must not make any assumptions. It may be one byte, it may be thousands. +The maximum amount of body data that is passed to the write callback is +defined in the curl.h header file: *CURL_MAX_WRITE_SIZE* (the usual default is +16K). If CURLOPT_HEADER(3) is enabled, which makes header data get passed to +the write callback, you can get up to *CURL_MAX_HTTP_HEADER* bytes of header +data passed into it. This usually means 100K. This function may be called with zero bytes data if the transferred file is empty. @@ -90,7 +89,7 @@ struct memory { static size_t cb(char *data, size_t size, size_t nmemb, void *clientp) { - size_t realsize = size * nmemb; + size_t realsize = nmemb; struct memory *mem = (struct memory *)clientp; char *ptr = realloc(mem->response, mem->size + realsize + 1); From 94eec0a788dbc80e87d7168be1bfb10d734d0ab3 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 17:14:10 +0200 Subject: [PATCH 097/465] schannel: assign result before using it curl_easy_strerror(result) was called *before* result was assigned. Reported in Joshua's sarif data Closes #18642 --- lib/vtls/schannel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index b511c43277e6..8b7f1d9306c1 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -2451,9 +2451,9 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, Curl_pSecFn->FreeContextBuffer(outbuf.pvBuffer); if(!result) { if(written < outbuf.cbBuffer) { + result = CURLE_SEND_ERROR; failf(data, "schannel: failed to send close msg: %s" " (bytes written: %zu)", curl_easy_strerror(result), written); - result = CURLE_SEND_ERROR; goto out; } backend->sent_shutdown = TRUE; @@ -2466,8 +2466,8 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, } else { if(!backend->recv_connection_closed) { - failf(data, "schannel: error sending close msg: %d", result); result = CURLE_SEND_ERROR; + failf(data, "schannel: error sending close msg: %d", result); goto out; } /* Looks like server already closed the connection. From d27d9c7ef1a37230ace8cc841027e6622c885df7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 16:56:14 +0200 Subject: [PATCH 098/465] cf-socket: use the right byte order for ports in bindlocal Reported in Joshua's sarif data Closes #18641 --- lib/cf-socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 365ddb62a144..2f0429efeae6 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -790,10 +790,10 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, infof(data, "Bind to local port %d failed, trying next", port - 1); /* We reuse/clobber the port variable here below */ if(sock->sa_family == AF_INET) - si4->sin_port = ntohs(port); + si4->sin_port = htons(port); #ifdef USE_IPV6 else - si6->sin6_port = ntohs(port); + si6->sin6_port = htons(port); #endif } else From e2d3b832445a05ed2e590fa5a40b0914f932bc42 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 14:51:01 +0200 Subject: [PATCH 099/465] libssh: return out of memory correctly if aprintf fails The code called set sshc->nextstate and returned SSH_OK without setting sshc->actualcode to an error code. Reported in Joshua's sarif data Closes #18637 --- lib/vssh/libssh.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 56f21d85e99a..eacc27a92110 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -765,7 +765,7 @@ static int myssh_in_SFTP_QUOTE_STATVFS(struct Curl_easy *data, #else #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64 #endif - CURLcode result; + CURLcode result = CURLE_OK; char *tmp = aprintf("statvfs:\n" "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" @@ -786,14 +786,13 @@ static int myssh_in_SFTP_QUOTE_STATVFS(struct Curl_easy *data, statvfs->f_namemax); sftp_statvfs_free(statvfs); - if(!tmp) { - myssh_to(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - return SSH_OK; - } + if(!tmp) + result = CURLE_OUT_OF_MEMORY; - result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); - free(tmp); + if(!result) { + result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + } if(result) { myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; From 66d6075af9c9bb5e4ef7985c7bc46942c9d4ae99 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 17:40:17 +0200 Subject: [PATCH 100/465] tftp: return error when sendto() fails The code just called failf() and then continued without returning error. Reported in Joshua's sarif data Closes #18643 --- lib/tftp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/tftp.c b/lib/tftp.c index 7dc06261b2c4..8b6246a34265 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -535,11 +535,12 @@ static CURLcode tftp_send_first(struct tftp_conn *state, (SEND_TYPE_ARG3)sbytes, 0, CURL_SENDTO_ARG5(&remote_addr->curl_sa_addr), (curl_socklen_t)remote_addr->addrlen); + free(filename); if(senddata != (ssize_t)sbytes) { char buffer[STRERROR_LEN]; failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + return CURLE_SEND_ERROR; } - free(filename); break; case TFTP_EVENT_OACK: From 979366a62568ca2ea0f8bed19fd901499c8dc178 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 12:21:26 +0200 Subject: [PATCH 101/465] openldap: improve check for receiving blank data It can't access the first byte either unless it has length. Followup to 232d5a2ed9c091c88e3b724a1e7d6 Closes #18632 --- lib/openldap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/openldap.c b/lib/openldap.c index 1f8737f5243a..717739b68d89 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -1171,8 +1171,8 @@ static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf, if(!binary) { /* check for leading or trailing whitespace */ - if(ISBLANK(bvals[i].bv_val[0]) || - (bvals[i].bv_len && + if(bvals[i].bv_len && + (ISBLANK(bvals[i].bv_val[0]) || ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))) binval = TRUE; else { From 50968d0378ebf05c90e8f1d167592797bbd258ba Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 12:12:02 +0200 Subject: [PATCH 102/465] httpsrr: free old pointers when storing new In case we get "funny" input and the same field is provided several times, free the old pointer before stored a new memdup. Reported in Joshua's sarif data Closes #18631 --- lib/httpsrr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/httpsrr.c b/lib/httpsrr.c index 26b8522cc964..8aa7f3b26e47 100644 --- a/lib/httpsrr.c +++ b/lib/httpsrr.c @@ -98,6 +98,7 @@ CURLcode Curl_httpsrr_set(struct Curl_easy *data, case HTTPS_RR_CODE_IPV4: /* addr4 list */ if(!vlen || (vlen & 3)) /* the size must be 4-byte aligned */ return CURLE_BAD_FUNCTION_ARGUMENT; + free(hi->ipv4hints); hi->ipv4hints = Curl_memdup(val, vlen); if(!hi->ipv4hints) return CURLE_OUT_OF_MEMORY; @@ -107,6 +108,7 @@ CURLcode Curl_httpsrr_set(struct Curl_easy *data, case HTTPS_RR_CODE_ECH: if(!vlen) return CURLE_BAD_FUNCTION_ARGUMENT; + free(hi->echconfiglist); hi->echconfiglist = Curl_memdup(val, vlen); if(!hi->echconfiglist) return CURLE_OUT_OF_MEMORY; @@ -116,6 +118,7 @@ CURLcode Curl_httpsrr_set(struct Curl_easy *data, case HTTPS_RR_CODE_IPV6: /* addr6 list */ if(!vlen || (vlen & 15)) /* the size must be 16-byte aligned */ return CURLE_BAD_FUNCTION_ARGUMENT; + free(hi->ipv6hints); hi->ipv6hints = Curl_memdup(val, vlen); if(!hi->ipv6hints) return CURLE_OUT_OF_MEMORY; @@ -186,6 +189,7 @@ CURLcode Curl_httpsrr_from_ares(struct Curl_easy *data, is in ServiceMode */ target = ares_dns_rr_get_str(rr, ARES_RR_HTTPS_TARGET); if(target && target[0]) { + free(hinfo->target); hinfo->target = strdup(target); if(!hinfo->target) { result = CURLE_OUT_OF_MEMORY; From cf3b9657bcb7acd3525ca081b4ed16e860604d6d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 19 Sep 2025 09:32:42 +0200 Subject: [PATCH 103/465] libssh2: up the minimum requirement to 1.9.0 Released on June 20 2019 --- .github/workflows/linux-old.yml | 10 +++--- configure.ac | 4 +-- docs/INTERNALS.md | 2 +- lib/vssh/libssh2.c | 59 ++------------------------------- 4 files changed, 10 insertions(+), 65 deletions(-) diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index e572c1745fb9..7e25cd213911 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -68,7 +68,7 @@ jobs: dpkg -i freexian-archive-keyring_2022.06.08_all.deb echo 'deb http://deb.freexian.com/extended-lts stretch-lts main contrib non-free' | tee /etc/apt/sources.list.d/extended-lts.list apt-get -o Dpkg::Use-Pty=0 update - apt-get -o Dpkg::Use-Pty=0 install -y --no-install-suggests --no-install-recommends cmake make automake autoconf libtool gcc pkg-config libpsl-dev libzstd-dev zlib1g-dev libgnutls28-dev libssh-dev libssh2-1-dev libc-ares-dev heimdal-dev libldap2-dev librtmp-dev stunnel4 groff + apt-get -o Dpkg::Use-Pty=0 install -y --no-install-suggests --no-install-recommends cmake make automake autoconf libtool gcc pkg-config libpsl-dev libzstd-dev zlib1g-dev libgnutls28-dev libc-ares-dev heimdal-dev libldap2-dev librtmp-dev stunnel4 groff # GitHub's actions/checkout needs newer glibc and libstdc++. The latter also depends on # gcc-8-base, but it doesn't actually seem used in our situation and isn't available in # the main repo, so force the install. @@ -80,12 +80,12 @@ jobs: with: persist-credentials: false - - name: 'cmake build-only (out-of-tree, libssh2)' + - name: 'cmake build-only (out-of-tree)' run: | mkdir bld-1 cd bld-1 cmake .. -DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON -DBUILD_SHARED_LIBS=ON \ - -DCURL_USE_GNUTLS=ON -DENABLE_ARES=OFF -DCURL_ZSTD=OFF -DCURL_USE_GSSAPI=OFF -DCURL_USE_LIBSSH2=ON -DCURL_USE_LIBSSH=OFF -DUSE_LIBRTMP=ON + -DCURL_USE_GNUTLS=ON -DENABLE_ARES=OFF -DCURL_ZSTD=OFF -DCURL_USE_GSSAPI=OFF -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=OFF -DUSE_LIBRTMP=ON make install src/curl --disable --version @@ -129,12 +129,12 @@ jobs: - name: 'autoreconf' run: autoreconf -if - - name: 'configure (out-of-tree, c-ares, libssh2, zstd, gssapi)' + - name: 'configure (out-of-tree, c-ares, zstd, gssapi)' run: | mkdir bld-am cd bld-am ../configure --disable-dependency-tracking --enable-unity --enable-warnings --enable-werror \ - --with-gnutls --enable-ares --with-libssh2 --with-zstd --with-gssapi --with-librtmp \ + --with-gnutls --enable-ares --without-libssh2 --with-zstd --with-gssapi --with-librtmp \ --prefix="$PWD"/../curl-install-am - name: 'autotools curl_config.h' diff --git a/configure.ac b/configure.ac index 6c33b561be37..fa23eb09b1e4 100644 --- a/configure.ac +++ b/configure.ac @@ -2292,8 +2292,8 @@ if test X"$OPT_LIBSSH2" != Xno; then CPPFLAGS="$CPPFLAGS $CPP_SSH2" LIBS="$LIB_SSH2 $LIBS" - dnl check for function added in libssh2 version 1.2.8 - AC_CHECK_LIB(ssh2, libssh2_free) + dnl check for function added in libssh2 version 1.9.0 + AC_CHECK_LIB(ssh2, libssh2_agent_get_identity_path) AC_CHECK_HEADER(libssh2.h, curl_ssh_msg="enabled (libssh2)" diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index de993c3e4bcd..93546ebe4bbe 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -29,7 +29,7 @@ versions of libs and build tools. - GnuTLS 3.1.10 - mbedTLS 3.2.0 - zlib 1.2.5.2 - - libssh2 1.2.8 + - libssh2 1.9.0 - c-ares 1.6.0 - libssh 0.9.0 - libidn2 2.0.0 diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index ebfd241e6c54..f68e3ee168f8 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -464,26 +464,18 @@ static CURLcode ssh_knownhost(struct Curl_easy *data, case LIBSSH2_HOSTKEY_TYPE_DSS: keybit = LIBSSH2_KNOWNHOST_KEY_SSHDSS; break; -#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_256; break; -#endif -#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384 case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_384; break; -#endif -#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521 case LIBSSH2_HOSTKEY_TYPE_ECDSA_521: keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_521; break; -#endif -#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 case LIBSSH2_HOSTKEY_TYPE_ED25519: keybit = LIBSSH2_KNOWNHOST_KEY_ED25519; break; -#endif default: infof(data, "unsupported key type, cannot check knownhosts"); keybit = 0; @@ -606,22 +598,9 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data, size_t pub_pos = 0; size_t b64_pos = 0; -#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 /* The fingerprint points to static storage (!), do not free() it. */ fingerprint = libssh2_hostkey_hash(sshc->ssh_session, LIBSSH2_HOSTKEY_HASH_SHA256); -#else - const char *hostkey; - size_t len = 0; - unsigned char hash[32]; - - hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL); - if(hostkey) { - if(!Curl_sha256it(hash, (const unsigned char *) hostkey, len)) - fingerprint = (char *) hash; - } -#endif - if(!fingerprint) { failf(data, "Denied establishing ssh session: sha256 fingerprint " @@ -755,24 +734,14 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, { CURLcode result = CURLE_OK; -#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 static const char * const hostkey_method_ssh_ed25519 = "ssh-ed25519"; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 static const char * const hostkey_method_ssh_ecdsa_521 = "ecdsa-sha2-nistp521"; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 static const char * const hostkey_method_ssh_ecdsa_384 = "ecdsa-sha2-nistp384"; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 static const char * const hostkey_method_ssh_ecdsa_256 = "ecdsa-sha2-nistp256"; -#endif - static const char * const hostkey_method_ssh_rsa - = "ssh-rsa"; static const char * const hostkey_method_ssh_rsa_all = "rsa-sha2-256,rsa-sha2-512,ssh-rsa"; static const char * const hostkey_method_ssh_dss @@ -830,35 +799,20 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]); switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) { -#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 case LIBSSH2_KNOWNHOST_KEY_ED25519: hostkey_method = hostkey_method_ssh_ed25519; break; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: hostkey_method = hostkey_method_ssh_ecdsa_521; break; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 case LIBSSH2_KNOWNHOST_KEY_ECDSA_384: hostkey_method = hostkey_method_ssh_ecdsa_384; break; -#endif -#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 case LIBSSH2_KNOWNHOST_KEY_ECDSA_256: hostkey_method = hostkey_method_ssh_ecdsa_256; break; -#endif case LIBSSH2_KNOWNHOST_KEY_SSHRSA: - if(libssh2_version(0x010900)) - /* since 1.9.0 libssh2_session_method_pref() works as expected */ - hostkey_method = hostkey_method_ssh_rsa_all; - else - /* old libssh2 which cannot correctly remove unsupported methods due - * to bug in src/kex.c or does not support the new methods anyways. - */ - hostkey_method = hostkey_method_ssh_rsa; + hostkey_method = hostkey_method_ssh_rsa_all; break; case LIBSSH2_KNOWNHOST_KEY_SSHDSS: hostkey_method = hostkey_method_ssh_dss; @@ -2428,18 +2382,9 @@ static CURLcode ssh_state_scp_download_init(struct Curl_easy *data, */ /* get a fresh new channel from the ssh layer */ -#if LIBSSH2_VERSION_NUM < 0x010700 - struct stat sb; - memset(&sb, 0, sizeof(struct stat)); - sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session, - sshp->path, &sb); -#else libssh2_struct_stat sb; memset(&sb, 0, sizeof(libssh2_struct_stat)); - sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, - sshp->path, &sb); -#endif - + sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, sshp->path, &sb); if(!sshc->ssh_channel) { int ssh_err; char *err_msg = NULL; From bb46d42407cd0503a9c499b4646af594a4db4947 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 22:49:46 +0200 Subject: [PATCH 104/465] openssl: make the asn1_object_dump name null terminated In case the buffer is too small. Reported in Joshua's sarif data Closes #18647 --- lib/vtls/openssl.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 49bc02230bea..4d37f5e77f20 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -293,20 +293,10 @@ do { \ } while(0) #endif -static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) +static int asn1_object_dump(const ASN1_OBJECT *a, char *buf, size_t len) { - int i, ilen; - - ilen = (int)len; - if(ilen < 0) - return 1; /* buffer too big */ - - i = i2t_ASN1_OBJECT(buf, ilen, a); - - if(i >= ilen) - return 1; /* buffer too small */ - - return 0; + int i = i2t_ASN1_OBJECT(buf, (int)len, a); + return (i >= (int)len); /* buffer too small */ } static CURLcode X509V3_ext(struct Curl_easy *data, @@ -337,7 +327,9 @@ static CURLcode X509V3_ext(struct Curl_easy *data, obj = X509_EXTENSION_get_object(ext); - asn1_object_dump(obj, namebuf, sizeof(namebuf)); + if(asn1_object_dump(obj, namebuf, sizeof(namebuf))) + /* make sure the name is null-terminated */ + namebuf [ sizeof(namebuf) - 1] = 0; if(!X509V3_EXT_print(bio_out, ext, 0, 0)) ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); From 5ab120bc4e6d9706efde14b37f8bd80c20981ac2 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Sep 2025 08:32:39 +0200 Subject: [PATCH 105/465] krb5: drop support for Kerberos FTP It was accidentally broken in commit 0f4c439fc7347f499cf5, shipped since 8.8.0 (May 2024) and yet not a single person has noticed or reported, indicating that we might as well drop support for FTP Kerberos. Krb5 support was added in 54967d2a3ab55596314 (July 2007), and we have been carrying the extra license information around since then for this code. This commit removes the last traces of that code and thus we can remove the extra copyright notices along with it. Reported-by: Joshua Rogers Closes #18577 --- .github/scripts/spellcheck.words | 3 - LICENSES/BSD-3-Clause.txt | 11 - README | 6 - README.md | 6 - docs/cmdline-opts/krb.md | 8 +- docs/libcurl/curl_easy_setopt.md | 2 +- docs/libcurl/opts/CURLOPT_KRBLEVEL.md | 15 +- docs/libcurl/symbols-in-versions | 2 +- include/curl/curl.h | 3 +- lib/Makefile.inc | 2 - lib/curl_krb5.h | 54 -- lib/ftp.c | 68 +- lib/ftp.h | 3 - lib/krb5.c | 953 -------------------------- lib/pingpong.c | 29 +- lib/setopt.c | 9 +- lib/url.c | 11 +- lib/urldata.h | 39 -- src/config2setopts.c | 1 - src/tool_getparam.c | 11 +- src/tool_listhelp.c | 2 +- tests/data/test1282 | 5 +- 22 files changed, 43 insertions(+), 1200 deletions(-) delete mode 100644 LICENSES/BSD-3-Clause.txt delete mode 100644 lib/curl_krb5.h delete mode 100644 lib/krb5.c diff --git a/.github/scripts/spellcheck.words b/.github/scripts/spellcheck.words index 46c05b741bcf..aafaeff6d927 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/spellcheck.words @@ -356,7 +356,6 @@ HTTPS https HTTPSRR hyper's -Högskolan IANA Icecast ICONV @@ -424,7 +423,6 @@ Krb krb Kubernetes Kuhrt -Kungliga Largefile LDAP ldap @@ -848,7 +846,6 @@ Tatsuhiro TBD TCP tcpdump -Tekniska testability testcurl TFTP diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt deleted file mode 100644 index 086d3992cb3a..000000000000 --- a/LICENSES/BSD-3-Clause.txt +++ /dev/null @@ -1,11 +0,0 @@ -Copyright (c) . - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README b/README index f5efbd70a69d..df320f94810e 100644 --- a/README +++ b/README @@ -47,9 +47,3 @@ SECURITY PROBLEMS Report suspected security problems via our HackerOne page and not in public. https://hackerone.com/curl - -NOTICE - - Curl contains pieces of source code that is Copyright (c) 1998, 1999 - Kungliga Tekniska Högskolan. This notice is included here to comply with the - distribution terms. diff --git a/README.md b/README.md index 3359818fd572..32a3c34fb0f2 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,6 @@ Download the latest source from the Git server: Report suspected security problems via [our HackerOne page](https://hackerone.com/curl) and not in public. -## Notice - -curl contains pieces of source code that is Copyright (c) 1998, 1999 Kungliga -Tekniska Högskolan. This notice is included here to comply with the -distribution terms. - ## Backers Thank you to all our backers :pray: [Become a backer](https://opencollective.com/curl#section-contribute). diff --git a/docs/cmdline-opts/krb.md b/docs/cmdline-opts/krb.md index c353a0c74009..6d47a76d6ec4 100644 --- a/docs/cmdline-opts/krb.md +++ b/docs/cmdline-opts/krb.md @@ -6,7 +6,7 @@ Arg: Help: Enable Kerberos with security Protocols: FTP Requires: Kerberos -Category: ftp +Category: deprecated Added: 7.3 Multi: single See-also: @@ -18,6 +18,8 @@ Example: # `--krb` +Deprecated option (added in 8.17.0). It has no function anymore. + Enable Kerberos authentication and use. The level must be entered and should -be one of 'clear', 'safe', 'confidential', or 'private'. Should you use a -level that is not one of these, 'private' is used. +be one of `clear`, `safe`, `confidential`, or `private`. Should you use a +level that is not one of these, `private` is used. diff --git a/docs/libcurl/curl_easy_setopt.md b/docs/libcurl/curl_easy_setopt.md index ccca56de6b24..430c3c14abbc 100644 --- a/docs/libcurl/curl_easy_setopt.md +++ b/docs/libcurl/curl_easy_setopt.md @@ -540,7 +540,7 @@ Client key password. See CURLOPT_KEYPASSWD(3) ## CURLOPT_KRBLEVEL -Kerberos security level. See CURLOPT_KRBLEVEL(3) +**OBSOLETE**. Kerberos security level. See CURLOPT_KRBLEVEL(3) ## CURLOPT_LOCALPORT diff --git a/docs/libcurl/opts/CURLOPT_KRBLEVEL.md b/docs/libcurl/opts/CURLOPT_KRBLEVEL.md index bdea064600cc..8dc5de7cee7c 100644 --- a/docs/libcurl/opts/CURLOPT_KRBLEVEL.md +++ b/docs/libcurl/opts/CURLOPT_KRBLEVEL.md @@ -5,7 +5,6 @@ Title: CURLOPT_KRBLEVEL Section: 3 Source: libcurl See-also: - - CURLOPT_KRBLEVEL (3) - CURLOPT_USE_SSL (3) Protocol: - FTP @@ -26,11 +25,13 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_KRBLEVEL, char *level); # DESCRIPTION +Deprecated. It serves no purpose anymore. + Pass a char pointer as parameter. Set the kerberos security level for FTP; this also enables kerberos awareness. This is a string that should match one -of the following: &'clear', &'safe', &'confidential' or &'private'. If the -string is set but does not match one of these, 'private' is used. Set the -string to NULL to disable kerberos support for FTP. +of the following: `clear`, `safe`, `confidential` or `private`. If the string +is set but does not match one of these, `private` is used. Set the string to +NULL to disable kerberos support for FTP. The application does not have to keep the string around after setting this option. @@ -62,8 +63,14 @@ int main(void) # HISTORY +Functionality removed in 8.17.0 + This option was known as CURLOPT_KRB4LEVEL up to 7.16.3 +# DEPRECATED + +Deprecated since 8.17.0 + # %AVAILABILITY% # RETURN VALUE diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index bfcf357bf6fb..43435cb16b5b 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -704,7 +704,7 @@ CURLOPT_ISSUERCERT_BLOB 7.71.0 CURLOPT_KEEP_SENDING_ON_ERROR 7.51.0 CURLOPT_KEYPASSWD 7.17.0 CURLOPT_KRB4LEVEL 7.3 7.17.0 -CURLOPT_KRBLEVEL 7.16.4 +CURLOPT_KRBLEVEL 7.16.4 8.17.0 CURLOPT_LOCALPORT 7.15.2 CURLOPT_LOCALPORTRANGE 7.15.2 CURLOPT_LOGIN_OPTIONS 7.34.0 diff --git a/include/curl/curl.h b/include/curl/curl.h index 6f4aa90f1349..49552558ddb7 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1357,7 +1357,8 @@ typedef enum { /* Set the krb4/5 security level, this also enables krb4/5 awareness. This * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string * is set but does not match one of these, 'private' will be used. */ - CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63), + CURLOPTDEPRECATED(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63, + 8.17.0, "removed"), /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64), diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 524fdcc53d5a..c17a8d9c3cad 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -209,7 +209,6 @@ LIB_CFILES = \ idn.c \ if2ip.c \ imap.c \ - krb5.c \ ldap.c \ llist.c \ macos.c \ @@ -292,7 +291,6 @@ LIB_HFILES = \ curl_gethostname.h \ curl_gssapi.h \ curl_hmac.h \ - curl_krb5.h \ curl_ldap.h \ curl_md4.h \ curl_md5.h \ diff --git a/lib/curl_krb5.h b/lib/curl_krb5.h deleted file mode 100644 index 574340fd3c58..000000000000 --- a/lib/curl_krb5.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef HEADER_CURL_KRB5_H -#define HEADER_CURL_KRB5_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ - -struct Curl_sec_client_mech { - const char *name; - size_t size; - int (*init)(void *); - int (*auth)(void *, struct Curl_easy *data, struct connectdata *); - void (*end)(void *); - int (*check_prot)(void *, int); - int (*encode)(void *, const void *, int, int, void **); - int (*decode)(void *, void *, int, int, struct connectdata *); -}; - -#define AUTH_OK 0 -#define AUTH_CONTINUE 1 -#define AUTH_ERROR 2 - -#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP) -void Curl_sec_conn_init(struct connectdata *); -void Curl_sec_conn_destroy(struct connectdata *); -int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, char *, - enum protection_level); -CURLcode Curl_sec_login(struct Curl_easy *, struct connectdata *); -int Curl_sec_request_prot(struct connectdata *conn, const char *level); -#else -#define Curl_sec_conn_init(x) Curl_nop_stmt -#define Curl_sec_conn_destroy(x) Curl_nop_stmt -#endif - -#endif /* HEADER_CURL_KRB5_H */ diff --git a/lib/ftp.c b/lib/ftp.c index 1e2cd4d3cfeb..df94ea5e6684 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -53,7 +53,6 @@ #include "fileinfo.h" #include "ftplistparser.h" #include "curl_range.h" -#include "curl_krb5.h" #include "strcase.h" #include "vtls/vtls.h" #include "cfilters.h" @@ -431,6 +430,9 @@ static const struct Curl_cwtype ftp_cw_lc = { #endif /* CURL_PREFER_LF_LINEENDS */ +static CURLcode getftpresponse(struct Curl_easy *data, ssize_t *nread, + int *ftpcode); + /*********************************************************************** * * ftp_check_ctrl_on_data_wait() @@ -450,7 +452,7 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data, if(curlx_dyn_len(&pp->recvbuf) && (*curlx_dyn_ptr(&pp->recvbuf) > '3')) { /* Data connection could not be established, let's return */ infof(data, "There is negative response in cache while serv connect"); - (void)Curl_GetFTPResponse(data, &nread, &ftpcode); + (void)getftpresponse(data, &nread, &ftpcode); return CURLE_FTP_ACCEPT_FAILED; } @@ -496,7 +498,7 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data, } } - (void)Curl_GetFTPResponse(data, &nread, &ftpcode); + (void)getftpresponse(data, &nread, &ftpcode); infof(data, "FTP code: %03d", ftpcode); @@ -578,28 +580,6 @@ static CURLcode ftp_readresp(struct Curl_easy *data, int code; CURLcode result = Curl_pp_readresp(data, sockindex, pp, &code, size); DEBUGASSERT(ftpcodep); -#ifdef HAVE_GSSAPI - { - struct connectdata *conn = data->conn; - char * const buf = curlx_dyn_ptr(&ftpc->pp.recvbuf); - - /* handle the security-oriented responses 6xx ***/ - switch(code) { - case 631: - code = Curl_sec_read_msg(data, conn, buf, PROT_SAFE); - break; - case 632: - code = Curl_sec_read_msg(data, conn, buf, PROT_PRIVATE); - break; - case 633: - code = Curl_sec_read_msg(data, conn, buf, PROT_CONFIDENTIAL); - break; - default: - /* normal ftp stuff we pass through! */ - break; - } - } -#endif /* store the latest code for later retrieval, except during shutdown */ if(!ftpc->shutdown) @@ -626,13 +606,14 @@ static CURLcode ftp_readresp(struct Curl_easy *data, /* --- parse FTP server responses --- */ /* - * Curl_GetFTPResponse() is a BLOCKING function to read the full response - * from a server after a command. + * getftpresponse() is a BLOCKING function to read the full response from a + * server after a command. * */ -CURLcode Curl_GetFTPResponse(struct Curl_easy *data, - ssize_t *nreadp, /* return number of bytes read */ - int *ftpcodep) /* return the ftp-code */ +static CURLcode getftpresponse(struct Curl_easy *data, + ssize_t *nreadp, /* return number of bytes + read */ + int *ftpcodep) /* return the ftp-code */ { /* * We cannot read just one byte per read() and then go back to select() as @@ -650,7 +631,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data, int cache_skip = 0; DEBUGASSERT(ftpcodep); - CURL_TRC_FTP(data, "getFTPResponse start"); + CURL_TRC_FTP(data, "getftpresponse start"); *nreadp = 0; *ftpcodep = 0; /* 0 for errors */ @@ -733,7 +714,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data, } /* while there is buffer left and loop is requested */ pp->pending_resp = FALSE; - CURL_TRC_FTP(data, "getFTPResponse -> result=%d, nread=%zd, ftpcode=%d", + CURL_TRC_FTP(data, "getftpresponse -> result=%d, nread=%zd, ftpcode=%d", result, *nreadp, *ftpcodep); return result; @@ -2814,25 +2795,6 @@ static CURLcode ftp_wait_resp(struct Curl_easy *data, return CURLE_WEIRD_SERVER_REPLY; } - /* We have received a 220 response fine, now we proceed. */ -#ifdef HAVE_GSSAPI - if(data->set.krb) { - /* If not anonymous login, try a secure login. Note that this - procedure is still BLOCKING. */ - - Curl_sec_request_prot(conn, "private"); - /* We set private first as default, in case the line below fails to - set a valid level */ - Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); - - if(Curl_sec_login(data, conn)) { - failf(data, "secure login failed"); - return CURLE_WEIRD_SERVER_REPLY; - } - infof(data, "Authentication successful"); - } -#endif - if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { /* We do not have an SSL/TLS control connection yet, but FTPS is requested. Try an FTPS connection now */ @@ -3403,7 +3365,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, pp->response_time = 60*1000; /* give it only a minute for now */ pp->response = curlx_now(); /* timeout relative now */ - result = Curl_GetFTPResponse(data, &nread, &ftpcode); + result = getftpresponse(data, &nread, &ftpcode); pp->response_time = old_time; /* set this back to previous value */ @@ -3526,7 +3488,7 @@ CURLcode ftp_sendquote(struct Curl_easy *data, result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); if(!result) { pp->response = curlx_now(); /* timeout relative now */ - result = Curl_GetFTPResponse(data, &nread, &ftpcode); + result = getftpresponse(data, &nread, &ftpcode); } if(result) return result; diff --git a/lib/ftp.h b/lib/ftp.h index aba1db7f2d3d..fdbb4b0539f2 100644 --- a/lib/ftp.h +++ b/lib/ftp.h @@ -35,9 +35,6 @@ extern const struct Curl_handler Curl_handler_ftp; extern const struct Curl_handler Curl_handler_ftps; #endif -CURLcode Curl_GetFTPResponse(struct Curl_easy *data, ssize_t *nread, - int *ftpcode); - bool ftp_conns_match(struct connectdata *needle, struct connectdata *conn); #endif /* CURL_DISABLE_FTP */ diff --git a/lib/krb5.c b/lib/krb5.c deleted file mode 100644 index b041d2f2277e..000000000000 --- a/lib/krb5.c +++ /dev/null @@ -1,953 +0,0 @@ -/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c - * - * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * Copyright (C) Daniel Stenberg - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. */ - -#include "curl_setup.h" - -#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP) - -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#include "urldata.h" -#include "url.h" -#include "cfilters.h" -#include "cf-socket.h" -#include "curlx/base64.h" -#include "ftp.h" -#include "curl_gssapi.h" -#include "sendf.h" -#include "transfer.h" -#include "curl_krb5.h" -#include "curlx/warnless.h" -#include "strdup.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -#if defined(__GNUC__) && defined(__APPLE__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - -static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn, - const char *cmd) -{ - size_t bytes_written; -#define SBUF_SIZE 1024 - char s[SBUF_SIZE]; - size_t write_len; - char *sptr = s; - CURLcode result = CURLE_OK; -#ifdef HAVE_GSSAPI - unsigned char data_sec = conn->data_prot; -#endif - - DEBUGASSERT(cmd); - - write_len = strlen(cmd); - if(!write_len || write_len > (sizeof(s) -3)) - return CURLE_BAD_FUNCTION_ARGUMENT; - - memcpy(&s, cmd, write_len); - strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ - write_len += 2; - bytes_written = 0; - - for(;;) { -#ifdef HAVE_GSSAPI - conn->data_prot = PROT_CMD; -#endif - result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written); -#ifdef HAVE_GSSAPI - DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); - conn->data_prot = data_sec; -#endif - - if(result) - break; - - Curl_debug(data, CURLINFO_HEADER_OUT, sptr, bytes_written); - - if(bytes_written != write_len) { - write_len -= bytes_written; - sptr += bytes_written; - } - else - break; - } - - return result; -} - -static int -krb5_init(void *app_data) -{ - gss_ctx_id_t *context = app_data; - /* Make sure our context is initialized for krb5_end. */ - *context = GSS_C_NO_CONTEXT; - return 0; -} - -static int -krb5_check_prot(void *app_data, int level) -{ - (void)app_data; - if(level == PROT_CONFIDENTIAL) - return -1; - return 0; -} - -static int -krb5_decode(void *app_data, void *buf, int len, - int level, struct connectdata *conn) -{ - gss_ctx_id_t *context = app_data; - OM_uint32 maj, min; - gss_buffer_desc enc, dec; - - (void)level; - (void)conn; - - enc.value = buf; - enc.length = len; - maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL); - if(maj != GSS_S_COMPLETE) - return -1; - - memcpy(buf, dec.value, dec.length); - len = curlx_uztosi(dec.length); - gss_release_buffer(&min, &dec); - - return len; -} - -static int -krb5_encode(void *app_data, const void *from, int length, int level, void **to) -{ - gss_ctx_id_t *context = app_data; - gss_buffer_desc dec, enc; - OM_uint32 maj, min; - int state; - int len; - - /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal - * libraries modify the input buffer in gss_wrap() - */ - dec.value = CURL_UNCONST(from); - dec.length = (size_t)length; - maj = gss_wrap(&min, *context, - level == PROT_PRIVATE, - GSS_C_QOP_DEFAULT, - &dec, &state, &enc); - - if(maj != GSS_S_COMPLETE) - return -1; - - /* malloc a new buffer, in case gss_release_buffer does not work as - expected */ - *to = malloc(enc.length); - if(!*to) - return -1; - memcpy(*to, enc.value, enc.length); - len = curlx_uztosi(enc.length); - gss_release_buffer(&min, &enc); - return len; -} - -static int -krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn) -{ - int ret = AUTH_OK; - char *p; - const char *host = conn->host.name; - ssize_t nread; - curl_socklen_t l = sizeof(conn->local_addr); - CURLcode result; - const char *service = data->set.str[STRING_SERVICE_NAME] ? - data->set.str[STRING_SERVICE_NAME] : - "ftp"; - const char *srv_host = "host"; - gss_buffer_desc input_buffer, output_buffer, *gssresp; - gss_buffer_desc _gssresp = GSS_C_EMPTY_BUFFER; - OM_uint32 maj, min; - gss_name_t gssname; - gss_ctx_id_t *context = app_data; - struct gss_channel_bindings_struct chan; - size_t base64_sz = 0; - const struct Curl_sockaddr_ex *remote_addr = - Curl_conn_get_remote_addr(data, FIRSTSOCKET); - struct sockaddr_in *remote_in_addr = remote_addr ? - (struct sockaddr_in *)CURL_UNCONST(&remote_addr->curl_sa_addr) : NULL; - char *stringp; - struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); - - if(!ftpc || !remote_in_addr) - return -2; - - if(getsockname(conn->sock[FIRSTSOCKET], - (struct sockaddr *)&conn->local_addr, &l) < 0) - perror("getsockname()"); - - chan.initiator_addrtype = GSS_C_AF_INET; - chan.initiator_address.length = l - 4; - chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr; - chan.acceptor_addrtype = GSS_C_AF_INET; - chan.acceptor_address.length = l - 4; - chan.acceptor_address.value = &remote_in_addr->sin_addr.s_addr; - chan.application_data.length = 0; - chan.application_data.value = NULL; - - /* this loop will execute twice (once for service, once for host) */ - for(;;) { - /* this really should not be repeated here, but cannot help it */ - if(service == srv_host) { - result = ftpsend(data, conn, "AUTH GSSAPI"); - if(result) - return -2; - - if(Curl_GetFTPResponse(data, &nread, NULL)) - return -1; - else { - char *line = curlx_dyn_ptr(&ftpc->pp.recvbuf); - if(line[0] != '3') - return -1; - } - } - - stringp = aprintf("%s@%s", service, host); - if(!stringp) - return -2; - - input_buffer.value = stringp; - input_buffer.length = strlen(stringp); - maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE, - &gssname); - free(stringp); - if(maj != GSS_S_COMPLETE) { - gss_release_name(&min, &gssname); - if(service == srv_host) { - failf(data, "Error importing service name %s@%s", service, host); - return AUTH_ERROR; - } - service = srv_host; - continue; - } - /* We pass NULL as |output_name_type| to avoid a leak. */ - gss_display_name(&min, gssname, &output_buffer, NULL); - infof(data, "Trying against %s", (char *)output_buffer.value); - gssresp = GSS_C_NO_BUFFER; - *context = GSS_C_NO_CONTEXT; - - do { - /* Release the buffer at each iteration to avoid leaking: the first time - we are releasing the memory from gss_display_name. The last item is - taken care by a final gss_release_buffer. */ - gss_release_buffer(&min, &output_buffer); - ret = AUTH_OK; - maj = Curl_gss_init_sec_context(data, - &min, - context, - gssname, - &Curl_krb5_mech_oid, - &chan, - gssresp, - &output_buffer, - TRUE, - NULL); - - if(gssresp) { - free(_gssresp.value); - gssresp = NULL; - } - - if(GSS_ERROR(maj)) { - infof(data, "Error creating security context"); - ret = AUTH_ERROR; - break; - } - - if(output_buffer.length) { - char *cmd; - - result = curlx_base64_encode((char *)output_buffer.value, - output_buffer.length, &p, &base64_sz); - if(result) { - infof(data, "base64-encoding: %s", curl_easy_strerror(result)); - ret = AUTH_ERROR; - break; - } - - cmd = aprintf("ADAT %s", p); - if(cmd) - result = ftpsend(data, conn, cmd); - else - result = CURLE_OUT_OF_MEMORY; - - free(p); - free(cmd); - - if(result) { - ret = -2; - break; - } - - if(Curl_GetFTPResponse(data, &nread, NULL)) { - ret = -1; - break; - } - else { - size_t len = curlx_dyn_len(&ftpc->pp.recvbuf); - p = curlx_dyn_ptr(&ftpc->pp.recvbuf); - if((len < 4) || (p[0] != '2' && p[0] != '3')) { - infof(data, "Server did not accept auth data"); - ret = AUTH_ERROR; - break; - } - } - - _gssresp.value = NULL; /* make sure it is initialized */ - _gssresp.length = 0; - p += 4; /* over '789 ' */ - p = strstr(p, "ADAT="); - if(p) { - unsigned char *outptr; - size_t outlen; - result = curlx_base64_decode(p + 5, &outptr, &outlen); - if(result) { - failf(data, "base64-decoding: %s", curl_easy_strerror(result)); - ret = AUTH_CONTINUE; - break; - } - _gssresp.value = outptr; - _gssresp.length = outlen; - } - - gssresp = &_gssresp; - } - } while(maj == GSS_S_CONTINUE_NEEDED); - - gss_release_name(&min, &gssname); - gss_release_buffer(&min, &output_buffer); - - if(gssresp) - free(_gssresp.value); - - if(ret == AUTH_OK || service == srv_host) - break; - - service = srv_host; - } - return ret; -} - -static void krb5_end(void *app_data) -{ - OM_uint32 min; - gss_ctx_id_t *context = app_data; - if(*context != GSS_C_NO_CONTEXT) { - OM_uint32 maj = Curl_gss_delete_sec_context(&min, context, - GSS_C_NO_BUFFER); - (void)maj; - DEBUGASSERT(maj == GSS_S_COMPLETE); - } -} - -static const struct Curl_sec_client_mech Curl_krb5_client_mech = { - "GSSAPI", - sizeof(gss_ctx_id_t), - krb5_init, - krb5_auth, - krb5_end, - krb5_check_prot, - - krb5_encode, - krb5_decode -}; - -static const struct { - unsigned char level; - const char *name; -} level_names[] = { - { PROT_CLEAR, "clear" }, - { PROT_SAFE, "safe" }, - { PROT_CONFIDENTIAL, "confidential" }, - { PROT_PRIVATE, "private" } -}; - -static unsigned char name_to_level(const char *name) -{ - int i; - for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++) - if(curl_strequal(name, level_names[i].name)) - return level_names[i].level; - return PROT_NONE; -} - -/* Convert a protocol |level| to its char representation. - We take an int to catch programming mistakes. */ -static char level_to_char(int level) -{ - switch(level) { - case PROT_CLEAR: - return 'C'; - case PROT_SAFE: - return 'S'; - case PROT_CONFIDENTIAL: - return 'E'; - case PROT_PRIVATE: - return 'P'; - case PROT_CMD: - default: - /* Those 2 cases should not be reached! */ - break; - } - DEBUGASSERT(0); - /* Default to the most secure alternative. */ - return 'P'; -} - -/* Send an FTP command defined by |message| and the optional arguments. The - function returns the ftp_code. If an error occurs, -1 is returned. */ -static int ftp_send_command(struct Curl_easy *data, const char *message, ...) - CURL_PRINTF(2, 3); - -static int ftp_send_command(struct Curl_easy *data, const char *message, ...) -{ - int ftp_code; - ssize_t nread = 0; - va_list args; - char print_buffer[50]; - - va_start(args, message); - mvsnprintf(print_buffer, sizeof(print_buffer), message, args); - va_end(args); - - if(ftpsend(data, data->conn, print_buffer)) { - ftp_code = -1; - } - else { - if(Curl_GetFTPResponse(data, &nread, &ftp_code)) - ftp_code = -1; - } - - (void)nread; - return ftp_code; -} - -/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode - saying whether an error occurred or CURLE_OK if |len| was read. */ -static CURLcode -socket_read(struct Curl_easy *data, int sockindex, void *to, size_t len) -{ - char *to_p = to; - CURLcode result; - size_t nread = 0; - - while(len > 0) { - result = Curl_conn_recv(data, sockindex, to_p, len, &nread); - if(result == CURLE_AGAIN) - continue; - if(result) - return result; - if(nread > len) - return CURLE_RECV_ERROR; - len -= nread; - to_p += nread; - } - return CURLE_OK; -} - - -/* Write |len| bytes from the buffer |to| to the socket |fd|. Return a - CURLcode saying whether an error occurred or CURLE_OK if |len| was - written. */ -static CURLcode -socket_write(struct Curl_easy *data, int sockindex, const void *to, - size_t len) -{ - const char *to_p = to; - CURLcode result; - size_t written; - - while(len > 0) { - result = Curl_conn_send(data, sockindex, to_p, len, FALSE, &written); - if(!result && written > 0) { - len -= written; - to_p += written; - } - else { - if(result == CURLE_AGAIN) - continue; - return result; - } - } - return CURLE_OK; -} - -static CURLcode krb5_read_data(struct Curl_easy *data, int sockindex, - struct krb5buffer *buf) -{ - struct connectdata *conn = data->conn; - int len; - CURLcode result; - int nread; - - result = socket_read(data, sockindex, &len, sizeof(len)); - if(result) - return result; - - if(len) { - len = (int)ntohl((uint32_t)len); - if(len > CURL_MAX_INPUT_LENGTH) - return CURLE_TOO_LARGE; - - curlx_dyn_reset(&buf->buf); - } - else - return CURLE_RECV_ERROR; - - do { - char buffer[1024]; - nread = CURLMIN(len, (int)sizeof(buffer)); - result = socket_read(data, sockindex, buffer, (size_t)nread); - if(result) - return result; - result = curlx_dyn_addn(&buf->buf, buffer, nread); - if(result) - return result; - len -= nread; - } while(len); - /* this decodes the dynbuf *in place* */ - nread = conn->mech->decode(conn->app_data, - curlx_dyn_ptr(&buf->buf), - len, conn->data_prot, conn); - if(nread < 0) - return CURLE_RECV_ERROR; - curlx_dyn_setlen(&buf->buf, nread); - buf->index = 0; - return CURLE_OK; -} - -static size_t -buffer_read(struct krb5buffer *buf, void *data, size_t len) -{ - size_t size = curlx_dyn_len(&buf->buf); - if(size - buf->index < len) - len = size - buf->index; - memcpy(data, curlx_dyn_ptr(&buf->buf) + buf->index, len); - buf->index += len; - return len; -} - -/* Matches Curl_recv signature */ -static CURLcode sec_recv(struct Curl_easy *data, int sockindex, - char *buffer, size_t len, size_t *pnread) -{ - struct connectdata *conn = data->conn; - CURLcode result = CURLE_OK; - size_t bytes_read; - - /* Handle clear text response. */ - if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) - return Curl_conn_recv(data, sockindex, buffer, len, pnread); - - if(conn->in_buffer.eof_flag) { - conn->in_buffer.eof_flag = 0; - *pnread = 0; - return CURLE_OK; - } - - bytes_read = buffer_read(&conn->in_buffer, buffer, len); - buffer += bytes_read; - len -= bytes_read; - *pnread += bytes_read; - - while(len > 0) { - result = krb5_read_data(data, sockindex, &conn->in_buffer); - if(result) - return result; - if(curlx_dyn_len(&conn->in_buffer.buf) == 0) { - if(*pnread > 0) - conn->in_buffer.eof_flag = 1; - return result; - } - bytes_read = buffer_read(&conn->in_buffer, buffer, len); - buffer += bytes_read; - len -= bytes_read; - *pnread += bytes_read; - } - return result; -} - -/* Send |length| bytes from |from| to the |sockindex| socket taking care of - encoding and negotiating with the server. |from| can be NULL. */ -static CURLcode do_sec_send(struct Curl_easy *data, struct connectdata *conn, - int sockindex, const char *from, size_t length) -{ - int bytes, htonl_bytes; /* 32-bit integers for htonl */ - char *buffer = NULL; - char *cmd_buffer; - size_t cmd_size = 0; - enum protection_level prot_level = conn->data_prot; - bool iscmd = (prot_level == PROT_CMD); - CURLcode result = CURLE_OK; - - DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST); - - if(iscmd) { - if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5)) - prot_level = PROT_PRIVATE; - else - prot_level = conn->command_prot; - } - bytes = conn->mech->encode(conn->app_data, from, (int)length, - (int)prot_level, (void **)&buffer); - if(!buffer || bytes <= 0) - return CURLE_OUT_OF_MEMORY; /* error */ - - if(iscmd) { - result = curlx_base64_encode(buffer, curlx_sitouz(bytes), - &cmd_buffer, &cmd_size); - if(result) { - free(buffer); - return result; /* error */ - } - if(cmd_size > 0) { - static const char *enc = "ENC "; - static const char *mic = "MIC "; - if(prot_level == PROT_PRIVATE) - result = socket_write(data, sockindex, enc, 4); - else - result = socket_write(data, sockindex, mic, 4); - if(!result) - result = socket_write(data, sockindex, cmd_buffer, cmd_size); - if(!result) - result = socket_write(data, sockindex, "\r\n", 2); - if(!result) - infof(data, "Send: %s%s", prot_level == PROT_PRIVATE ? enc : mic, - cmd_buffer); - } - free(cmd_buffer); - } - else { - htonl_bytes = (int)htonl((OM_uint32)bytes); - result = socket_write(data, sockindex, &htonl_bytes, sizeof(htonl_bytes)); - if(!result) - result = socket_write(data, sockindex, buffer, curlx_sitouz(bytes)); - } - free(buffer); - return result; -} - -static CURLcode sec_write(struct Curl_easy *data, int sockindex, - const char *buffer, size_t length, - size_t *pnwritten) -{ - struct connectdata *conn = data->conn; - size_t len = conn->buffer_size; - - *pnwritten = 0; - if(len <= 0) - len = length; - while(length) { - CURLcode result; - if(length < len) - len = length; - - result = do_sec_send(data, conn, sockindex, buffer, len); - if(result) - return result; - length -= len; - buffer += len; - *pnwritten += len; - } - return CURLE_OK; -} - -/* Matches Curl_send signature */ -static CURLcode sec_send(struct Curl_easy *data, int sockindex, - const void *buffer, size_t len, bool eos, - size_t *pnwritten) -{ - (void)eos; - return sec_write(data, sockindex, buffer, len, pnwritten); -} - -int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, - char *buffer, enum protection_level level) -{ - /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an - int */ - int decoded_len; - char *buf; - int ret_code = 0; - size_t decoded_sz = 0; - CURLcode error; - - (void)data; - - if(!conn->mech) - /* not initialized, return error */ - return -1; - - DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); - - error = curlx_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz); - if(error || decoded_sz == 0) - return -1; - - if(decoded_sz > (size_t)INT_MAX) { - free(buf); - return -1; - } - decoded_len = curlx_uztosi(decoded_sz); - - decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len, - (int)level, conn); - if(decoded_len <= 0) { - free(buf); - return -1; - } - - { - buf[decoded_len] = '\n'; - Curl_debug(data, CURLINFO_HEADER_IN, buf, decoded_len + 1); - } - - buf[decoded_len] = '\0'; - if(decoded_len <= 3) - /* suspiciously short */ - return 0; - - if(buf[3] != '-') - ret_code = atoi(buf); - - if(buf[decoded_len - 1] == '\n') - buf[decoded_len - 1] = '\0'; - strcpy(buffer, buf); - free(buf); - return ret_code; -} - -static int sec_set_protection_level(struct Curl_easy *data) -{ - int code; - struct connectdata *conn = data->conn; - unsigned char level = conn->request_data_prot; - - DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); - - if(!conn->sec_complete) { - infof(data, "Trying to change the protection level after the" - " completion of the data exchange."); - return -1; - } - - /* Bail out if we try to set up the same level */ - if(conn->data_prot == level) - return 0; - - if(level) { - char *pbsz; - unsigned int buffer_size = 1 << 20; /* 1048576 */ - struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); - char *line; - - if(!ftpc) - return -2; - - code = ftp_send_command(data, "PBSZ %u", buffer_size); - if(code < 0) - return -1; - - if(code/100 != 2) { - failf(data, "Failed to set the protection's buffer size."); - return -1; - } - conn->buffer_size = buffer_size; - - line = curlx_dyn_ptr(&ftpc->pp.recvbuf); - pbsz = strstr(line, "PBSZ="); - if(pbsz) { - /* stick to default value if the check fails */ - if(ISDIGIT(pbsz[5])) - buffer_size = (unsigned int)atoi(&pbsz[5]); - if(buffer_size < conn->buffer_size) - conn->buffer_size = buffer_size; - } - } - - /* Now try to negotiate the protection level. */ - code = ftp_send_command(data, "PROT %c", level_to_char(level)); - - if(code < 0) - return -1; - - if(code/100 != 2) { - failf(data, "Failed to set the protection level."); - return -1; - } - - conn->data_prot = level; - if(level == PROT_PRIVATE) - conn->command_prot = level; - - return 0; -} - -int -Curl_sec_request_prot(struct connectdata *conn, const char *level) -{ - unsigned char l = name_to_level(level); - if(l == PROT_NONE) - return -1; - DEBUGASSERT(l > PROT_NONE && l < PROT_LAST); - conn->request_data_prot = l; - return 0; -} - -static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn) -{ - int ret; - void *tmp_allocation; - const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; - - tmp_allocation = realloc(conn->app_data, mech->size); - if(!tmp_allocation) { - failf(data, "Failed realloc of size %zu", mech->size); - mech = NULL; - return CURLE_OUT_OF_MEMORY; - } - conn->app_data = tmp_allocation; - - if(mech->init) { - ret = mech->init(conn->app_data); - if(ret) { - infof(data, "Failed initialization for %s. Skipping it.", - mech->name); - return CURLE_FAILED_INIT; - } - } - - infof(data, "Trying mechanism %s...", mech->name); - ret = ftp_send_command(data, "AUTH %s", mech->name); - if(ret < 0) - return CURLE_COULDNT_CONNECT; - - if(ret/100 != 3) { - switch(ret) { - case 504: - infof(data, "Mechanism %s is not supported by the server (server " - "returned ftp code: 504).", mech->name); - break; - case 534: - infof(data, "Mechanism %s was rejected by the server (server returned " - "ftp code: 534).", mech->name); - break; - default: - if(ret/100 == 5) { - infof(data, "server does not support the security extensions"); - return CURLE_USE_SSL_FAILED; - } - break; - } - return CURLE_LOGIN_DENIED; - } - - /* Authenticate */ - ret = mech->auth(conn->app_data, data, conn); - - if(ret != AUTH_CONTINUE) { - if(ret != AUTH_OK) { - /* Mechanism has dumped the error to stderr, do not error here. */ - return CURLE_USE_SSL_FAILED; - } - DEBUGASSERT(ret == AUTH_OK); - - conn->mech = mech; - conn->sec_complete = 1; - conn->recv[FIRSTSOCKET] = sec_recv; - conn->send[FIRSTSOCKET] = sec_send; - conn->recv[SECONDARYSOCKET] = sec_recv; - conn->send[SECONDARYSOCKET] = sec_send; - conn->command_prot = PROT_SAFE; - /* Set the requested protection level */ - /* BLOCKING */ - (void)sec_set_protection_level(data); - } - - return CURLE_OK; -} - -CURLcode -Curl_sec_login(struct Curl_easy *data, struct connectdata *conn) -{ - return choose_mech(data, conn); -} - -void -Curl_sec_conn_init(struct connectdata *conn) -{ - curlx_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH); - conn->in_buffer.index = 0; - conn->in_buffer.eof_flag = 0; -} - -void -Curl_sec_conn_destroy(struct connectdata *conn) -{ - if(conn->mech && conn->mech->end) - conn->mech->end(conn->app_data); - Curl_safefree(conn->app_data); - curlx_dyn_free(&conn->in_buffer.buf); - conn->in_buffer.index = 0; - conn->in_buffer.eof_flag = 0; - conn->sec_complete = 0; - conn->data_prot = PROT_CLEAR; - conn->mech = NULL; -} - -#if defined(__GNUC__) && defined(__APPLE__) -#pragma GCC diagnostic pop -#endif - -#endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */ diff --git a/lib/pingpong.c b/lib/pingpong.c index 003ad58441c7..195e059ed1f4 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -182,10 +182,6 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data, CURLcode result; struct connectdata *conn = data->conn; -#ifdef HAVE_GSSAPI - enum protection_level data_sec; -#endif - DEBUGASSERT(pp->sendleft == 0); DEBUGASSERT(pp->sendsize == 0); DEBUGASSERT(pp->sendthis == NULL); @@ -208,9 +204,6 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data, write_len = curlx_dyn_len(&pp->sendbuf); s = curlx_dyn_ptr(&pp->sendbuf); -#ifdef HAVE_GSSAPI - conn->data_prot = PROT_CMD; -#endif result = Curl_conn_send(data, FIRSTSOCKET, s, write_len, FALSE, &bytes_written); if(result == CURLE_AGAIN) { @@ -218,11 +211,6 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data, } else if(result) return result; -#ifdef HAVE_GSSAPI - data_sec = conn->data_prot; - DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); - conn->data_prot = (unsigned char)data_sec; -#endif Curl_debug(data, CURLINFO_HEADER_OUT, s, bytes_written); @@ -272,17 +260,7 @@ static CURLcode pingpong_read(struct Curl_easy *data, size_t buflen, size_t *nread) { - CURLcode result; -#ifdef HAVE_GSSAPI - enum protection_level prot = data->conn->data_prot; - data->conn->data_prot = PROT_CLEAR; -#endif - result = Curl_conn_recv(data, sockindex, buffer, buflen, nread); -#ifdef HAVE_GSSAPI - DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST); - data->conn->data_prot = (unsigned char)prot; -#endif - return result; + return Curl_conn_recv(data, sockindex, buffer, buflen, nread); } /* @@ -348,10 +326,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data, size_t length = nl - line + 1; /* output debug output if that is requested */ -#ifdef HAVE_GSSAPI - if(!conn->sec_complete) -#endif - Curl_debug(data, CURLINFO_HEADER_IN, line, length); + Curl_debug(data, CURLINFO_HEADER_IN, line, length); /* * Pass all response-lines to the callback function registered for diff --git a/lib/setopt.c b/lib/setopt.c index d958c5492a8d..3f628c443ca4 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -1967,15 +1967,8 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, case CURLOPT_FTP_ALTERNATIVE_TO_USER: return Curl_setstropt(&s->str[STRING_FTP_ALTERNATIVE_TO_USER], ptr); -#ifdef HAVE_GSSAPI case CURLOPT_KRBLEVEL: - /* - * A string that defines the kerberos security level. - */ - result = Curl_setstropt(&s->str[STRING_KRB_LEVEL], ptr); - s->krb = !!(s->str[STRING_KRB_LEVEL]); - break; -#endif + return CURLE_NOT_BUILT_IN; /* removed in 8.17.0 */ #endif case CURLOPT_URL: /* diff --git a/lib/url.c b/lib/url.c index 3f792ec7655e..a03a111995e2 100644 --- a/lib/url.c +++ b/lib/url.c @@ -98,7 +98,6 @@ #include "hsts.h" #include "noproxy.h" #include "cfilters.h" -#include "curl_krb5.h" #include "idn.h" /* And now for the protocols */ @@ -606,7 +605,6 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn) Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ #endif - Curl_sec_conn_destroy(conn); Curl_safefree(conn->user); Curl_safefree(conn->passwd); Curl_safefree(conn->sasl_authzid); @@ -1455,10 +1453,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) /* Initialize the attached xfers bitset */ Curl_uint_spbset_init(&conn->xfers_attached); -#ifdef HAVE_GSSAPI - conn->data_prot = PROT_CLEAR; -#endif - /* Store the local bind parameters that will be used for this connection */ if(data->set.str[STRING_DEVICE]) { conn->localdev = strdup(data->set.str[STRING_DEVICE]); @@ -3473,10 +3467,7 @@ static CURLcode create_conn(struct Curl_easy *data, /* Do the unfailable inits first, before checks that may early return */ Curl_hash_init(&conn->meta_hash, 23, - Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry); - - /* GSSAPI related inits */ - Curl_sec_conn_init(conn); + Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry); result = parseurlandfillconn(data, conn); if(result) diff --git a/lib/urldata.h b/lib/urldata.h index 4f00c8c9a093..b2e83c4a0eef 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -234,25 +234,6 @@ typedef CURLcode (Curl_recv)(struct Curl_easy *data, /* transfer */ ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) #endif -#ifdef HAVE_GSSAPI -/* Types needed for krb5-ftp connections */ -struct krb5buffer { - struct dynbuf buf; - size_t index; - BIT(eof_flag); -}; - -enum protection_level { - PROT_NONE, /* first in list */ - PROT_CLEAR, - PROT_SAFE, - PROT_CONFIDENTIAL, - PROT_PRIVATE, - PROT_CMD, - PROT_LAST /* last in list */ -}; -#endif - /* SSL backend-specific data; declared differently by each SSL backend */ struct ssl_backend_data; struct Curl_ssl_scache_entry; @@ -703,20 +684,6 @@ struct connectdata { was used on this connection. */ struct curltime keepalive; - /**** curl_get() phase fields */ - -#ifdef HAVE_GSSAPI - BIT(sec_complete); /* if Kerberos is enabled for this connection */ - unsigned char command_prot; /* enum protection_level */ - unsigned char data_prot; /* enum protection_level */ - unsigned char request_data_prot; /* enum protection_level */ - size_t buffer_size; - struct krb5buffer in_buffer; - void *app_data; - const struct Curl_sec_client_mech *mech; - struct sockaddr_in local_addr; -#endif - struct uint_spbset xfers_attached; /* mids of attached transfers */ /* A connection cache from a SHARE might be used in several multi handles. * We MUST not reuse connections that are running in another multi, @@ -1239,9 +1206,6 @@ enum dupstring { STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */ STRING_FTPPORT, /* port to send with the FTP PORT command */ #endif -#ifdef HAVE_GSSAPI - STRING_KRB_LEVEL, /* krb security level */ -#endif #ifndef CURL_DISABLE_NETRC STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find $HOME/.netrc */ @@ -1604,9 +1568,6 @@ struct UserDefined { location: */ BIT(opt_no_body); /* as set with CURLOPT_NOBODY */ BIT(verbose); /* output verbosity */ -#ifdef HAVE_GSSAPI - BIT(krb); /* Kerberos connection requested */ -#endif BIT(reuse_forbid); /* forbidden to be reused, close after use */ BIT(reuse_fresh); /* do not reuse an existing connection */ BIT(no_signal); /* do not use any signal/alarm handler */ diff --git a/src/config2setopts.c b/src/config2setopts.c index e8f4b0a407ae..533fe992d34b 100644 --- a/src/config2setopts.c +++ b/src/config2setopts.c @@ -973,7 +973,6 @@ CURLcode config2setopts(struct OperationConfig *config, customrequest_helper(config->httpreq, config->customrequest); my_setopt(curl, CURLOPT_STDERR, tool_stderr); my_setopt_str(curl, CURLOPT_INTERFACE, config->iface); - my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel); progressbarinit(&per->progressbar, config); my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers); my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface); diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 43d30778de64..d7bdadb5d6d3 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -196,8 +196,8 @@ static const struct LongShort aliases[]= { {"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME}, {"key", ARG_FILE, ' ', C_KEY}, {"key-type", ARG_STRG|ARG_TLS, ' ', C_KEY_TYPE}, - {"krb", ARG_STRG, ' ', C_KRB}, - {"krb4", ARG_STRG, ' ', C_KRB4}, + {"krb", ARG_STRG|ARG_DEPR, ' ', C_KRB}, + {"krb4", ARG_STRG|ARG_DEPR, ' ', C_KRB4}, {"libcurl", ARG_STRG, ' ', C_LIBCURL}, {"limit-rate", ARG_STRG, ' ', C_LIMIT_RATE}, {"list-only", ARG_BOOL, 'l', C_LIST_ONLY}, @@ -2371,13 +2371,6 @@ static ParameterError opt_string(struct OperationConfig *config, /* interface */ err = getstr(&config->iface, nextarg, DENY_BLANK); break; - case C_KRB: /* --krb */ - /* kerberos level string */ - if(!feature_spnego) - err = PARAM_LIBCURL_DOESNT_SUPPORT; - else - err = getstr(&config->krblevel, nextarg, DENY_BLANK); - break; case C_HAPROXY_CLIENTIP: /* --haproxy-clientip */ err = getstr(&config->haproxy_clientip, nextarg, DENY_BLANK); break; diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c index ecbd8bf4595e..bd72dbe15c51 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -343,7 +343,7 @@ const struct helptxt helptext[] = { CURLHELP_TLS}, {" --krb ", "Enable Kerberos with security ", - CURLHELP_FTP}, + CURLHELP_DEPRECATED}, {" --libcurl ", "Generate libcurl code for this command line", CURLHELP_CURL | CURLHELP_GLOBAL}, diff --git a/tests/data/test1282 b/tests/data/test1282 index f57275187f2e..a54166be9661 100644 --- a/tests/data/test1282 +++ b/tests/data/test1282 @@ -18,11 +18,8 @@ REPLY PASS 633 XXXXXXXX\x00\x00XXXXXXXX ftp - -GSS-API - -FTP with 633 response before gss initialized +FTP with 633 response to auth ftp://%HOSTIP:%FTPPORT/%TESTNUMBER From 3dad0cfd779413866a2a0a8353ee9a98212673f8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 8 Sep 2025 00:18:52 +0200 Subject: [PATCH 106/465] write-out: make %header{} able to output *all* occurances of a header By appending `:all:[separator]` to the header name. The `[separator]` string is output between each header value if there are more than one to output. Test 764 and 765 verify Idea-by: kapsiR on github Ref: #18449 Closes #18491 --- docs/cmdline-opts/write-out.md | 8 +++ src/tool_writeout.c | 122 ++++++++++++++++++++++++++++----- tests/data/Makefile.am | 2 +- tests/data/test764 | 67 ++++++++++++++++++ tests/data/test765 | 67 ++++++++++++++++++ 5 files changed, 249 insertions(+), 17 deletions(-) create mode 100644 tests/data/test764 create mode 100644 tests/data/test765 diff --git a/docs/cmdline-opts/write-out.md b/docs/cmdline-opts/write-out.md index b365eeb22de3..9946349c1552 100644 --- a/docs/cmdline-opts/write-out.md +++ b/docs/cmdline-opts/write-out.md @@ -93,6 +93,14 @@ The value of header `name` from the transfer's most recent server response. Unlike other variables, the variable name `header` is not in braces. For example `%header{date}`. Refer to --write-out remarks. (Added in 7.84.0) +Starting with 8.17.0, output the contents of *all* header fields using a +specific name - even for a whole redirect "chain" by appending +`:all:[separator]` to the header name. The `[separator]` string (if not blank) +is output between the headers if there are more than one. When more than one +header is shown, they are output in the chronological order of appearance over +the wire. To include a close brace (`}`) in the separator, escape it with a +backslash: `\}`. + ## `header_json` A JSON object with all HTTP response headers from the recent transfer. Values are provided as arrays, since in the case of multiple headers there can be diff --git a/src/tool_writeout.c b/src/tool_writeout.c index 225cf91fd4e6..cdde28c90950 100644 --- a/src/tool_writeout.c +++ b/src/tool_writeout.c @@ -615,6 +615,111 @@ static const char *outtime(const char *ptr, /* %time{ ... */ return ptr; } +static void separator(const char *sep, size_t seplen, FILE *stream) +{ + while(seplen) { + if(*sep == '\\') { + switch(sep[1]) { + case 'r': + fputc('\r', stream); + break; + case 'n': + fputc('\n', stream); + break; + case 't': + fputc('\t', stream); + break; + case '}': + fputc('}', stream); + break; + case '\0': + break; + default: + /* unknown, just output this */ + fputc(sep[0], stream); + fputc(sep[1], stream); + break; + } + sep += 2; + seplen -= 2; + } + else { + fputc(*sep, stream); + sep++; + seplen--; + } + } +} + +static void output_header(struct per_transfer *per, + FILE *stream, + const char **pptr) +{ + const char *ptr = *pptr; + const char *end; + end = strchr(ptr, '}'); + do { + if(!end || (end[-1] != '\\')) + break; + end = strchr(&end[1], '}'); + } while(end); + if(end) { + char hname[256]; /* holds the longest header field name */ + struct curl_header *header; + const char *instr; + const char *sep = NULL; + size_t seplen = 0; + size_t vlen = end - ptr; + instr = memchr(ptr, ':', vlen); + if(instr) { + /* instructions follow */ + if(!strncmp(&instr[1], "all:", 4)) { + sep = &instr[5]; + seplen = end - sep; + vlen -= (seplen + 5); + } + } + if(vlen < sizeof(hname)) { + memcpy(hname, ptr, vlen); + hname[vlen] = 0; + if(sep) { + /* get headers from all requests */ + int reqno = 0; + size_t indno = 0; + bool output = FALSE; + do { + if(CURLHE_OK == curl_easy_header(per->curl, hname, indno, + CURLH_HEADER, reqno, + &header)) { + if(output) + /* output separator */ + separator(sep, seplen, stream); + fputs(header->value, stream); + output = TRUE; + } + else + break; + if((header->index + 1) < header->amount) + indno++; + else { + ++reqno; + indno = 0; + } + } while(1); + } + else { + if(CURLHE_OK == curl_easy_header(per->curl, hname, 0, + CURLH_HEADER, -1, &header)) + fputs(header->value, stream); + } + } + ptr = end + 1; + } + else + fputs("%header{", stream); + *pptr = ptr; +} + void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, CURLcode per_result) { @@ -699,22 +804,7 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, } else if(!strncmp("header{", &ptr[1], 7)) { ptr += 8; - end = strchr(ptr, '}'); - if(end) { - char hname[256]; /* holds the longest header field name */ - struct curl_header *header; - vlen = end - ptr; - if(vlen < sizeof(hname)) { - memcpy(hname, ptr, vlen); - hname[vlen] = 0; - if(CURLHE_OK == curl_easy_header(per->curl, hname, 0, - CURLH_HEADER, -1, &header)) - fputs(header->value, stream); - } - ptr = end + 1; - } - else - fputs("%header{", stream); + output_header(per, stream, &ptr); } else if(!strncmp("time{", &ptr[1], 5)) { ptr = outtime(ptr, stream); diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index dfff0122575c..854791fba0e9 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -109,7 +109,7 @@ 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 test758 test759 test760 test761 test762 \ -test763 \ +test763 test764 test765 \ \ test780 test781 test782 test783 test784 test785 test786 test787 test788 \ test789 test790 test791 test792 test793 test794 test796 test797 \ diff --git a/tests/data/test764 b/tests/data/test764 new file mode 100644 index 000000000000..dd138e108432 --- /dev/null +++ b/tests/data/test764 @@ -0,0 +1,67 @@ + + + +HTTP +HTTP GET +-w +%header + + + +# +# Server-side + + +HTTP/1.1 301 Redirect +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 +This: one +This: two +Content-Length: 6 +Location: %TESTNUMBER0002 +Content-Type: text/html +Funny-head: yesyes + +-foo- + + +HTTP/1.1 200 Not a redirect +Accept-Ranges: bytes +This: three +This: four +Content-Length: 6 +Funny-head: yesyes + +-foo- + + + + +# +# Client-side + + +headers-api + + +http + + +-w with multiple header output + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER -L -w '%header{this:all:***}\n' -o %LOGDIR/%TESTNUMBER.out + + + +# +# Verify data after the test has been "shot" + + +one***two***three***four + + + diff --git a/tests/data/test765 b/tests/data/test765 new file mode 100644 index 000000000000..2a868620c806 --- /dev/null +++ b/tests/data/test765 @@ -0,0 +1,67 @@ + + + +HTTP +HTTP GET +-w +%header + + + +# +# Server-side + + +HTTP/1.1 301 Redirect +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 +This: one +This: two +Content-Length: 6 +Location: %TESTNUMBER0002 +Content-Type: text/html +Funny-head: yesyes + +-foo- + + +HTTP/1.1 200 Not a redirect +Accept-Ranges: bytes +This: three +This: four +Content-Length: 6 +Funny-head: yesyes + +-foo- + + + + +# +# Client-side + + +headers-api + + +http + + +-w with multiple header output using } in separator + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER -L -w '%header{this:all:-{\}-}\n' -o %LOGDIR/%TESTNUMBER.out + + + +# +# Verify data after the test has been "shot" + + +one-{}-two-{}-three-{}-four + + + From 4189c2c0fe15b3a6afecadb56fd50b6875d7170b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 00:05:55 +0200 Subject: [PATCH 107/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 78 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 69b05b895a9f..0fb4e0be115e 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,66 +4,97 @@ curl and libcurl 8.17.0 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3504 + Contributors: 3505 This release includes the following changes: + o build: drop the winbuild build system [81] + o krb5: drop support for Kerberos FTP [43] + o libssh2: up the minimum requirement to 1.9.0 [85] + o write-out: make %header{} able to output *all* occurances of a header [25] This release includes the following bugfixes: o asyn-thrdd: drop pthread_cancel [30] + o autotools: make `--enable-code-coverage` support llvm/clang [79] o aws-lc: re-enable large read-ahead with v1.61.0 again [16] + o base64: accept zero length argument to base64_encode [82] + o build: address some `-Weverything` warnings, update picky warnings [74] + o build: avoid overriding system symbols for socket functions [68] + o cf-socket: use the right byte order for ports in bindlocal [61] o cf_socket_recv: don't count reading zero bytes as first byte [23] o cfilter: unlink and discard [46] + o cmake: add `CURL_CODE_COVERAGE` option [78] o cmake: fix building docs when the base directory contains `.3` [18] o cmdline-docs: extended, clarified, refreshed [28] o configure: add "-mt" for pthread support on HP-UX [52] o cookie: avoid saving a cookie file if no transfer was done [11] o curl_easy_getinfo: error code on NULL arg [2] o curl_mem_undef.h: limit to `CURLDEBUG` for non-memalloc overrides [19] + o curl_slist_append.md: clarify that a NULL pointer is not acceptable [72] o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] + o CURLOPT_HEADER/WRITEFUNCTION.md: drop '* size' since size is always 1 [63] o CURLOPT_MAXLIFETIME_CONN: make default 24 hours [10] o CURLOPT_SSL_VERIFYHOST.md: add see-also to two other VERIFYHOST options [32] o CURLOPT_TIMECONDITION.md: works for FILE and FTP as well [27] + o digest_sspi: fix two memory leaks in error branches [77] o dist: do not distribute `CI.md` [29] o docs/libcurl: clarify some timeout option behavior [15] o docs/libcurl: remove ancient version references [7] o docs/libcurl: use lowercase must [5] o easy_getinfo: check magic, Curl_close safety [3] o examples: fix two issues found by CodeQL [35] + o ftp: fix port number range loop for PORT commands [66] + o gtls: avoid potential use of uninitialized variable in trace output [83] + o httpsrr: free old pointers when storing new [57] o krb5: return appropriate error on send failures [22] o ldap: do not base64 encode zero length string [42] o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] o libssh2: drop two redundant null-terminations [26] o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] + o libssh: error on bad chgrp number [71] + o libssh: error on bad chown number and store the value [64] o libssh: react on errors from ssh_scp_read [24] + o libssh: return out of memory correctly if aprintf fails [60] o Makefile.example: simplify and make it configurable [20] o managen: ignore version mentions < 7.66.0 [55] o managen: render better manpage references/links [54] o multi.h: add CURLMINFO_LASTENTRY [51] o ngtcp2: check error code on connect failure [13] o openldap: avoid indexing the result at -1 for blank responses [44] + o openssl: make the asn1_object_dump name null terminated [56] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o rustls: typecast variable for safer trace output [69] o sasl: clear canceled mechanism instead of toggling it [41] + o schannel: assign result before using it [62] o setopt: accept *_SSL_VERIFYHOST set to 2L [31] o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] o smb: adjust buffer size checks [45] o smtp: check EHLO responses case insensitively [50] + o socks: make Curl_blockread_all return CURLcode [67] o socks_sspi: fix memory cleanup calls [40] o socks_sspi: restore non-blocking socket on error paths [48] o ssl-sessions.md: mark option experimental [12] o sws: fix checking `sscanf()` return value [17] o telnet: make printsub require another byte input [21] o tftp: check and act on tftp_set_timeouts() returning error [38] + o tftp: handle tftp_multi_statemach() return code [65] o tftp: propagate expired timer from tftp_state_timeout() [39] + o tftp: return error when sendto() fails [59] + o tidy-up: avoid using the reserved macro namespace [76] + o tidy-up: update MS links, allow long URLs via `checksrc` [73] o TODO: remove already implemented or bad items [36] o tool: fix exponential retry delay [47] o tool_cb_hdr: fix fwrite check in header callback [49] + o tool_cb_hdr: size is always 1 [70] + o tool_getparam/set_rate: skip the multiplication on overflow [84] o tool_operate: improve wording in retry message [37] o tool_operate: keep the progress meter for --out-null [33] o urldata: FILE is not a list-only protocol [9] + o windows: replace `_beginthreadex()` with `CreateThread()` [80] + o windows: stop passing unused, optional argument for Win9x compatibility [75] This release includes the following known bugs: @@ -79,7 +110,6 @@ Planned upcoming removals include: o OpenSSL 1.x support o Support for c-ares versions before 1.16.0 o Support for Windows XP/2003 - o The winbuild build system o Windows CE support See https://curl.se/dev/deprecate.html @@ -87,12 +117,13 @@ Planned upcoming removals include: This release would not have looked like this without help, code, reports and advice from friends like these: - Adam Light, Andrew Kirillov, Andrew Olsen, Christian Schmitz, Dan Fandrich, - Daniel Stenberg, dependabot[bot], divinity76 on github, - Emilio Pozuelo Monfort, Ethan Everett, fds242 on github, Javier Blazquez, - Jicea, Joshua Rogers, Michael Osipov, Nir Azkiel, Ray Satiro, renovate[bot], - Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats - (21 contributors) + Adam Light, Andrew Kirillov, Andrew Olsen, BobodevMm on github, + Christian Schmitz, Dan Fandrich, Daniel Stenberg, dependabot[bot], + divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, + fds242 on github, Javier Blazquez, Jicea, Joshua Rogers, kapsiR on github, + Marcel Raad, Michael Osipov, Michał Petryka, Nir Azkiel, Ray Satiro, + renovate[bot], Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats + (25 contributors) References to bug reports and discussions on issues: @@ -120,6 +151,7 @@ References to bug reports and discussions on issues: [22] = https://curl.se/bug/?i=18561 [23] = https://curl.se/bug/?i=18615 [24] = https://curl.se/bug/?i=18616 + [25] = https://curl.se/bug/?i=18491 [26] = https://curl.se/bug/?i=18606 [27] = https://curl.se/bug/?i=18551 [28] = https://curl.se/bug/?i=18550 @@ -137,6 +169,7 @@ References to bug reports and discussions on issues: [40] = https://curl.se/bug/?i=18587 [41] = https://curl.se/bug/?i=18573 [42] = https://curl.se/bug/?i=18602 + [43] = https://curl.se/bug/?i=18577 [44] = https://curl.se/bug/?i=18600 [45] = https://curl.se/bug/?i=18599 [46] = https://curl.se/bug/?i=18596 @@ -149,3 +182,32 @@ References to bug reports and discussions on issues: [53] = https://curl.se/bug/?i=18579 [54] = https://curl.se/bug/?i=18580 [55] = https://curl.se/bug/?i=18583 + [56] = https://curl.se/bug/?i=18647 + [57] = https://curl.se/bug/?i=18631 + [59] = https://curl.se/bug/?i=18643 + [60] = https://curl.se/bug/?i=18637 + [61] = https://curl.se/bug/?i=18641 + [62] = https://curl.se/bug/?i=18642 + [63] = https://curl.se/bug/?i=18640 + [64] = https://curl.se/bug/?i=18639 + [65] = https://curl.se/bug/?i=18638 + [66] = https://curl.se/bug/?i=18636 + [67] = https://curl.se/bug/?i=18635 + [68] = https://curl.se/bug/?i=18503 + [69] = https://curl.se/bug/?i=18628 + [70] = https://curl.se/bug/?i=18630 + [71] = https://curl.se/bug/?i=18629 + [72] = https://curl.se/bug/?i=18627 + [73] = https://curl.se/bug/?i=18626 + [74] = https://curl.se/bug/?i=18477 + [75] = https://curl.se/bug/?i=18490 + [76] = https://curl.se/bug/?i=18482 + [77] = https://curl.se/bug/?i=18488 + [78] = https://curl.se/bug/?i=18468 + [79] = https://curl.se/bug/?i=18473 + [80] = https://curl.se/bug/?i=18451 + [81] = https://curl.se/bug/?i=18040 + [82] = https://curl.se/bug/?i=18617 + [83] = https://curl.se/bug/?i=18620 + [84] = https://curl.se/bug/?i=18624 + [85] = https://curl.se/bug/?i=18612 From 0513f9f8786e0cc4246e05d56bd264d0292d9c92 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 20 Sep 2025 19:04:21 +0200 Subject: [PATCH 108/465] build: show llvm/clang in platform flags and `buildinfo.txt` Show these flags: - `LLVM-CLANG` for mainline llvm/clang. - `APPLE-CLANG` for Apple clang. - `CLANG-CL` for clang-cl. (cmake only) Also: - GHA/linux: fix a job to build with clang, to match its descriptions. Closes #18645 --- .github/workflows/linux.yml | 1 + CMakeLists.txt | 9 +++++++++ acinclude.m4 | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index af2edf0e092b..c9f090a969e3 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -179,6 +179,7 @@ jobs: - name: 'openssl clang krb5 LTO' install_packages: zlib1g-dev libkrb5-dev clang install_steps: skiprun + CC: clang generate: -DCURL_USE_OPENSSL=ON -DCURL_USE_GSSAPI=ON -DENABLE_DEBUG=ON -DCURL_LTO=ON - name: 'openssl !ipv6 !--libcurl !--digest-auth' diff --git a/CMakeLists.txt b/CMakeLists.txt index ad78c58ed1db..a0587327db5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,15 @@ endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU") string(APPEND _target_flags " GCC") endif() +if(CMAKE_C_COMPILER_ID MATCHES "Clang") + if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + string(APPEND _target_flags " APPLE-CLANG") + elseif(MSVC) + string(APPEND _target_flags " CLANG-CL") + else() + string(APPEND _target_flags " LLVM-CLANG") + endif() +endif() if(MINGW) string(APPEND _target_flags " MINGW") endif() diff --git a/acinclude.m4 b/acinclude.m4 index fe10c2ec9715..f6a785277969 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1492,6 +1492,11 @@ AC_DEFUN([CURL_PREPARE_BUILDINFO], [ if test "x$compiler_id" = 'xGNU_C'; then curl_pflags="${curl_pflags} GCC" fi + if "$compiler_id" = "APPLECLANG"; then + curl_pflags="${curl_pflags} APPLE-CLANG" + elif test "$compiler_id" = "CLANG"; then + curl_pflags="${curl_pflags} LLVM-CLANG" + fi case $host_os in mingw*) curl_pflags="${curl_pflags} MINGW";; esac From 4e8dfe2093c83c708d4ee0b6952a8495608d708d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 09:39:58 +0200 Subject: [PATCH 109/465] RELEASE-NOTES: spellcheck! --- RELEASE-NOTES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 0fb4e0be115e..698c81d3a868 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -11,7 +11,7 @@ This release includes the following changes: o build: drop the winbuild build system [81] o krb5: drop support for Kerberos FTP [43] o libssh2: up the minimum requirement to 1.9.0 [85] - o write-out: make %header{} able to output *all* occurances of a header [25] + o write-out: make %header{} able to output *all* occurrences of a header [25] This release includes the following bugfixes: From fd61ed062bdad9ad9abdcc839f1c6c51b88e1c05 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 00:09:09 +0200 Subject: [PATCH 110/465] ws: clarify an error message Instead of: "[WS] frame length longer than 64 signed not supported" Use: "[WS] frame length longer than 63 bit not supported" Closes #18654 --- lib/ws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ws.c b/lib/ws.c index 00fdeb3e97f8..c840961d1017 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -453,7 +453,7 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, break; case 10: if(dec->head[2] > 127) { - failf(data, "[WS] frame length longer than 64 signed not supported"); + failf(data, "[WS] frame length longer than 63 bit not supported"); return CURLE_RECV_ERROR; } dec->payload_len = ((curl_off_t)dec->head[2] << 56) | From 3d8e15650ccc02cb7384f3b991478363e9498f3f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 17:44:32 +0200 Subject: [PATCH 111/465] vtls_int.h: clarify data_pending Suggested-by: Joseph Birr-Pixton Closes #18644 --- lib/vtls/vtls_int.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h index de0b735e22bf..8bf6c6c64be9 100644 --- a/lib/vtls/vtls_int.h +++ b/lib/vtls/vtls_int.h @@ -153,6 +153,10 @@ struct Curl_ssl { size_t (*version)(char *buffer, size_t size); CURLcode (*shut_down)(struct Curl_cfilter *cf, struct Curl_easy *data, bool send_shutdown, bool *done); + + /* data_pending() shall return TRUE when it wants to get called again to + drain internal buffers and deliver data instead of waiting for the socket + to get readable */ bool (*data_pending)(struct Curl_cfilter *cf, const struct Curl_easy *data); From 3b22ed999ef046cbd7a3503746bf9acf927623e7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 22:55:50 +0200 Subject: [PATCH 112/465] telnet: return error on crazy TTYPE or XDISPLOC lengths Also use the packet size msnprintf() stores instead of calculating it separately. Reported in Joshua's sarif data Closes #18648 --- lib/telnet.c | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/lib/telnet.c b/lib/telnet.c index 05e5ebe60cc7..b475910baf6e 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -164,7 +164,7 @@ static void set_remote_option(struct Curl_easy *data, struct TELNET *tn, static void printsub(struct Curl_easy *data, int direction, unsigned char *pointer, size_t length); -static void suboption(struct Curl_easy *data, struct TELNET *tn); +static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn); static void sendsuboption(struct Curl_easy *data, struct TELNET *tn, int option); @@ -932,7 +932,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data, * side. */ -static void suboption(struct Curl_easy *data, struct TELNET *tn) +static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) { struct curl_slist *v; unsigned char temp[2048]; @@ -944,22 +944,30 @@ static void suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); switch(CURL_SB_GET(tn)) { case CURL_TELOPT_TTYPE: - len = strlen(tn->subopt_ttype) + 4 + 2; - msnprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, - CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); + if(strlen(tn->subopt_ttype) > 1000) { + failf(data, "Tool long telnet TTYPE"); + return CURLE_SEND_ERROR; + } + len = msnprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", + CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, + CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); + if(bytes_written < 0) { err = SOCKERRNO; - failf(data,"Sending data failed (%d)",err); + failf(data, "Sending data failed (%d)", err); + return CURLE_SEND_ERROR; } printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_XDISPLOC: - len = strlen(tn->subopt_xdisploc) + 4 + 2; - msnprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, - CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); + if(strlen(tn->subopt_xdisploc) > 1000) { + failf(data, "Tool long telnet XDISPLOC"); + return CURLE_SEND_ERROR; + } + len = msnprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", + CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, + CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { err = SOCKERRNO; @@ -968,11 +976,9 @@ static void suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_NEW_ENVIRON: - msnprintf((char *)temp, sizeof(temp), - "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, - CURL_TELQUAL_IS); - len = 4; - + len = msnprintf((char *)temp, sizeof(temp), "%c%c%c%c", + CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, + CURL_TELQUAL_IS); for(v = tn->telnet_vars; v; v = v->next) { size_t tmplen = (strlen(v->data) + 1); /* Add the variable if it fits */ @@ -1000,7 +1006,7 @@ static void suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '>', &temp[2], len-2); break; } - return; + return CURLE_OK; } @@ -1204,7 +1210,9 @@ CURLcode telrcv(struct Curl_easy *data, CURL_SB_TERM(tn); printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); - suboption(data, tn); /* handle sub-option */ + result = suboption(data, tn); /* handle sub-option */ + if(result) + return result; tn->telrcv_state = CURL_TS_IAC; goto process_iac; } @@ -1216,7 +1224,9 @@ CURLcode telrcv(struct Curl_easy *data, CURL_SB_ACCUM(tn, CURL_SE); tn->subpointer -= 2; CURL_SB_TERM(tn); - suboption(data, tn); /* handle sub-option */ + result = suboption(data, tn); /* handle sub-option */ + if(result) + return result; tn->telrcv_state = CURL_TS_DATA; } break; From a9baf82a9b4291a948c908bce3f843c556d67deb Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 23:23:07 +0200 Subject: [PATCH 113/465] ftp: fix ftp_do_more returning with *completep unset Specifically, when ftpc->wait_data_conn was true and Curl_conn_connect(...) returned with serv_conned == false the code called ftp_check_ctrl_on_data_wait and returned without setting *completep. Now set it to 0 at function start to avoid this happening again. Reported in Joshua's sarif data Closes #18650 --- lib/ftp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ftp.c b/lib/ftp.c index df94ea5e6684..13b613bc1e86 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -3594,6 +3594,9 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) if(!ftpc || !ftp) return CURLE_FAILED_INIT; + + *completep = 0; /* default to stay in the state */ + /* if the second connection has been set up, try to connect it fully * to the remote host. This may not complete at this time, for several * reasons: @@ -3612,7 +3615,6 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) /* this is a EPSV connect failing, try PASV instead */ return ftp_epsv_disable(data, ftpc, conn); } - *completep = (int)complete; return result; } } From 05930f304bbf1492951b71d828f0de9fe253d4ea Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 23:33:05 +0200 Subject: [PATCH 114/465] rustls: use %zu for size_t in failf() format string Reported in Joshua's sarif data Closes #18651 --- lib/vtls/rustls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index e5d85aa38f38..c89fadf96665 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -1231,8 +1231,8 @@ cr_connect(struct Curl_cfilter *cf, size_t errorlen; rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); failf(data, - "Failed getting DER of server certificate #%ld: %.*s", i, - (int)errorlen, errorbuf); + "Failed getting DER of server certificate #%zu: %.*s", i, + (int)errorlen, errorbuf); return map_error(rresult); } { From ab3a293fd0cca2045cc2e3bf1a73f75b1bd7d4bc Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 23:38:04 +0200 Subject: [PATCH 115/465] libssh: fix range parsing error handling mistake The range-parsing returned CURLE_RANGE_ERROR directly on one error instead of calling myssh_to_ERROR() like it should and like it does for all other errors. Reported in Joshua's sarif data Closes #18652 --- lib/vssh/libssh.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index eacc27a92110..cb2e8cde4d43 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1319,8 +1319,7 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, if(size < 0) { failf(data, "Bad file size (%" FMT_OFF_T ")", size); - rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); - return rc; + return myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); } if(data->state.use_range) { curl_off_t from, to; @@ -1328,16 +1327,15 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, int from_t, to_t; from_t = curlx_str_number(&p, &from, CURL_OFF_T_MAX); - if(from_t == STRE_OVERFLOW) { - rc = myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); - return rc; - } + if(from_t == STRE_OVERFLOW) + return myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); + curlx_str_passblanks(&p); (void)curlx_str_single(&p, '-'); to_t = curlx_str_numblanks(&p, &to); if(to_t == STRE_OVERFLOW) - return CURLE_RANGE_ERROR; + return myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); if((to_t == STRE_NO_NUM) || (to >= size)) { to = size - 1; @@ -1353,26 +1351,21 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, if(from > size) { failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" FMT_OFF_T ")", from, size); - rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); - return rc; + return myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); } if(from > to) { from = to; size = 0; } else { - if((to - from) == CURL_OFF_T_MAX) { - rc = myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); - return rc; - } + if((to - from) == CURL_OFF_T_MAX) + return myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); size = to - from + 1; } rc = sftp_seek64(sshc->sftp_file, from); - if(rc) { - rc = myssh_to_SFTP_CLOSE(data, sshc); - return rc; - } + if(rc) + return myssh_to_SFTP_CLOSE(data, sshc); } data->req.size = size; data->req.maxdownload = size; @@ -1386,8 +1379,7 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, if((curl_off_t)size < -data->state.resume_from) { failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" FMT_OFF_T ")", data->state.resume_from, size); - rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); - return rc; + return myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); } /* download from where? */ data->state.resume_from += size; @@ -1397,8 +1389,7 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" FMT_OFF_T ")", data->state.resume_from, size); - rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); - return rc; + return myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); } } /* Now store the number of bytes we are expected to download */ @@ -1408,10 +1399,8 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, size - data->state.resume_from); rc = sftp_seek64(sshc->sftp_file, data->state.resume_from); - if(rc) { - rc = myssh_to_SFTP_CLOSE(data, sshc); - return rc; - } + if(rc) + return myssh_to_SFTP_CLOSE(data, sshc); } /* Setup the actual download */ From 0c53a5e5dcca82dfa57a209c350c77db1572a7c6 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 23:53:52 +0200 Subject: [PATCH 116/465] openldap: check ldap_get_option() return codes Do not just assume that they always work. Reported in Joshua's sarif data Closes #18653 --- lib/openldap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/openldap.c b/lib/openldap.c index 717739b68d89..7d25d1842112 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -538,7 +538,8 @@ static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate) Sockbuf *sb; /* Install the libcurl SSL handlers into the sockbuf. */ - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) + return CURLE_FAILED_INIT; ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); li->recv = conn->recv[FIRSTSOCKET]; li->send = conn->send[FIRSTSOCKET]; @@ -951,7 +952,8 @@ static CURLcode oldap_disconnect(struct Curl_easy *data, #ifdef USE_SSL if(ssl_installed(conn)) { Sockbuf *sb; - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) + return CURLE_FAILED_INIT; ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); } #endif @@ -986,7 +988,8 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done) if(ssl_installed(conn)) { Sockbuf *sb; /* re-install the libcurl SSL handlers into the sockbuf. */ - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) + return CURLE_FAILED_INIT; ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); } #endif From d57e7cf20d805032740a8b173ea53ea0da1cce62 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 10:18:13 +0200 Subject: [PATCH 117/465] ws: reject curl_ws_recv called with NULL buffer with a buflen Arguably this is just a bad application. Reported in Joshua's sarif data Closes #18656 --- lib/ws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ws.c b/lib/ws.c index c840961d1017..b6ab28a35ad0 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -1502,7 +1502,7 @@ CURLcode curl_ws_recv(CURL *d, void *buffer, *nread = 0; *metap = NULL; - if(!GOOD_EASY_HANDLE(data)) + if(!GOOD_EASY_HANDLE(data) || (buflen && !buffer)) return CURLE_BAD_FUNCTION_ARGUMENT; conn = data->conn; From c23d7e7a980d172e2134225933440b05404a1f14 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 20 Sep 2025 11:35:01 +0200 Subject: [PATCH 118/465] GHA/codeql: enable ECH and HTTPS-RR Switch to Linuxbrew c-ares to hit the minimum version. (Ubuntu offers 1.27.0, HTTPS-RR requires 1.28.0.) Closes #18661 --- .github/workflows/codeql.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index bb3c07482163..808ee0b63a91 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -75,9 +75,9 @@ jobs: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get -o Dpkg::Use-Pty=0 update sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libc-ares-dev \ + sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev \ libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev - /home/linuxbrew/.linuxbrew/bin/brew install gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi + /home/linuxbrew/.linuxbrew/bin/brew install c-ares gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: @@ -104,10 +104,10 @@ jobs: eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" # MultiSSL - export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix mbedtls)/lib/pkgconfig:$(brew --prefix rustls-ffi)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" + export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix c-ares)/lib/pkgconfig:$(brew --prefix mbedtls)/lib/pkgconfig:$(brew --prefix rustls-ffi)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" cmake -B _bld1 -G Ninja -DENABLE_DEBUG=ON \ -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DCURL_USE_WOLFSSL=ON \ - -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON -DENABLE_ARES=ON + -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON -DUSE_ECH=ON -DENABLE_ARES=ON cmake --build _bld1 --verbose cmake --build _bld1 --verbose --target curlinfo cmake --build _bld1 --verbose --target servers From 06d00e3879bbfe167972ee45f1dad0ec591a04fb Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 13:31:35 +0200 Subject: [PATCH 119/465] cmake: clang detection tidy-ups Follow-up to 0513f9f8786e0cc4246e05d56bd264d0292d9c92 #18645 Follow-up to fe5225b5eaf3a1a0ce149023d38a9922a114798b #18209 Closes #18659 --- CMakeLists.txt | 14 ++++++-------- docs/examples/CMakeLists.txt | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0587327db5f..083c2f37b9c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,14 +148,12 @@ endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU") string(APPEND _target_flags " GCC") endif() -if(CMAKE_C_COMPILER_ID MATCHES "Clang") - if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") - string(APPEND _target_flags " APPLE-CLANG") - elseif(MSVC) - string(APPEND _target_flags " CLANG-CL") - else() - string(APPEND _target_flags " LLVM-CLANG") - endif() +if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + string(APPEND _target_flags " APPLE-CLANG") +elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND MSVC) + string(APPEND _target_flags " CLANG-CL") +elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") + string(APPEND _target_flags " LLVM-CLANG") endif() if(MINGW) string(APPEND _target_flags " MINGW") diff --git a/docs/examples/CMakeLists.txt b/docs/examples/CMakeLists.txt index cb1d983890c6..bc0f3ce359b8 100644 --- a/docs/examples/CMakeLists.txt +++ b/docs/examples/CMakeLists.txt @@ -37,7 +37,7 @@ foreach(_target IN LISTS check_PROGRAMS _all) # keep '_all' last set(_examples_c "${check_PROGRAMS}") list(TRANSFORM _examples_c APPEND ".c") add_library(${_target_name} OBJECT EXCLUDE_FROM_ALL ${_examples_c}) - if(MSVC AND NOT CMAKE_C_COMPILER_ID STREQUAL "Clang") + if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") # MSVC but exclude clang-cl # CMake generates a static library for the OBJECT target. Silence these 'lib.exe' warnings: # warning LNK4006: main already defined in ....obj; second definition ignored # warning LNK4221: This object file does not define any previously undefined public symbols, From e5d9c871f0b54c8382b2f417b5923ac78d6a4e12 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 21 Aug 2025 22:27:41 +0200 Subject: [PATCH 120/465] tidy-up: assortment of small fixes - examples/headerapi: fix wrong cast. - curl_ngtcp2: delete stray character from error message. - rustls: fix inline variable declaration. - sendf: drop redundant `int` cast. - libtest/cli_ws_data: drop cast with mismatched signedness. Cherry-picked from #18343 Closes #18664 --- docs/examples/headerapi.c | 2 +- lib/sendf.c | 2 +- lib/vquic/curl_ngtcp2.c | 2 +- lib/vtls/rustls.c | 3 ++- tests/libtest/cli_ws_data.c | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/examples/headerapi.c b/docs/examples/headerapi.c index 95c366884a42..ede0c5cbdaed 100644 --- a/docs/examples/headerapi.c +++ b/docs/examples/headerapi.c @@ -69,7 +69,7 @@ int main(void) do { h = curl_easy_nextheader(curl, CURLH_HEADER, -1, prev); if(h) - printf(" %s: %s (%u)\n", h->name, h->value, (int)h->amount); + printf(" %s: %s (%u)\n", h->name, h->value, (unsigned int)h->amount); prev = h; } while(h); diff --git a/lib/sendf.c b/lib/sendf.c index f759fb61a4af..a262d9036fd9 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -857,7 +857,7 @@ static CURLcode cr_in_rewind(struct Curl_easy *data, Curl_set_in_callback(data, FALSE); CURL_TRC_READ(data, "cr_in, rewind via set.seek_func -> %d", err); if(err) { - failf(data, "seek callback returned error %d", (int)err); + failf(data, "seek callback returned error %d", err); return CURLE_SEND_FAIL_REWIND; } } diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 246e0d51f661..f902c190ef58 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -1337,7 +1337,7 @@ static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, result = Curl_1st_err(result, cf_progress_egress(cf, data, &pktx)); result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %dm, %zu", + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %d, %zu", stream ? stream->id : -1, blen, result, *pnread); CF_DATA_RESTORE(cf, save); return result; diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index c89fadf96665..87c23544ef4c 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -1212,13 +1212,14 @@ cr_connect(struct Curl_cfilter *cf, } if(data->set.ssl.certinfo) { size_t num_certs = 0; + size_t i; while(rustls_connection_get_peer_certificate(rconn, (int)num_certs)) { num_certs++; } result = Curl_ssl_init_certinfo(data, (int)num_certs); if(result) return result; - for(size_t i = 0; i < num_certs; i++) { + for(i = 0; i < num_certs; i++) { const rustls_certificate *cert; const unsigned char *der_data; size_t der_len; diff --git a/tests/libtest/cli_ws_data.c b/tests/libtest/cli_ws_data.c index 36d5dea25b1c..32356552a807 100644 --- a/tests/libtest/cli_ws_data.c +++ b/tests/libtest/cli_ws_data.c @@ -106,7 +106,7 @@ static CURLcode test_ws_data_m2_echo(const char *url, curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */ r = curl_easy_perform(curl); - curl_mfprintf(stderr, "curl_easy_perform() returned %u\n", (int)r); + curl_mfprintf(stderr, "curl_easy_perform() returned %u\n", r); if(r != CURLE_OK) goto out; From e21cc7844db33fe6b77e8dbe687cd720ec9d738e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 17:51:34 +0200 Subject: [PATCH 121/465] autotools: fix silly mistake in clang detection for `buildinfo.txt` Follow-up to 0513f9f8786e0cc4246e05d56bd264d0292d9c92 #18645 Closes #18666 --- acinclude.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acinclude.m4 b/acinclude.m4 index f6a785277969..febb8961cca3 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1492,7 +1492,7 @@ AC_DEFUN([CURL_PREPARE_BUILDINFO], [ if test "x$compiler_id" = 'xGNU_C'; then curl_pflags="${curl_pflags} GCC" fi - if "$compiler_id" = "APPLECLANG"; then + if test "$compiler_id" = "APPLECLANG"; then curl_pflags="${curl_pflags} APPLE-CLANG" elif test "$compiler_id" = "CLANG"; then curl_pflags="${curl_pflags} LLVM-CLANG" From 374c23c617322ecd76794d058461f69b8abbef0e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 18:02:21 +0200 Subject: [PATCH 122/465] autotools: fix duplicate `UNIX` and `BSD` flags in `buildinfo.txt` Follow-up to 2a292c39846107228201674d686be5b3ed96674d #15975 Closes #18667 --- acinclude.m4 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index febb8961cca3..7b26dfd466a3 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1474,14 +1474,6 @@ AC_DEFUN([CURL_PREPARE_BUILDINFO], [ if test "$curl_cv_winuwp" = 'yes'; then curl_pflags="${curl_pflags} UWP" fi - case $host in - *-*-*bsd*|*-*-aix*|*-*-hpux*|*-*-interix*|*-*-irix*|*-*-linux*|*-*-solaris*|*-*-sunos*|*-apple-*|*-*-cygwin*|*-*-msys*) - curl_pflags="${curl_pflags} UNIX";; - esac - case $host in - *-*-*bsd*) - curl_pflags="${curl_pflags} BSD";; - esac if test "$curl_cv_cygwin" = 'yes'; then curl_pflags="${curl_pflags} CYGWIN" fi From 989a274e45318b290b7ddf28d7562ff6ec0cba4a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 20:25:04 +0200 Subject: [PATCH 123/465] autotools: add support for libgsasl auto-detection via pkg-config Enable with `--with-gsasl`, as before. Cherry-picked from #18660 Closes #18669 --- configure.ac | 71 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index fa23eb09b1e4..1aa0c2759651 100644 --- a/configure.ac +++ b/configure.ac @@ -2204,20 +2204,67 @@ dnl ********************************************************************** dnl Check for libgsasl dnl ********************************************************************** -AC_ARG_WITH(libgsasl, - AS_HELP_STRING([--without-libgsasl], - [disable libgsasl support for SCRAM]), - with_libgsasl=$withval, - with_libgsasl=yes) -if test $with_libgsasl != "no"; then - AC_SEARCH_LIBS(gsasl_init, gsasl, - [curl_gsasl_msg="enabled"; - AC_DEFINE([USE_GSASL], [1], [GSASL support enabled]) - LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libgsasl" +OPT_LIBGSASL=no +AC_ARG_WITH(libgsasl,dnl +AS_HELP_STRING([--with-libgsasl=PATH],[Where to look for libgsasl, PATH points to the libgsasl installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AS_HELP_STRING([--without-libgsasl], [disable libgsasl support for SCRAM]), + OPT_LIBGSASL=$withval) + +if test "$OPT_LIBGSASL" != no; then + dnl backup the pre-libgsasl variables + CLEANLDFLAGS="$LDFLAGS" + CLEANLDFLAGSPC="$LDFLAGSPC" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_LIBGSASL" in + yes) + dnl --with-libgsasl (without path) used + CURL_CHECK_PKGCONFIG(libgsasl) + + if test "$PKGCONFIG" != "no"; then + LIB_GSASL=`$PKGCONFIG --libs-only-l libgsasl` + LD_GSASL=`$PKGCONFIG --libs-only-L libgsasl` + CPP_GSASL=`$PKGCONFIG --cflags-only-I libgsasl` + else + dnl no libgsasl pkg-config found + LIB_GSASL="-lgsasl" + fi + ;; + *) + dnl use the given --with-libgsasl spot + PREFIX_GSASL=$OPT_LIBGSASL + ;; + esac + + dnl if given with a prefix, we set -L and -I based on that + if test -n "$PREFIX_GSASL"; then + LIB_GSASL="-lgsasl" + LD_GSASL=-L${PREFIX_GSASL}/lib$libsuff + CPP_GSASL=-I${PREFIX_GSASL}/include + fi + + LDFLAGS="$LDFLAGS $LD_GSASL" + LDFLAGSPC="$LDFLAGSPC $LD_GSASL" + CPPFLAGS="$CPPFLAGS $CPP_GSASL" + LIBS="$LIB_GSASL $LIBS" + + AC_CHECK_LIB(gsasl, gsasl_init, + [ + AC_CHECK_HEADERS(gsasl.h, + curl_gsasl_msg="enabled" + AC_DEFINE(USE_GSASL, 1, [GSASL support enabled]) + USE_LIBGSASL=1 + LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libgsasl" + ) ], - [curl_gsasl_msg="no (libgsasl not found)"; + dnl not found, revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + LDFLAGSPC=$CLEANLDFLAGSPC + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + curl_gsasl_msg="no (libgsasl not found)" AC_MSG_WARN([libgsasl was not found]) - ] ) fi AM_CONDITIONAL([USE_GSASL], [test "$curl_gsasl_msg" = "enabled"]) From a72e1552f224f3785d8aafc9819cd4ad0821c01d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 10:48:00 +0200 Subject: [PATCH 124/465] telnet: refuse IAC codes in content Ban the use of IAC (0xff) in telnet options set by the application. They need to be escaped when sent but I can't see any valid reason for an application to send them. Of course, an application sending such data basically ask for trouble. Reported in Joshua's sarif data Closes #18657 --- lib/telnet.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/telnet.c b/lib/telnet.c index b475910baf6e..f2226a7f7dd8 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -925,6 +925,14 @@ static CURLcode check_telnet_options(struct Curl_easy *data, return result; } +/* if the option contains an IAC code, it should be escaped in the output, but + as we cannot think of any legit way to send that as part of the content we + rather just ban its use instead */ +static bool bad_option(const char *data) +{ + return !!strchr(data, CURL_IAC); +} + /* * suboption() * @@ -944,6 +952,8 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); switch(CURL_SB_GET(tn)) { case CURL_TELOPT_TTYPE: + if(bad_option(tn->subopt_ttype)) + return CURLE_BAD_FUNCTION_ARGUMENT; if(strlen(tn->subopt_ttype) > 1000) { failf(data, "Tool long telnet TTYPE"); return CURLE_SEND_ERROR; @@ -961,6 +971,8 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_XDISPLOC: + if(bad_option(tn->subopt_xdisploc)) + return CURLE_BAD_FUNCTION_ARGUMENT; if(strlen(tn->subopt_xdisploc) > 1000) { failf(data, "Tool long telnet XDISPLOC"); return CURLE_SEND_ERROR; @@ -981,6 +993,8 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) CURL_TELQUAL_IS); for(v = tn->telnet_vars; v; v = v->next) { size_t tmplen = (strlen(v->data) + 1); + if(bad_option(v->data)) + return CURLE_BAD_FUNCTION_ARGUMENT; /* Add the variable if it fits */ if(len + tmplen < (int)sizeof(temp)-6) { char *s = strchr(v->data, ','); From c4f9977c66bbb05a837a7eb03004dd79c3cc9b44 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 11:07:31 +0200 Subject: [PATCH 125/465] tftp: pin the first used address Store the used remote address on the first receive call and then make sure that it remains the same address on subsequent calls to reduce the risk of tampering. Doesn't make the transfer secure because it is still unauthenticated and clear text. Reported in Joshua's sarif data Closes #18658 --- lib/tftp.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/tftp.c b/lib/tftp.c index 8b6246a34265..736b14b67364 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -126,6 +126,10 @@ struct tftp_packet { #define CURL_META_TFTP_CONN "meta:proto:tftp:conn" struct tftp_conn { + struct Curl_sockaddr_storage local_addr; + struct Curl_sockaddr_storage remote_addr; + struct tftp_packet rpacket; + struct tftp_packet spacket; tftp_state_t state; tftp_mode_t mode; tftp_error_t error; @@ -136,16 +140,13 @@ struct tftp_conn { int retry_time; int retry_max; time_t rx_time; - struct Curl_sockaddr_storage local_addr; - struct Curl_sockaddr_storage remote_addr; curl_socklen_t remote_addrlen; int rbytes; size_t sbytes; unsigned int blksize; unsigned int requested_blksize; unsigned short block; - struct tftp_packet rpacket; - struct tftp_packet spacket; + BIT(remote_pinned); }; @@ -1094,18 +1095,31 @@ static CURLcode tftp_pollset(struct Curl_easy *data, static CURLcode tftp_receive_packet(struct Curl_easy *data, struct tftp_conn *state) { - curl_socklen_t fromlen; - CURLcode result = CURLE_OK; + CURLcode result = CURLE_OK; + struct Curl_sockaddr_storage remote_addr; + curl_socklen_t fromlen = sizeof(remote_addr); /* Receive the packet */ - fromlen = sizeof(state->remote_addr); state->rbytes = (int)recvfrom(state->sockfd, (void *)state->rpacket.data, (RECV_TYPE_ARG3)state->blksize + 4, 0, - (struct sockaddr *)&state->remote_addr, + (struct sockaddr *)&remote_addr, &fromlen); - state->remote_addrlen = fromlen; + if(state->remote_pinned) { + /* pinned, verify that it comes from the same address */ + if((state->remote_addrlen != fromlen) || + memcmp(&remote_addr, &state->remote_addr, fromlen)) { + failf(data, "Data received from another address"); + return CURLE_RECV_ERROR; + } + } + else { + /* pin address on first use */ + state->remote_pinned = TRUE; + state->remote_addrlen = fromlen; + memcpy(&state->remote_addr, &remote_addr, fromlen); + } /* Sanity check packet length */ if(state->rbytes < 4) { From 1f0f0bdb192a71b6b8b654115ee2c08f8411e356 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 08:33:20 +0200 Subject: [PATCH 126/465] managen: strict protocol check - protocols MUST match one in the accept-list - protocols are typically all uppercase - drop All - use SCP and SFTP instead of SSH - add Protocols: to some options previously missing one Closes #18675 --- docs/cmdline-opts/doh-cert-status.md | 1 + docs/cmdline-opts/doh-insecure.md | 1 + docs/cmdline-opts/doh-url.md | 1 + docs/cmdline-opts/follow.md | 1 + docs/cmdline-opts/form-escape.md | 2 +- docs/cmdline-opts/ip-tos.md | 1 - docs/cmdline-opts/key.md | 2 +- docs/cmdline-opts/pass.md | 2 +- docs/cmdline-opts/sasl-authzid.md | 1 + docs/cmdline-opts/sasl-ir.md | 1 + docs/cmdline-opts/socks5-gssapi-nec.md | 1 + docs/cmdline-opts/socks5-gssapi.md | 1 + docs/cmdline-opts/telnet-option.md | 1 + docs/cmdline-opts/upload-flags.md | 1 + docs/cmdline-opts/url-query.md | 1 - docs/cmdline-opts/vlan-priority.md | 1 - scripts/managen | 34 ++++++++++++++++++++++++-- 17 files changed, 45 insertions(+), 8 deletions(-) diff --git a/docs/cmdline-opts/doh-cert-status.md b/docs/cmdline-opts/doh-cert-status.md index 7c497cf16f42..445eb3dcd04c 100644 --- a/docs/cmdline-opts/doh-cert-status.md +++ b/docs/cmdline-opts/doh-cert-status.md @@ -5,6 +5,7 @@ Long: doh-cert-status Help: Verify DoH server cert status OCSP-staple Added: 7.76.0 Category: dns tls +Protocols: DNS Multi: boolean See-also: - doh-insecure diff --git a/docs/cmdline-opts/doh-insecure.md b/docs/cmdline-opts/doh-insecure.md index 72f3cb77252b..ee1602a242fd 100644 --- a/docs/cmdline-opts/doh-insecure.md +++ b/docs/cmdline-opts/doh-insecure.md @@ -5,6 +5,7 @@ Long: doh-insecure Help: Allow insecure DoH server connections Added: 7.76.0 Category: dns tls +Protocols: DNS Multi: boolean See-also: - doh-url diff --git a/docs/cmdline-opts/doh-url.md b/docs/cmdline-opts/doh-url.md index dcc6e52f8a4f..60cf6caab016 100644 --- a/docs/cmdline-opts/doh-url.md +++ b/docs/cmdline-opts/doh-url.md @@ -6,6 +6,7 @@ Arg: Help: Resolve hostnames over DoH Added: 7.62.0 Category: dns +Protocols: DNS Multi: single See-also: - doh-insecure diff --git a/docs/cmdline-opts/follow.md b/docs/cmdline-opts/follow.md index 47d912844180..e791e36adf34 100644 --- a/docs/cmdline-opts/follow.md +++ b/docs/cmdline-opts/follow.md @@ -4,6 +4,7 @@ SPDX-License-Identifier: curl Long: follow Help: Follow redirects per spec Category: http +Protocols: HTTP Added: 8.16.0 Multi: boolean See-also: diff --git a/docs/cmdline-opts/form-escape.md b/docs/cmdline-opts/form-escape.md index 0f93fde7eb26..7cf1cb7403db 100644 --- a/docs/cmdline-opts/form-escape.md +++ b/docs/cmdline-opts/form-escape.md @@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. SPDX-License-Identifier: curl Long: form-escape Help: Escape form fields using backslash -Protocols: HTTP imap smtp +Protocols: HTTP IMAP SMTP Added: 7.81.0 Category: http upload post Multi: single diff --git a/docs/cmdline-opts/ip-tos.md b/docs/cmdline-opts/ip-tos.md index 3d6473f31282..f5ef589e2354 100644 --- a/docs/cmdline-opts/ip-tos.md +++ b/docs/cmdline-opts/ip-tos.md @@ -6,7 +6,6 @@ Arg: Help: Set IP Type of Service or Traffic Class Added: 8.9.0 Category: connection -Protocols: All Multi: single See-also: - tcp-nodelay diff --git a/docs/cmdline-opts/key.md b/docs/cmdline-opts/key.md index 967119a8b50e..cc4bc73fa5b3 100644 --- a/docs/cmdline-opts/key.md +++ b/docs/cmdline-opts/key.md @@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. SPDX-License-Identifier: curl Long: key Arg: -Protocols: TLS SSH +Protocols: TLS SCP SFTP Help: Private key filename Category: tls ssh Added: 7.9.3 diff --git a/docs/cmdline-opts/pass.md b/docs/cmdline-opts/pass.md index 0527334f2ab9..79c2f8738a13 100644 --- a/docs/cmdline-opts/pass.md +++ b/docs/cmdline-opts/pass.md @@ -4,7 +4,7 @@ SPDX-License-Identifier: curl Long: pass Arg: Help: Passphrase for the private key -Protocols: SSH TLS +Protocols: TLS SCP SFTP Category: ssh tls auth Added: 7.9.3 Multi: single diff --git a/docs/cmdline-opts/sasl-authzid.md b/docs/cmdline-opts/sasl-authzid.md index 4c4282d14dd3..4e92a2054152 100644 --- a/docs/cmdline-opts/sasl-authzid.md +++ b/docs/cmdline-opts/sasl-authzid.md @@ -4,6 +4,7 @@ SPDX-License-Identifier: curl Long: sasl-authzid Arg: Help: Identity for SASL PLAIN authentication +Protocols: LDAP IMAP POP3 SMTP Added: 7.66.0 Category: auth Multi: single diff --git a/docs/cmdline-opts/sasl-ir.md b/docs/cmdline-opts/sasl-ir.md index 0f759c6d1005..206bf29317a8 100644 --- a/docs/cmdline-opts/sasl-ir.md +++ b/docs/cmdline-opts/sasl-ir.md @@ -3,6 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. SPDX-License-Identifier: curl Long: sasl-ir Help: Initial response in SASL authentication +Protocols: LDAP IMAP POP3 SMTP Added: 7.31.0 Category: auth Multi: boolean diff --git a/docs/cmdline-opts/socks5-gssapi-nec.md b/docs/cmdline-opts/socks5-gssapi-nec.md index eef6b2de9df1..9cd91b96150f 100644 --- a/docs/cmdline-opts/socks5-gssapi-nec.md +++ b/docs/cmdline-opts/socks5-gssapi-nec.md @@ -5,6 +5,7 @@ Long: socks5-gssapi-nec Help: Compatibility with NEC SOCKS5 server Added: 7.19.4 Category: proxy auth +Protocols: GSS/kerberos Multi: boolean See-also: - socks5 diff --git a/docs/cmdline-opts/socks5-gssapi.md b/docs/cmdline-opts/socks5-gssapi.md index e17425431b30..b8520b22cc72 100644 --- a/docs/cmdline-opts/socks5-gssapi.md +++ b/docs/cmdline-opts/socks5-gssapi.md @@ -5,6 +5,7 @@ Long: socks5-gssapi Help: Enable GSS-API auth for SOCKS5 proxies Added: 7.55.0 Category: proxy auth +Protocols: GSS/kerberos Multi: boolean See-also: - socks5 diff --git a/docs/cmdline-opts/telnet-option.md b/docs/cmdline-opts/telnet-option.md index a332b1a5cddb..ca82a4ceb8e5 100644 --- a/docs/cmdline-opts/telnet-option.md +++ b/docs/cmdline-opts/telnet-option.md @@ -6,6 +6,7 @@ Short: t Arg: Help: Set telnet option Category: telnet +Protocols: TELNET Added: 7.7 Multi: append See-also: diff --git a/docs/cmdline-opts/upload-flags.md b/docs/cmdline-opts/upload-flags.md index e30fb3dbdb9f..d17614876836 100644 --- a/docs/cmdline-opts/upload-flags.md +++ b/docs/cmdline-opts/upload-flags.md @@ -4,6 +4,7 @@ SPDX-License-Identifier: curl Long: upload-flags Arg: Help: IMAP upload behavior +Protocols: IMAP Category: curl output Added: 8.13.0 Multi: single diff --git a/docs/cmdline-opts/url-query.md b/docs/cmdline-opts/url-query.md index 43bf43d9325c..3953eda4c72f 100644 --- a/docs/cmdline-opts/url-query.md +++ b/docs/cmdline-opts/url-query.md @@ -4,7 +4,6 @@ SPDX-License-Identifier: curl Long: url-query Arg: Help: Add a URL query part -Protocols: all Added: 7.87.0 Category: http post upload Multi: append diff --git a/docs/cmdline-opts/vlan-priority.md b/docs/cmdline-opts/vlan-priority.md index 34dc8ce06613..c49c659e5c46 100644 --- a/docs/cmdline-opts/vlan-priority.md +++ b/docs/cmdline-opts/vlan-priority.md @@ -6,7 +6,6 @@ Arg: Help: Set VLAN priority Added: 8.9.0 Category: connection -Protocols: All Multi: single See-also: - ip-tos diff --git a/scripts/managen b/scripts/managen index 929068067099..4849fe8378db 100755 --- a/scripts/managen +++ b/scripts/managen @@ -241,8 +241,38 @@ sub overrides { } } +my %protexists = ( + 'DNS' => 1, + 'FILE' => 1, + 'FTP' => 1, + 'FTPS' => 1, + 'GSS/kerberos' => 1, + 'HTTP' => 1, + 'HTTPS' => 1, + 'IMAP' => 1, + 'IPFS' => 1, + 'LDAP' => 1, + 'MQTT' => 1, + 'POP3' => 1, + 'SCP' => 1, + 'SFTP' => 1, + 'SMTP' => 1, + 'SSL' => 2, # deprecated + 'TELNET' => 1, + 'TFTP' => 1, + 'TLS' => 1, + ); + sub protocols { - my ($manpage, $standalone, $data)=@_; + my ($f, $line, $manpage, $standalone, $data)=@_; + my @e = split(/ +/, $data); + for my $pr (@e) { + if(!$protexists{$pr}) { + + print STDERR "$f:$line:1:ERROR: unrecognized protocol: $pr\n"; + exit 2; + } + } if($standalone) { return ".SH \"PROTOCOLS\"\n$data\n"; } @@ -716,7 +746,7 @@ sub single { } my @leading; if($protocols) { - push @leading, protocols($manpage, $standalone, $protocols); + push @leading, protocols($f, $line, $manpage, $standalone, $protocols); } if($standalone) { From c9eff26c179222e7de077c0f59a6dfd9ba6dcce8 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 20 Sep 2025 13:34:08 +0200 Subject: [PATCH 127/465] tool_doswin: fix to use curl socket functions Replace `WSASocketW()` with `CURL_SOCKET()`. Also replace a call to `socketclose()` with `sclose()`. According to a comment, `socketclose()` was chosen to silence test 1498 (and 2300) reporting `MEMORY FAILURE`. These reports were accurate, and were caused by calling `WSASocketW()` instead of `socket()` (now `CURL_SOCKET()`). This also fixes the curl `sclose()` call on an error branch, which is now correctly paired with a curl socket open. The mismatched open/close calls caused an issue in TrackMemory-enabled (aka `CURLDEBUG`) builds. Docs confirm that `socket()` is defaulting to overlapped I/O, matching the replaced `WSASocketW()` call: https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-socket#remarks Also: - checksrc: ban `WSASocket*()` functions. - report `SOCKERRNO` instead of `GetLastError()` for socket calls, to match the rest of the codebase. Follow-up to 9a2663322c330ff11275abafd612e9c99407a94a #17572 Closes #18633 --- scripts/checksrc.pl | 3 +++ src/tool_doswin.c | 24 +++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 0eeab72323f9..0012ccdae1ad 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -74,6 +74,9 @@ "LoadLibraryEx" => 1, "LoadLibraryExA" => 1, "LoadLibraryExW" => 1, + "WSASocket" => 1, + "WSASocketA" => 1, + "WSASocketW" => 1, "_waccess" => 1, "_access" => 1, "access" => 1, diff --git a/src/tool_doswin.c b/src/tool_doswin.c index 0450e5707ba2..29f8cecbd799 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -769,14 +769,14 @@ static DWORD WINAPI win_stdin_thread_func(void *thread_data) &clientAddrLen); if(socket_w == CURL_SOCKET_BAD) { - errorf("accept error: %08lx", GetLastError()); + errorf("accept error: %d", SOCKERRNO); goto ThreadCleanup; } - closesocket(tdata->socket_l); /* sclose here fails test 1498 */ + sclose(tdata->socket_l); tdata->socket_l = CURL_SOCKET_BAD; if(shutdown(socket_w, SD_RECEIVE) == SOCKET_ERROR) { - errorf("shutdown error: %08lx", GetLastError()); + errorf("shutdown error: %d", SOCKERRNO); goto ThreadCleanup; } for(;;) { @@ -835,11 +835,9 @@ curl_socket_t win32_stdin_read_thread(void) } /* Create the listening socket for the thread. When it starts, it will * accept our connection and begin writing STDIN data to the connection. */ - tdata->socket_l = WSASocketW(AF_INET, SOCK_STREAM, - IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); - + tdata->socket_l = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(tdata->socket_l == CURL_SOCKET_BAD) { - errorf("WSASocketW error: %08lx", GetLastError()); + errorf("socket() error: %d", SOCKERRNO); break; } @@ -850,20 +848,20 @@ curl_socket_t win32_stdin_read_thread(void) /* Bind to any available loopback port */ result = bind(tdata->socket_l, (SOCKADDR*)&selfaddr, socksize); if(result == SOCKET_ERROR) { - errorf("bind error: %08lx", GetLastError()); + errorf("bind error: %d", SOCKERRNO); break; } /* Bind to any available loopback port */ result = getsockname(tdata->socket_l, (SOCKADDR*)&selfaddr, &socksize); if(result == SOCKET_ERROR) { - errorf("getsockname error: %08lx", GetLastError()); + errorf("getsockname error: %d", SOCKERRNO); break; } result = listen(tdata->socket_l, 1); if(result == SOCKET_ERROR) { - errorf("listen error: %08lx", GetLastError()); + errorf("listen error: %d", SOCKERRNO); break; } @@ -891,7 +889,7 @@ curl_socket_t win32_stdin_read_thread(void) /* Connect to the thread and rearrange our own STDIN handles */ socket_r = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(socket_r == CURL_SOCKET_BAD) { - errorf("socket error: %08lx", GetLastError()); + errorf("socket error: %d", SOCKERRNO); break; } @@ -899,12 +897,12 @@ curl_socket_t win32_stdin_read_thread(void) setsockopt(socket_r, SOL_SOCKET, SO_DONTLINGER, 0, 0); if(connect(socket_r, (SOCKADDR*)&selfaddr, socksize) == SOCKET_ERROR) { - errorf("connect error: %08lx", GetLastError()); + errorf("connect error: %d", SOCKERRNO); break; } if(shutdown(socket_r, SD_SEND) == SOCKET_ERROR) { - errorf("shutdown error: %08lx", GetLastError()); + errorf("shutdown error: %d", SOCKERRNO); break; } From aa9fa4d68e1f0e059c3df8d01838a650136e6f6f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 21:55:30 +0200 Subject: [PATCH 128/465] rustls: fix clang-tidy warning Seen with v21.1.1, non-debug-enabled build: ``` lib/vtls/rustls.c:415:23: error: File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior [clang-analyzer-unix.Stream,-warnings-as-errors] 415 | const size_t rr = fread(buf, 1, sizeof(buf), f); | ^ ``` Ref: https://github.com/curl/curl/actions/runs/17898248031/job/50887746633?pr=18660#step:11:174 Cherry-picked from #18660 Closes #18670 --- lib/vtls/rustls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 87c23544ef4c..e081c4651ac8 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -410,7 +410,7 @@ read_file_into(const char *filename, return 0; } - while(!feof(f)) { + for(;;) { uint8_t buf[256]; const size_t rr = fread(buf, 1, sizeof(buf), f); if(rr == 0 || @@ -418,6 +418,8 @@ read_file_into(const char *filename, fclose(f); return 0; } + if(rr < sizeof(buf)) + break; } return fclose(f) == 0; From 7f5ff8f2769a0d771bbc0f5cad513cd07de79d08 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 22 Sep 2025 02:03:08 +0200 Subject: [PATCH 129/465] autotools: capitalize 'Rustls' in the log output To match the rest of the codebase. Follow-up to 548d8a842123c854ba92aac90a24c6191e2a8bd4 Cherry-picked from #18660 Closes #18671 --- configure.ac | 4 ++-- m4/curl-rustls.m4 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 1aa0c2759651..922978bfc106 100644 --- a/configure.ac +++ b/configure.ac @@ -272,8 +272,8 @@ AC_ARG_WITH(rustls,dnl AS_HELP_STRING([--with-rustls=PATH],[where to look for Rustls, PATH points to the installation root]),[ OPT_RUSTLS=$withval if test X"$withval" != Xno; then - TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }rustls" - experimental="$experimental rustls" + TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }Rustls" + experimental="$experimental Rustls" fi ]) diff --git a/m4/curl-rustls.m4 b/m4/curl-rustls.m4 index 13022f3963b1..8abcc6544bc5 100644 --- a/m4/curl-rustls.m4 +++ b/m4/curl-rustls.m4 @@ -132,7 +132,7 @@ if test "x$OPT_RUSTLS" != xno; then dnl don't need any. LIBS="$SSL_LIBS $LIBS" link_pkgconfig=1 - ssl_msg="rustls" + ssl_msg="Rustls" AC_DEFINE(USE_RUSTLS, 1, [if Rustls is enabled]) USE_RUSTLS="yes" RUSTLS_ENABLED=1 @@ -176,7 +176,7 @@ if test "x$OPT_RUSTLS" != xno; then AC_DEFINE(USE_RUSTLS, 1, [if Rustls is enabled]) RUSTLS_ENABLED=1 USE_RUSTLS="yes" - ssl_msg="rustls" + ssl_msg="Rustls" test rustls != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes ], AC_MSG_ERROR([--with-rustls was specified but could not find compatible Rustls.]), From 330129c836b3ff9d904d4c0083ec4d71ac2c67c6 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 21 Sep 2025 19:48:22 +0200 Subject: [PATCH 130/465] GHA/linux: install zlib in all jobs by default Cherry-picked from #18660 Closes #18672 --- .github/workflows/linux.yml | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index c9f090a969e3..7aa7bc5707f4 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -74,27 +74,26 @@ jobs: matrix: build: - name: 'libressl heimdal' - install_packages: zlib1g-dev libidn2-dev libnghttp2-dev libldap-dev heimdal-dev + install_packages: libidn2-dev libnghttp2-dev libldap-dev heimdal-dev install_steps: libressl pytest codeset-test configure: LDFLAGS=-Wl,-rpath,/home/runner/libressl/lib --with-openssl=/home/runner/libressl --with-gssapi --enable-debug - name: 'libressl heimdal valgrind' - install_packages: zlib1g-dev libnghttp2-dev libldap-dev heimdal-dev valgrind + install_packages: libnghttp2-dev libldap-dev heimdal-dev valgrind install_steps: libressl generate: -DOPENSSL_ROOT_DIR=/home/runner/libressl -DCURL_USE_GSSAPI=ON -DENABLE_DEBUG=ON -DCURL_LIBCURL_VERSIONED_SYMBOLS=ON - name: 'libressl clang' - install_packages: zlib1g-dev clang + install_packages: clang install_steps: libressl configure: CC=clang LDFLAGS=-Wl,-rpath,/home/runner/libressl/lib --with-openssl=/home/runner/libressl --enable-debug - name: 'wolfssl-all' - install_packages: zlib1g-dev install_steps: wolfssl-all configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-all/lib --with-wolfssl=/home/runner/wolfssl-all --enable-ech --enable-debug - name: 'wolfssl-opensslextra valgrind' - install_packages: zlib1g-dev valgrind + install_packages: valgrind install_steps: wolfssl-opensslextra wolfssh configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --with-wolfssh=/home/runner/wolfssh --enable-ech --enable-debug @@ -133,17 +132,15 @@ jobs: -DCURL_COMPLETION_FISH=ON -DCURL_COMPLETION_ZSH=ON - name: 'awslc' - install_packages: zlib1g-dev install_steps: awslc pytest configure: LDFLAGS=-Wl,-rpath,/home/runner/awslc/lib --with-openssl=/home/runner/awslc --enable-ech - name: 'awslc' - install_packages: zlib1g-dev libidn2-dev + install_packages: libidn2-dev install_steps: awslc generate: -DOPENSSL_ROOT_DIR=/home/runner/awslc -DUSE_ECH=ON -DCMAKE_UNITY_BUILD=OFF - name: 'boringssl' - install_packages: zlib1g-dev install_steps: boringssl pytest generate: -DOPENSSL_ROOT_DIR=/home/runner/boringssl -DUSE_ECH=ON @@ -152,32 +149,30 @@ jobs: configure: --with-openssl --enable-debug --disable-unity - name: 'openssl libssh2 sync-resolver valgrind' - install_packages: zlib1g-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev valgrind + install_packages: libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev valgrind generate: -DENABLE_DEBUG=ON -DENABLE_THREADED_RESOLVER=OFF -DCURL_USE_LIBSSH2=ON - name: 'openssl' - install_packages: zlib1g-dev install_steps: pytest configure: CFLAGS=-std=gnu89 --with-openssl --enable-debug - name: 'openssl arm' - install_packages: zlib1g-dev install_steps: pytest configure: CFLAGS=-std=gnu89 --with-openssl --enable-debug image: 'ubuntu-24.04-arm' - name: 'openssl -O3 libssh valgrind' - install_packages: zlib1g-dev libssh-dev valgrind + install_packages: libssh-dev valgrind CFLAGS: -O3 generate: -DENABLE_DEBUG=ON -DCURL_USE_LIBSSH=ON -DCMAKE_UNITY_BUILD_BATCH_SIZE=50 - name: 'openssl clang krb5 openldap static' install_steps: openldap-static - install_packages: zlib1g-dev libidn2-dev libkrb5-dev clang libssl-dev + install_packages: libidn2-dev libkrb5-dev clang libssl-dev configure: CC=clang --disable-shared --with-openssl --with-gssapi --enable-debug --disable-docs --disable-manual --with-ldap=/home/runner/openldap-static --with-ldap-lib=ldap --with-lber-lib=lber - name: 'openssl clang krb5 LTO' - install_packages: zlib1g-dev libkrb5-dev clang + install_packages: libkrb5-dev clang install_steps: skiprun CC: clang generate: -DCURL_USE_OPENSSL=ON -DCURL_USE_GSSAPI=ON -DENABLE_DEBUG=ON -DCURL_LTO=ON @@ -195,13 +190,13 @@ jobs: --disable-tftp --disable-ftp --disable-file --disable-smb - name: 'openssl torture !FTP' - install_packages: zlib1g-dev libnghttp2-dev libssh2-1-dev libc-ares-dev + install_packages: libnghttp2-dev libssh2-1-dev libc-ares-dev generate: -DCURL_USE_OPENSSL=ON -DENABLE_DEBUG=ON -DENABLE_ARES=ON tflags: -t --shallow=25 !FTP torture: true - name: 'openssl torture FTP' - install_packages: zlib1g-dev libnghttp2-dev libssh2-1-dev libc-ares-dev + install_packages: libnghttp2-dev libssh2-1-dev libc-ares-dev generate: -DCURL_USE_OPENSSL=ON -DENABLE_DEBUG=ON -DENABLE_ARES=ON tflags: -t --shallow=20 FTP torture: true @@ -220,7 +215,7 @@ jobs: configure: --without-ssl --enable-debug --disable-http --disable-smtp --disable-imap --disable-unity - name: 'clang-tidy' - install_packages: clang-tidy zlib1g-dev libssl-dev libkrb5-dev + install_packages: clang-tidy libkrb5-dev install_steps: skipall wolfssl-opensslextra wolfssh configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --with-wolfssh=/home/runner/wolfssh --with-openssl --enable-ech --with-gssapi --enable-ssls-export make-custom-target: tidy @@ -234,7 +229,7 @@ jobs: make-prefix: scan-build --status-bugs - name: 'address-sanitizer' - install_packages: zlib1g-dev libssh2-1-dev clang libssl-dev libubsan1 libasan8 libtsan2 + install_packages: libssh2-1-dev clang libssl-dev libubsan1 libasan8 libtsan2 install_steps: pytest randcurl CFLAGS: -fsanitize=address,undefined,signed-integer-overflow -fno-sanitize-recover=undefined,integer -Wformat -Werror=format-security -Werror=array-bounds -g LDFLAGS: -fsanitize=address,undefined -fno-sanitize-recover=undefined,integer @@ -242,7 +237,7 @@ jobs: configure: CC=clang --with-openssl --enable-debug - name: 'thread-sanitizer' - install_packages: zlib1g-dev clang libtsan2 + install_packages: clang libtsan2 install_steps: pytest openssl-tsan CFLAGS: -fsanitize=thread -g LDFLAGS: -fsanitize=thread @@ -278,7 +273,7 @@ jobs: configure: --with-rustls --enable-ech --enable-debug - name: 'IntelC openssl' - install_packages: zlib1g-dev libssl-dev + install_packages: libssl-dev install_steps: intel configure: CC=icc --enable-debug --with-openssl @@ -311,7 +306,7 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install \ libtool autoconf automake pkgconf \ - libpsl-dev libbrotli-dev libzstd-dev \ + libpsl-dev zlib1g-dev libbrotli-dev libzstd-dev \ ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} python3 -m venv ~/venv From cd20f7b6532198162ddd5bfa816a284c1ad66a7e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 22 Sep 2025 11:27:10 +0200 Subject: [PATCH 131/465] libssh: drop two unused assigments Reported in macOS clang-tidy v21.1.1 build, after enabling libssh in it: ``` lib/vssh/libssh.c lib/vssh/libssh.c:1342:9: error: Value stored to 'to_t' is never read [clang-analyzer-deadcode.DeadStores,-warnings-as-errors] 1342 | to_t = STRE_OK; | ^ lib/vssh/libssh.c:1342:9: note: Value stored to 'to_t' is never read lib/vssh/libssh.c:1349:9: error: Value stored to 'from_t' is never read [clang-analyzer-deadcode.DeadStores,-warnings-as-errors] 1349 | from_t = STRE_OK; | ^ lib/vssh/libssh.c:1349:9: note: Value stored to 'from_t' is never read 2 warnings generated. ``` Ref: https://github.com/curl/curl/actions/runs/17909917954/job/50918955923?pr=18660#step:11:182 Cherry-picked from #18660 Closes #18684 --- lib/vssh/libssh.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index cb2e8cde4d43..576ac3b0c042 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1339,14 +1339,12 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, if((to_t == STRE_NO_NUM) || (to >= size)) { to = size - 1; - to_t = STRE_OK; } if(from_t == STRE_NO_NUM) { /* from is relative to end of file */ from = size - to; to = size - 1; - from_t = STRE_OK; } if(from > size) { failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" From d75785c7dea214d12525beb659694d3fcc483731 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 20 Sep 2025 11:43:59 +0200 Subject: [PATCH 132/465] GHA: enable more options in static analyzer jobs This is an effort to pass more code through clang-tidt and scan-build static analyzers. Following CodeQL Linux jobs. GHA/codeql: - also build with libssh. - disable verbose output in build steps. GHA/linux: - enable more build options for the clang-tidy and scan-build jobs: libidn2, nghttp2, ldap, kerberos, rtmp, gnutls, gsasl, rustls, mbedtls, wolfssl Use Linuxbrew where necessary. - also enable ECH, gssapi in the scan-build job. - fix 'scanbuild' to be 'scan-build' in the job name. GHA/macos: - build with Rustls in the clang-tidy job. - add a new clang-tidy job to test HTTP/3 (with openssl + ngtcp2). - build with libssh in one of the clang-tidy jobs. - build with LibreSSL in the MultiSSL clang-tidy job. - build with heimdal and kerberos in the clang-tidy jobs respectively. - build with OpenLDAP in one clang-tidy job. - add support for `skipall`, `skiprun` job options, and use it. Closes #18660 --- .github/workflows/codeql.yml | 17 +++++++++-------- .github/workflows/linux.yml | 31 +++++++++++++++++++++++-------- .github/workflows/macos.yml | 34 ++++++++++++++++++++++++++-------- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 808ee0b63a91..97b0ddd42c5c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -75,7 +75,7 @@ jobs: sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get -o Dpkg::Use-Pty=0 update sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev \ + sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libssh-dev \ libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev /home/linuxbrew/.linuxbrew/bin/brew install c-ares gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi @@ -108,19 +108,20 @@ jobs: cmake -B _bld1 -G Ninja -DENABLE_DEBUG=ON \ -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DCURL_USE_WOLFSSL=ON \ -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON -DUSE_ECH=ON -DENABLE_ARES=ON - cmake --build _bld1 --verbose - cmake --build _bld1 --verbose --target curlinfo - cmake --build _bld1 --verbose --target servers - cmake --build _bld1 --verbose --target tunits - cmake --build _bld1 --verbose --target curl-examples-build + cmake --build _bld1 + cmake --build _bld1 --target curlinfo + cmake --build _bld1 --target servers + cmake --build _bld1 --target tunits + cmake --build _bld1 --target curl-examples-build # HTTP/3 export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix libnghttp3)/lib/pkgconfig:$(brew --prefix libngtcp2)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" cmake -B _bld2 -G Ninja \ -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR="$(brew --prefix openssl)" -DUSE_NGTCP2=ON \ + -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON \ -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON - cmake --build _bld2 --verbose - cmake --build _bld2 --verbose --target servers + cmake --build _bld2 + cmake --build _bld2 --target servers _bld1/src/curl --disable --version _bld2/src/curl --disable --version diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 7aa7bc5707f4..969b460d1dd4 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -215,18 +215,31 @@ jobs: configure: --without-ssl --enable-debug --disable-http --disable-smtp --disable-imap --disable-unity - name: 'clang-tidy' - install_packages: clang-tidy libkrb5-dev - install_steps: skipall wolfssl-opensslextra wolfssh - configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --with-wolfssh=/home/runner/wolfssh --with-openssl --enable-ech --with-gssapi --enable-ssls-export + install_packages: clang-tidy libssl-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev libkrb5-dev librtmp-dev libgnutls28-dev + install_steps: skipall mbedtls rustls wolfssl-opensslextra + install_steps_brew: gsasl make-custom-target: tidy - - - name: 'scanbuild' - install_packages: clang-tools clang libssl-dev libssh2-1-dev - install_steps: skipall - configure: --with-openssl --enable-debug --with-libssh2 --disable-unity + PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/opt/gsasl/lib/pkgconfig + LDFLAGS: -Wl,-rpath,/home/runner/wolfssl-opensslextra/lib -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/gsasl/lib + configure: >- + --with-wolfssl=/home/runner/wolfssl-opensslextra --with-openssl --with-rustls --with-mbedtls=/home/runner/mbedtls --with-gnutls --with-libgsasl + --with-librtmp --with-libssh2 --with-libidn2 + --enable-ech --with-gssapi --enable-ssls-export + + - name: 'scan-build' + install_packages: clang-tools clang libssl-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev libkrb5-dev librtmp-dev libgnutls28-dev + install_steps: skipall mbedtls rustls wolfssl-opensslextra + install_steps_brew: gsasl CC: clang configure-prefix: scan-build make-prefix: scan-build --status-bugs + PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/opt/gsasl/lib/pkgconfig + LDFLAGS: -Wl,-rpath,/home/runner/wolfssl-opensslextra/lib -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/gsasl/lib + configure: >- + --with-wolfssl=/home/runner/wolfssl-opensslextra --with-openssl --with-rustls --with-mbedtls=/home/runner/mbedtls --with-gnutls --with-libgsasl + --with-librtmp --with-libssh2 --with-libidn2 + --enable-ech --with-gssapi --enable-ssls-export + --disable-debug --disable-unity - name: 'address-sanitizer' install_packages: libssh2-1-dev clang libssl-dev libubsan1 libasan8 libtsan2 @@ -296,6 +309,7 @@ jobs: - name: 'install prereqs' if: ${{ matrix.build.container == null && !contains(matrix.build.name, 'i686') }} env: + INSTALL_PACKAGES_BREW: '${{ matrix.build.install_steps_brew }}' INSTALL_PACKAGES: >- ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'stunnel4' || '' }} ${{ contains(matrix.build.install_steps, 'pytest') && 'apache2 apache2-dev libnghttp2-dev vsftpd dante-server' || '' }} @@ -309,6 +323,7 @@ jobs: libpsl-dev zlib1g-dev libbrotli-dev libzstd-dev \ ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} + [ -n "${INSTALL_PACKAGES_BREW}" ] && /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} python3 -m venv ~/venv - name: 'install prereqs' diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index be8565303eb8..0fd9d20f5b38 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -281,10 +281,27 @@ jobs: generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON -DUSE_APPLE_IDN=ON -DUSE_NGTCP2=ON - name: 'MultiSSL AppleIDN clang-tidy +examples' compiler: clang - install: llvm brotli zstd gnutls nettle mbedtls gsasl rtmpdump fish - install_steps: clang-tidy - generate: -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_DEFAULT_SSL_BACKEND=openssl -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DENABLE_ARES=ON -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON -DUSE_APPLE_IDN=ON -DUSE_SSLS_EXPORT=ON -DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy -DCURL_COMPLETION_FISH=ON -DCURL_COMPLETION_ZSH=ON + install: llvm brotli zstd gnutls nettle libressl krb5 mbedtls gsasl rustls-ffi rtmpdump libssh fish + install_steps: clang-tidy skiprun chkprefill: _chkprefill + generate: >- + -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/libressl -DCURL_DEFAULT_SSL_BACKEND=openssl + -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DENABLE_ARES=ON -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON + -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON -DUSE_APPLE_IDN=ON -DUSE_SSLS_EXPORT=ON + -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/krb5 + -DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy + -DCURL_COMPLETION_FISH=ON -DCURL_COMPLETION_ZSH=ON + + - name: 'HTTP/3 clang-tidy' + compiler: clang + install: llvm brotli zstd libnghttp3 libngtcp2 openldap heimdal + install_steps: clang-tidy skipall + generate: >- + -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DUSE_NGTCP2=ON + -DLDAP_INCLUDE_DIR=/opt/homebrew/opt/openldap/include -DLDAP_LIBRARY=/opt/homebrew/opt/openldap/lib/libldap.dylib -DLDAP_LBER_LIBRARY=/opt/homebrew/opt/openldap/lib/liblber.dylib + -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/heimdal + -DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy + - name: 'quictls +static libssh +examples' install: quictls libssh generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/quictls -DBUILD_STATIC_LIBS=ON -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON @@ -340,7 +357,7 @@ jobs: env: INSTALL_PACKAGES: >- ${{ matrix.build.generate && 'ninja' || 'automake libtool' }} - ${{ !contains(matrix.build.install_steps, 'clang-tidy') && 'nghttp2 stunnel' || '' }} + ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && 'nghttp2 stunnel' || '' }} ${{ contains(matrix.build.install_steps, 'pytest') && 'caddy httpd vsftpd' || '' }} run: | @@ -459,6 +476,7 @@ jobs: fi - name: 'build tests' + if: ${{ !contains(matrix.build.install_steps, 'skipall') }} run: | if [ "${MATRIX_BUILD}" = 'cmake' ]; then cmake --build bld --verbose --target testdeps @@ -467,14 +485,14 @@ jobs: fi - name: 'install test prereqs' - if: ${{ !contains(matrix.build.install_steps, 'clang-tidy') }} + if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} run: | python3 -m venv ~/venv source ~/venv/bin/activate python3 -m pip install -r tests/requirements.txt - name: 'run tests' - if: ${{ !contains(matrix.build.install_steps, 'clang-tidy') }} + if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} timeout-minutes: ${{ contains(matrix.build.install_steps, 'torture') && 20 || 10 }} env: TEST_TARGET: ${{ contains(matrix.build.install_steps, 'torture') && 'test-torture' || 'test-ci' }} @@ -496,13 +514,13 @@ jobs: fi - name: 'install pytest prereqs' - if: ${{ !contains(matrix.build.install_steps, 'clang-tidy') && contains(matrix.build.install_steps, 'pytest') }} + if: ${{ contains(matrix.build.install_steps, 'pytest') }} run: | source ~/venv/bin/activate python3 -m pip install -r tests/http/requirements.txt - name: 'run pytest' - if: ${{ !contains(matrix.build.install_steps, 'clang-tidy') && contains(matrix.build.install_steps, 'pytest') }} + if: ${{ contains(matrix.build.install_steps, 'pytest') }} env: PYTEST_ADDOPTS: '--color=yes' PYTEST_XDIST_AUTO_NUM_WORKERS: 4 From f833d5d1fb0cabaaf646e4c630a2cf7b80f55d0f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 22 Sep 2025 18:02:49 +0200 Subject: [PATCH 133/465] cmake: use modern alternatives for `get_filename_component()` - use `cmake_path()` to query filenames, with CMake 3.20 or upper. https://cmake.org/cmake/help/v4.1/command/cmake_path.html#query - use `cmake_host_system_information()` to query the registry, with CMake 3.24 or upper. https://cmake.org/cmake/help/v4.1/command/cmake_host_system_information.html#query-windows-registry Replacing the undocumented method. - also quote the value passed to `get_filename_component()` where missing. (Could not cause an actual issue as used in the code.) Closes #18688 --- CMake/FindGSS.cmake | 15 ++++++++++++--- CMake/FindNGTCP2.cmake | 6 +++++- CMakeLists.txt | 9 +++++++-- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index 9000445acb3f..172259e28253 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -230,7 +230,11 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr if(GSS_FLAVOUR) set(_gss_libdir_suffixes "") set(_gss_libdir_hints ${_gss_root_hints}) - get_filename_component(_gss_calculated_potential_root "${_gss_INCLUDE_DIRS}" DIRECTORY) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET _gss_INCLUDE_DIRS PARENT_PATH _gss_calculated_potential_root) + else() + get_filename_component(_gss_calculated_potential_root "${_gss_INCLUDE_DIRS}" DIRECTORY) + endif() list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root}) if(WIN32) @@ -323,8 +327,13 @@ if(GSS_FLAVOUR) set(GSS_VERSION "Heimdal Unknown") endif() elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT") - get_filename_component(_mit_version "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME - CACHE) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24) + cmake_host_system_information(RESULT _mit_version QUERY WINDOWS_REGISTRY + "HKLM/SOFTWARE/MIT/Kerberos/SDK/CurrentVersion" VALUE "VersionString") + else() + get_filename_component(_mit_version + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE) + endif() if(WIN32 AND _mit_version) set(GSS_VERSION "${_mit_version}") else() diff --git a/CMake/FindNGTCP2.cmake b/CMake/FindNGTCP2.cmake index 700017f859f7..eb4358ef00a7 100644 --- a/CMake/FindNGTCP2.cmake +++ b/CMake/FindNGTCP2.cmake @@ -104,7 +104,11 @@ else() endif() if(_ngtcp2_crypto_backend) - get_filename_component(_ngtcp2_library_dir "${NGTCP2_LIBRARY}" DIRECTORY) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET NGTCP2_LIBRARY PARENT_PATH _ngtcp2_library_dir) + else() + get_filename_component(_ngtcp2_library_dir "${NGTCP2_LIBRARY}" DIRECTORY) + endif() find_library(${_crypto_library_upper}_LIBRARY NAMES ${_crypto_library_lower} HINTS ${_ngtcp2_library_dir}) if(${_crypto_library_upper}_LIBRARY) diff --git a/CMakeLists.txt b/CMakeLists.txt index 083c2f37b9c0..f817b61a81e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2339,8 +2339,13 @@ if(NOT CURL_DISABLE_INSTALL) elseif(_lib MATCHES "/") # This gets a bit more complex, because we want to specify the # directory separately, and only once per directory - get_filename_component(_libdir ${_lib} DIRECTORY) - get_filename_component(_libname ${_lib} NAME_WE) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET _lib PARENT_PATH _libdir) + cmake_path(GET _lib STEM _libname) + else() + get_filename_component(_libdir "${_lib}" DIRECTORY) + get_filename_component(_libname "${_lib}" NAME_WE) + endif() if(_libname MATCHES "^lib") if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) cmake_path(SET _libdir NORMALIZE "${_libdir}") From 051839eb8fcac5ed384e9c3911cb2511119c2c8a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 22 Sep 2025 23:58:41 +0200 Subject: [PATCH 134/465] tidy-up: URLs Closes #18689 --- docs/BINDINGS.md | 6 +++--- docs/BUG-BOUNTY.md | 4 ++-- docs/ECH.md | 4 ++-- docs/HTTP-COOKIES.md | 2 +- docs/HTTPSRR.md | 2 +- docs/INSTALL.md | 9 +++++---- docs/RUSTLS.md | 2 +- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/BINDINGS.md b/docs/BINDINGS.md index 8bba1d9c9a8d..a72482cf8dfd 100644 --- a/docs/BINDINGS.md +++ b/docs/BINDINGS.md @@ -22,7 +22,7 @@ libcurl bindings [Basic](https://scriptbasic.com/) ScriptBasic bindings written by Peter Verhas -C++: [curlpp](https://github.com/jpbarrette/curlpp/) Written by Jean-Philippe Barrette-LaPierre, +C++: [curlpp](https://github.com/jpbarrette/curlpp) Written by Jean-Philippe Barrette-LaPierre, [curlcpp](https://github.com/JosephP91/curlcpp) by Giuseppe Persico and [C++ Requests](https://github.com/libcpr/cpr) by Huu Nguyen @@ -75,7 +75,7 @@ Go: [go-curl](https://github.com/andelf/go-curl) by ShuYu Wang Lua: [luacurl](https://web.archive.org/web/20201205052437/luacurl.luaforge.net/) by Alexander Marinov, [Lua-cURL](https://github.com/Lua-cURL) by Jürgen Hötzel -[Mono](https://web.archive.org/web/20070606064500/https://forge.novell.com/modules/xfmod/project/?libcurl-mono) Written by Jeffrey Phillips +[Mono](https://web.archive.org/web/20070606064500/forge.novell.com/modules/xfmod/project/?libcurl-mono) Written by Jeffrey Phillips [.NET](https://sourceforge.net/projects/libcurl-net/) libcurl-net by Jeffrey Phillips @@ -121,7 +121,7 @@ Ruby: [curb](https://github.com/taf2/curb) written by Ross Bamford, [Rust](https://github.com/alexcrichton/curl-rust) curl-rust - by Carl Lerche -[Scheme](https://www.metapaper.net/lisovsky/web/curl/) Bigloo binding by Kirill Lisovsky +[Scheme](https://metapaper.net/lisovsky/web/curl/) Bigloo binding by Kirill Lisovsky [Scilab](https://help.scilab.org/docs/current/fr_FR/getURL.html) binding by Sylvestre Ledru diff --git a/docs/BUG-BOUNTY.md b/docs/BUG-BOUNTY.md index 6933c61b3470..d75ea28e0248 100644 --- a/docs/BUG-BOUNTY.md +++ b/docs/BUG-BOUNTY.md @@ -7,8 +7,8 @@ SPDX-License-Identifier: curl # The curl bug bounty The curl project runs a bug bounty program in association with -[HackerOne](https://www.hackerone.com) and the [Internet Bug -Bounty](https://internetbugbounty.org). +[HackerOne](https://www.hackerone.com/) and the [Internet Bug +Bounty](https://internetbugbounty.org/). ## How does it work? diff --git a/docs/ECH.md b/docs/ECH.md index 969bbfa27f54..712bf2d774f0 100644 --- a/docs/ECH.md +++ b/docs/ECH.md @@ -375,8 +375,8 @@ There are some known issues with the ECH implementation in wolfSSL: - The main issue is that the client currently handles HelloRetryRequest incorrectly. [HRR issue](https://github.com/wolfSSL/wolfssl/issues/6802).) The HRR issue means that the client does not work for - [this ECH test web site](https://tls-ech.dev) and any other similarly configured - sites. + [this ECH test web site](https://tls-ech.dev/) and any other similarly + configured sites. - There is also an issue related to so-called middlebox compatibility mode. [middlebox compatibility issue](https://github.com/wolfSSL/wolfssl/issues/6774) diff --git a/docs/HTTP-COOKIES.md b/docs/HTTP-COOKIES.md index 62905dbc6c19..41faecdcb9ec 100644 --- a/docs/HTTP-COOKIES.md +++ b/docs/HTTP-COOKIES.md @@ -23,7 +23,7 @@ SPDX-License-Identifier: curl For a long time, the only spec explaining how to use cookies was the original [Netscape spec from 1994](https://curl.se/rfc/cookie_spec.html). - In 2011, [RFC 6265](https://www.ietf.org/rfc/rfc6265.txt) was finally + In 2011, [RFC 6265](https://datatracker.ietf.org/doc/html/rfc6265) was finally published and details how cookies work within HTTP. In 2016, an update which added support for prefixes was [proposed](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-cookie-prefixes-00), diff --git a/docs/HTTPSRR.md b/docs/HTTPSRR.md index 22184a253e68..7e828063481e 100644 --- a/docs/HTTPSRR.md +++ b/docs/HTTPSRR.md @@ -6,7 +6,7 @@ SPDX-License-Identifier: curl # HTTPS RR -[RFC 9460](https://www.rfc-editor.org/rfc/rfc9460.html) documents the HTTPS +[RFC 9460](https://datatracker.ietf.org/doc/html/rfc9460) documents the HTTPS DNS Resource Record. curl features **experimental** support for HTTPS RR. diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 3972d242399f..ff0a36d3658c 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -15,7 +15,8 @@ libcurl from [source code](https://curl.se/download.html). ## Building using vcpkg -You can download and install curl and libcurl using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager: +You can download and install curl and libcurl using +the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: git clone https://github.com/Microsoft/vcpkg.git cd vcpkg @@ -30,8 +31,8 @@ or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. ## Building from git If you get your code off a git repository instead of a release tarball, see -the [GIT-INFO.md](https://github.com/curl/curl/blob/master/GIT-INFO.md) file in the root directory for specific instructions on how -to proceed. +the [GIT-INFO.md](https://github.com/curl/curl/blob/master/GIT-INFO.md) file in +the root directory for specific instructions on how to proceed. # Unix @@ -217,7 +218,7 @@ executable in `/bin/` or you see the configure fail toward the end. Download the setup installer from [`cygwin`](https://cygwin.com/) to begin. Additional `cygwin` packages are needed for the install. For more on installing packages visit -[`cygwin setup`](https://www.cygwin.com/faq/faq.html#faq.setup.cli). +[`cygwin setup`](https://cygwin.com/faq/faq.html#faq.setup.cli). Either run setup-x86_64.exe, then search and select packages individually, or try: diff --git a/docs/RUSTLS.md b/docs/RUSTLS.md index e46e1d802516..4f904a97e082 100644 --- a/docs/RUSTLS.md +++ b/docs/RUSTLS.md @@ -8,7 +8,7 @@ SPDX-License-Identifier: curl [Rustls is a TLS backend written in Rust](https://docs.rs/rustls/). curl can be built to use it as an alternative to OpenSSL or other TLS backends. We use -the [rustls-ffi C bindings](https://github.com/rustls/rustls-ffi/). This +the [rustls-ffi C bindings](https://github.com/rustls/rustls-ffi). This version of curl is compatible with `rustls-ffi` v0.15.x. ## Getting rustls-ffi From 71fc11e6bbf530b90bf6e93a02cb32bdaecc933b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 23 Sep 2025 11:19:18 +0200 Subject: [PATCH 135/465] GHA/codeql: build `units` on Linux Closes #18695 --- .github/workflows/codeql.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 97b0ddd42c5c..8cc7e9f48c2c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -112,6 +112,7 @@ jobs: cmake --build _bld1 --target curlinfo cmake --build _bld1 --target servers cmake --build _bld1 --target tunits + cmake --build _bld1 --target units cmake --build _bld1 --target curl-examples-build # HTTP/3 From b326293619996ff88f965cc3baf90cee2038ba36 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 23 Sep 2025 11:50:23 +0200 Subject: [PATCH 136/465] GHA/linux: fix address sanitizer error output Same issue as seen earlier in the tsan job. Fix it the same way, by switching to cmake to avoid autotools' libtool confusing the analyzer. Ref: 2a46df31fdb91851895bc46d81f0065e6cafc80b #18274 Configuration remains identical. I removed libssh2 from the installed packages, because it was unused before, but cmake enabled it by default and libssh2 has memory leaks: Ref: https://github.com/curl/curl/actions/runs/17941312820/job/51018425159 Fixing: ``` /usr/bin/llvm-symbolizer-18: /home/runner/work/curl/curl/bld/lib/.libs/libcurl.so.4: no version information available (required by /usr/bin/llvm-symbolizer-18) /usr/bin/llvm-symbolizer-18: symbol lookup error: /home/runner/work/curl/curl/bld/lib/.libs/libcurl.so.4: undefined symbol: __asan_option_detect_stack_use_after_return ==33900==WARNING: Can't read from symbolizer at fd 3 [..] ==33900==WARNING: Can't write to symbolizer at fd 6 ==33900==WARNING: Failed to use and restart external symbolizer ``` Ref: https://github.com/curl/curl/actions/runs/17939949191/job/51013953675?pr=18693 Cherry-picked from #18693 Closes #18696 --- .github/workflows/linux.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 969b460d1dd4..4badcad40773 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -242,12 +242,12 @@ jobs: --disable-debug --disable-unity - name: 'address-sanitizer' - install_packages: libssh2-1-dev clang libssl-dev libubsan1 libasan8 libtsan2 + install_packages: clang libssl-dev libubsan1 libasan8 libtsan2 install_steps: pytest randcurl CFLAGS: -fsanitize=address,undefined,signed-integer-overflow -fno-sanitize-recover=undefined,integer -Wformat -Werror=format-security -Werror=array-bounds -g - LDFLAGS: -fsanitize=address,undefined -fno-sanitize-recover=undefined,integer - LIBS: -ldl -lubsan - configure: CC=clang --with-openssl --enable-debug + LDFLAGS: -fsanitize=address,undefined -fno-sanitize-recover=undefined,integer -ldl -lubsan + CC: clang + generate: -DENABLE_DEBUG=ON - name: 'thread-sanitizer' install_packages: clang libtsan2 From 67de9924eb9dfcff009271b1fe9c901fc8a52807 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 23 Sep 2025 12:47:45 +0200 Subject: [PATCH 137/465] GHA/linux: enable libidn2 and libssh in asan job Closes #18697 --- .github/workflows/linux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 4badcad40773..dbdccf61ffd7 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -242,12 +242,12 @@ jobs: --disable-debug --disable-unity - name: 'address-sanitizer' - install_packages: clang libssl-dev libubsan1 libasan8 libtsan2 + install_packages: clang libssl-dev libssh-dev libidn2-dev libnghttp2-dev libubsan1 libasan8 libtsan2 install_steps: pytest randcurl CFLAGS: -fsanitize=address,undefined,signed-integer-overflow -fno-sanitize-recover=undefined,integer -Wformat -Werror=format-security -Werror=array-bounds -g LDFLAGS: -fsanitize=address,undefined -fno-sanitize-recover=undefined,integer -ldl -lubsan CC: clang - generate: -DENABLE_DEBUG=ON + generate: -DENABLE_DEBUG=ON -DCURL_USE_LIBSSH=ON - name: 'thread-sanitizer' install_packages: clang libtsan2 From 1acdf3bd64b6344ff818621155acf4cf5c3d1f50 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 23 Sep 2025 15:45:49 +0200 Subject: [PATCH 138/465] GHA/macos: add macos-26, llvm20, gcc15, drop macos-14, gcc14 Number of combo jobs down to 22 from 24. Also: - update the version matrix. - update exclusion matrix. - include verbose compiler configuration dump. It makes the Apple-included, default `-I/usr/local/include` visible. Ref: #18683 Closes #18698 --- .github/workflows/macos.yml | 45 ++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 0fd9d20f5b38..0eb8f7e8423e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -104,6 +104,7 @@ jobs: xcodebuild -sdk -version | grep '^Path:' || true xcrun --sdk iphoneos --show-sdk-path 2>/dev/null || true xcrun --sdk iphoneos --show-sdk-version || true + echo '::group::compiler defaults'; echo 'int main(void) {}' | "${CC}" -v -x c -; echo '::endgroup::' echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::' echo '::group::brew packages installed'; ls -l /opt/homebrew/opt; echo '::endgroup::' @@ -555,18 +556,24 @@ jobs: strategy: fail-fast: false matrix: - compiler: [gcc-12, gcc-13, gcc-14, llvm@15, llvm@18, clang] + # Sources: + # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-arm64-Readme.md + # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md + # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md + # https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md + compiler: [gcc-12, gcc-13, gcc-15, llvm@15, llvm@18, llvm@20, clang] # Xcode support matrix as of 2024-07, with default macOS SDK versions and OS names, years: # * = default Xcode on the runner. # macos-13: 14.1, 14.2, 14.3.1, 15.0.1, 15.1,*15.2 # macos-14: 15.0.1, 15.1, 15.2, 15.3,*15.4 - # macos-15: *16.0, 16.1 - # macOSSDK: 13.0, 13.1, 13.3, 14.0, 14.2, 14.2, 14.4, 14.5, 15.0, 15.1 - # Ventura (2022) Sonoma (2023) Sequoia (2024) + # macos-15: 16.0, 16.1, 16.2, 16.3,*16.4, 26.0 + # macos-26: 16.4 *26.0 + # macOSSDK: 13.0, 13.1, 13.3, 14.0, 14.2, 14.2, 14.4, 14.5, 15.0, 15.1, 15.2, 15.4, 15.5, 26.0 + # Ventura (2022) Sonoma (2023) Sequoia (2024) Tahoe (2025) # https://github.com/actions/runner-images/tree/main/images/macos # https://en.wikipedia.org/wiki/MacOS_version_history # TODO when dropping macos-13: replace '$(brew --prefix ...' with /opt/homebrew - image: [macos-13, macos-14, macos-15] + image: [macos-13, macos-15, macos-26] # Can skip these to reduce jobs: # 15.1 has the same default macOS SDK as 15.2 and identical test results. # 14.1, 15.4 not revealing new fallouts. @@ -582,11 +589,19 @@ jobs: - { image: macos-13, xcode: '15.4' } - { image: macos-13, xcode: '16.0' } - { image: macos-13, xcode: '16.1' } + - { image: macos-13, xcode: '16.2' } + - { image: macos-13, xcode: '16.3' } + - { image: macos-13, xcode: '16.4' } + - { image: macos-13, xcode: '26.0' } - { image: macos-14, xcode: '14.1' } - { image: macos-14, xcode: '14.2' } - { image: macos-14, xcode: '14.3.1' } - { image: macos-14, xcode: '16.0' } - { image: macos-14, xcode: '16.1' } + - { image: macos-14, xcode: '16.2' } + - { image: macos-14, xcode: '16.3' } + - { image: macos-14, xcode: '16.4' } + - { image: macos-14, xcode: '26.0' } - { image: macos-15, xcode: '14.1' } - { image: macos-15, xcode: '14.2' } - { image: macos-15, xcode: '14.3.1' } @@ -595,12 +610,31 @@ jobs: - { image: macos-15, xcode: '15.2' } - { image: macos-15, xcode: '15.3' } - { image: macos-15, xcode: '15.4' } + - { image: macos-26, xcode: '14.1' } + - { image: macos-26, xcode: '14.2' } + - { image: macos-26, xcode: '14.3.1' } + - { image: macos-26, xcode: '15.0.1' } + - { image: macos-26, xcode: '15.1' } + - { image: macos-26, xcode: '15.2' } + - { image: macos-26, xcode: '15.3' } + - { image: macos-26, xcode: '15.4' } + - { image: macos-26, xcode: '16.0' } + - { image: macos-26, xcode: '16.1' } + - { image: macos-26, xcode: '16.2' } + - { image: macos-26, xcode: '16.3' } - { image: macos-13, compiler: 'llvm@18' } + - { image: macos-13, compiler: 'llvm@20' } - { image: macos-14, compiler: 'llvm@18' } + - { image: macos-14, compiler: 'llvm@20' } - { image: macos-15, compiler: 'llvm@15' } + - { image: macos-15, compiler: 'llvm@20' } + - { image: macos-26, compiler: 'llvm@15' } + - { image: macos-26, compiler: 'llvm@18' } + - { image: macos-26, compiler: 'gcc-12' } # Reduce build combinations, by dropping less interesting ones - { compiler: gcc-13, build: cmake } - { compiler: gcc-14, build: autotools } + - { compiler: gcc-15, build: autotools } steps: - name: 'install autotools' if: ${{ matrix.build == 'autotools' }} @@ -617,6 +651,7 @@ jobs: xcrun --sdk macosx --show-sdk-path 2>/dev/null || true xcrun --sdk macosx --show-sdk-version || true ls -l /Library/Developer/CommandLineTools/SDKs || true + echo '::group::compiler defaults'; echo 'int main(void) {}' | "${CC}" -v -x c -; echo '::endgroup::' echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::' echo '::group::brew packages preinstalled'; ls -l "$(brew --prefix)/opt"; echo '::endgroup::' From 135e4ec1ddd664d3274447553db71f4959331858 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 22:35:46 +0000 Subject: [PATCH 139/465] GHA: update dependency awslabs/aws-lc to v1.61.3 Closes #18690 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 3d3b35dee093..03e978565d19 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -46,7 +46,7 @@ env: # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com LIBRESSL_VERSION: 4.1.0 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com - AWSLC_VERSION: 1.60.0 + AWSLC_VERSION: 1.61.3 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # renovate: datasource=github-tags depName=gnutls/gnutls versioning=semver registryUrl=https://github.com diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index dbdccf61ffd7..7598137a9548 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -46,7 +46,7 @@ env: # renovate: datasource=github-tags depName=Mbed-TLS/mbedtls versioning=semver registryUrl=https://github.com MBEDTLS_VERSION: 3.6.4 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com - AWSLC_VERSION: 1.60.0 + AWSLC_VERSION: 1.61.3 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # handled in renovate.json From bdbb50a63e0d713102ffb3a29fd4d3544ff7d90d Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 10:29:30 +0200 Subject: [PATCH 140/465] GHA/dist: fix number of parallel jobs on macos runner It was using the global parallel value in cmake integration tests, while on macos runners, this should be lower by one, as used in other macos jobs. Performance impact is minimal. Follow-up to fb70812437ad28b74dbdc1031e46c1d86bc9db3c #16126 Closes #18701 --- .github/workflows/distcheck.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index 9d893481bcfd..de06f5aeab7c 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -258,6 +258,7 @@ jobs: shell: ${{ contains(matrix.image, 'windows') && 'msys2 {0}' || 'bash' }} env: CC: ${{ !contains(matrix.image, 'windows') && 'clang' || '' }} + MAKEFLAGS: ${{ contains(matrix.image, 'macos') && '-j 4' || '-j 5' }} MATRIX_IMAGE: '${{ matrix.image }}' TESTOPTS: ${{ contains(matrix.image, 'macos') && '-D_CURL_PREFILL=ON' || '' }} ${{ contains(matrix.image, 'windows') && '-DCMAKE_UNITY_BUILD_BATCH_SIZE=30' || '' }} OLD_CMAKE_VERSION: 3.11.4 From cc157b49635f3d8d16f445d7af3c8152ff47ae18 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 10:16:05 +0200 Subject: [PATCH 141/465] GHA/distcheck: bump timeout for the cmake integration It may take 1.5 minutes to find the C compiler on macos with old cmake. The build is also slow due to no unity and Ninja support. ``` Wed, 24 Sep 2025 04:56:51 GMT -- Using CMake version 3.11.4 Wed, 24 Sep 2025 04:58:01 GMT -- The C compiler identification is AppleClang 17.0.0.17000013 Wed, 24 Sep 2025 04:58:02 GMT -- Check for working C compiler: /Applications/Xcode_16.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang Wed, 24 Sep 2025 04:59:33 GMT -- Check for working C compiler: /Applications/Xcode_16.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -- works Wed, 24 Sep 2025 04:59:33 GMT -- Detecting C compiler ABI info Wed, 24 Sep 2025 04:59:35 GMT -- Detecting C compiler ABI info - done ``` Ref: https://github.com/curl/curl/actions/runs/17966736478/job/51100678487?pr=18700#step:10:50 Closes #18702 --- .github/workflows/distcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index de06f5aeab7c..da65bf4bd0cf 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -252,7 +252,7 @@ jobs: cmake-integration: name: 'CM integration ${{ matrix.image }}' runs-on: ${{ matrix.image }} - timeout-minutes: 10 + timeout-minutes: 15 defaults: run: shell: ${{ contains(matrix.image, 'windows') && 'msys2 {0}' || 'bash' }} From a99d79616b5df3442dac5598303179e33163a851 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 09:26:19 +0000 Subject: [PATCH 142/465] GHA: update ngtcp2/nghttp3 to v1.12.0 Closes #18705 --- .github/workflows/http3-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 03e978565d19..cd2d381092d0 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -54,7 +54,7 @@ env: # renovate: datasource=github-tags depName=wolfSSL/wolfssl versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com WOLFSSL_VERSION: 5.8.2 # renovate: datasource=github-tags depName=ngtcp2/nghttp3 versioning=semver registryUrl=https://github.com - NGHTTP3_VERSION: 1.11.0 + NGHTTP3_VERSION: 1.12.0 # renovate: datasource=github-tags depName=ngtcp2/ngtcp2 versioning=semver registryUrl=https://github.com NGTCP2_VERSION: 1.15.1 # renovate: datasource=github-tags depName=nghttp2/nghttp2 versioning=semver registryUrl=https://github.com From f8f84b40ccf6e73b89f6f27e2831d6ba1c70e334 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 09:26:25 +0000 Subject: [PATCH 143/465] GHA: Update ngtcp2/ngtcp2 to v1.16.0 Closes #18706 --- .github/workflows/http3-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index cd2d381092d0..780320e383aa 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -56,7 +56,7 @@ env: # renovate: datasource=github-tags depName=ngtcp2/nghttp3 versioning=semver registryUrl=https://github.com NGHTTP3_VERSION: 1.12.0 # renovate: datasource=github-tags depName=ngtcp2/ngtcp2 versioning=semver registryUrl=https://github.com - NGTCP2_VERSION: 1.15.1 + NGTCP2_VERSION: 1.16.0 # renovate: datasource=github-tags depName=nghttp2/nghttp2 versioning=semver registryUrl=https://github.com NGHTTP2_VERSION: 1.67.1 # renovate: datasource=github-tags depName=cloudflare/quiche versioning=semver registryUrl=https://github.com From 976a08985a93e105cdffc1a581e8b0a7f9ebc4c8 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 23 Sep 2025 09:55:11 +0200 Subject: [PATCH 144/465] ares: fix leak in tracing When DNS tracing is enabled, a string allocated by ares was not freed. Reported-by: jmaggard10 on github Bug: https://github.com/curl/curl/pull/18251#pullrequestreview-3255785083 Closes #18691 --- lib/asyn-ares.c | 7 +++++-- lib/curl_trc.h | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 807ca5c0bd00..0a04f4cc367f 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -747,8 +747,11 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data, ares->result = CURLE_OK; #if ARES_VERSION >= 0x011800 /* >= v1.24.0 */ - CURL_TRC_DNS(data, "asyn-ares: servers=%s", - ares_get_servers_csv(ares->channel)); + if(CURL_TRC_DNS_is_verbose(data)) { + char *csv = ares_get_servers_csv(ares->channel); + CURL_TRC_DNS(data, "asyn-ares: servers=%s", csv); + ares_free_string(csv); + } #endif #ifdef HAVE_CARES_GETADDRINFO diff --git a/lib/curl_trc.h b/lib/curl_trc.h index 2819abe2dd48..37a373e4a6a6 100644 --- a/lib/curl_trc.h +++ b/lib/curl_trc.h @@ -123,6 +123,8 @@ void Curl_trc_ws(struct Curl_easy *data, #define CURL_TRC_M_is_verbose(data) \ Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi) +#define CURL_TRC_DNS_is_verbose(data) \ + Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns) #if defined(CURL_HAVE_C99) && !defined(CURL_DISABLE_VERBOSE_STRINGS) #define infof(data, ...) \ @@ -141,7 +143,7 @@ void Curl_trc_ws(struct Curl_easy *data, do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) \ Curl_trc_read(data, __VA_ARGS__); } while(0) #define CURL_TRC_DNS(data, ...) \ - do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) \ + do { if(CURL_TRC_DNS_is_verbose(data)) \ Curl_trc_dns(data, __VA_ARGS__); } while(0) #ifndef CURL_DISABLE_FTP From 7cb5e39f3682daf99d21a25c61841e1bf05ea693 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 11:08:43 +0200 Subject: [PATCH 145/465] socks_gssapi: reject too long tokens If GSS returns a token to use that is longer than 65535 bytes, it can't be transmitted since the length field is an unisgned 16 bit field and thus needs to trigger an error. Reported in Joshua's sarif data Closes #18681 --- lib/socks_gssapi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 0a7ddd5ff1dc..037515e576f6 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -195,7 +195,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(gss_token != GSS_C_NO_BUFFER) gss_release_buffer(&gss_status, &gss_recv_token); if(check_gss_err(data, gss_major_status, - gss_minor_status, "gss_init_sec_context")) { + gss_minor_status, "gss_init_sec_context") || + /* the size needs to fit in a 16 bit field */ + (gss_send_token.length > 0xffff)) { gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); From 66c7e92ae4ab824d5c838a207f742af1df6edaec Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 09:10:39 +0200 Subject: [PATCH 146/465] Revert "cf_socket_recv: don't count reading zero bytes as first byte" This reverts commit df60e8fe701e189e7629fd08b61950a0fb1b697a. The "first byte" checkpoint is not strictly the first byte received, but the sign of first traffic from the server, which a closed connection also is. Closes #18676 --- lib/cf-socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 2f0429efeae6..d5add9723f0d 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1578,7 +1578,7 @@ static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, *pnread = (size_t)nread; CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread); - if(!result && !ctx->got_first_byte && nread) { + if(!result && !ctx->got_first_byte) { ctx->first_byte_at = curlx_now(); ctx->got_first_byte = TRUE; } From 470611d76c118995c64d3b738f02b89b76da6c43 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 10:30:15 +0200 Subject: [PATCH 147/465] hostip: remove unnecessary leftover INT_MAX check in Curl_dnscache_prune The math already uses timediff_t so no need for the extra logic Ref: #18678 Closes #18680 --- lib/hostip.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/hostip.c b/lib/hostip.c index fd8f706e7f25..da260d713009 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -279,13 +279,9 @@ void Curl_dnscache_prune(struct Curl_easy *data) /* Remove outdated and unused entries from the hostcache */ timediff_t oldest_ms = dnscache_prune(&dnscache->entries, timeout_ms, now); - if(Curl_hash_count(&dnscache->entries) > MAX_DNS_CACHE_SIZE) { - if(oldest_ms < INT_MAX) - /* prune the ones over half this age */ - timeout_ms = (int)oldest_ms / 2; - else - timeout_ms = INT_MAX/2; - } + if(Curl_hash_count(&dnscache->entries) > MAX_DNS_CACHE_SIZE) + /* prune the ones over half this age */ + timeout_ms = oldest_ms / 2; else break; From acd0aa2c9d58c4aa849aa17ad6ff3f76ace02692 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 14:53:18 +0200 Subject: [PATCH 148/465] docs: fix/tidy code fences - INSTALL.md: fence code to avoid wrong rendering. Reported-by: rinsuki on github Fixes: https://github.com/curl/curl-www/issues/480 - use `sh` instead of `bash` as fence language, for less visual noise. - INSTALL.md: drop stray shebang. - ECH.md: drop indent from fenced code. - minor tidy-ups. Ref: https://curl.se/docs/install.html Closes #18707 --- docs/ECH.md | 234 ++++++++++++++++++++++++------------------------ docs/INSTALL.md | 139 +++++++++++++++------------- 2 files changed, 193 insertions(+), 180 deletions(-) diff --git a/docs/ECH.md b/docs/ECH.md index 712bf2d774f0..d39f4b2f36a2 100644 --- a/docs/ECH.md +++ b/docs/ECH.md @@ -20,31 +20,31 @@ discussion about a good path forward for ECH support in curl. To build the OpenSSL project's ECH feature branch: -```bash - cd $HOME/code - git clone https://github.com/openssl/openssl - cd openssl - git checkout feature/ech - ./config --libdir=lib --prefix=$HOME/code/openssl-local-inst - ...stuff... - make -j8 - ...more stuff... - make install_sw - ...a little bit of stuff... +```sh +cd $HOME/code +git clone https://github.com/openssl/openssl +cd openssl +git checkout feature/ech +./config --libdir=lib --prefix=$HOME/code/openssl-local-inst +...stuff... +make -j8 +...more stuff... +make install_sw +...a little bit of stuff... ``` To build curl ECH-enabled, making use of the above: -```bash - cd $HOME/code - git clone https://github.com/curl/curl - cd curl - autoreconf -fi - LDFLAGS="-Wl,-rpath,$HOME/code/openssl-local-inst/lib/" ./configure --with-ssl=$HOME/code/openssl-local-inst --enable-ech - ...lots of output... - WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL... - make - ...lots more output... +```sh +cd $HOME/code +git clone https://github.com/curl/curl +cd curl +autoreconf -fi +LDFLAGS="-Wl,-rpath,$HOME/code/openssl-local-inst/lib/" ./configure --with-ssl=$HOME/code/openssl-local-inst --enable-ech +...lots of output... +WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL... +make +...lots more output... ``` If you do not get that WARNING at the end of the ``configure`` command, then @@ -63,24 +63,24 @@ not be the best solution. curl supports using DoH for A/AAAA lookups so it was relatively easy to add retrieval of HTTPS RRs in that situation. To use ECH and DoH together: -```bash - cd $HOME/code/curl - LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech true --doh-url https://one.one.one.one/dns-query https://defo.ie/ech-check.php - ... - SSL_ECH_STATUS: success good
- ... +```sh +cd $HOME/code/curl +LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech true --doh-url https://one.one.one.one/dns-query https://defo.ie/ech-check.php +... +SSL_ECH_STATUS: success good
+... ``` The output snippet above is within the HTML for the webpage, when things work. The above works for these test sites: -```bash - https://defo.ie/ech-check.php - https://draft-13.esni.defo.ie:8413/stats - https://draft-13.esni.defo.ie:8414/stats - https://crypto.cloudflare.com/cdn-cgi/trace - https://tls-ech.dev +```sh +https://defo.ie/ech-check.php +https://draft-13.esni.defo.ie:8413/stats +https://draft-13.esni.defo.ie:8414/stats +https://crypto.cloudflare.com/cdn-cgi/trace +https://tls-ech.dev ``` The list above has 4 different server technologies, implemented by 3 different @@ -107,18 +107,18 @@ reasons. To supply the ECHConfigList on the command line, you might need a bit of cut-and-paste, e.g.: -```bash - dig +short https defo.ie - 1 . ipv4hint=213.108.108.101 ech=AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA ipv6hint=2a00:c6c0:0:116:5::10 +```sh +dig +short https defo.ie +1 . ipv4hint=213.108.108.101 ech=AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA ipv6hint=2a00:c6c0:0:116:5::10 ``` Then paste the base64 encoded ECHConfigList onto the curl command line: -```bash - LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech ecl:AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php - ... - SSL_ECH_STATUS: success good
- ... +```sh +LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech ecl:AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php +... +SSL_ECH_STATUS: success good
+... ``` The output snippet above is within the HTML for the webpage. @@ -126,11 +126,11 @@ The output snippet above is within the HTML for the webpage. If you paste in the wrong ECHConfigList (it changes hourly for ``defo.ie``) you should get an error like this: -```bash - LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php - ... - * OpenSSL/3.3.0: error:0A00054B:SSL routines::ech required - ... +```sh +LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php +... +* OpenSSL/3.3.0: error:0A00054B:SSL routines::ech required +... ``` There is a reason to want this command line option - for use before publishing @@ -141,12 +141,12 @@ If you do use a wrong ECHConfigList value, then the server might return a good value, via the ``retry_configs`` mechanism. You can see that value in the verbose output, e.g.: -```bash - LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php - ... +```sh +LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php +... * ECH: retry_configs AQD+DQA8DAAgACBvYqJy+Hgk33wh/ZLBzKSPgwxeop7gvojQzfASq7zeZQAEAAEAAQANY292ZXIuZGVmby5pZQAA/g0APEMAIAAgXkT5r4cYs8z19q5rdittyIX8gfQ3ENW4wj1fVoiJZBoABAABAAEADWNvdmVyLmRlZm8uaWUAAP4NADw2ACAAINXSE9EdXzEQIJZA7vpwCIQsWqsFohZARXChgPsnfI1kAAQAAQABAA1jb3Zlci5kZWZvLmllAAD+DQA8cQAgACASeiD5F+UoSnVoHvA2l1EifUVMFtbVZ76xwDqmMPraHQAEAAEAAQANY292ZXIuZGVmby5pZQAA * ECH: retry_configs for defo.ie from cover.defo.ie, 319 - ... +... ``` At that point, you could copy the base64 encoded value above and try again. @@ -157,11 +157,11 @@ For now, this only works for the OpenSSL and BoringSSL/AWS-LC builds. curl has various ways to configure default settings, e.g. in ``$HOME/.curlrc``, so one can set the DoH URL and enable ECH that way: -```bash - cat ~/.curlrc - doh-url=https://one.one.one.one/dns-query - silent - ech=true +```sh +cat ~/.curlrc +doh-url=https://one.one.one.one/dns-query +silent +ech=true ``` Note that when you use the system's curl command (rather than our ECH-enabled @@ -176,27 +176,27 @@ now that seems to cause a problem, so that the following line(s) are ignored. If you want to always use our OpenSSL build you can set ``LD_LIBRARY_PATH`` in the environment: -```bash - export LD_LIBRARY_PATH=$HOME/code/openssl +```sh +export LD_LIBRARY_PATH=$HOME/code/openssl ``` When you do the above, there can be a mismatch between OpenSSL versions for applications that check that. A ``git push`` for example fails so you should unset ``LD_LIBRARY_PATH`` before doing that or use a different shell. -```bash - git push - OpenSSL version mismatch. Built against 30000080, you have 30200000 - ... +```sh +git push +OpenSSL version mismatch. Built against 30000080, you have 30200000 +... ``` With all that setup as above the command line gets simpler: -```bash - ./src/curl https://defo.ie/ech-check.php - ... - SSL_ECH_STATUS: success good
- ... +```sh +./src/curl https://defo.ie/ech-check.php +... +SSL_ECH_STATUS: success good
+... ``` The ``--ech true`` option is opportunistic, so tries to do ECH but does not fail if @@ -291,17 +291,17 @@ produce spurious failures. To build with cmake, assuming our ECH-enabled OpenSSL is as before: -```bash - cd $HOME/code - git clone https://github.com/curl/curl - cd curl - mkdir build - cd build - cmake -DOPENSSL_ROOT_DIR=$HOME/code/openssl -DUSE_ECH=1 .. - ... - make - ... - [100%] Built target curl +```sh +cd $HOME/code +git clone https://github.com/curl/curl +cd curl +mkdir build +cd build +cmake -DOPENSSL_ROOT_DIR=$HOME/code/openssl -DUSE_ECH=1 .. +... +make +... +[100%] Built target curl ``` The binary produced by the cmake build does not need any ECH-specific @@ -312,27 +312,27 @@ The binary produced by the cmake build does not need any ECH-specific BoringSSL is also supported by curl and also supports ECH, so to build with that, instead of our ECH-enabled OpenSSL: -```bash - cd $HOME/code - git clone https://boringssl.googlesource.com/boringssl - cd boringssl - cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/code/boringssl/inst -DBUILD_SHARED_LIBS=1 - make - ... - make install +```sh +cd $HOME/code +git clone https://boringssl.googlesource.com/boringssl +cd boringssl +cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/code/boringssl/inst -DBUILD_SHARED_LIBS=1 +make +... +make install ``` Then: -```bash - cd $HOME/code - git clone https://github.com/curl/curl - cd curl - autoreconf -fi - LDFLAGS="-Wl,-rpath,$HOME/code/boringssl/inst/lib" ./configure --with-ssl=$HOME/code/boringssl/inst --enable-ech - ...lots of output... - WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL. Use with caution. - make +```sh +cd $HOME/code +git clone https://github.com/curl/curl +cd curl +autoreconf -fi +LDFLAGS="-Wl,-rpath,$HOME/code/boringssl/inst/lib" ./configure --with-ssl=$HOME/code/boringssl/inst --enable-ech +...lots of output... +WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL. Use with caution. +make ``` The BoringSSL/AWS-LC APIs are fairly similar to those in our ECH-enabled @@ -346,14 +346,14 @@ line variant as of now. wolfSSL also supports ECH and can be used by curl, so here's how: -```bash - cd $HOME/code - git clone https://github.com/wolfSSL/wolfssl - cd wolfssl - ./autogen.sh - ./configure --prefix=$HOME/code/wolfssl/inst --enable-ech --enable-debug --enable-opensslextra - make - make install +```sh +cd $HOME/code +git clone https://github.com/wolfSSL/wolfssl +cd wolfssl +./autogen.sh +./configure --prefix=$HOME/code/wolfssl/inst --enable-ech --enable-debug --enable-opensslextra +make +make install ``` The install prefix (``inst``) in the above causes wolfSSL to be installed there @@ -361,13 +361,13 @@ and we seem to need that for the curl configure command to work out. The ``--enable-opensslextra`` turns out (after much faffing about;-) to be important or else we get build problems with curl below. -```bash - cd $HOME/code - git clone https://github.com/curl/curl - cd curl - autoreconf -fi - ./configure --with-wolfssl=$HOME/code/wolfssl/inst --enable-ech - make +```sh +cd $HOME/code +git clone https://github.com/curl/curl +cd curl +autoreconf -fi +./configure --with-wolfssl=$HOME/code/wolfssl/inst --enable-ech +make ``` There are some known issues with the ECH implementation in wolfSSL: @@ -439,7 +439,7 @@ this for now. Just a note to self as remembering this is a nuisance: -```bash +```sh LD_LIBRARY_PATH=$HOME/code/openssl:./lib/.libs gdb ./src/.libs/curl ``` @@ -451,10 +451,10 @@ for testing. We have published instructions for such in another repository. Once you have that set up, you can start a server and then run curl against that: -```bash - cd $HOME/code/ech-dev-utils - ./scripts/echsvr.sh -d - ... +```sh +cd $HOME/code/ech-dev-utils +./scripts/echsvr.sh -d +... ``` The ``echsvr.sh`` script supports many ECH-related options. Use ``echsvr.sh -h`` @@ -462,9 +462,9 @@ for details. In another window: -```bash - cd $HOME/code/curl/ - ./src/curl -vvv --insecure --connect-to foo.example.com:8443:localhost:8443 --ech ecl:AD7+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAA== +```sh +cd $HOME/code/curl/ +./src/curl -vvv --insecure --connect-to foo.example.com:8443:localhost:8443 --ech ecl:AD7+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAA== ``` ### Automated use of ``retry_configs`` not supported so far... diff --git a/docs/INSTALL.md b/docs/INSTALL.md index ff0a36d3658c..80fcb9321613 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -275,28 +275,32 @@ If any error occurs during curl installation, try: You can use either autotools or cmake: - ./configure \ - CC=/path/to/djgpp/bin/i586-pc-msdosdjgpp-gcc \ - AR=/path/to/djgpp/bin/i586-pc-msdosdjgpp-ar \ - RANLIB=/path/to/djgpp/bin/i586-pc-msdosdjgpp-ranlib \ - WATT_ROOT=/path/to/djgpp/net/watt \ - --host=i586-pc-msdosdjgpp \ - --with-openssl=/path/to/djgpp \ - --with-zlib=/path/to/djgpp \ - --without-libpsl \ - --disable-shared - - cmake . \ - -DCMAKE_SYSTEM_NAME=DOS \ - -DCMAKE_C_COMPILER_TARGET=i586-pc-msdosdjgpp \ - -DCMAKE_C_COMPILER=/path/to/djgpp/bin/i586-pc-msdosdjgpp-gcc \ - -DWATT_ROOT=/path/to/djgpp/net/watt \ - -DOPENSSL_INCLUDE_DIR=/path/to/djgpp/include \ - -DOPENSSL_SSL_LIBRARY=/path/to/djgpp/lib/libssl.a \ - -DOPENSSL_CRYPTO_LIBRARY=/path/to/djgpp/lib/libcrypto.a \ - -DZLIB_INCLUDE_DIR=/path/to/djgpp/include \ - -DZLIB_LIBRARY=/path/to/djgpp/lib/libz.a \ - -DCURL_USE_LIBPSL=OFF +```sh +./configure \ + CC=/path/to/djgpp/bin/i586-pc-msdosdjgpp-gcc \ + AR=/path/to/djgpp/bin/i586-pc-msdosdjgpp-ar \ + RANLIB=/path/to/djgpp/bin/i586-pc-msdosdjgpp-ranlib \ + WATT_ROOT=/path/to/djgpp/net/watt \ + --host=i586-pc-msdosdjgpp \ + --with-openssl=/path/to/djgpp \ + --with-zlib=/path/to/djgpp \ + --without-libpsl \ + --disable-shared +``` + +```sh +cmake . \ + -DCMAKE_SYSTEM_NAME=DOS \ + -DCMAKE_C_COMPILER_TARGET=i586-pc-msdosdjgpp \ + -DCMAKE_C_COMPILER=/path/to/djgpp/bin/i586-pc-msdosdjgpp-gcc \ + -DWATT_ROOT=/path/to/djgpp/net/watt \ + -DOPENSSL_INCLUDE_DIR=/path/to/djgpp/include \ + -DOPENSSL_SSL_LIBRARY=/path/to/djgpp/lib/libssl.a \ + -DOPENSSL_CRYPTO_LIBRARY=/path/to/djgpp/lib/libcrypto.a \ + -DZLIB_INCLUDE_DIR=/path/to/djgpp/include \ + -DZLIB_LIBRARY=/path/to/djgpp/lib/libz.a \ + -DCURL_USE_LIBPSL=OFF +``` Notes: @@ -310,29 +314,33 @@ Notes: You can use either autotools or cmake: - ./configure \ - CC=/opt/amiga/bin/m68k-amigaos-gcc \ - AR=/opt/amiga/bin/m68k-amigaos-ar \ - RANLIB=/opt/amiga/bin/m68k-amigaos-ranlib \ - --host=m68k-amigaos \ - --with-amissl \ - CFLAGS='-O0 -msoft-float -mcrt=clib2' \ - CPPFLAGS=-I/path/to/AmiSSL/Developer/include \ - LDFLAGS=-L/path/to/AmiSSL/Developer/lib/AmigaOS3 \ - LIBS='-lnet -lm -latomic' \ - --without-libpsl \ - --disable-shared - - cmake . \ - -DAMIGA=1 \ - -DCMAKE_SYSTEM_NAME=Generic \ - -DCMAKE_C_COMPILER_TARGET=m68k-unknown-amigaos \ - -DCMAKE_C_COMPILER=/opt/amiga/bin/m68k-amigaos-gcc \ - -DCMAKE_C_FLAGS='-O0 -msoft-float -mcrt=clib2' \ - -DAMISSL_INCLUDE_DIR=/path/to/AmiSSL/Developer/include \ - -DAMISSL_STUBS_LIBRARY=/path/to/AmiSSL/Developer/lib/AmigaOS3/libamisslstubs.a \ - -DAMISSL_AUTO_LIBRARY=/path/to/AmiSSL/Developer/lib/AmigaOS3/libamisslauto.a \ - -DCURL_USE_LIBPSL=OFF +```sh +./configure \ + CC=/opt/amiga/bin/m68k-amigaos-gcc \ + AR=/opt/amiga/bin/m68k-amigaos-ar \ + RANLIB=/opt/amiga/bin/m68k-amigaos-ranlib \ + --host=m68k-amigaos \ + --with-amissl \ + CFLAGS='-O0 -msoft-float -mcrt=clib2' \ + CPPFLAGS=-I/path/to/AmiSSL/Developer/include \ + LDFLAGS=-L/path/to/AmiSSL/Developer/lib/AmigaOS3 \ + LIBS='-lnet -lm -latomic' \ + --without-libpsl \ + --disable-shared +``` + +```sh +cmake . \ + -DAMIGA=1 \ + -DCMAKE_SYSTEM_NAME=Generic \ + -DCMAKE_C_COMPILER_TARGET=m68k-unknown-amigaos \ + -DCMAKE_C_COMPILER=/opt/amiga/bin/m68k-amigaos-gcc \ + -DCMAKE_C_FLAGS='-O0 -msoft-float -mcrt=clib2' \ + -DAMISSL_INCLUDE_DIR=/path/to/AmiSSL/Developer/include \ + -DAMISSL_STUBS_LIBRARY=/path/to/AmiSSL/Developer/lib/AmigaOS3/libamisslstubs.a \ + -DAMISSL_AUTO_LIBRARY=/path/to/AmiSSL/Developer/lib/AmigaOS3/libamisslauto.a \ + -DCURL_USE_LIBPSL=OFF +``` ## Disabling Specific Protocols in Windows builds @@ -408,18 +416,22 @@ Examples to compile for `aarch64` and API level 29: with CMake, where `ANDROID_NDK_HOME` points into your NDK: - cmake . \ - -DANDROID_ABI=arm64-v8a \ - -DANDROID_PLATFORM=android-29 \ - -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \ - -DCURL_ENABLE_SSL=OFF \ - -DCURL_USE_LIBPSL=OFF +```sh +cmake . \ + -DANDROID_ABI=arm64-v8a \ + -DANDROID_PLATFORM=android-29 \ + -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \ + -DCURL_ENABLE_SSL=OFF \ + -DCURL_USE_LIBPSL=OFF +``` with `configure`, on macOS: -```bash +```sh export ANDROID_NDK_HOME=~/Library/Android/sdk/ndk/25.1.8937393 # Point into your NDK. -export HOST_TAG=darwin-x86_64 # Same tag for Apple Silicon. Other OS values here: https://developer.android.com/ndk/guides/other_build_systems#overview +# Same tag for Apple Silicon. Other OS values here: +# https://developer.android.com/ndk/guides/other_build_systems#overview +export HOST_TAG=darwin-x86_64 export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG export AR=$TOOLCHAIN/bin/llvm-ar export AS=$TOOLCHAIN/bin/llvm-as @@ -443,8 +455,10 @@ install `libssl.a` and `libcrypto.a` to `$TOOLCHAIN/sysroot/usr/lib` and copy `include/openssl` to `$TOOLCHAIN/sysroot/usr/include`. Now you can build curl for Android using OpenSSL like this: -```bash -LIBS="-lssl -lcrypto -lc++" # For OpenSSL/BoringSSL. In general, you need to the SSL/TLS layer's transitive dependencies if you are linking statically. +```sh +# For OpenSSL/BoringSSL. In general, you need to the SSL/TLS layer's transitive +# dependencies if you are linking statically. +LIBS='-lssl -lcrypto -lc++' ./configure --host aarch64-linux-android --with-pic --disable-shared --with-openssl="$TOOLCHAIN/sysroot/usr" ``` @@ -493,9 +507,7 @@ configure with any options you need. Be sure and specify the `--host` and of cross-compiling for the IBM 405GP PowerPC processor using the toolchain on Linux. -```bash -#! /bin/sh - +```sh export PATH=$PATH:/opt/hardhat/devkit/ppc/405/bin export CPPFLAGS="-I/opt/hardhat/devkit/ppc/405/target/usr/include" export AR=ppc_405-ar @@ -505,11 +517,12 @@ export RANLIB=ppc_405-ranlib export CC=ppc_405-gcc export NM=ppc_405-nm -./configure --target=powerpc-hardhat-linux - --host=powerpc-hardhat-linux - --build=i586-pc-linux-gnu - --prefix=/opt/hardhat/devkit/ppc/405/target/usr/local - --exec-prefix=/usr/local +./configure \ + --target=powerpc-hardhat-linux + --host=powerpc-hardhat-linux + --build=i586-pc-linux-gnu + --prefix=/opt/hardhat/devkit/ppc/405/target/usr/local + --exec-prefix=/usr/local ``` The `--prefix` parameter specifies where curl gets installed. If `configure` From 22b9f77e38cda5d7721059664140b37c74ed1d3f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 17:44:47 +0200 Subject: [PATCH 149/465] GHA/curl-for-win: use `DOCKER_IMAGE_STABLE` Replacing the hard-wired stable image. After this patch, it will automatically follow upstream updates. Follow-up to https://github.com/curl/curl-for-win/commit/6870bc1b35baff03168af1d0506ec8610851a819 Follow-up to https://github.com/curl/curl-for-win/commit/5a25df253da4f68de52b14a2e612df5fc60b8aa6 Closes #18709 --- .github/workflows/curl-for-win.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/curl-for-win.yml b/.github/workflows/curl-for-win.yml index 0090c7d6e22e..e29a2a66e85d 100644 --- a/.github/workflows/curl-for-win.yml +++ b/.github/workflows/curl-for-win.yml @@ -58,17 +58,17 @@ jobs: mv curl-for-win/* . export CW_CONFIG='-main-werror-unitybatch-linux-a64-x64-gcc' export CW_REVISION="${GITHUB_SHA}" - DOCKER_IMAGE='debian:bookworm-slim' + . ./_versions.sh export CW_CCSUFFIX='-15' export CW_GCCSUFFIX='-12' sudo podman image trust set --type reject default sudo podman image trust set --type accept docker.io/library - time podman pull "${DOCKER_IMAGE}" + time podman pull "${DOCKER_IMAGE_STABLE}" podman images --digests time podman run --volume "$(pwd):$(pwd)" --workdir "$(pwd)" \ --env-file <(env | grep -a -E \ '^(CW_|GITHUB_)') \ - "${DOCKER_IMAGE}" \ + "${DOCKER_IMAGE_STABLE}" \ sh -c ./_ci-linux-debian.sh linux-musl-llvm: From b011e3fcfb06d6c0278595ee2ee297036fbe9793 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 24 Sep 2025 06:52:52 +0200 Subject: [PATCH 150/465] vssh: drop support for wolfSSH The implementation was incomplete and lesser than the other backends. No one ever reported a bug or requested enhancements for this, indicating that this backend was never used. Closes #18700 --- .circleci/config.yml | 38 - .github/scripts/cmp-config.pl | 2 - .github/workflows/linux.yml | 34 +- .github/workflows/macos.yml | 2 +- CMake/FindWolfSSH.cmake | 65 -- CMakeLists.txt | 21 +- Makefile.am | 1 - configure.ac | 31 - docs/INSTALL-CMAKE.md | 3 - docs/KNOWN_BUGS | 16 - docs/tests/FILEFORMAT.md | 1 - lib/Makefile.inc | 3 +- lib/curl_config.h.cmake | 3 - lib/curl_setup.h | 2 +- lib/url.c | 2 +- lib/version.c | 4 +- lib/vssh/ssh.h | 11 - lib/vssh/wolfssh.c | 1225 --------------------------------- packages/OS400/ccsidcurl.c | 2 +- scripts/schemetable.c | 2 +- tests/runtests.pl | 3 - 21 files changed, 13 insertions(+), 1458 deletions(-) delete mode 100644 CMake/FindWolfSSH.cmake delete mode 100644 lib/vssh/wolfssh.c diff --git a/.circleci/config.yml b/.circleci/config.yml index c67f572c527e..1603e7f7d0f0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -61,20 +61,6 @@ commands: ./configure --disable-dependency-tracking --enable-tls13 --enable-all --enable-harden --prefix=$HOME/wssl make install - install-wolfssh: - steps: - - run: - command: | - # renovate: datasource=github-tags depName=wolfSSL/wolfssh versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com - WOLFSSH_VERSION=1.4.19 - echo "Installing wolfSSH $WOLFSSH_VERSION" - curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ - --location "https://github.com/wolfSSL/wolfssh/archive/v$WOLFSSH_VERSION-stable.tar.gz" | tar -xz - cd wolfssh-$WOLFSSH_VERSION-stable - ./autogen.sh - ./configure --disable-dependency-tracking --with-wolfssl=$HOME/wssl --prefix=$HOME/wssh --enable-scp --enable-sftp --disable-term --disable-examples - make install - configure: steps: - run: @@ -120,16 +106,6 @@ commands: --with-openssl --enable-ares \ || { tail -1000 config.log; false; } - configure-wolfssh: - steps: - - run: - command: | - autoreconf -fi - LDFLAGS="-Wl,-rpath,$HOME/wssh/lib" \ - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror --enable-warnings \ - --with-wolfssl=$HOME/wssl --with-wolfssh=$HOME/wssh \ - || { tail -1000 config.log; false; } - configure-cares-debug: steps: - run: @@ -171,16 +147,6 @@ jobs: - configure-openssl-no-verbose - build - wolfssh: - executor: ubuntu - steps: - - checkout - - install-deps - - install-wolfssl - - install-wolfssh - - configure-wolfssh - - build - no-proxy: executor: ubuntu steps: @@ -254,10 +220,6 @@ workflows: jobs: - no-verbose - wolfssl-wolfssh: - jobs: - - wolfssh - arm-openssl: jobs: - arm diff --git a/.github/scripts/cmp-config.pl b/.github/scripts/cmp-config.pl index 88df37b795bb..5fb8c0abdcaf 100755 --- a/.github/scripts/cmp-config.pl +++ b/.github/scripts/cmp-config.pl @@ -56,7 +56,6 @@ '#define HAVE_LIBSSH' => 1, '#define HAVE_LIBSSH2 1' => 1, '#define HAVE_LIBSSL 1' => 1, - '#define HAVE_LIBWOLFSSH' => 1, '#define HAVE_LIBZSTD 1' => 1, '#define HAVE_NGHTTP2_NGHTTP2_H 1' => 1, '#define HAVE_NGHTTP3_NGHTTP3_H 1' => 1, @@ -78,7 +77,6 @@ '#define HAVE_SYS_STAT_H 1' => 1, '#define HAVE_SYS_XATTR_H 1' => 1, '#define HAVE_UNICODE_UIDNA_H 1' => 1, - '#define HAVE_WOLFSSH_SSH_H 1' => 1, '#define HAVE_WOLFSSL_SET_QUIC_USE_LEGACY_CODEPOINT 1' => 1, '#define HAVE_ZSTD 1' => 1, '#define HAVE_ZSTD_H 1' => 1, diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 7598137a9548..20a5849d4dbd 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -41,8 +41,6 @@ env: LIBRESSL_VERSION: 4.1.0 # renovate: datasource=github-tags depName=wolfSSL/wolfssl versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com WOLFSSL_VERSION: 5.8.2 - # renovate: datasource=github-tags depName=wolfSSL/wolfssh versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com - WOLFSSH_VERSION: 1.4.19 # renovate: datasource=github-tags depName=Mbed-TLS/mbedtls versioning=semver registryUrl=https://github.com MBEDTLS_VERSION: 3.6.4 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com @@ -94,8 +92,8 @@ jobs: - name: 'wolfssl-opensslextra valgrind' install_packages: valgrind - install_steps: wolfssl-opensslextra wolfssh - configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --with-wolfssh=/home/runner/wolfssh --enable-ech --enable-debug + install_steps: wolfssl-opensslextra + configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --enable-ech --enable-debug - name: 'mbedtls valgrind' install_packages: libnghttp2-dev libidn2-dev libldap-dev valgrind @@ -186,7 +184,7 @@ jobs: --disable-dict --disable-gopher --disable-ldap --disable-telnet --disable-imap --disable-pop3 --disable-smtp --without-librtmp --disable-rtsp - --without-libssh2 --without-libssh --without-wolfssh + --without-libssh2 --without-libssh --disable-tftp --disable-ftp --disable-file --disable-smb - name: 'openssl torture !FTP' @@ -405,31 +403,10 @@ jobs: --location "https://github.com/wolfSSL/wolfssl/archive/v${WOLFSSL_VERSION}-stable.tar.gz" | tar -xz cd "wolfssl-${WOLFSSL_VERSION}-stable" ./autogen.sh - ./configure --disable-dependency-tracking --enable-tls13 --enable-harden --enable-wolfssh --enable-ech --enable-opensslextra \ + ./configure --disable-dependency-tracking --enable-tls13 --enable-harden --enable-ech --enable-opensslextra \ --disable-benchmark --disable-crypttests --disable-examples --prefix=/home/runner/wolfssl-opensslextra make install - - name: 'cache wolfssh' - if: ${{ contains(matrix.build.install_steps, 'wolfssh') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - id: cache-wolfssh - env: - cache-name: cache-wolfssh - with: - path: ~/wolfssh - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.WOLFSSH_VERSION }}-${{ env.WOLFSSL_VERSION }} - - - name: 'build wolfssh' - if: ${{ contains(matrix.build.install_steps, 'wolfssh') && steps.cache-wolfssh.outputs.cache-hit != 'true' }} - run: | - curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ - --location "https://github.com/wolfSSL/wolfssh/archive/v${WOLFSSH_VERSION}-stable.tar.gz" | tar -xz - cd "wolfssh-${WOLFSSH_VERSION}-stable" - ./autogen.sh - ./configure --disable-dependency-tracking --with-wolfssl=/home/runner/wolfssl-opensslextra --enable-scp --enable-sftp --disable-term \ - --disable-examples --prefix=/home/runner/wolfssh - make install - - name: 'cache mbedtls' if: ${{ contains(matrix.build.install_steps, 'mbedtls') }} uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 @@ -691,9 +668,6 @@ jobs: TFLAGS: '${{ matrix.build.tflags }}' run: | if [ "${TEST_TARGET}" = 'test-ci' ]; then - if [[ "${MATRIX_INSTALL_STEPS}" = *'wolfssh'* ]]; then - TFLAGS+=' ~SFTP' # curl: (79) wolfssh SFTP connect error -1051 / WS_MATCH_KEY_ALGO_E / cannot match key algo with peer - fi if [[ "${MATRIX_INSTALL_PACKAGES}" = *'valgrind'* ]]; then TFLAGS+=' -j6' if [[ "${MATRIX_INSTALL_PACKAGES}" = *'heimdal-dev'* ]]; then diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 0eb8f7e8423e..ee8cec7d70bb 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -253,7 +253,7 @@ jobs: --disable-ldap --disable-pop3 --without-librtmp --disable-rtsp --disable-shared --disable-smb --disable-smtp --disable-telnet --disable-tftp --disable-unix-sockets --without-brotli --without-gssapi --without-libidn2 --without-libpsl --without-librtmp - --without-libssh2 --without-libssh --without-wolfssh + --without-libssh2 --without-libssh --without-nghttp2 --disable-ntlm --without-ssl --without-zlib --without-zstd macos-version-min: '10.15' # Catalina (2019) diff --git a/CMake/FindWolfSSH.cmake b/CMake/FindWolfSSH.cmake deleted file mode 100644 index 98de656b923a..000000000000 --- a/CMake/FindWolfSSH.cmake +++ /dev/null @@ -1,65 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.se/docs/copyright.html. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -# SPDX-License-Identifier: curl -# -########################################################################### -# Find the wolfSSH library -# -# Input variables: -# -# - `WOLFSSH_INCLUDE_DIR`: The wolfSSH include directory. -# - `WOLFSSH_LIBRARY`: Path to `wolfssh` library. -# -# Result variables: -# -# - `WOLFSSH_FOUND`: System has wolfSSH. -# - `WOLFSSH_INCLUDE_DIRS`: The wolfSSH include directories. -# - `WOLFSSH_LIBRARIES`: The wolfSSH library names. -# - `WOLFSSH_VERSION`: Version of wolfSSH. - -find_path(WOLFSSH_INCLUDE_DIR NAMES "wolfssh/ssh.h") -find_library(WOLFSSH_LIBRARY NAMES "wolfssh" "libwolfssh") - -unset(WOLFSSH_VERSION CACHE) -if(WOLFSSH_INCLUDE_DIR AND EXISTS "${WOLFSSH_INCLUDE_DIR}/wolfssh/version.h") - set(_version_regex "#[\t ]*define[\t ]+LIBWOLFSSH_VERSION_STRING[\t ]+\"([^\"]*)\"") - file(STRINGS "${WOLFSSH_INCLUDE_DIR}/wolfssh/version.h" _version_str REGEX "${_version_regex}") - string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}") - set(WOLFSSH_VERSION "${_version_str}") - unset(_version_regex) - unset(_version_str) -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(WolfSSH - REQUIRED_VARS - WOLFSSH_INCLUDE_DIR - WOLFSSH_LIBRARY - VERSION_VAR - WOLFSSH_VERSION -) - -if(WOLFSSH_FOUND) - set(WOLFSSH_INCLUDE_DIRS ${WOLFSSH_INCLUDE_DIR}) - set(WOLFSSH_LIBRARIES ${WOLFSSH_LIBRARY}) -endif() - -mark_as_advanced(WOLFSSH_INCLUDE_DIR WOLFSSH_LIBRARY) diff --git a/CMakeLists.txt b/CMakeLists.txt index f817b61a81e9..115eaa5f3419 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1391,23 +1391,6 @@ if(NOT USE_LIBSSH2 AND CURL_USE_LIBSSH) set(USE_LIBSSH ON) endif() -# wolfSSH -option(CURL_USE_WOLFSSH "Use wolfSSH" OFF) -mark_as_advanced(CURL_USE_WOLFSSH) -set(USE_WOLFSSH OFF) -if(NOT USE_LIBSSH2 AND NOT USE_LIBSSH AND CURL_USE_WOLFSSH) - if(USE_WOLFSSL) - find_package(WolfSSH) - if(WOLFSSH_FOUND) - set(CURL_LIBS ${WOLFSSH_LIBRARIES} ${CURL_LIBS}) # keep it before TLS-crypto, compression - include_directories(SYSTEM ${WOLFSSH_INCLUDE_DIRS}) - set(USE_WOLFSSH ON) - endif() - else() - message(WARNING "wolfSSH requires wolfSSL. Skipping.") - endif() -endif() - option(CURL_USE_GSASL "Use libgsasl" OFF) mark_as_advanced(CURL_USE_GSASL) if(CURL_USE_GSASL) @@ -2144,8 +2127,8 @@ curl_add_if("SMBS" NOT CURL_DISABLE_SMB AND _ssl_enabled AND _use_curl_ntlm_core AND (SIZEOF_CURL_OFF_T GREATER 4)) curl_add_if("SMTP" NOT CURL_DISABLE_SMTP) curl_add_if("SMTPS" NOT CURL_DISABLE_SMTP AND _ssl_enabled) -curl_add_if("SCP" USE_LIBSSH2 OR USE_LIBSSH OR USE_WOLFSSH) -curl_add_if("SFTP" USE_LIBSSH2 OR USE_LIBSSH OR USE_WOLFSSH) +curl_add_if("SCP" USE_LIBSSH2 OR USE_LIBSSH) +curl_add_if("SFTP" USE_LIBSSH2 OR USE_LIBSSH) curl_add_if("IPFS" NOT CURL_DISABLE_IPFS) curl_add_if("IPNS" NOT CURL_DISABLE_IPFS) curl_add_if("RTSP" NOT CURL_DISABLE_RTSP) diff --git a/Makefile.am b/Makefile.am index fd97e61d9df3..76873854160c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,7 +50,6 @@ CMAKE_DIST = \ CMake/FindNettle.cmake \ CMake/FindQuiche.cmake \ CMake/FindRustls.cmake \ - CMake/FindWolfSSH.cmake \ CMake/FindWolfSSL.cmake \ CMake/FindZstd.cmake \ CMake/Macros.cmake \ diff --git a/configure.ac b/configure.ac index 922978bfc106..56ac66de2369 100644 --- a/configure.ac +++ b/configure.ac @@ -2290,12 +2290,6 @@ AS_HELP_STRING([--with-libssh=PATH],[Where to look for libssh, PATH points to th AS_HELP_STRING([--with-libssh], [enable libssh]), OPT_LIBSSH=$withval, OPT_LIBSSH=no) -OPT_WOLFSSH=off -AC_ARG_WITH(wolfssh,dnl -AS_HELP_STRING([--with-wolfssh=PATH],[Where to look for wolfssh, PATH points to the wolfSSH installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) -AS_HELP_STRING([--with-wolfssh], [enable wolfssh]), - OPT_WOLFSSH=$withval, OPT_WOLFSSH=no) - if test X"$OPT_LIBSSH2" != Xno; then dnl backup the pre-libssh2 variables CLEANLDFLAGS="$LDFLAGS" @@ -2453,28 +2447,6 @@ elif test X"$OPT_LIBSSH" != Xno; then CPPFLAGS=$CLEANCPPFLAGS LIBS=$CLEANLIBS fi -elif test X"$OPT_WOLFSSH" != Xno; then - dnl backup the pre-wolfssh variables - CLEANLDFLAGS="$LDFLAGS" - CLEANLDFLAGSPC="$LDFLAGSPC" - CLEANCPPFLAGS="$CPPFLAGS" - CLEANLIBS="$LIBS" - - if test "$OPT_WOLFSSH" != yes; then - WOLFCONFIG="$OPT_WOLFSSH/bin/wolfssh-config" - WOLFSSH_LIBS=`$WOLFCONFIG --libs` - LDFLAGS="$LDFLAGS $WOLFSSH_LIBS" - LDFLAGSPC="$LDFLAGSPC $WOLFSSH_LIBS" - CPPFLAGS="$CPPFLAGS `$WOLFCONFIG --cflags`" - fi - - AC_CHECK_LIB(wolfssh, wolfSSH_Init) - - AC_CHECK_HEADERS(wolfssh/ssh.h, - curl_ssh_msg="enabled (wolfSSH)" - AC_DEFINE(USE_WOLFSSH, 1, [if wolfSSH is in use]) - USE_WOLFSSH=1 - ) fi dnl ********************************************************************** @@ -5501,9 +5473,6 @@ if test "x$USE_LIBSSH" = "x1"; then SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP" SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" fi -if test "x$USE_WOLFSSH" = "x1"; then - SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP" -fi if test "x$CURL_DISABLE_IPFS" != "x1"; then SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS IPFS IPNS" fi diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index 94a19c71c749..566fee742314 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -363,7 +363,6 @@ Details via CMake - `CURL_USE_PKGCONFIG`: Enable `pkg-config` to detect dependencies. Default: `ON` for Unix (except Android, Apple devices), vcpkg, MinGW if not cross-compiling. - `CURL_USE_RUSTLS`: Enable Rustls for SSL/TLS. Default: `OFF` - `CURL_USE_SCHANNEL`: Enable Windows native SSL/TLS (Schannel). Default: `OFF` -- `CURL_USE_WOLFSSH`: Use wolfSSH. Default: `OFF` - `CURL_USE_WOLFSSL`: Enable wolfSSL for SSL/TLS. Default: `OFF` - `CURL_ZLIB`: Use zlib (`ON`, `OFF` or `AUTO`). Default: `AUTO` - `CURL_ZSTD`: Use zstd (`ON`, `OFF` or `AUTO`). Default: `AUTO` @@ -447,8 +446,6 @@ Details via CMake - `RUSTLS_INCLUDE_DIR`: The Rustls include directory. - `RUSTLS_LIBRARY`: Path to `rustls` library. - `WATT_ROOT`: Set this variable to the root installation of Watt-32. -- `WOLFSSH_INCLUDE_DIR`: The wolfSSH include directory. -- `WOLFSSH_LIBRARY`: Path to `wolfssh` library. - `WOLFSSL_INCLUDE_DIR`: The wolfSSL include directory. - `WOLFSSL_LIBRARY`: Path to `wolfssl` library. - `ZSTD_INCLUDE_DIR`: The zstd include directory. diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 170132f507d3..1eb5716f8b94 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -60,11 +60,9 @@ problems may have been fixed or changed somewhat since this was written. 9. SFTP and SCP 9.1 SFTP does not do CURLOPT_POSTQUOTE correct - 9.2 wolfssh: publickey auth does not work 9.3 Remote recursive folder creation with SFTP 9.4 libssh blocking and infinite loop problem 9.5 Cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!" - 9.6 wolfssh: all tests fail 10. Connection 10.1 --interface with link-scoped IPv6 address @@ -400,14 +398,6 @@ problems may have been fixed or changed somewhat since this was written. report but it cannot be accepted as-is. See https://curl.se/bug/view.cgi?id=748 -9.2 wolfssh: publickey auth does not work - - When building curl to use the wolfSSH backend for SFTP, the publickey - authentication does not work. This is simply functionality not written for curl - yet, the necessary API for make this work is provided by wolfSSH. - - See https://github.com/curl/curl/issues/4820 - 9.3 Remote recursive folder creation with SFTP On this servers, the curl fails to create directories on the remote server @@ -429,12 +419,6 @@ problems may have been fixed or changed somewhat since this was written. https://github.com/curl/curl/issues/11244 -9.6 wolfssh: all tests fail - - Something fundamental stops them all from working properly. - - https://github.com/curl/curl/issues/16794 - 10. Connection 10.1 --interface with link-scoped IPv6 address diff --git a/docs/tests/FILEFORMAT.md b/docs/tests/FILEFORMAT.md index b28e819ebe3a..91aa9a587028 100644 --- a/docs/tests/FILEFORMAT.md +++ b/docs/tests/FILEFORMAT.md @@ -513,7 +513,6 @@ Features testable here are: - `wakeup` - `win32` - `WinIDN` -- `wolfssh` - `wolfssl` - `xattr` - `zstd` diff --git a/lib/Makefile.inc b/lib/Makefile.inc index c17a8d9c3cad..6391eb2c4351 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -127,8 +127,7 @@ LIB_VQUIC_HFILES = \ LIB_VSSH_CFILES = \ vssh/libssh.c \ vssh/libssh2.c \ - vssh/curl_path.c \ - vssh/wolfssh.c + vssh/curl_path.c LIB_VSSH_HFILES = \ vssh/curl_path.h \ diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index ca516710e42c..30183c20092f 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -706,9 +706,6 @@ ${SIZEOF_TIME_T_CODE} /* if libssh2 is in use */ #cmakedefine USE_LIBSSH2 1 -/* if wolfssh is in use */ -#cmakedefine USE_WOLFSSH 1 - /* if libpsl is in use */ #cmakedefine USE_LIBPSL 1 diff --git a/lib/curl_setup.h b/lib/curl_setup.h index e49c57231d2f..55c65c99f696 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -776,7 +776,7 @@ # endif #endif -#if defined(USE_LIBSSH2) || defined(USE_LIBSSH) || defined(USE_WOLFSSH) +#if defined(USE_LIBSSH2) || defined(USE_LIBSSH) #define USE_SSH #endif diff --git a/lib/url.c b/lib/url.c index a03a111995e2..6af2b7fb8b75 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1611,7 +1611,7 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme, #else NULL, #endif -#if defined(USE_SSH) && !defined(USE_WOLFSSH) +#if defined(USE_SSH) &Curl_handler_scp, #else NULL, diff --git a/lib/version.c b/lib/version.c index a2d486720091..8158f26e735b 100644 --- a/lib/version.c +++ b/lib/version.c @@ -368,10 +368,8 @@ static const char * const supported_protocols[] = { #ifndef CURL_DISABLE_RTSP "rtsp", #endif -#if defined(USE_SSH) && !defined(USE_WOLFSSH) - "scp", -#endif #ifdef USE_SSH + "scp", "sftp", #endif #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) diff --git a/lib/vssh/ssh.h b/lib/vssh/ssh.h index 75b31bd931f5..9a5f1b7e3187 100644 --- a/lib/vssh/ssh.h +++ b/lib/vssh/ssh.h @@ -34,9 +34,6 @@ #define SSH_SUPPRESS_DEPRECATED #include #include -#elif defined(USE_WOLFSSH) -#include -#include #endif #include "curl_path.h" @@ -211,14 +208,6 @@ struct ssh_conn { struct libssh2_agent_publickey *sshagent_identity; struct libssh2_agent_publickey *sshagent_prev_identity; LIBSSH2_KNOWNHOSTS *kh; -#elif defined(USE_WOLFSSH) - CURLcode actualcode; /* the actual error code */ - WOLFSSH *ssh_session; - WOLFSSH_CTX *ctx; - word32 handleSz; - byte handle[WOLFSSH_MAX_HANDLE]; - curl_off_t offset; - BIT(initialised); #endif /* USE_LIBSSH */ BIT(authed); /* the connection has been authenticated fine */ BIT(acceptfail); /* used by the SFTP_QUOTE (continue if diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c deleted file mode 100644 index 7cd0402a99d2..000000000000 --- a/lib/vssh/wolfssh.c +++ /dev/null @@ -1,1225 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ - -#include "../curl_setup.h" - -#ifdef USE_WOLFSSH - -#include - -#include "../urldata.h" -#include "../url.h" -#include "../cfilters.h" -#include "../connect.h" -#include "../sendf.h" -#include "../progress.h" -#include "curl_path.h" -#include "../transfer.h" -#include "../speedcheck.h" -#include "../select.h" -#include "../multiif.h" -#include "../curlx/warnless.h" -#include "../strdup.h" - -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" -#include "../curl_memory.h" -#include "../memdebug.h" - -static CURLcode wssh_connect(struct Curl_easy *data, bool *done); -static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done); -static CURLcode wssh_do(struct Curl_easy *data, bool *done); -#if 0 -static CURLcode wscp_done(struct Curl_easy *data, - CURLcode, bool premature); -static CURLcode wscp_doing(struct Curl_easy *data, - bool *dophase_done); -static CURLcode wscp_disconnect(struct Curl_easy *data, - struct connectdata *conn, - bool dead_connection); -#endif -static CURLcode wsftp_done(struct Curl_easy *data, - CURLcode, bool premature); -static CURLcode wsftp_doing(struct Curl_easy *data, - bool *dophase_done); -static CURLcode wsftp_disconnect(struct Curl_easy *data, - struct connectdata *conn, - bool dead); -static CURLcode wssh_pollset(struct Curl_easy *data, - struct easy_pollset *ps); -static CURLcode wssh_setup_connection(struct Curl_easy *data, - struct connectdata *conn); -static void wssh_sshc_cleanup(struct ssh_conn *sshc); - -#if 0 -/* - * SCP protocol handler. - */ - -const struct Curl_handler Curl_handler_scp = { - "SCP", /* scheme */ - wssh_setup_connection, /* setup_connection */ - wssh_do, /* do_it */ - wscp_done, /* done */ - ZERO_NULL, /* do_more */ - wssh_connect, /* connect_it */ - wssh_multi_statemach, /* connecting */ - wscp_doing, /* doing */ - wssh_pollset, /* proto_pollset */ - wssh_pollset, /* doing_pollset */ - ZERO_NULL, /* domore_pollset */ - wssh_pollset, /* perform_pollset */ - wscp_disconnect, /* disconnect */ - ZERO_NULL, /* write_resp */ - ZERO_NULL, /* write_resp_hd */ - ZERO_NULL, /* connection_check */ - ZERO_NULL, /* attach connection */ - ZERO_NULL, /* follow */ - PORT_SSH, /* defport */ - CURLPROTO_SCP, /* protocol */ - PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION - | PROTOPT_NOURLQUERY /* flags */ -}; - -#endif - -/* - * SFTP protocol handler. - */ - -const struct Curl_handler Curl_handler_sftp = { - "SFTP", /* scheme */ - wssh_setup_connection, /* setup_connection */ - wssh_do, /* do_it */ - wsftp_done, /* done */ - ZERO_NULL, /* do_more */ - wssh_connect, /* connect_it */ - wssh_multi_statemach, /* connecting */ - wsftp_doing, /* doing */ - wssh_pollset, /* proto_pollset */ - wssh_pollset, /* doing_pollset */ - ZERO_NULL, /* domore_pollset */ - wssh_pollset, /* perform_pollset */ - wsftp_disconnect, /* disconnect */ - ZERO_NULL, /* write_resp */ - ZERO_NULL, /* write_resp_hd */ - ZERO_NULL, /* connection_check */ - ZERO_NULL, /* attach connection */ - ZERO_NULL, /* follow */ - PORT_SSH, /* defport */ - CURLPROTO_SFTP, /* protocol */ - CURLPROTO_SFTP, /* family */ - PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION - | PROTOPT_NOURLQUERY /* flags */ -}; - -/* - * SSH State machine related code - */ -/* This is the ONLY way to change SSH state! */ -static void wssh_state(struct Curl_easy *data, - struct ssh_conn *sshc, - sshstate nowstate) -{ -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - /* for debug purposes */ - static const char * const names[] = { - "SSH_STOP", - "SSH_INIT", - "SSH_S_STARTUP", - "SSH_HOSTKEY", - "SSH_AUTHLIST", - "SSH_AUTH_PKEY_INIT", - "SSH_AUTH_PKEY", - "SSH_AUTH_PASS_INIT", - "SSH_AUTH_PASS", - "SSH_AUTH_AGENT_INIT", - "SSH_AUTH_AGENT_LIST", - "SSH_AUTH_AGENT", - "SSH_AUTH_HOST_INIT", - "SSH_AUTH_HOST", - "SSH_AUTH_KEY_INIT", - "SSH_AUTH_KEY", - "SSH_AUTH_GSSAPI", - "SSH_AUTH_DONE", - "SSH_SFTP_INIT", - "SSH_SFTP_REALPATH", - "SSH_SFTP_QUOTE_INIT", - "SSH_SFTP_POSTQUOTE_INIT", - "SSH_SFTP_QUOTE", - "SSH_SFTP_NEXT_QUOTE", - "SSH_SFTP_QUOTE_STAT", - "SSH_SFTP_QUOTE_SETSTAT", - "SSH_SFTP_QUOTE_SYMLINK", - "SSH_SFTP_QUOTE_MKDIR", - "SSH_SFTP_QUOTE_RENAME", - "SSH_SFTP_QUOTE_RMDIR", - "SSH_SFTP_QUOTE_UNLINK", - "SSH_SFTP_QUOTE_STATVFS", - "SSH_SFTP_GETINFO", - "SSH_SFTP_FILETIME", - "SSH_SFTP_TRANS_INIT", - "SSH_SFTP_UPLOAD_INIT", - "SSH_SFTP_CREATE_DIRS_INIT", - "SSH_SFTP_CREATE_DIRS", - "SSH_SFTP_CREATE_DIRS_MKDIR", - "SSH_SFTP_READDIR_INIT", - "SSH_SFTP_READDIR", - "SSH_SFTP_READDIR_LINK", - "SSH_SFTP_READDIR_BOTTOM", - "SSH_SFTP_READDIR_DONE", - "SSH_SFTP_DOWNLOAD_INIT", - "SSH_SFTP_DOWNLOAD_STAT", - "SSH_SFTP_CLOSE", - "SSH_SFTP_SHUTDOWN", - "SSH_SCP_TRANS_INIT", - "SSH_SCP_UPLOAD_INIT", - "SSH_SCP_DOWNLOAD_INIT", - "SSH_SCP_DOWNLOAD", - "SSH_SCP_DONE", - "SSH_SCP_SEND_EOF", - "SSH_SCP_WAIT_EOF", - "SSH_SCP_WAIT_CLOSE", - "SSH_SCP_CHANNEL_FREE", - "SSH_SESSION_DISCONNECT", - "SSH_SESSION_FREE", - "QUIT" - }; - - /* a precaution to make sure the lists are in sync */ - DEBUGASSERT(CURL_ARRAYSIZE(names) == SSH_LAST); - - if(sshc->state != nowstate) { - infof(data, "wolfssh %p state change from %s to %s", - (void *)sshc, names[sshc->state], names[nowstate]); - } -#endif - (void)data; - sshc->state = nowstate; -} - -static CURLcode wscp_send(struct Curl_easy *data, int sockindex, - const void *mem, size_t len, bool eos, - size_t *pnwritten) -{ - (void)data; - (void)sockindex; /* we only support SCP on the fixed known primary socket */ - (void)mem; - (void)len; - (void)eos; - *pnwritten = 0; - return CURLE_OK; -} - -static CURLcode wscp_recv(struct Curl_easy *data, int sockindex, - char *mem, size_t len, size_t *pnread) -{ - (void)data; - (void)sockindex; /* we only support SCP on the fixed known primary socket */ - (void)mem; - (void)len; - *pnread = 0; - - return CURLE_OK; -} - -/* return number of sent bytes */ -static CURLcode wsftp_send(struct Curl_easy *data, int sockindex, - const void *mem, size_t len, bool eos, - size_t *pnwritten) -{ - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - word32 offset[2]; - int rc; - (void)sockindex; - (void)eos; - - *pnwritten = 0; - if(!sshc) - return CURLE_FAILED_INIT; - - offset[0] = (word32)sshc->offset & 0xFFFFFFFF; - offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF; - - rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle, - sshc->handleSz, - &offset[0], - (byte *)CURL_UNCONST(mem), (word32)len); - - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - conn->waitfor = KEEP_RECV; - return CURLE_AGAIN; - } - else if(rc == WS_WANT_WRITE) { - conn->waitfor = KEEP_SEND; - return CURLE_AGAIN; - } - if(rc < 0) { - failf(data, "wolfSSH_SFTP_SendWritePacket returned %d", rc); - return CURLE_SEND_ERROR; - } - DEBUGASSERT(rc == (int)len); - *pnwritten = (size_t)rc; - sshc->offset += *pnwritten; - infof(data, "sent %zu bytes SFTP from offset %" FMT_OFF_T, - *pnwritten, sshc->offset); - return CURLE_OK; -} - -/* - * Return number of received (decrypted) bytes - * or <0 on error - */ -static CURLcode wsftp_recv(struct Curl_easy *data, int sockindex, - char *mem, size_t len, size_t *pnread) -{ - int rc; - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - word32 offset[2]; - (void)sockindex; - - *pnread = 0; - if(!sshc) - return CURLE_FAILED_INIT; - - offset[0] = (word32)sshc->offset & 0xFFFFFFFF; - offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF; - - rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle, - sshc->handleSz, - &offset[0], - (byte *)mem, (word32)len); - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - conn->waitfor = KEEP_RECV; - return CURLE_AGAIN; - } - else if(rc == WS_WANT_WRITE) { - conn->waitfor = KEEP_SEND; - return CURLE_AGAIN; - } - - DEBUGASSERT(rc <= (int)len); - - if(rc < 0) { - failf(data, "wolfSSH_SFTP_SendReadPacket returned %d", rc); - return CURLE_RECV_ERROR; - } - *pnread = (size_t)rc; - sshc->offset += *pnread; - return CURLE_OK; -} - -static void wssh_easy_dtor(void *key, size_t klen, void *entry) -{ - struct SSHPROTO *sshp = entry; - (void)key; - (void)klen; - Curl_safefree(sshp->path); - free(sshp); -} - -static void wssh_conn_dtor(void *key, size_t klen, void *entry) -{ - struct ssh_conn *sshc = entry; - (void)key; - (void)klen; - wssh_sshc_cleanup(sshc); - free(sshc); -} - -/* - * SSH setup and connection - */ -static CURLcode wssh_setup_connection(struct Curl_easy *data, - struct connectdata *conn) -{ - struct ssh_conn *sshc; - struct SSHPROTO *sshp; - (void)conn; - - sshc = calloc(1, sizeof(*sshc)); - if(!sshc) - return CURLE_OUT_OF_MEMORY; - - sshc->initialised = TRUE; - if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, wssh_conn_dtor)) - return CURLE_OUT_OF_MEMORY; - - sshp = calloc(1, sizeof(*sshp)); - if(!sshp || - Curl_meta_set(data, CURL_META_SSH_EASY, sshp, wssh_easy_dtor)) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; -} - -static int userauth(byte authtype, - WS_UserAuthData* authdata, - void *ctx) -{ - struct Curl_easy *data = ctx; - DEBUGF(infof(data, "wolfssh callback: type %s", - authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" : - "PUBLICCKEY")); - if(authtype == WOLFSSH_USERAUTH_PASSWORD) { - authdata->sf.password.password = (byte *)data->conn->passwd; - authdata->sf.password.passwordSz = (word32) strlen(data->conn->passwd); - } - - return 0; -} - -static CURLcode wssh_connect(struct Curl_easy *data, bool *done) -{ - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int rc; - - if(!sshc || !sshp) - return CURLE_FAILED_INIT; - - /* We default to persistent connections. We set this already in this connect - function to make the reuse checks properly be able to check this bit. */ - connkeep(conn, "SSH default"); - - if(conn->handler->protocol & CURLPROTO_SCP) { - conn->recv[FIRSTSOCKET] = wscp_recv; - conn->send[FIRSTSOCKET] = wscp_send; - } - else { - conn->recv[FIRSTSOCKET] = wsftp_recv; - conn->send[FIRSTSOCKET] = wsftp_send; - } - sshc->ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); - if(!sshc->ctx) { - failf(data, "No wolfSSH context"); - goto error; - } - - sshc->ssh_session = wolfSSH_new(sshc->ctx); - if(!sshc->ssh_session) { - failf(data, "No wolfSSH session"); - goto error; - } - - rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user); - if(rc != WS_SUCCESS) { - failf(data, "wolfSSH failed to set username"); - goto error; - } - - /* set callback for authentication */ - wolfSSH_SetUserAuth(sshc->ctx, userauth); - wolfSSH_SetUserAuthCtx(sshc->ssh_session, data); - - rc = wolfSSH_set_fd(sshc->ssh_session, (int)sock); - if(rc) { - failf(data, "wolfSSH failed to set socket"); - goto error; - } - -#if 0 - wolfSSH_Debugging_ON(); -#endif - - *done = TRUE; - if(conn->handler->protocol & CURLPROTO_SCP) - wssh_state(data, sshc, SSH_INIT); - else - wssh_state(data, sshc, SSH_SFTP_INIT); - - return wssh_multi_statemach(data, done); -error: - wssh_sshc_cleanup(sshc); - return CURLE_FAILED_INIT; -} - -static CURLcode wssh_sftp_upload_init(struct Curl_easy *data, - struct ssh_conn *sshc, - struct SSHPROTO *sftp_scp, - bool *block) -{ - word32 flags; - WS_SFTP_FILEATRB createattrs; - struct connectdata *conn = data->conn; - int rc; - if(data->state.resume_from) { - WS_SFTP_FILEATRB attrs; - if(data->state.resume_from < 0) { - rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, - &attrs); - if(rc != WS_SUCCESS) - return CURLE_SSH; - - if(rc) { - data->state.resume_from = 0; - } - else { - curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0]; - if(size < 0) { - failf(data, "Bad file size (%" FMT_OFF_T ")", size); - return CURLE_BAD_DOWNLOAD_RESUME; - } - data->state.resume_from = size; - } - } - } - - if(data->set.remote_append) - /* Try to open for append, but create if nonexisting */ - flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND; - else if(data->state.resume_from > 0) - /* If we have restart position then open for append */ - flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND; - else - /* Clear file before writing (normal behavior) */ - flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC; - - memset(&createattrs, 0, sizeof(createattrs)); - createattrs.per = (word32)data->set.new_file_perms; - sshc->handleSz = sizeof(sshc->handle); - rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, - flags, &createattrs, - sshc->handle, &sshc->handleSz); - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - infof(data, "wolfssh SFTP open succeeded"); - } - else { - failf(data, "wolfssh SFTP upload open failed: %d", rc); - return CURLE_SSH; - } - wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); - - /* If we have a restart point then we need to seek to the correct - position. */ - if(data->state.resume_from > 0) { - /* Let's read off the proper amount of bytes from the input. */ - int seekerr = CURL_SEEKFUNC_OK; - if(data->set.seek_func) { - Curl_set_in_callback(data, TRUE); - seekerr = data->set.seek_func(data->set.seek_client, - data->state.resume_from, SEEK_SET); - Curl_set_in_callback(data, FALSE); - } - - if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed = 0; - - if(seekerr != CURL_SEEKFUNC_CANTSEEK) { - failf(data, "Could not seek stream"); - return CURLE_FTP_COULDNT_USE_REST; - } - /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */ - do { - char scratch[4*1024]; - size_t readthisamountnow = - (data->state.resume_from - passed > - (curl_off_t)sizeof(scratch)) ? - sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); - - size_t actuallyread; - Curl_set_in_callback(data, TRUE); - actuallyread = data->state.fread_func(scratch, 1, - readthisamountnow, - data->state.in); - Curl_set_in_callback(data, FALSE); - - passed += actuallyread; - if((actuallyread == 0) || (actuallyread > readthisamountnow)) { - /* this checks for greater-than only to make sure that the - CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Failed to read data"); - return CURLE_FTP_COULDNT_USE_REST; - } - } while(passed < data->state.resume_from); - } - - /* now, decrease the size of the read */ - if(data->state.infilesize > 0) { - data->state.infilesize -= data->state.resume_from; - data->req.size = data->state.infilesize; - Curl_pgrsSetUploadSize(data, data->state.infilesize); - } - - sshc->offset += data->state.resume_from; - } - if(data->state.infilesize > 0) { - data->req.size = data->state.infilesize; - Curl_pgrsSetUploadSize(data, data->state.infilesize); - } - /* upload data */ - Curl_xfer_setup_send(data, FIRSTSOCKET); - - /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->recv_idx = FIRSTSOCKET; - - /* store this original bitmask setup to use later on if we cannot - figure out a "real" bitmask */ - sshc->orig_waitfor = data->req.keepon; - - /* since we do not really wait for anything at this point, we want the state - machine to move on as soon as possible */ - Curl_multi_mark_dirty(data); - - wssh_state(data, sshc, SSH_STOP); - - return CURLE_OK; -} - -/* - * wssh_statemach_act() runs the SSH state machine as far as it can without - * blocking and without reaching the end. The data the pointer 'block' points - * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it - * wants to be called again when the socket is ready - */ - -static CURLcode wssh_statemach_act(struct Curl_easy *data, - struct ssh_conn *sshc, - bool *block) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - struct SSHPROTO *sftp_scp = Curl_meta_get(data, CURL_META_SSH_EASY); - WS_SFTPNAME *name; - int rc = 0; - *block = FALSE; /* we are not blocking by default */ - - if(!sftp_scp) - return CURLE_FAILED_INIT; - - do { - switch(sshc->state) { - case SSH_INIT: - wssh_state(data, sshc, SSH_S_STARTUP); - break; - - case SSH_S_STARTUP: - rc = wolfSSH_connect(sshc->ssh_session); - if(rc != WS_SUCCESS) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc != WS_SUCCESS) { - wssh_state(data, sshc, SSH_STOP); - return CURLE_SSH; - } - infof(data, "wolfssh connected"); - wssh_state(data, sshc, SSH_STOP); - break; - case SSH_STOP: - break; - - case SSH_SFTP_INIT: - rc = wolfSSH_SFTP_connect(sshc->ssh_session); - if(rc != WS_SUCCESS) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - infof(data, "wolfssh SFTP connected"); - wssh_state(data, sshc, SSH_SFTP_REALPATH); - } - else { - failf(data, "wolfssh SFTP connect error %d", rc); - return CURLE_SSH; - } - break; - case SSH_SFTP_REALPATH: - name = wolfSSH_SFTP_RealPath(sshc->ssh_session, - (char *)CURL_UNCONST(".")); - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(name && (rc == WS_SUCCESS)) { - sshc->homedir = Curl_memdup0(name->fName, name->fSz); - if(!sshc->homedir) - sshc->actualcode = CURLE_OUT_OF_MEMORY; - wolfSSH_SFTPNAME_list_free(name); - wssh_state(data, sshc, SSH_STOP); - return CURLE_OK; - } - failf(data, "wolfssh SFTP realpath %d", rc); - return CURLE_SSH; - - case SSH_SFTP_QUOTE_INIT: - result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path); - if(result) { - sshc->actualcode = result; - wssh_state(data, sshc, SSH_STOP); - break; - } - - if(data->set.quote) { - infof(data, "Sending quote commands"); - sshc->quote_item = data->set.quote; - wssh_state(data, sshc, SSH_SFTP_QUOTE); - } - else { - wssh_state(data, sshc, SSH_SFTP_GETINFO); - } - break; - case SSH_SFTP_GETINFO: - if(data->set.get_filetime) { - wssh_state(data, sshc, SSH_SFTP_FILETIME); - } - else { - wssh_state(data, sshc, SSH_SFTP_TRANS_INIT); - } - break; - case SSH_SFTP_TRANS_INIT: - if(data->state.upload) - wssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); - else { - if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') - wssh_state(data, sshc, SSH_SFTP_READDIR_INIT); - else - wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT); - } - break; - case SSH_SFTP_UPLOAD_INIT: - result = wssh_sftp_upload_init(data, sshc, sftp_scp, block); - break; - - case SSH_SFTP_DOWNLOAD_INIT: - sshc->handleSz = sizeof(sshc->handle); - rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, - WOLFSSH_FXF_READ, NULL, - sshc->handle, &sshc->handleSz); - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - infof(data, "wolfssh SFTP open succeeded"); - wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); - return CURLE_OK; - } - - failf(data, "wolfssh SFTP open failed: %d", rc); - return CURLE_SSH; - - case SSH_SFTP_DOWNLOAD_STAT: { - WS_SFTP_FILEATRB attrs; - curl_off_t size; - - rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, &attrs); - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - infof(data, "wolfssh STAT succeeded"); - } - else { - failf(data, "wolfssh SFTP open failed: %d", rc); - data->req.size = -1; - data->req.maxdownload = -1; - Curl_pgrsSetDownloadSize(data, -1); - return CURLE_SSH; - } - - size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0]; - - data->req.size = size; - data->req.maxdownload = size; - Curl_pgrsSetDownloadSize(data, size); - - infof(data, "SFTP download %" FMT_OFF_T " bytes", size); - - /* We cannot seek with wolfSSH so resuming and range requests are not - possible */ - if(data->state.use_range || data->state.resume_from) { - infof(data, "wolfSSH cannot do range/seek on SFTP"); - return CURLE_BAD_DOWNLOAD_RESUME; - } - - /* Setup the actual download */ - if(data->req.size == 0) { - /* no data to transfer */ - Curl_xfer_setup_nop(data); - infof(data, "File already completely downloaded"); - wssh_state(data, sshc, SSH_STOP); - break; - } - Curl_xfer_setup_recv(data, FIRSTSOCKET, data->req.size); - - /* not set by Curl_xfer_setup to preserve keepon bits */ - conn->send_idx = 0; - - if(result) { - /* this should never occur; the close state should be entered - at the time the error occurs */ - wssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->actualcode = result; - } - else { - wssh_state(data, sshc, SSH_STOP); - } - break; - } - case SSH_SFTP_CLOSE: - if(sshc->handleSz) { - rc = wolfSSH_SFTP_Close(sshc->ssh_session, sshc->handle, - sshc->handleSz); - if(rc != WS_SUCCESS) - rc = wolfSSH_get_error(sshc->ssh_session); - } - else { - rc = WS_SUCCESS; /* directory listing */ - } - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - wssh_state(data, sshc, SSH_STOP); - return CURLE_OK; - } - - failf(data, "wolfssh SFTP CLOSE failed: %d", rc); - return CURLE_SSH; - - case SSH_SFTP_READDIR_INIT: - Curl_pgrsSetDownloadSize(data, -1); - if(data->req.no_body) { - wssh_state(data, sshc, SSH_STOP); - break; - } - wssh_state(data, sshc, SSH_SFTP_READDIR); - break; - - case SSH_SFTP_READDIR: - name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path); - if(!name) - rc = wolfSSH_get_error(sshc->ssh_session); - else - rc = WS_SUCCESS; - - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(name && (rc == WS_SUCCESS)) { - WS_SFTPNAME *origname = name; - result = CURLE_OK; - while(name) { - char *line = aprintf("%s\n", - data->set.list_only ? - name->fName : name->lName); - if(!line) { - wssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - result = Curl_client_write(data, CLIENTWRITE_BODY, - line, strlen(line)); - free(line); - if(result) { - sshc->actualcode = result; - break; - } - name = name->next; - } - wolfSSH_SFTPNAME_list_free(origname); - wssh_state(data, sshc, SSH_STOP); - return result; - } - failf(data, "wolfssh SFTP ls failed: %d", rc); - return CURLE_SSH; - - case SSH_SFTP_SHUTDOWN: - wssh_sshc_cleanup(sshc); - wssh_state(data, sshc, SSH_STOP); - return CURLE_OK; - default: - break; - } - } while(!rc && (sshc->state != SSH_STOP)); - return result; -} - -/* called repeatedly until done from multi.c */ -static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done) -{ - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - CURLcode result = CURLE_OK; - bool block; /* we store the status and use that to provide a ssh_pollset() - implementation */ - if(!sshc) - return CURLE_FAILED_INIT; - - do { - result = wssh_statemach_act(data, sshc, &block); - *done = (sshc->state == SSH_STOP); - /* if there is no error, it is not done and it did not EWOULDBLOCK, then - try again */ - if(*done) { - DEBUGF(infof(data, "wssh_statemach_act says DONE")); - } - } while(!result && !*done && !block); - - return result; -} - -static -CURLcode wscp_perform(struct Curl_easy *data, - bool *connected, - bool *dophase_done) -{ - (void)data; - (void)connected; - (void)dophase_done; - return CURLE_OK; -} - -static -CURLcode wsftp_perform(struct Curl_easy *data, - struct ssh_conn *sshc, - bool *connected, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - - DEBUGF(infof(data, "DO phase starts")); - - *dophase_done = FALSE; /* not done yet */ - - /* start the first command in the DO phase */ - wssh_state(data, sshc, SSH_SFTP_QUOTE_INIT); - - /* run the state-machine */ - result = wssh_multi_statemach(data, dophase_done); - - *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); - - if(*dophase_done) { - DEBUGF(infof(data, "DO phase is complete")); - } - - return result; -} - -/* - * The DO function is generic for both protocols. - */ -static CURLcode wssh_do(struct Curl_easy *data, bool *done) -{ - CURLcode result; - bool connected = FALSE; - struct connectdata *conn = data->conn; - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - - *done = FALSE; /* default to false */ - if(!sshc) - return CURLE_FAILED_INIT; - - data->req.size = -1; /* make sure this is unknown at this point */ - sshc->actualcode = CURLE_OK; /* reset error code */ - sshc->secondCreateDirs = 0; /* reset the create dir attempt state - variable */ - - Curl_pgrsSetUploadCounter(data, 0); - Curl_pgrsSetDownloadCounter(data, 0); - Curl_pgrsSetUploadSize(data, -1); - Curl_pgrsSetDownloadSize(data, -1); - - if(conn->handler->protocol & CURLPROTO_SCP) - result = wscp_perform(data, &connected, done); - else - result = wsftp_perform(data, sshc, &connected, done); - - return result; -} - -static CURLcode wssh_block_statemach(struct Curl_easy *data, - struct ssh_conn *sshc, - bool disconnect) -{ - struct connectdata *conn = data->conn; - CURLcode result = CURLE_OK; - - while((sshc->state != SSH_STOP) && !result) { - bool block; - timediff_t left = 1000; - struct curltime now = curlx_now(); - - result = wssh_statemach_act(data, sshc, &block); - if(result) - break; - - if(!disconnect) { - if(Curl_pgrsUpdate(data)) - return CURLE_ABORTED_BY_CALLBACK; - - result = Curl_speedcheck(data, now); - if(result) - break; - - left = Curl_timeleft(data, NULL, FALSE); - if(left < 0) { - failf(data, "Operation timed out"); - return CURLE_OPERATION_TIMEDOUT; - } - } - - if(!result) { - int dir = conn->waitfor; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - curl_socket_t fd_read = CURL_SOCKET_BAD; - curl_socket_t fd_write = CURL_SOCKET_BAD; - if(dir == KEEP_RECV) - fd_read = sock; - else if(dir == KEEP_SEND) - fd_write = sock; - - /* wait for the socket to become ready */ - (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, - left > 1000 ? 1000 : left); /* ignore result */ - } - } - - return result; -} - -/* generic done function for both SCP and SFTP called from their specific - done functions */ -static CURLcode wssh_done(struct Curl_easy *data, - struct ssh_conn *sshc, - CURLcode status) -{ - CURLcode result = CURLE_OK; - - if(!status) { - /* run the state-machine */ - result = wssh_block_statemach(data, sshc, FALSE); - } - else - result = status; - - if(Curl_pgrsDone(data)) - return CURLE_ABORTED_BY_CALLBACK; - - data->req.keepon = 0; /* clear all bits */ - return result; -} - -static void wssh_sshc_cleanup(struct ssh_conn *sshc) -{ - if(sshc->ssh_session) { - wolfSSH_free(sshc->ssh_session); - sshc->ssh_session = NULL; - } - if(sshc->ctx) { - wolfSSH_CTX_free(sshc->ctx); - sshc->ctx = NULL; - } - Curl_safefree(sshc->homedir); -} - -#if 0 -static CURLcode wscp_done(struct Curl_easy *data, - CURLcode code, bool premature) -{ - CURLcode result = CURLE_OK; - (void)conn; - (void)code; - (void)premature; - - return result; -} - -static CURLcode wscp_doing(struct Curl_easy *data, - bool *dophase_done) -{ - CURLcode result = CURLE_OK; - (void)conn; - (void)dophase_done; - - return result; -} - -static CURLcode wscp_disconnect(struct Curl_easy *data, - struct connectdata *conn, bool dead_connection) -{ - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - CURLcode result = CURLE_OK; - (void)dead_connection; - if(sshc) - wssh_sshc_cleanup(sshc); - return result; -} -#endif - -static CURLcode wsftp_done(struct Curl_easy *data, - CURLcode code, bool premature) -{ - struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); - (void)premature; - if(!sshc) - return CURLE_FAILED_INIT; - - wssh_state(data, sshc, SSH_SFTP_CLOSE); - - return wssh_done(data, sshc, code); -} - -static CURLcode wsftp_doing(struct Curl_easy *data, - bool *dophase_done) -{ - CURLcode result = wssh_multi_statemach(data, dophase_done); - - if(*dophase_done) { - DEBUGF(infof(data, "DO phase is complete")); - } - return result; -} - -static CURLcode wsftp_disconnect(struct Curl_easy *data, - struct connectdata *conn, - bool dead) -{ - struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - CURLcode result = CURLE_OK; - (void)dead; - - DEBUGF(infof(data, "SSH DISCONNECT starts now")); - - if(sshc && sshc->ssh_session) { - /* only if there is a session still around to use! */ - wssh_state(data, sshc, SSH_SFTP_SHUTDOWN); - result = wssh_block_statemach(data, sshc, TRUE); - } - - if(sshc) - wssh_sshc_cleanup(sshc); - DEBUGF(infof(data, "SSH DISCONNECT is done")); - return result; -} - -static CURLcode wssh_pollset(struct Curl_easy *data, - struct easy_pollset *ps) -{ - int flags = 0; - if(data->conn->waitfor & KEEP_RECV) - flags |= CURL_POLL_IN; - if(data->conn->waitfor & KEEP_SEND) - flags |= CURL_POLL_OUT; - return flags ? - Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], flags, 0) : - CURLE_OK; -} - -void Curl_ssh_version(char *buffer, size_t buflen) -{ - (void)msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING); -} - -CURLcode Curl_ssh_init(void) -{ - if(WS_SUCCESS != wolfSSH_Init()) { - DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n")); - return CURLE_FAILED_INIT; - } - - return CURLE_OK; -} -void Curl_ssh_cleanup(void) -{ - (void)wolfSSH_Cleanup(); -} - -#endif /* USE_WOLFSSH */ diff --git a/packages/OS400/ccsidcurl.c b/packages/OS400/ccsidcurl.c index a9c04d5a420e..101cf9024705 100644 --- a/packages/OS400/ccsidcurl.c +++ b/packages/OS400/ccsidcurl.c @@ -1213,8 +1213,8 @@ curl_easy_setopt_ccsid(CURL *easy, CURLoption tag, ...) if(!s) { result = CURLE_OUT_OF_MEMORY; break; - } } + } else { /* Data length specified. */ size_t len; diff --git a/scripts/schemetable.c b/scripts/schemetable.c index 7da4613212cc..e65c462f7b36 100644 --- a/scripts/schemetable.c +++ b/scripts/schemetable.c @@ -60,7 +60,7 @@ static const struct detail scheme[] = { {"rtmps", "#ifdef USE_LIBRTMP" }, {"rtmpts", "#ifdef USE_LIBRTMP" }, {"rtsp", "#ifndef CURL_DISABLE_RTSP" }, - {"scp", "#if defined(USE_SSH) && !defined(USE_WOLFSSH)" }, + {"scp", "#ifdef USE_SSH" }, {"sftp", "#ifdef USE_SSH" }, {"smb", "#if !defined(CURL_DISABLE_SMB) && \\\n" " defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)" }, diff --git a/tests/runtests.pl b/tests/runtests.pl index 4945e94cdabb..6b6e5b076191 100755 --- a/tests/runtests.pl +++ b/tests/runtests.pl @@ -639,9 +639,6 @@ sub checksystemfeatures { } } } - if($libcurl =~ /wolfssh/i) { - $feature{"wolfssh"} = 1; - } } elsif($_ =~ /^Protocols: (.*)/i) { $proto = $1; From 9a5810f6c1ebac17dae149c517cb520d4abaa4bf Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 24 Sep 2025 23:03:03 +0200 Subject: [PATCH 151/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 69 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 698c81d3a868..fadadb8c87d1 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,28 +4,36 @@ curl and libcurl 8.17.0 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3505 + Contributors: 3508 This release includes the following changes: o build: drop the winbuild build system [81] o krb5: drop support for Kerberos FTP [43] o libssh2: up the minimum requirement to 1.9.0 [85] + o vssh: drop support for wolfSSH [58] o write-out: make %header{} able to output *all* occurrences of a header [25] This release includes the following bugfixes: + o ares: fix leak in tracing [91] o asyn-thrdd: drop pthread_cancel [30] + o autotools: add support for libgsasl auto-detection via pkg-config [112] + o autotools: capitalize 'Rustls' in the log output [106] + o autotools: fix duplicate `UNIX` and `BSD` flags in `buildinfo.txt` [113] + o autotools: fix silly mistake in clang detection for `buildinfo.txt` [114] o autotools: make `--enable-code-coverage` support llvm/clang [79] o aws-lc: re-enable large read-ahead with v1.61.0 again [16] o base64: accept zero length argument to base64_encode [82] o build: address some `-Weverything` warnings, update picky warnings [74] o build: avoid overriding system symbols for socket functions [68] + o build: show llvm/clang in platform flags and `buildinfo.txt` [126] o cf-socket: use the right byte order for ports in bindlocal [61] - o cf_socket_recv: don't count reading zero bytes as first byte [23] o cfilter: unlink and discard [46] o cmake: add `CURL_CODE_COVERAGE` option [78] + o cmake: clang detection tidy-ups [116] o cmake: fix building docs when the base directory contains `.3` [18] + o cmake: use modern alternatives for `get_filename_component()` [102] o cmdline-docs: extended, clarified, refreshed [28] o configure: add "-mt" for pthread support on HP-UX [52] o cookie: avoid saving a cookie file if no transfer was done [11] @@ -42,10 +50,13 @@ This release includes the following bugfixes: o docs/libcurl: clarify some timeout option behavior [15] o docs/libcurl: remove ancient version references [7] o docs/libcurl: use lowercase must [5] + o docs: fix/tidy code fences [87] o easy_getinfo: check magic, Curl_close safety [3] o examples: fix two issues found by CodeQL [35] + o ftp: fix ftp_do_more returning with *completep unset [122] o ftp: fix port number range loop for PORT commands [66] o gtls: avoid potential use of uninitialized variable in trace output [83] + o hostip: remove leftover INT_MAX check in Curl_dnscache_prune [88] o httpsrr: free old pointers when storing new [57] o krb5: return appropriate error on send failures [22] o ldap: do not base64 encode zero length string [42] @@ -53,20 +64,26 @@ This release includes the following bugfixes: o libcurl-security.md: mention long-running connections [6] o libssh2: drop two redundant null-terminations [26] o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] + o libssh: drop two unused assigments [104] o libssh: error on bad chgrp number [71] o libssh: error on bad chown number and store the value [64] + o libssh: fix range parsing error handling mistake [120] o libssh: react on errors from ssh_scp_read [24] o libssh: return out of memory correctly if aprintf fails [60] o Makefile.example: simplify and make it configurable [20] o managen: ignore version mentions < 7.66.0 [55] o managen: render better manpage references/links [54] + o managen: strict protocol check [109] o multi.h: add CURLMINFO_LASTENTRY [51] o ngtcp2: check error code on connect failure [13] o openldap: avoid indexing the result at -1 for blank responses [44] + o openldap: check ldap_get_option() return codes [119] o openssl: make the asn1_object_dump name null terminated [56] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o rustls: fix clang-tidy warning [107] o rustls: typecast variable for safer trace output [69] + o rustls: use %zu for size_t in failf() format string [121] o sasl: clear canceled mechanism instead of toggling it [41] o schannel: assign result before using it [62] o setopt: accept *_SSL_VERIFYHOST set to 2L [31] @@ -74,27 +91,37 @@ This release includes the following bugfixes: o smb: adjust buffer size checks [45] o smtp: check EHLO responses case insensitively [50] o socks: make Curl_blockread_all return CURLcode [67] + o socks_gssapi: reject too long tokens [90] o socks_sspi: fix memory cleanup calls [40] o socks_sspi: restore non-blocking socket on error paths [48] o ssl-sessions.md: mark option experimental [12] o sws: fix checking `sscanf()` return value [17] o telnet: make printsub require another byte input [21] + o telnet: refuse IAC codes in content [111] + o telnet: return error on crazy TTYPE or XDISPLOC lengths [123] o tftp: check and act on tftp_set_timeouts() returning error [38] o tftp: handle tftp_multi_statemach() return code [65] + o tftp: pin the first used address [110] o tftp: propagate expired timer from tftp_state_timeout() [39] o tftp: return error when sendto() fails [59] + o tidy-up: assortment of small fixes [115] o tidy-up: avoid using the reserved macro namespace [76] o tidy-up: update MS links, allow long URLs via `checksrc` [73] + o tidy-up: URLs [101] o TODO: remove already implemented or bad items [36] o tool: fix exponential retry delay [47] o tool_cb_hdr: fix fwrite check in header callback [49] o tool_cb_hdr: size is always 1 [70] + o tool_doswin: fix to use curl socket functions [108] o tool_getparam/set_rate: skip the multiplication on overflow [84] o tool_operate: improve wording in retry message [37] o tool_operate: keep the progress meter for --out-null [33] o urldata: FILE is not a list-only protocol [9] + o vtls_int.h: clarify data_pending [124] o windows: replace `_beginthreadex()` with `CreateThread()` [80] o windows: stop passing unused, optional argument for Win9x compatibility [75] + o ws: clarify an error message [125] + o ws: reject curl_ws_recv called with NULL buffer with a buflen [118] This release includes the following known bugs: @@ -120,10 +147,11 @@ advice from friends like these: Adam Light, Andrew Kirillov, Andrew Olsen, BobodevMm on github, Christian Schmitz, Dan Fandrich, Daniel Stenberg, dependabot[bot], divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, - fds242 on github, Javier Blazquez, Jicea, Joshua Rogers, kapsiR on github, - Marcel Raad, Michael Osipov, Michał Petryka, Nir Azkiel, Ray Satiro, - renovate[bot], Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats - (25 contributors) + fds242 on github, Javier Blazquez, Jicea, jmaggard10 on github, + Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, Marcel Raad, + Michael Osipov, Michał Petryka, Nir Azkiel, Ray Satiro, renovate[bot], + rinsuki on github, Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats + (28 contributors) References to bug reports and discussions on issues: @@ -149,7 +177,6 @@ References to bug reports and discussions on issues: [20] = https://curl.se/bug/?i=18554 [21] = https://curl.se/bug/?i=18618 [22] = https://curl.se/bug/?i=18561 - [23] = https://curl.se/bug/?i=18615 [24] = https://curl.se/bug/?i=18616 [25] = https://curl.se/bug/?i=18491 [26] = https://curl.se/bug/?i=18606 @@ -184,6 +211,7 @@ References to bug reports and discussions on issues: [55] = https://curl.se/bug/?i=18583 [56] = https://curl.se/bug/?i=18647 [57] = https://curl.se/bug/?i=18631 + [58] = https://curl.se/bug/?i=18700 [59] = https://curl.se/bug/?i=18643 [60] = https://curl.se/bug/?i=18637 [61] = https://curl.se/bug/?i=18641 @@ -211,3 +239,30 @@ References to bug reports and discussions on issues: [83] = https://curl.se/bug/?i=18620 [84] = https://curl.se/bug/?i=18624 [85] = https://curl.se/bug/?i=18612 + [87] = https://curl.se/bug/?i=18707 + [88] = https://curl.se/bug/?i=18680 + [90] = https://curl.se/bug/?i=18681 + [91] = https://curl.se/bug/?i=18251 + [101] = https://curl.se/bug/?i=18689 + [102] = https://curl.se/bug/?i=18688 + [104] = https://curl.se/bug/?i=18684 + [106] = https://curl.se/bug/?i=18671 + [107] = https://curl.se/bug/?i=18670 + [108] = https://curl.se/bug/?i=18633 + [109] = https://curl.se/bug/?i=18675 + [110] = https://curl.se/bug/?i=18658 + [111] = https://curl.se/bug/?i=18657 + [112] = https://curl.se/bug/?i=18669 + [113] = https://curl.se/bug/?i=18667 + [114] = https://curl.se/bug/?i=18666 + [115] = https://curl.se/bug/?i=18664 + [116] = https://curl.se/bug/?i=18659 + [118] = https://curl.se/bug/?i=18656 + [119] = https://curl.se/bug/?i=18653 + [120] = https://curl.se/bug/?i=18652 + [121] = https://curl.se/bug/?i=18651 + [122] = https://curl.se/bug/?i=18650 + [123] = https://curl.se/bug/?i=18648 + [124] = https://curl.se/bug/?i=18644 + [125] = https://curl.se/bug/?i=18654 + [126] = https://curl.se/bug/?i=18645 From 977595772c6e650b538da965cde676c9bc15cfd8 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 23:48:13 +0200 Subject: [PATCH 152/465] RELEASE-NOTES: codespell --- RELEASE-NOTES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index fadadb8c87d1..da62171c7198 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -64,7 +64,7 @@ This release includes the following bugfixes: o libcurl-security.md: mention long-running connections [6] o libssh2: drop two redundant null-terminations [26] o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] - o libssh: drop two unused assigments [104] + o libssh: drop two unused assignments [104] o libssh: error on bad chgrp number [71] o libssh: error on bad chown number and store the value [64] o libssh: fix range parsing error handling mistake [120] From 9d3f878e59d155ee2b916550bdca531424643710 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 21:01:05 +0000 Subject: [PATCH 153/465] GHA: update actions/cache digest to 0057852 Closes #18710 --- .github/workflows/http3-linux.yml | 46 +++++++++++++++---------------- .github/workflows/linux.yml | 20 +++++++------- .github/workflows/macos.yml | 2 +- .github/workflows/windows.yml | 10 +++---- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 780320e383aa..61164913ad28 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -69,7 +69,7 @@ jobs: steps: - name: 'cache openssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-openssl-http3 env: cache-name: cache-openssl-http3 @@ -78,7 +78,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }} - name: 'cache libressl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-libressl env: cache-name: cache-libressl @@ -87,7 +87,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.LIBRESSL_VERSION }} - name: 'cache awslc' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-awslc env: cache-name: cache-awslc @@ -96,7 +96,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.AWSLC_VERSION }} - name: 'cache boringssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-boringssl env: cache-name: cache-boringssl @@ -105,7 +105,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.BORINGSSL_VERSION }} - name: 'cache quictls' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-quictls-no-deprecated env: cache-name: cache-quictls-no-deprecated @@ -114,7 +114,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.QUICTLS_VERSION }}-quic1 - name: 'cache gnutls' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-gnutls env: cache-name: cache-gnutls @@ -123,7 +123,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.GNUTLS_VERSION }} - name: 'cache wolfssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-wolfssl env: cache-name: cache-wolfssl @@ -132,7 +132,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.WOLFSSL_VERSION }} - name: 'cache nghttp3' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-nghttp3 env: cache-name: cache-nghttp3 @@ -141,7 +141,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGHTTP3_VERSION }} - name: 'cache ngtcp2' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-ngtcp2 env: cache-name: cache-ngtcp2 @@ -150,7 +150,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGTCP2_VERSION }}-${{ env.OPENSSL_VERSION }}-${{ env.LIBRESSL_VERSION }}-${{ env.AWSLC_VERSION }}-${{ env.QUICTLS_VERSION }}-${{ env.GNUTLS_VERSION }}-${{ env.WOLFSSL_VERSION }} - name: 'cache ngtcp2 boringssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-ngtcp2-boringssl env: cache-name: cache-ngtcp2-boringssl @@ -159,7 +159,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGTCP2_VERSION }}-${{ env.BORINGSSL_VERSION }} - name: 'cache nghttp2' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-nghttp2 env: cache-name: cache-nghttp2 @@ -518,7 +518,7 @@ jobs: - name: 'cache openssl' if: ${{ matrix.build.name == 'openssl' || matrix.build.name == 'openssl-quic' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-openssl-http3 env: cache-name: cache-openssl-http3 @@ -528,7 +528,7 @@ jobs: fail-on-cache-miss: true - name: 'cache libressl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-libressl env: cache-name: cache-libressl @@ -538,7 +538,7 @@ jobs: fail-on-cache-miss: true - name: 'cache awslc' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-awslc env: cache-name: cache-awslc @@ -548,7 +548,7 @@ jobs: fail-on-cache-miss: true - name: 'cache boringssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-boringssl env: cache-name: cache-boringssl @@ -558,7 +558,7 @@ jobs: fail-on-cache-miss: true - name: 'cache quictls' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-quictls-no-deprecated env: cache-name: cache-quictls-no-deprecated @@ -569,7 +569,7 @@ jobs: - name: 'cache gnutls' if: ${{ matrix.build.name == 'gnutls' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-gnutls env: cache-name: cache-gnutls @@ -580,7 +580,7 @@ jobs: - name: 'cache wolfssl' if: ${{ matrix.build.name == 'wolfssl' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-wolfssl env: cache-name: cache-wolfssl @@ -590,7 +590,7 @@ jobs: fail-on-cache-miss: true - name: 'cache nghttp3' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-nghttp3 env: cache-name: cache-nghttp3 @@ -600,7 +600,7 @@ jobs: fail-on-cache-miss: true - name: 'cache ngtcp2' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-ngtcp2 env: cache-name: cache-ngtcp2 @@ -610,7 +610,7 @@ jobs: fail-on-cache-miss: true - name: 'cache ngtcp2 boringssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-ngtcp2-boringssl env: cache-name: cache-ngtcp2-boringssl @@ -620,7 +620,7 @@ jobs: fail-on-cache-miss: true - name: 'cache nghttp2' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-nghttp2 env: cache-name: cache-nghttp2 @@ -631,7 +631,7 @@ jobs: - name: 'cache quiche' if: ${{ matrix.build.name == 'quiche' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-quiche env: cache-name: cache-quiche diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 20a5849d4dbd..4f164382672a 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -348,7 +348,7 @@ jobs: - name: 'cache libressl' if: ${{ contains(matrix.build.install_steps, 'libressl') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-libressl env: cache-name: cache-libressl @@ -367,7 +367,7 @@ jobs: - name: 'cache wolfssl (all)' if: ${{ contains(matrix.build.install_steps, 'wolfssl-all') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-wolfssl-all env: cache-name: cache-wolfssl-all @@ -388,7 +388,7 @@ jobs: - name: 'cache wolfssl (opensslextra)' # does support `OPENSSL_COEXIST` if: ${{ contains(matrix.build.install_steps, 'wolfssl-opensslextra') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-wolfssl-opensslextra env: cache-name: cache-wolfssl-opensslextra @@ -409,7 +409,7 @@ jobs: - name: 'cache mbedtls' if: ${{ contains(matrix.build.install_steps, 'mbedtls') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-mbedtls env: cache-name: cache-mbedtls-threadsafe @@ -432,7 +432,7 @@ jobs: - name: 'cache openldap-static' if: ${{ contains(matrix.build.install_steps, 'openldap-static') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-openldap-static env: cache-name: cache-openldap-static @@ -452,7 +452,7 @@ jobs: - name: 'cache openssl (thread sanitizer)' if: ${{ contains(matrix.build.install_steps, 'openssl-tsan') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-openssl-tsan env: cache-name: cache-openssl-tsan @@ -471,7 +471,7 @@ jobs: - name: 'cache quictls' if: ${{ contains(matrix.build.install_steps, 'quictls') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-quictls env: cache-name: cache-quictls @@ -490,7 +490,7 @@ jobs: - name: 'cache awslc' if: ${{ contains(matrix.build.install_steps, 'awslc') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-awslc env: cache-name: cache-awslc @@ -511,7 +511,7 @@ jobs: - name: 'cache boringssl' if: ${{ contains(matrix.build.install_steps, 'boringssl') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-boringssl env: cache-name: cache-boringssl @@ -532,7 +532,7 @@ jobs: - name: 'cache rustls' if: ${{ contains(matrix.build.install_steps, 'rustls') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-rustls env: cache-name: cache-rustls diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index ee8cec7d70bb..c111eaf4193e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -110,7 +110,7 @@ jobs: - name: 'cache libressl' if: ${{ contains(matrix.build.install_steps, 'libressl') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-libressl env: cache-name: cache-libressl diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d45979c05ac2..0f802b690257 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -62,7 +62,7 @@ jobs: run: perl --version | tee "$GITHUB_WORKSPACE"/perlversion - name: 'cache perl packages' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs @@ -433,7 +433,7 @@ jobs: - name: 'cache perl packages' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' && matrix.sys != 'msys' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs @@ -570,7 +570,7 @@ jobs: ${{ matrix.install }} - name: 'cache compiler (gcc ${{ matrix.ver }}-${{ matrix.env }})' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-compiler with: path: D:\my-cache @@ -663,7 +663,7 @@ jobs: - name: 'cache perl packages' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs @@ -1057,7 +1057,7 @@ jobs: - name: 'cache perl packages' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs From 97e5a471e0d7a6ade6476c71801ae2a89961919b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 10:09:18 +0200 Subject: [PATCH 154/465] KNOWN_BUGS: Access violation sending client cert with SChannel It seems we can select between crashing or leaking sensitive files because Schannel is buggy. Closes #17626 Closes #18679 --- docs/KNOWN_BUGS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 1eb5716f8b94..3785d73aa49e 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -15,6 +15,7 @@ problems may have been fixed or changed somewhat since this was written. 2. TLS 2.1 IMAPS connection fails with Rustls error + 2.2 Access violation sending client cert with Schannel 2.5 Client cert handling with Issuer DN differs between backends 2.7 Client cert (MTLS) issues with Schannel 2.11 Schannel TLS 1.2 handshake bug in old Windows versions @@ -120,6 +121,14 @@ problems may have been fixed or changed somewhat since this was written. https://github.com/curl/curl/issues/10457 +2.2 Access violation sending client cert with Schannel + + When using Schannel to do client certs, curl sets PKCS12_NO_PERSIST_KEY to + avoid leaking the private key into the filesystem. Unfortunately that flag + instead seems to trigger a crash. + + See https://github.com/curl/curl/issues/17626 + 2.5 Client cert handling with Issuer DN differs between backends When the specified client certificate does not match any of the From 0f1657ca75fcca4dbdbccf31d9d6cf4fae4a98e5 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 Sep 2025 11:27:27 +0200 Subject: [PATCH 155/465] mbedtls: handle WANT_WRITE from mbedtls_ssl_read() The mbedtls_ssl_read() function is documented to be able to also return MBEDTLS_ERR_SSL_WANT_WRITE, so act on that accordingly instead of returning error for it. Assisted-by: Stefan Eissing Reported in Joshua's sarif data Closes #18682 --- lib/vtls/mbedtls.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index a8abd0fe09a5..0a62da2b58bf 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -1113,8 +1113,9 @@ static CURLcode mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, int nwritten; (void)data; - *pnwritten = 0; DEBUGASSERT(backend); + *pnwritten = 0; + connssl->io_need = CURL_SSL_IO_NEED_NONE; /* mbedtls is picky when a mbedtls_ssl_write) was previously blocked. * It requires to be called with the same amount of bytes again, or it * will lose bytes, e.g. reporting all was sent but they were not. @@ -1135,11 +1136,22 @@ static CURLcode mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, else { CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X", len, -nwritten); - result = ((nwritten == MBEDTLS_ERR_SSL_WANT_WRITE) + switch(nwritten) { #ifdef MBEDTLS_SSL_PROTO_TLS1_3 - || (nwritten == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) + case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET: #endif - ) ? CURLE_AGAIN : CURLE_SEND_ERROR; + case MBEDTLS_ERR_SSL_WANT_READ: + connssl->io_need = CURL_SSL_IO_NEED_RECV; + result = CURLE_AGAIN; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + connssl->io_need = CURL_SSL_IO_NEED_SEND; + result = CURLE_AGAIN; + break; + default: + result = CURLE_SEND_ERROR; + break; + } if((result == CURLE_AGAIN) && !backend->send_blocked) { backend->send_blocked = TRUE; backend->send_blocked_len = len; @@ -1280,6 +1292,7 @@ static CURLcode mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, (void)data; DEBUGASSERT(backend); *pnread = 0; + connssl->io_need = CURL_SSL_IO_NEED_NONE; nread = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, buffersize); if(nread > 0) @@ -1294,6 +1307,11 @@ static CURLcode mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, FALLTHROUGH(); #endif case MBEDTLS_ERR_SSL_WANT_READ: + connssl->io_need = CURL_SSL_IO_NEED_RECV; + result = CURLE_AGAIN; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + connssl->io_need = CURL_SSL_IO_NEED_SEND; result = CURLE_AGAIN; break; case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: From aaa39873ea7cd2a5031cfaa16b54fa3b09af7ff1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 08:45:53 +0200 Subject: [PATCH 156/465] socks_gssapi: make the gss_context a local variable Reported-by: Stanislav Fort Closes #18711 --- lib/socks_gssapi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 037515e576f6..b6530d5d7d55 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -49,8 +49,6 @@ #define MAX_GSS_LEN 1024 -static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; - /* * Helper GSS-API error functions. */ @@ -134,6 +132,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; const size_t serviceptr_length = strlen(serviceptr); + gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; + /* GSS-API request looks like * +----+------+-----+----------------+ From 98dae1d992aa1b048230f9d4934aefe8128b2f6c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 21 Sep 2025 23:34:37 +0200 Subject: [PATCH 157/465] socks_gssapi: remove the forced "no protection" If a protected connection is requested, don't claim to drop down to "no protection". Reported in Joshua's sarif data Closes #18712 --- lib/socks_gssapi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index b6530d5d7d55..0aa6f7245fe3 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -359,8 +359,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, infof(data, "SOCKS5 server supports GSS-API %s data protection.", (gss_enc == 0) ? "no" : ((gss_enc == 1) ? "integrity" : "confidentiality")); - /* force for the moment to no data protection */ - gss_enc = 0; + /* * Sending the encryption type in clear seems wrong. It should be * protected with gss_seal()/gss_wrap(). See RFC1961 extract below From 7f38bf51ad42506b5e4bf3a4c8ad6075a61b566b Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Thu, 25 Sep 2025 01:14:19 +0200 Subject: [PATCH 158/465] OS400: fix a use-after-free/double-free case Closes #18713 --- packages/OS400/ccsidcurl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/OS400/ccsidcurl.c b/packages/OS400/ccsidcurl.c index 101cf9024705..b40367fd960b 100644 --- a/packages/OS400/ccsidcurl.c +++ b/packages/OS400/ccsidcurl.c @@ -1246,6 +1246,7 @@ curl_easy_setopt_ccsid(CURL *easy, CURLoption tag, ...) data->set.postfieldsize = pfsize; /* Replace data size. */ s = cp; + cp = NULL; } result = curl_easy_setopt(easy, CURLOPT_POSTFIELDS, s); From 7d5f8be532c19ec73063aaa4f27057047bdae5ac Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 24 Sep 2025 17:22:52 +0200 Subject: [PATCH 159/465] GHA: use pip `requirements.txt` with pins, and more venv - requirements.txt: shorten copyright headers. - requirements.txt: pin packages to versions. - GHA/windows: use `tests/requirements.txt`. Pick a `cryptography` package version that satifies both `impacket` and pytests dependencies. - GHA/checksrc: move pip deps into a new `requirements.txt`. To make Dependabot detect and bump them. - GHA/checksrc: replace apt packages for python test deps with pip install `tests/**/requirements.txt` to a venv. - GHA/checksrc: use venv and drop `--break-system-packages`. - GHA/linux: fix to actually activate venvs. Follow-up to 2638570241cb9e68240d7621f0213916334a4765 #15578 - GHA/linux: fixup (did not cause an issue) Follow-up to d75785c7dea214d12525beb659694d3fcc483731 #18660 - GHA: create venvs later, simplify commands. - GHA: sync pip command-line options, e.g. drop progress-bar, everywhere. Assisted-by: Dan Fandrich Closes #18708 --- .github/scripts/requirements.txt | 8 +++++++ .github/workflows/checksrc.yml | 27 +++++++++++++----------- .github/workflows/http3-linux.yml | 9 ++++---- .github/workflows/linux.yml | 18 ++++++++-------- .github/workflows/macos.yml | 7 +++---- .github/workflows/windows.yml | 4 ++-- tests/http/requirements.txt | 35 +++++++------------------------ tests/requirements.txt | 25 ++-------------------- 8 files changed, 50 insertions(+), 83 deletions(-) create mode 100644 .github/scripts/requirements.txt diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt new file mode 100644 index 000000000000..f94a9d93a8bd --- /dev/null +++ b/.github/scripts/requirements.txt @@ -0,0 +1,8 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +cmakelang == 0.6.13 +codespell == 2.4.1 +pytype == 2024.10.11 +ruff == 0.11.9 diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index a0ff120becb3..5aca2f941a78 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -55,18 +55,15 @@ jobs: env: DEBIAN_FRONTEND: noninteractive run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - sudo apt-get -o Dpkg::Use-Pty=0 update - sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install \ - python3-pip python3-networkx python3-pydot python3-yaml \ - python3-toml python3-markupsafe python3-jinja2 python3-tabulate \ - python3-typing-extensions python3-libcst python3-impacket \ - python3-websockets python3-pytest python3-filelock python3-pytest-xdist - python3 -m pip install --break-system-packages cmakelang==0.6.13 pytype==2024.10.11 ruff==0.11.9 codespell==2.4.1 + python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary \ + -r .github/scripts/requirements.txt \ + -r tests/http/requirements.txt \ + -r tests/requirements.txt - name: 'codespell' run: | + source ~/venv/bin/activate codespell --version .github/scripts/codespell.sh @@ -78,13 +75,19 @@ jobs: .github/scripts/typos.sh - name: 'cmakelint' - run: scripts/cmakelint.sh + run: | + source ~/venv/bin/activate + scripts/cmakelint.sh - name: 'pytype' - run: find . -name '*.py' -exec pytype -j auto -k {} + + run: | + source ~/venv/bin/activate + find . -name '*.py' -exec pytype -j auto -k {} + - name: 'ruff' - run: scripts/pythonlint.sh + run: | + source ~/venv/bin/activate + scripts/pythonlint.sh reuse: name: 'REUSE' diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 61164913ad28..019790b68e5d 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -512,7 +512,6 @@ jobs: libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev libidn2-0-dev libldap-dev libuv1-dev \ ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} - python3 -m venv ~/venv echo 'CC=gcc-12' >> "$GITHUB_ENV" echo 'CXX=g++-12' >> "$GITHUB_ENV" @@ -726,8 +725,8 @@ jobs: - name: 'install test prereqs' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} run: | - source ~/venv/bin/activate - python3 -m pip install -r tests/requirements.txt + python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt - name: 'run tests' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} @@ -744,8 +743,8 @@ jobs: - name: 'install pytest prereqs' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} run: | - source ~/venv/bin/activate - python3 -m pip install -r tests/http/requirements.txt + [ -d ~/venv ] || python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/http/requirements.txt - name: 'run pytest event based' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 4f164382672a..556ff8df1ec9 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -321,8 +321,9 @@ jobs: libpsl-dev zlib1g-dev libbrotli-dev libzstd-dev \ ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} - [ -n "${INSTALL_PACKAGES_BREW}" ] && /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} - python3 -m venv ~/venv + if [ -n "${INSTALL_PACKAGES_BREW}" ]; then + /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} + fi - name: 'install prereqs' if: ${{ contains(matrix.build.name, 'i686') }} @@ -335,7 +336,6 @@ jobs: libtool autoconf automake pkgconf stunnel4 \ libpsl-dev:i386 libbrotli-dev:i386 libzstd-dev:i386 \ ${MATRIX_INSTALL_PACKAGES} - python3 -m venv ~/venv - name: 'install dependencies' if: ${{ startsWith(matrix.build.container, 'alpine') }} @@ -657,8 +657,8 @@ jobs: - name: 'install test prereqs' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') && matrix.build.container == null }} run: | - [ -x ~/venv/bin/activate ] && source ~/venv/bin/activate - python3 -m pip install -r tests/requirements.txt + python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt - name: 'run tests' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} @@ -675,7 +675,7 @@ jobs: fi fi fi - [ -x ~/venv/bin/activate ] && source ~/venv/bin/activate + [ -f ~/venv/bin/activate ] && source ~/venv/bin/activate if [[ "${MATRIX_INSTALL_STEPS}" = *'codeset-test'* ]]; then locale || true export LC_ALL=C @@ -691,8 +691,8 @@ jobs: - name: 'install pytest prereqs' if: ${{ contains(matrix.build.install_steps, 'pytest') }} run: | - [ -x ~/venv/bin/activate ] && source ~/venv/bin/activate - python3 -m pip install -r tests/http/requirements.txt + [ -d ~/venv ] || python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/http/requirements.txt - name: 'run pytest' if: ${{ contains(matrix.build.install_steps, 'pytest') }} @@ -700,7 +700,7 @@ jobs: PYTEST_ADDOPTS: '--color=yes' PYTEST_XDIST_AUTO_NUM_WORKERS: 4 run: | - [ -x ~/venv/bin/activate ] && source ~/venv/bin/activate + [ -f ~/venv/bin/activate ] && source ~/venv/bin/activate if [ "${MATRIX_BUILD}" = 'cmake' ]; then cmake --build bld --verbose --target curl-pytest-ci else diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index c111eaf4193e..88b7ee880062 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -489,8 +489,7 @@ jobs: if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} run: | python3 -m venv ~/venv - source ~/venv/bin/activate - python3 -m pip install -r tests/requirements.txt + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt - name: 'run tests' if: ${{ !contains(matrix.build.install_steps, 'skipall') && !contains(matrix.build.install_steps, 'skiprun') }} @@ -517,8 +516,8 @@ jobs: - name: 'install pytest prereqs' if: ${{ contains(matrix.build.install_steps, 'pytest') }} run: | - source ~/venv/bin/activate - python3 -m pip install -r tests/http/requirements.txt + [ -d ~/venv ] || python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/http/requirements.txt - name: 'run pytest' if: ${{ contains(matrix.build.install_steps, 'pytest') }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 0f802b690257..e5d66ccc87fc 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -658,7 +658,7 @@ jobs: timeout-minutes: 5 run: | /c/ProgramData/chocolatey/choco.exe install --yes --no-progress --limit-output --timeout 180 --force stunnel || true - python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary impacket + python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt perl --version | tee "$GITHUB_WORKSPACE"/perlversion - name: 'cache perl packages' @@ -1051,7 +1051,7 @@ jobs: fi /c/ProgramData/chocolatey/choco.exe install --yes --no-progress --limit-output --timeout 180 --force stunnel || true if [ "${MATRIX_IMAGE}" != 'windows-11-arm' ]; then # save 30-60 seconds, to counteract the slower test run step - python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary impacket + python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt fi perl --version | tee "$GITHUB_WORKSPACE"/perlversion diff --git a/tests/http/requirements.txt b/tests/http/requirements.txt index c87960560864..8dddcd1e1c24 100644 --- a/tests/http/requirements.txt +++ b/tests/http/requirements.txt @@ -1,31 +1,10 @@ -# -*- coding: utf-8 -*- -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# # Copyright (C) Daniel Stenberg, , et al. # -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.se/docs/copyright.html. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# # SPDX-License-Identifier: curl -# -########################################################################### -# -pytest -cryptography -filelock -websockets -psutil -pytest-xdist + +cryptography == 42.0.8 +filelock == 3.19.1 +psutil == 7.1.0 +pytest == 8.4.2 +pytest-xdist == 3.8.0 +websockets == 15.0.1 diff --git a/tests/requirements.txt b/tests/requirements.txt index 706043ac395f..dab4784c5fa1 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,26 +1,5 @@ -# -*- coding: utf-8 -*- -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# # Copyright (C) Daniel Stenberg, , et al. # -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.se/docs/copyright.html. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# # SPDX-License-Identifier: curl -# -########################################################################### -# -impacket + +impacket == 0.12.0 From c9fce97dcb190eac5591ecab683d49ffd30b1c71 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 10:42:24 +0200 Subject: [PATCH 160/465] cf-h2-proxy: break loop on edge case nghttp2 always consumes the memory, but be safe in case it ever decideds to not to. Fixes J2 Reported in Joshua's sarif data Closes #18715 --- lib/cf-h2-proxy.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/cf-h2-proxy.c b/lib/cf-h2-proxy.c index d67bbd55adfb..17a15c1d2ada 100644 --- a/lib/cf-h2-proxy.c +++ b/lib/cf-h2-proxy.c @@ -433,6 +433,11 @@ static int proxy_h2_process_pending_input(struct Curl_cfilter *cf, *err = CURLE_RECV_ERROR; return -1; } + else if(!rv) { + /* nghttp2 does not want to process more, but has no error. This + * probably cannot happen, but be safe. */ + break; + } Curl_bufq_skip(&ctx->inbufq, (size_t)rv); if(Curl_bufq_is_empty(&ctx->inbufq)) { CURL_TRC_CF(data, cf, "[0] all data in connection buffer processed"); From 20d1c6e92ebb19a78e9b6848a210cac15cc14540 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 10:35:40 +0200 Subject: [PATCH 161/465] socks_gssapi: remove superfluous releases of the gss_recv_token Reported in Joshua's sarif data Closes #18714 --- lib/socks_gssapi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 0aa6f7245fe3..a88b6f7b75f7 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -199,7 +199,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, /* the size needs to fit in a 16 bit field */ (gss_send_token.length > 0xffff)) { gss_release_name(&gss_status, &server); - gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); failf(data, "Failed to initial GSS-API token."); @@ -217,7 +216,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(code || (nwritten != 4)) { failf(data, "Failed to send GSS-API authentication request."); gss_release_name(&gss_status, &server); - gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -229,7 +227,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(code || (gss_send_token.length != nwritten)) { failf(data, "Failed to send GSS-API authentication token."); gss_release_name(&gss_status, &server); - gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; @@ -238,7 +235,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } gss_release_buffer(&gss_status, &gss_send_token); - gss_release_buffer(&gss_status, &gss_recv_token); if(gss_major_status != GSS_S_CONTINUE_NEEDED) break; From 8e13e4258373e8f58f269f62f38637302a46f8f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 08:48:20 +0000 Subject: [PATCH 162/465] GHA: update dependency ruff to v0.13.1 --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index f94a9d93a8bd..dd66a5ef454d 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,4 +5,4 @@ cmakelang == 0.6.13 codespell == 2.4.1 pytype == 2024.10.11 -ruff == 0.11.9 +ruff == 0.13.1 From 6796147910168476a5ca9c22fbf297e544b577a7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 11:53:47 +0200 Subject: [PATCH 163/465] GHA/checksrc: run `reuse` directly, merge into the linters workflow To eliminate dependencies on an Action, Docker Hub and to simplify. Closes #18721 --- .github/scripts/requirements.txt | 1 + .github/workflows/checksrc.yml | 20 +++++++------------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index dd66a5ef454d..5e876b0cb2b8 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,4 +5,5 @@ cmakelang == 0.6.13 codespell == 2.4.1 pytype == 2024.10.11 +reuse == 5.1.1 ruff == 0.13.1 diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 5aca2f941a78..59fc930fa76d 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -43,8 +43,8 @@ jobs: - name: 'check' run: scripts/checksrc-all.pl - spellcheck-cmakelint-pytype-ruff: - name: 'spellcheck, cmakelint, pytype, ruff' + linters: + name: 'spellcheck, linters, REUSE' runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 @@ -61,6 +61,11 @@ jobs: -r tests/http/requirements.txt \ -r tests/requirements.txt + - name: 'REUSE check' + run: | + source ~/venv/bin/activate + reuse lint + - name: 'codespell' run: | source ~/venv/bin/activate @@ -89,17 +94,6 @@ jobs: source ~/venv/bin/activate scripts/pythonlint.sh - reuse: - name: 'REUSE' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - persist-credentials: false - - - name: 'check' - uses: fsfe/reuse-action@bb774aa972c2a89ff34781233d275075cbddf542 # v5 - complexity: name: 'complexity' runs-on: ubuntu-latest From 943166fed3d1b8ce6a73b6a1de5de5338dda1428 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 11:30:24 +0200 Subject: [PATCH 164/465] socks_sspi: bail out on too long fields A probably unnecessary precaution but since the field sizes are 16 bit in the protocol this makes sure to fail if they would ever be larger as that would go wrong. Reported in Joshua's sarif data Closes #18719 --- lib/socks_sspi.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 6afc3eac3481..16e22d1f39f5 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -193,6 +193,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(sspi_send_token.cbBuffer) { socksreq[0] = 1; /* GSS-API subnegotiation version */ socksreq[1] = 1; /* authentication message type */ + if(sspi_send_token.cbBuffer > 0xffff) { + /* needs to fit in an unsigned 16 bit field */ + result = CURLE_COULDNT_CONNECT; + goto error; + } us_length = htons((unsigned short)sspi_send_token.cbBuffer); memcpy(socksreq + 2, &us_length, sizeof(short)); @@ -399,9 +404,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, goto error; } - etbuf_size = sspi_w_token[0].cbBuffer + - sspi_w_token[1].cbBuffer + - sspi_w_token[2].cbBuffer; + etbuf_size = sspi_w_token[0].cbBuffer + sspi_w_token[1].cbBuffer + + sspi_w_token[2].cbBuffer; + if(etbuf_size > 0xffff) { + /* needs to fit in an unsigned 16 bit field */ + result = CURLE_COULDNT_CONNECT; + goto error; + } etbuf = malloc(etbuf_size); if(!etbuf) { result = CURLE_OUT_OF_MEMORY; From b3fc692568ad3f01528e726223126e3fe870b1c1 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 8 Aug 2025 12:15:25 +0200 Subject: [PATCH 165/465] lib: upgrade/multiplex handling Improvements around HTTP Upgrade: and multiplex hanndling: * add `Curl_conn_set_multiplex()` to set connection's multiplex bit and trigger "connchanged" events * call `Curl_conn_set_multiplex()` in filters' `CF_CTRL_CONN_INFO_UPDATE` implementation where other connection properties are updated. This prevents connection updates before the final filter chain is chosen. * rename enum `UPGR101_INIT` to `UPGR101_NONE` * rename connection bit `asks_multiplex` to `upgrade_in_progress` * trigger "connchanged" when `upgrade_in_progress` clears * rename `WebSockets` to `WebSocket` as it is the common term used in documentation Closes #18227 --- lib/connect.c | 10 ++++++ lib/connect.h | 3 ++ lib/curl_config.h.cmake | 2 +- lib/http.c | 71 ++++++++++++++++++++++------------------- lib/http2.c | 27 +++++++++------- lib/request.c | 2 +- lib/request.h | 7 ++-- lib/url.c | 5 +-- lib/urldata.h | 2 +- lib/vquic/curl_ngtcp2.c | 5 +-- lib/vquic/curl_osslq.c | 7 ++-- lib/vquic/curl_quiche.c | 7 ++-- lib/ws.c | 7 ++-- 13 files changed, 90 insertions(+), 65 deletions(-) diff --git a/lib/connect.c b/lib/connect.c index f0628d6206ed..1182a42d31fa 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -621,3 +621,13 @@ CURLcode Curl_conn_setup(struct Curl_easy *data, Curl_resolv_unlink(data, &data->state.dns[sockindex]); return result; } + +void Curl_conn_set_multiplex(struct connectdata *conn) +{ + if(!conn->bits.multiplex) { + conn->bits.multiplex = TRUE; + if(conn->attached_multi) { + Curl_multi_connchanged(conn->attached_multi); + } + } +} diff --git a/lib/connect.h b/lib/connect.h index 6a2487ff5383..cb185b2c571b 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -123,6 +123,9 @@ CURLcode Curl_conn_setup(struct Curl_easy *data, struct Curl_dns_entry *dns, int ssl_mode); +/* Set conn to allow multiplexing. */ +void Curl_conn_set_multiplex(struct connectdata *conn); + extern struct Curl_cftype Curl_cft_setup; #endif /* HEADER_CURL_CONNECT_H */ diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 30183c20092f..bc8c1cd487cc 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -148,7 +148,7 @@ /* disables SMTP */ #cmakedefine CURL_DISABLE_SMTP 1 -/* disabled WebSockets */ +/* disabled WebSocket */ #cmakedefine CURL_DISABLE_WEBSOCKETS 1 /* disables use of socketpair for curl_multi_poll */ diff --git a/lib/http.c b/lib/http.c index e01de6f4772c..ce31e6dff005 100644 --- a/lib/http.c +++ b/lib/http.c @@ -2289,7 +2289,7 @@ static CURLcode addexpect(struct Curl_easy *data, struct dynbuf *r, *announced_exp100 = FALSE; /* Avoid Expect: 100-continue if Upgrade: is used */ - if(data->req.upgr101 != UPGR101_INIT) + if(data->req.upgr101 != UPGR101_NONE) return CURLE_OK; /* For really small puts we do not use Expect: headers at all, and for @@ -2622,6 +2622,7 @@ static CURLcode http_check_new_conn(struct Curl_easy *data) info_version = "HTTP/2"; /* There is no ALPN here, but the connection is now definitely h2 */ conn->httpversion_seen = 20; + Curl_conn_set_multiplex(conn); } else info_version = "HTTP/1.x"; @@ -3571,10 +3572,6 @@ static CURLcode http_statusline(struct Curl_easy *data, infof(data, "HTTP 1.0, assume close after body"); connclose(conn, "HTTP/1.0 close after body"); } - else if(k->httpversion == 20 || - (k->upgr101 == UPGR101_H2 && k->httpcode == 101)) { - DEBUGF(infof(data, "HTTP/2 found, allow multiplexing")); - } k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200; switch(k->httpcode) { @@ -3717,6 +3714,7 @@ static CURLcode http_on_response(struct Curl_easy *data, struct connectdata *conn = data->conn; CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; + bool conn_changed = FALSE; (void)buf; /* not used without HTTP2 enabled */ *pconsumed = 0; @@ -3757,47 +3755,54 @@ static CURLcode http_on_response(struct Curl_easy *data, */ http_exp100_got100(data); break; - case 101: - /* Switching Protocols only allowed from HTTP/1.1 */ + case 101: { + int upgr101_requested = k->upgr101; + if(k->httpversion_sent != 11) { /* invalid for other HTTP versions */ - failf(data, "unexpected 101 response code"); + failf(data, "server sent 101 response while not talking HTTP/1.1"); result = CURLE_WEIRD_SERVER_REPLY; goto out; } - if(k->upgr101 == UPGR101_H2) { - /* Switching to HTTP/2, where we will get more responses */ + + /* Whatever the success, upgrade was selected. */ + k->upgr101 = UPGR101_RECEIVED; + data->conn->bits.upgrade_in_progress = FALSE; + conn_changed = TRUE; + + /* To be fully conform, we would check the "Upgrade:" response header + * to mention the protocol we requested. */ + switch(upgr101_requested) { + case UPGR101_H2: + /* Switch to HTTP/2, where we will get more responses. + * blen bytes in bug are already h2 protocol bytes */ infof(data, "Received 101, Switching to HTTP/2"); - k->upgr101 = UPGR101_RECEIVED; - data->conn->bits.asks_multiplex = FALSE; - /* We expect more response from HTTP/2 later */ - k->header = TRUE; - k->headerline = 0; /* restart the header line counter */ - k->httpversion_sent = 20; /* It's an HTTP/2 request now */ - /* Any remaining `buf` bytes are already HTTP/2 and passed to - * be processed. */ result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen); if(result) goto out; *pconsumed += blen; - } + break; #ifndef CURL_DISABLE_WEBSOCKETS - else if(k->upgr101 == UPGR101_WS) { - /* verify the response. Any passed `buf` bytes are already in - * WebSockets format and taken in by the protocol handler. */ + case UPGR101_WS: + /* Switch to WebSocket, where we now stream ws frames. + * blen bytes in bug are already ws protocol bytes */ + infof(data, "Received 101, Switching to WebSocket"); result = Curl_ws_accept(data, buf, blen); if(result) goto out; *pconsumed += blen; /* ws accept handled the data */ - } + break; #endif - else { + default: /* We silently accept this as the final response. What are we * switching to if we did not ask for an Upgrade? Maybe the * application provided an `Upgrade: xxx` header? */ k->header = FALSE; + break; } + /* processed 101 */ break; + } default: /* The server may send us other 1xx responses, like informative * 103. This have no influence on request processing and we expect @@ -3809,12 +3814,10 @@ static CURLcode http_on_response(struct Curl_easy *data, /* k->httpcode >= 200, final response */ k->header = FALSE; - - if(k->upgr101 == UPGR101_H2) { - /* A requested upgrade was denied, poke the multi handle to possibly - allow a pending pipewait to continue */ - data->conn->bits.asks_multiplex = FALSE; - Curl_multi_connchanged(data->multi); + if(data->conn->bits.upgrade_in_progress) { + /* Asked for protocol upgrade, but it was not selected by the server */ + data->conn->bits.upgrade_in_progress = FALSE; + conn_changed = TRUE; } if((k->size == -1) && !k->chunk && !conn->bits.close && @@ -3863,9 +3866,9 @@ static CURLcode http_on_response(struct Curl_easy *data, #endif #ifndef CURL_DISABLE_WEBSOCKETS - /* All >=200 HTTP status codes are errors when wanting WebSockets */ + /* All >=200 HTTP status codes are errors when wanting WebSocket */ if(data->req.upgr101 == UPGR101_WS) { - failf(data, "Refused WebSockets upgrade: %d", k->httpcode); + failf(data, "Refused WebSocket upgrade: %d", k->httpcode); result = CURLE_HTTP_RETURNED_ERROR; goto out; } @@ -3985,6 +3988,10 @@ static CURLcode http_on_response(struct Curl_easy *data, result = Curl_1st_err( result, http_write_header(data, last_hd, last_hd_len)); } + if(conn_changed) { + /* poke the multi handle to allow any pending pipewait to retry now */ + Curl_multi_connchanged(data->multi); + } return result; } diff --git a/lib/http2.c b/lib/http2.c index e2cdc9181f5f..c526bf0fa4c3 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -1829,7 +1829,7 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req, free(base64); k->upgr101 = UPGR101_H2; - data->conn->bits.asks_multiplex = TRUE; + data->conn->bits.upgrade_in_progress = TRUE; return result; } @@ -2696,6 +2696,12 @@ static CURLcode cf_h2_cntrl(struct Curl_cfilter *cf, case CF_CTRL_DATA_DONE: http2_data_done(cf, data); break; + case CF_CTRL_CONN_INFO_UPDATE: + if(!cf->sockindex && cf->connected) { + cf->conn->httpversion_seen = 20; + Curl_conn_set_multiplex(cf->conn); + } + break; default: break; } @@ -2895,9 +2901,6 @@ CURLcode Curl_http2_switch(struct Curl_easy *data) return result; CURL_TRC_CF(data, cf, "switching connection to HTTP/2"); - data->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - Curl_multi_connchanged(data->multi); - if(cf->next) { bool done; return Curl_conn_cf_connect(cf, data, &done); @@ -2917,8 +2920,6 @@ CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data) return result; cf_h2 = cf->next; - cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - Curl_multi_connchanged(data->multi); if(cf_h2->next) { bool done; @@ -2936,7 +2937,6 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, CURLcode result; DEBUGASSERT(Curl_conn_http_version(data, conn) < 20); - DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED); result = http2_cfilter_add(&cf, data, conn, sockindex, TRUE); if(result) @@ -2946,6 +2946,10 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, DEBUGASSERT(cf->cft == &Curl_cft_nghttp2); ctx = cf->ctx; + data->req.httpversion_sent = 20; /* it is an h2 request now */ + data->req.header = TRUE; /* we expect the real response to come in h2 */ + data->req.headerline = 0; /* restart the header line counter */ + if(nread > 0) { /* Remaining data from the protocol switch reply is already using * the switched protocol, ie. HTTP/2. We add that to the network @@ -2968,14 +2972,13 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, " after upgrade: len=%zu", nread); } - conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - Curl_multi_connchanged(data->multi); - if(cf->next) { bool done; - return Curl_conn_cf_connect(cf, data, &done); + result = Curl_conn_cf_connect(cf, data, &done); + if(!result) + cf->cft->cntrl(cf, data, CF_CTRL_CONN_INFO_UPDATE, 0, NULL); } - return CURLE_OK; + return result; } /* Only call this function for a transfer that already got an HTTP/2 diff --git a/lib/request.c b/lib/request.c index 8751ada55987..2d5ad9521209 100644 --- a/lib/request.c +++ b/lib/request.c @@ -139,7 +139,7 @@ void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data) req->offset = 0; req->httpcode = 0; req->keepon = 0; - req->upgr101 = UPGR101_INIT; + req->upgr101 = UPGR101_NONE; req->sendbuf_hds_len = 0; req->timeofdoc = 0; req->location = NULL; diff --git a/lib/request.h b/lib/request.h index bce34de8ba9e..e12d5efdcb23 100644 --- a/lib/request.h +++ b/lib/request.h @@ -42,11 +42,10 @@ enum expect100 { }; enum upgrade101 { - UPGR101_INIT, /* default state */ - UPGR101_WS, /* upgrade to WebSockets requested */ + UPGR101_NONE, /* default state */ + UPGR101_WS, /* upgrade to WebSocket requested */ UPGR101_H2, /* upgrade to HTTP/2 requested */ - UPGR101_RECEIVED, /* 101 response received */ - UPGR101_WORKING /* talking upgraded protocol */ + UPGR101_RECEIVED /* 101 response received */ }; diff --git a/lib/url.c b/lib/url.c index 6af2b7fb8b75..41a63890e6ef 100644 --- a/lib/url.c +++ b/lib/url.c @@ -907,8 +907,8 @@ static bool url_match_fully_connected(struct connectdata *conn, struct url_conn_match *m) { if(!Curl_conn_is_connected(conn, FIRSTSOCKET) || - conn->bits.asks_multiplex) { - /* Not yet connected, or not yet decided if it multiplexes. The later + conn->bits.upgrade_in_progress) { + /* Not yet connected, or a protocol upgrade is in progress. The later * happens for HTTP/2 Upgrade: requests that need a response. */ if(m->may_multiplex) { m->seen_pending_conn = TRUE; @@ -1268,6 +1268,7 @@ static bool url_match_conn(struct connectdata *conn, void *userdata) if(!url_match_connect_config(conn, m)) return FALSE; + /* match for destination and protocol? */ if(!url_match_destination(conn, m)) return FALSE; diff --git a/lib/urldata.h b/lib/urldata.h index b2e83c4a0eef..3c7e634b0008 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -389,7 +389,7 @@ struct ConnectBits { #endif BIT(bound); /* set true if bind() has already been done on this socket/ connection */ - BIT(asks_multiplex); /* connection asks for multiplexing, but is not yet */ + BIT(upgrade_in_progress); /* protocol upgrade is in progress */ BIT(multiplex); /* connection is multiplexed */ BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(tls_enable_alpn); /* TLS ALPN extension? */ diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index f902c190ef58..0e05694992a0 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -464,7 +464,6 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) ctx->handshake_at = curlx_now(); ctx->tls_handshake_complete = TRUE; - cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ Curl_vquic_report_handshake(&ctx->tls, cf, data); ctx->tls_vrfy_result = Curl_vquic_tls_verify_peer(&ctx->tls, cf, @@ -1989,8 +1988,10 @@ static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf, break; } case CF_CTRL_CONN_INFO_UPDATE: - if(!cf->sockindex && cf->connected) + if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; + Curl_conn_set_multiplex(cf->conn); + } break; default: break; diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index c292072a65b6..5e9b0727360b 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -564,9 +564,6 @@ static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_osslq_ctx *ctx = cf->ctx; - - cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); } @@ -2205,8 +2202,10 @@ static CURLcode cf_osslq_cntrl(struct Curl_cfilter *cf, break; } case CF_CTRL_CONN_INFO_UPDATE: - if(!cf->sockindex && cf->connected) + if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; + Curl_conn_set_multiplex(cf->conn); + } break; default: break; diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index b88b4e97bd3d..523f04e33bd9 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1234,8 +1234,10 @@ static CURLcode cf_quiche_cntrl(struct Curl_cfilter *cf, break; } case CF_CTRL_CONN_INFO_UPDATE: - if(!cf->sockindex && cf->connected) + if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; + Curl_conn_set_multiplex(cf->conn); + } break; default: break; @@ -1350,9 +1352,6 @@ static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_quiche_ctx *ctx = cf->ctx; - - cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); } diff --git a/lib/ws.c b/lib/ws.c index b6ab28a35ad0..6a265fccc700 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -582,7 +582,7 @@ static void update_meta(struct websocket *ws, ws->recvframe.bytesleft = bytesleft; } -/* WebSockets decoding client writer */ +/* WebSocket decoding client writer */ struct ws_cw_ctx { struct Curl_cwriter super; struct bufq buf; @@ -1268,6 +1268,7 @@ CURLcode Curl_ws_request(struct Curl_easy *data, struct dynbuf *req) } data->state.http_hd_upgrade = TRUE; k->upgr101 = UPGR101_WS; + data->conn->bits.upgrade_in_progress = TRUE; return result; } @@ -1359,6 +1360,8 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, goto out; ws_dec_writer = NULL; /* owned by transfer now */ + k->header = FALSE; /* we will not get more response headers */ + if(data->set.connect_only) { size_t nwritten; /* In CONNECT_ONLY setup, the payloads from `mem` need to be received @@ -1806,7 +1809,7 @@ CURLcode curl_ws_send(CURL *d, const void *buffer_arg, static CURLcode ws_setup_conn(struct Curl_easy *data, struct connectdata *conn) { - /* WebSockets is 1.1 only (for now) */ + /* WebSocket is 1.1 only (for now) */ data->state.http_neg.accept_09 = FALSE; data->state.http_neg.only_10 = FALSE; data->state.http_neg.wanted = CURL_HTTP_V1x; From ccd2b03b0d32536c909ca056ba84216b3c5efaf5 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 26 Aug 2025 15:54:32 +0200 Subject: [PATCH 166/465] socks: rewwork, cleaning up socks state handling Restructured the code in the following ways: * add terminal states SUCCESS and FAILED * split SOCK4 and SOCK5 states to be more clear * use `bufq` for send/recv of SOCK messages * reduce SOCKS4 states, more speaking names * for most states, move code into static function * reduce SOCKS5 states, more speaking names * add helpers for traversing to FAILED state * add helper to flush bufq * add hepler to read minimum amount into bufq Closes #18401 --- lib/bufq.h | 2 +- lib/socks.c | 1755 +++++++++++++++++++++------------------- tests/libtest/lib564.c | 6 + 3 files changed, 950 insertions(+), 813 deletions(-) diff --git a/lib/bufq.h b/lib/bufq.h index 7cd1826a955c..ad8e6435fae1 100644 --- a/lib/bufq.h +++ b/lib/bufq.h @@ -225,7 +225,7 @@ typedef CURLcode Curl_bufq_reader(void *reader_ctx, size_t *pnread); /** - * Read date and append it to the end of the buffer queue until the + * Read bytes and append them to the end of the buffer queue until the * reader returns blocking or the queue is full. A reader returns * CURLE_AGAIN to indicate blocking. * Returns the total amount of buf read (may be 0) in `pnread` on success. diff --git a/lib/socks.c b/lib/socks.c index 4cb8619d7bd5..6927e32c3ecb 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -34,6 +34,7 @@ #endif #include "urldata.h" +#include "bufq.h" #include "sendf.h" #include "select.h" #include "cfilters.h" @@ -49,46 +50,74 @@ #include "curl_memory.h" #include "memdebug.h" +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) +#define DEBUG_AND_VERBOSE +#endif + /* for the (SOCKS) connect state machine */ -enum connect_t { - CONNECT_INIT, - CONNECT_SOCKS_INIT, /* 1 */ - CONNECT_SOCKS_SEND, /* 2 waiting to send more first data */ - CONNECT_SOCKS_READ_INIT, /* 3 set up read */ - CONNECT_SOCKS_READ, /* 4 read server response */ - CONNECT_GSSAPI_INIT, /* 5 */ - CONNECT_AUTH_INIT, /* 6 setup outgoing auth buffer */ - CONNECT_AUTH_SEND, /* 7 send auth */ - CONNECT_AUTH_READ, /* 8 read auth response */ - CONNECT_REQ_INIT, /* 9 init SOCKS "request" */ - CONNECT_RESOLVING, /* 10 */ - CONNECT_RESOLVED, /* 11 */ - CONNECT_RESOLVE_REMOTE, /* 12 */ - CONNECT_REQ_SEND, /* 13 */ - CONNECT_REQ_SENDING, /* 14 */ - CONNECT_REQ_READ, /* 15 */ - CONNECT_REQ_READ_MORE, /* 16 */ - CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */ +enum socks_state_t { + SOCKS_ST_INIT, + /* SOCKS Version 4 states */ + SOCKS4_ST_START, + SOCKS4_ST_RESOLVING, + SOCKS4_ST_SEND, + SOCKS4_ST_RECV, + /* SOCKS Version 5 states */ + SOCKS5_ST_START, + SOCKS5_ST_REQ0_SEND, + SOCKS5_ST_RESP0_RECV, /* set up read */ + SOCKS5_ST_GSSAPI_INIT, + SOCKS5_ST_AUTH_INIT, /* setup outgoing auth buffer */ + SOCKS5_ST_AUTH_SEND, /* send auth */ + SOCKS5_ST_AUTH_RECV, /* read auth response */ + SOCKS5_ST_REQ1_INIT, /* init SOCKS "request" */ + SOCKS5_ST_RESOLVING, + SOCKS5_ST_REQ1_SEND, + SOCKS5_ST_RESP1_RECV, + /* Terminal states, all SOCKS versions */ + SOCKS_ST_SUCCESS, + SOCKS_ST_FAILED }; -#define CURL_SOCKS_BUF_SIZE 600 - -/* make sure we configure it not too low */ -#if CURL_SOCKS_BUF_SIZE < 600 -#error CURL_SOCKS_BUF_SIZE must be at least 600 +#ifdef DEBUG_AND_VERBOSE +static const char * const cf_socks_statename[] = { + "SOCKS_INIT", + "SOCKS4_START", + "SOCKS4_RESOLVING", + "SOCKS4_SEND", + "SOCKS4_RECV", + "SOCKS5_START", + "SOCKS5_REQ0_SEND", + "SOCKS5_RESP0_RECV", + "SOCKS5_GSSAPI_INIT", + "SOCKS5_AUTH_INIT", + "SOCKS5_AUTH_SEND", + "SOCKS5_AUTH_RECV", + "SOCKS5_REQ1_INIT", + "SOCKS5_RESOLVING", + "SOCKS5_REQ1_SEND", + "SOCKS5_RESP1_RECV", + "SOCKS_SUCCESS", + "SOCKS_FAILED" +}; #endif +#define SOCKS_CHUNK_SIZE 1024 +#define SOCKS_CHUNKS 1 -struct socks_state { - enum connect_t state; - size_t outstanding; /* send this many bytes more */ - unsigned char buffer[CURL_SOCKS_BUF_SIZE]; - unsigned char *outp; /* send from this pointer */ +struct socks_state { + enum socks_state_t state; + struct bufq iobuf; const char *hostname; int remote_port; const char *proxy_user; const char *proxy_password; + CURLproxycode presult; + unsigned char version; + BIT(resolve_local); + BIT(start_resolving); + BIT(socks4a); }; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) @@ -149,37 +178,13 @@ CURLcode Curl_blockread_all(struct Curl_cfilter *cf, static void socksstate(struct socks_state *sx, struct Curl_cfilter *cf, struct Curl_easy *data, - enum connect_t state + enum socks_state_t state #ifdef DEBUG_AND_VERBOSE , int lineno #endif ) { - enum connect_t oldstate = sx->state; -#ifdef DEBUG_AND_VERBOSE - /* synced with the state list in urldata.h */ - static const char * const socks_statename[] = { - "INIT", - "SOCKS_INIT", - "SOCKS_SEND", - "SOCKS_READ_INIT", - "SOCKS_READ", - "GSSAPI_INIT", - "AUTH_INIT", - "AUTH_SEND", - "AUTH_READ", - "REQ_INIT", - "RESOLVING", - "RESOLVED", - "RESOLVE_REMOTE", - "REQ_SEND", - "REQ_SENDING", - "REQ_READ", - "REQ_READ_MORE", - "DONE" - }; -#endif - + enum socks_state_t oldstate = sx->state; (void)cf; (void)data; if(oldstate == state) @@ -190,274 +195,209 @@ static void socksstate(struct socks_state *sx, #ifdef DEBUG_AND_VERBOSE CURL_TRC_CF(data, cf, "[%s] -> [%s] (line %d)", - socks_statename[oldstate], socks_statename[sx->state], lineno); + cf_socks_statename[oldstate], + cf_socks_statename[sx->state], lineno); #endif } -static CURLproxycode socks_state_send(struct Curl_cfilter *cf, - struct socks_state *sx, - struct Curl_easy *data, - CURLproxycode failcode, - const char *description) +static CURLproxycode socks_failed(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + CURLproxycode presult) +{ + sxstate(sx, cf, data, SOCKS_ST_FAILED); + sx->presult = presult; + return presult; +} + +static CURLproxycode socks_flush(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { - size_t nwritten; CURLcode result; + size_t nwritten; - result = Curl_conn_cf_send(cf->next, data, (char *)sx->outp, - sx->outstanding, FALSE, &nwritten); - if(result) { - if(CURLE_AGAIN == result) + *done = FALSE; + while(!Curl_bufq_is_empty(&sx->iobuf)) { + result = Curl_cf_send_bufq(cf->next, data, &sx->iobuf, NULL, 0, + &nwritten); + if(result == CURLE_AGAIN) return CURLPX_OK; - - failf(data, "Failed to send %s: %s", description, - curl_easy_strerror(result)); - return failcode; - } - else if(!nwritten) { - /* connection closed */ - failf(data, "connection to proxy closed"); - return CURLPX_CLOSED; + else if(result) { + failf(data, "Failed to send SOCKS request: %s", + curl_easy_strerror(result)); + return socks_failed(sx, cf, data, CURLPX_SEND_CONNECT); + } } - - DEBUGASSERT(sx->outstanding >= nwritten); - /* not done, remain in state */ - sx->outstanding -= nwritten; - sx->outp += nwritten; + *done = TRUE; return CURLPX_OK; } -static CURLproxycode socks_state_recv(struct Curl_cfilter *cf, - struct socks_state *sx, - struct Curl_easy *data, - CURLproxycode failcode, - const char *description) +static CURLproxycode socks_recv(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + size_t min_bytes, + bool *done) { - size_t nread; CURLcode result; + size_t nread; - result = Curl_conn_cf_recv(cf->next, data, (char *)sx->outp, - sx->outstanding, &nread); - if(result) { - if(CURLE_AGAIN == result) + *done = FALSE; + while(Curl_bufq_len(&sx->iobuf) < min_bytes) { + result = Curl_cf_recv_bufq(cf->next, data, &sx->iobuf, + min_bytes - Curl_bufq_len(&sx->iobuf), + &nread); + if(result == CURLE_AGAIN) return CURLPX_OK; - - failf(data, "SOCKS: Failed receiving %s: %s", description, - curl_easy_strerror(result)); - return failcode; - } - else if(!nread) { - /* connection closed */ - failf(data, "connection to proxy closed"); - return CURLPX_CLOSED; + else if(result) { + failf(data, "Failed to receive SOCKS response: %s", + curl_easy_strerror(result)); + return CURLPX_RECV_CONNECT; + } + else if(!nread) /* EOF */ + break; } - /* remain in reading state */ - DEBUGASSERT(sx->outstanding >= nread); - sx->outstanding -= nread; - sx->outp += nread; + *done = TRUE; return CURLPX_OK; } -/* -* This function logs in to a SOCKS4 proxy and sends the specifics to the final -* destination server. -* -* Reference : -* https://www.openssh.com/txt/socks4.protocol -* -* Note : -* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" -* Nonsupport "Identification Protocol (RFC1413)" -*/ -static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, - struct socks_state *sx, - struct Curl_easy *data) +static CURLproxycode socks4_req_add_hd(struct socks_state *sx, + struct Curl_easy *data) { - struct connectdata *conn = cf->conn; - const bool protocol4a = - (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A); - unsigned char *socksreq = sx->buffer; + unsigned char buf[4]; + size_t nwritten; CURLcode result; - CURLproxycode presult; - struct Curl_dns_entry *dns = NULL; - - switch(sx->state) { - case CONNECT_SOCKS_INIT: - /* SOCKS4 can only do IPv4, insist! */ - conn->ip_version = CURL_IPRESOLVE_V4; - CURL_TRC_CF(data, cf, "SOCKS4%s communication to%s %s:%d", - protocol4a ? "a" : "", - conn->bits.httpproxy ? " HTTP proxy" : "", - sx->hostname, sx->remote_port); - /* - * Compose socks4 request - * - * Request format - * - * +----+----+----+----+----+----+----+----+----+----+....+----+ - * | VN | CD | DSTPORT | DSTIP | USERID |NULL| - * +----+----+----+----+----+----+----+----+----+----+....+----+ - * # of bytes: 1 1 2 4 variable 1 - */ + (void)data; + buf[0] = 4; /* version (SOCKS4) */ + buf[1] = 1; /* connect */ + buf[2] = (unsigned char)((sx->remote_port >> 8) & 0xffu); /* MSB */ + buf[3] = (unsigned char)(sx->remote_port & 0xffu); /* LSB */ + + result = Curl_bufq_write(&sx->iobuf, buf, 4, &nwritten); + if(result || (nwritten != 4)) + return CURLPX_SEND_REQUEST; + return CURLPX_OK; +} - socksreq[0] = 4; /* version (SOCKS4) */ - socksreq[1] = 1; /* connect */ - socksreq[2] = (unsigned char)((sx->remote_port >> 8) & 0xff); /* MSB */ - socksreq[3] = (unsigned char)(sx->remote_port & 0xff); /* LSB */ +static CURLproxycode socks4_req_add_user(struct socks_state *sx, + struct Curl_easy *data) +{ + CURLcode result; + size_t nwritten; - /* DNS resolve only for SOCKS4, not SOCKS4a */ - if(!protocol4a) { - result = Curl_resolv(data, sx->hostname, sx->remote_port, - cf->conn->ip_version, TRUE, &dns); - - if(result == CURLE_AGAIN) { - sxstate(sx, cf, data, CONNECT_RESOLVING); - CURL_TRC_CF(data, cf, "SOCKS4 non-blocking resolve of %s", - sx->hostname); - return CURLPX_OK; - } - else if(result) - return CURLPX_RESOLVE_HOST; - sxstate(sx, cf, data, CONNECT_RESOLVED); - goto CONNECT_RESOLVED; + if(sx->proxy_user) { + size_t plen = strlen(sx->proxy_user); + if(plen > 255) { + /* there is no real size limit to this field in the protocol, but + SOCKS5 limits the proxy user field to 255 bytes and it seems likely + that a longer field is either a mistake or malicious input */ + failf(data, "Too long SOCKS proxy username"); + return CURLPX_LONG_USER; } + /* add proxy name WITH trailing zero */ + result = Curl_bufq_cwrite(&sx->iobuf, sx->proxy_user, plen + 1, + &nwritten); + if(result || (nwritten != (plen + 1))) + return CURLPX_SEND_REQUEST; + } + else { + /* empty user name */ + unsigned char b = 0; + result = Curl_bufq_write(&sx->iobuf, &b, 1, &nwritten); + if(result || (nwritten != 1)) + return CURLPX_SEND_REQUEST; + } + return CURLPX_OK; +} + +static CURLproxycode socks4_resolving(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + struct Curl_dns_entry *dns = NULL; + struct Curl_addrinfo *hp = NULL; + CURLcode result; + size_t nwritten; - /* socks4a does not resolve anything locally */ - sxstate(sx, cf, data, CONNECT_REQ_INIT); - goto CONNECT_REQ_INIT; + *done = FALSE; + if(sx->start_resolving) { + /* need to resolve hostname to add destination address */ + sx->start_resolving = FALSE; - case CONNECT_RESOLVING: + result = Curl_resolv(data, sx->hostname, sx->remote_port, + cf->conn->ip_version, TRUE, &dns); + if(result == CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "SOCKS4 non-blocking resolve of %s", + sx->hostname); + return CURLPX_OK; + } + else if(result) + return CURLPX_RESOLVE_HOST; + } + else { /* check if we have the name resolved by now */ result = Curl_resolv_check(data, &dns); - if(!dns) { - if(result) - return CURLPX_RESOLVE_HOST; + if(!result && !dns) return CURLPX_OK; - } - FALLTHROUGH(); - case CONNECT_RESOLVED: -CONNECT_RESOLVED: - { - struct Curl_addrinfo *hp = NULL; - /* - * We cannot use 'hostent' as a struct that Curl_resolv() returns. It - * returns a Curl_addrinfo pointer that may not always look the same. - */ - if(dns) { - hp = dns->addr; - - /* scan for the first IPv4 address */ - while(hp && (hp->ai_family != AF_INET)) - hp = hp->ai_next; - - if(hp) { - struct sockaddr_in *saddr_in; - char buf[64]; - Curl_printable_address(hp, buf, sizeof(buf)); - - saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; - socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0]; - socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1]; - socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2]; - socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3]; - - CURL_TRC_CF(data, cf, "SOCKS4 connect to IPv4 %s (locally resolved)", - buf); - Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ - } - else - failf(data, "SOCKS4 connection to %s not supported", sx->hostname); - } - else - failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", - sx->hostname); + } - if(!hp) - return CURLPX_RESOLVE_HOST; + if(result || !dns) { + failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", + sx->hostname); + return CURLPX_RESOLVE_HOST; } - FALLTHROUGH(); - case CONNECT_REQ_INIT: -CONNECT_REQ_INIT: - /* - * This is currently not supporting "Identification Protocol (RFC1413)". - */ - socksreq[8] = 0; /* ensure empty userid is null-terminated */ - if(sx->proxy_user) { - size_t plen = strlen(sx->proxy_user); - if(plen > 255) { - /* there is no real size limit to this field in the protocol, but - SOCKS5 limits the proxy user field to 255 bytes and it seems likely - that a longer field is either a mistake or malicious input */ - failf(data, "Too long SOCKS proxy username"); - return CURLPX_LONG_USER; - } - /* copy the proxy name WITH trailing zero */ - memcpy(socksreq + 8, sx->proxy_user, plen + 1); - } - /* - * Make connection - */ - { - size_t packetsize = 9 + - strlen((char *)socksreq + 8); /* size including NUL */ - - /* If SOCKS4a, set special invalid IP address 0.0.0.x */ - if(protocol4a) { - size_t hostnamelen = 0; - socksreq[4] = 0; - socksreq[5] = 0; - socksreq[6] = 0; - socksreq[7] = 1; - /* append hostname */ - hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */ - if((hostnamelen <= 255) && - (packetsize + hostnamelen < sizeof(sx->buffer))) - strcpy((char *)socksreq + packetsize, sx->hostname); - else { - failf(data, "SOCKS4: too long hostname"); - return CURLPX_LONG_HOSTNAME; - } - packetsize += hostnamelen; - } - sx->outp = socksreq; - DEBUGASSERT(packetsize <= sizeof(sx->buffer)); - sx->outstanding = packetsize; - sxstate(sx, cf, data, CONNECT_REQ_SENDING); - } - FALLTHROUGH(); - case CONNECT_REQ_SENDING: - /* Send request */ - presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, - "SOCKS4 connect request"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in sending state */ - return CURLPX_OK; - } - /* done sending! */ - sx->outstanding = 8; /* receive data size */ - sx->outp = socksreq; - sxstate(sx, cf, data, CONNECT_SOCKS_READ); + /* + * We cannot use 'hostent' as a struct that Curl_resolv() returns. It + * returns a Curl_addrinfo pointer that may not always look the same. + */ + /* scan for the first IPv4 address */ + hp = dns->addr; + while(hp && (hp->ai_family != AF_INET)) + hp = hp->ai_next; - FALLTHROUGH(); - case CONNECT_SOCKS_READ: - /* Receive response */ - presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, - "connect request ack"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in reading state */ - return CURLPX_OK; - } - sxstate(sx, cf, data, CONNECT_DONE); - break; - default: /* lots of unused states in SOCKS4 */ - break; + if(hp) { + struct sockaddr_in *saddr_in; + char ipbuf[64]; + + Curl_printable_address(hp, ipbuf, sizeof(ipbuf)); + CURL_TRC_CF(data, cf, "SOCKS4 connect to IPv4 %s (locally resolved)", + ipbuf); + + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + result = Curl_bufq_write(&sx->iobuf, + (unsigned char *)&saddr_in->sin_addr.s_addr, 4, + &nwritten); + + Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ + if(result || (nwritten != 4)) + return CURLPX_SEND_REQUEST; + } + else { + failf(data, "SOCKS4 connection to %s not supported", sx->hostname); + return CURLPX_RESOLVE_HOST; + } + + *done = TRUE; + return CURLPX_OK; +} + +static CURLproxycode socks4_check_resp(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + const unsigned char *resp; + size_t rlen; + + if(!Curl_bufq_peek(&sx->iobuf, &resp, &rlen) || rlen < 8) { + failf(data, "SOCKS4 reply is incomplete."); + return CURLPX_RECV_CONNECT; } + DEBUGASSERT(rlen == 8); /* * Response format * @@ -478,72 +418,194 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, */ /* wrong version ? */ - if(socksreq[0]) { - failf(data, - "SOCKS4 reply has wrong version, version should be 0."); + if(resp[0]) { + failf(data, "SOCKS4 reply has wrong version, version should be 0."); return CURLPX_BAD_VERSION; } /* Result */ - switch(socksreq[1]) { + switch(resp[1]) { case 90: - CURL_TRC_CF(data, cf, "SOCKS4%s request granted.", protocol4a ? "a" : ""); - break; + CURL_TRC_CF(data, cf, "SOCKS4%s request granted.", sx->socks4a ? "a" : ""); + Curl_bufq_reset(&sx->iobuf); + return CURLPX_OK; case 91: failf(data, - "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %u.%u.%u.%u:%u. (%u)" ", request rejected or failed.", - socksreq[4], socksreq[5], socksreq[6], socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); + resp[4], resp[5], resp[6], resp[7], + ((resp[2] << 8) | resp[3]), resp[1]); return CURLPX_REQUEST_FAILED; case 92: failf(data, - "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %u.%u.%u.%u:%u. (%u)" ", request rejected because SOCKS server cannot connect to " "identd on the client.", - socksreq[4], socksreq[5], socksreq[6], socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); + resp[4], resp[5], resp[6], resp[7], + ((resp[2] << 8) | resp[3]), resp[1]); return CURLPX_IDENTD; case 93: failf(data, - "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %u.%u.%u.%u:%u. (%u)" ", request rejected because the client program and identd " "report different user-ids.", - socksreq[4], socksreq[5], socksreq[6], socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); + resp[4], resp[5], resp[6], resp[7], + ((resp[2] << 8) | resp[3]), resp[1]); return CURLPX_IDENTD_DIFFER; default: failf(data, - "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %u.%u.%u.%u:%u. (%u)" ", Unknown.", - socksreq[4], socksreq[5], socksreq[6], socksreq[7], - (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), - (unsigned char)socksreq[1]); + resp[4], resp[5], resp[6], resp[7], + ((resp[2] << 8) | resp[3]), resp[1]); return CURLPX_UNKNOWN_FAIL; } - - return CURLPX_OK; /* Proxy was successful! */ } -static CURLproxycode socks5_init(struct Curl_cfilter *cf, - struct socks_state *sx, - struct Curl_easy *data, - const bool socks5_resolve_local, - const size_t hostname_len) +/* +* This function logs in to a SOCKS4 proxy and sends the specifics to the final +* destination server. +* +* Reference : +* https://www.openssh.com/txt/socks4.protocol +* +* Note : +* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)" +* Nonsupport "Identification Protocol (RFC1413)" +*/ +static CURLproxycode socks4_connect(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) { - struct connectdata *conn = cf->conn; - const unsigned char auth = data->set.socks5auth; - unsigned char *socksreq = sx->buffer; + size_t nwritten; + CURLproxycode presult; + CURLcode result; + bool done; + +process_state: + switch(sx->state) { + case SOCKS_ST_INIT: + sx->version = 4; + sxstate(sx, cf, data, SOCKS4_ST_START); + FALLTHROUGH(); - if(conn->bits.httpproxy) - CURL_TRC_CF(data, cf, "SOCKS5: connecting to HTTP proxy %s port %d", + case SOCKS4_ST_START: + Curl_bufq_reset(&sx->iobuf); + sx->start_resolving = FALSE; + sx->socks4a = (cf->conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A); + sx->resolve_local = !sx->socks4a; + sx->presult = CURLPX_OK; + + /* SOCKS4 can only do IPv4, insist! */ + cf->conn->ip_version = CURL_IPRESOLVE_V4; + CURL_TRC_CF(data, cf, "SOCKS4%s communication to%s %s:%d", + sx->socks4a ? "a" : "", + cf->conn->bits.httpproxy ? " HTTP proxy" : "", sx->hostname, sx->remote_port); + /* + * Compose socks4 request + * + * Request format + * + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * | VN | CD | DSTPORT | DSTIP | USERID |NULL| + * +----+----+----+----+----+----+----+----+----+----+....+----+ + * # of bytes: 1 1 2 4 variable 1 + */ + presult = socks4_req_add_hd(sx, data); + if(presult) + return socks_failed(sx, cf, data, presult); + + /* DNS resolve only for SOCKS4, not SOCKS4a */ + if(!sx->resolve_local) { + /* socks4a, not resolving locally, sends the hostname. + * add an invalid address + user + hostname */ + unsigned char buf[4] = { 0, 0, 0, 1 }; + size_t hlen = strlen(sx->hostname) + 1; /* including NUL */ + + if(hlen > 255) { + failf(data, "SOCKS4: too long hostname"); + return socks_failed(sx, cf, data, CURLPX_LONG_HOSTNAME); + } + result = Curl_bufq_write(&sx->iobuf, buf, 4, &nwritten); + if(result || (nwritten != 4)) + return socks_failed(sx, cf, data, CURLPX_SEND_REQUEST); + presult = socks4_req_add_user(sx, data); + if(presult) + return socks_failed(sx, cf, data, presult); + result = Curl_bufq_cwrite(&sx->iobuf, sx->hostname, hlen, &nwritten); + if(result || (nwritten != hlen)) + return socks_failed(sx, cf, data, CURLPX_SEND_REQUEST); + /* request complete */ + sxstate(sx, cf, data, SOCKS4_ST_SEND); + goto process_state; + } + sx->start_resolving = TRUE; + sxstate(sx, cf, data, SOCKS4_ST_RESOLVING); + FALLTHROUGH(); + + case SOCKS4_ST_RESOLVING: + presult = socks4_resolving(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + if(!done) + return CURLPX_OK; + /* append user */ + presult = socks4_req_add_user(sx, data); + if(presult) + return socks_failed(sx, cf, data, presult); + sxstate(sx, cf, data, SOCKS4_ST_SEND); + FALLTHROUGH(); + + case SOCKS4_ST_SEND: + presult = socks_flush(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) + return CURLPX_OK; + sxstate(sx, cf, data, SOCKS4_ST_RECV); + FALLTHROUGH(); + + case SOCKS4_ST_RECV: + /* Receive 8 byte response */ + presult = socks_recv(sx, cf, data, 8, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) + return CURLPX_OK; + presult = socks4_check_resp(sx, cf, data); + if(presult) + return socks_failed(sx, cf, data, presult); + sxstate(sx, cf, data, SOCKS_ST_SUCCESS); + FALLTHROUGH(); + + case SOCKS_ST_SUCCESS: + return CURLPX_OK; + + case SOCKS_ST_FAILED: + DEBUGASSERT(sx->presult); + return sx->presult; + + default: + DEBUGASSERT(0); + return socks_failed(sx, cf, data, CURLPX_SEND_REQUEST); + } +} + +static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + const unsigned char auth = data->set.socks5auth; + unsigned char req[5]; /* version + len + 3 possible auth methods */ + unsigned char nauths; + size_t req_len, nwritten; + CURLcode result; + + (void)cf; /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ - if(!socks5_resolve_local && hostname_len > 255) { + if(!sx->resolve_local && strlen(sx->hostname) > 255) { failf(data, "SOCKS5: the destination hostname is too long to be " "resolved remotely by the proxy."); return CURLPX_LONG_HOSTNAME; @@ -556,27 +618,73 @@ static CURLproxycode socks5_init(struct Curl_cfilter *cf, /* disable username/password auth */ sx->proxy_user = NULL; - if(!sx->outstanding) { - size_t idx = 0; - socksreq[idx++] = 5; /* version */ - idx++; /* number of authentication methods */ - socksreq[idx++] = 0; /* no authentication */ + req[0] = 5; /* version */ + nauths = 1; + req[1 + nauths] = 0; /* 1. no authentication */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(auth & CURLAUTH_GSSAPI) - socksreq[idx++] = 1; /* GSS-API */ + if(auth & CURLAUTH_GSSAPI) { + ++nauths; + req[1 + nauths] = 1; /* GSS-API */ + } #endif - if(sx->proxy_user) - socksreq[idx++] = 2; /* username/password */ - /* write the number of authentication methods */ - socksreq[1] = (unsigned char) (idx - 2); - - sx->outp = socksreq; - DEBUGASSERT(idx <= sizeof(sx->buffer)); - sx->outstanding = idx; + if(sx->proxy_user) { + ++nauths; + req[1 + nauths] = 2; /* username/password */ } + req[1] = nauths; + req_len = 2 + nauths; + + result = Curl_bufq_write(&sx->iobuf, req, req_len, &nwritten); + if(result || (nwritten != req_len)) + return CURLPX_SEND_REQUEST; + return CURLPX_OK; +} + +static CURLproxycode socks5_check_resp0(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + const unsigned char *resp; + unsigned char auth_mode; + size_t rlen; - return socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, - "initial SOCKS5 request"); + if(!Curl_bufq_peek(&sx->iobuf, &resp, &rlen) || rlen < 2) { + failf(data, "SOCKS5 initial reply is incomplete."); + return CURLPX_RECV_CONNECT; + } + + if(resp[0] != 5) { + failf(data, "Received invalid version in initial SOCKS5 response."); + return CURLPX_BAD_VERSION; + } + + auth_mode = resp[1]; + Curl_bufq_reset(&sx->iobuf); + + switch(auth_mode) { + case 0: + /* DONE! No authentication needed. Send request. */ + sxstate(sx, cf, data, SOCKS5_ST_REQ1_INIT); + return CURLPX_OK; + case 1: + if(data->set.socks5auth & CURLAUTH_GSSAPI) { + sxstate(sx, cf, data, SOCKS5_ST_GSSAPI_INIT); + return CURLPX_OK; + } + failf(data, + "SOCKS5 GSSAPI per-message authentication is not enabled."); + return CURLPX_GSSAPI_PERMSG; + case 2: + /* regular name + password authentication */ + sxstate(sx, cf, data, SOCKS5_ST_AUTH_INIT); + return CURLPX_OK; + case 255: + failf(data, "No authentication method was acceptable."); + return CURLPX_NO_AUTH; + default: + failf(data, "Unknown SOCKS5 mode attempted to be used by server."); + return CURLPX_UNKNOWN_MODE; + } } static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf, @@ -584,17 +692,22 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf, struct Curl_easy *data) { /* Needs username and password */ - size_t proxy_user_len, proxy_password_len; - size_t len = 0; - unsigned char *socksreq = sx->buffer; + size_t ulen = 0, plen = 0, nwritten; + unsigned char buf[2]; + CURLcode result; if(sx->proxy_user && sx->proxy_password) { - proxy_user_len = strlen(sx->proxy_user); - proxy_password_len = strlen(sx->proxy_password); - } - else { - proxy_user_len = 0; - proxy_password_len = 0; + ulen = strlen(sx->proxy_user); + plen = strlen(sx->proxy_password); + /* the lengths must fit in a single byte */ + if(ulen > 255) { + failf(data, "Excessive username length for proxy auth"); + return CURLPX_LONG_USER; + } + if(plen > 255) { + failf(data, "Excessive password length for proxy auth"); + return CURLPX_LONG_PASSWD; + } } /* username/password request looks like @@ -604,499 +717,494 @@ static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf, * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | * +----+------+----------+------+----------+ */ - socksreq[len++] = 1; /* username/pw subnegotiation version */ - socksreq[len++] = (unsigned char) proxy_user_len; - if(sx->proxy_user && proxy_user_len) { - /* the length must fit in a single byte */ - if(proxy_user_len > 255) { - failf(data, "Excessive username length for proxy auth"); - return CURLPX_LONG_USER; - } - memcpy(socksreq + len, sx->proxy_user, proxy_user_len); + buf[0] = 1; /* username/pw subnegotiation version */ + buf[1] = (unsigned char)ulen; + result = Curl_bufq_write(&sx->iobuf, buf, 2, &nwritten); + if(result || (nwritten != 2)) + return CURLPX_SEND_REQUEST; + if(ulen) { + result = Curl_bufq_cwrite(&sx->iobuf, sx->proxy_user, ulen, &nwritten); + if(result || (nwritten != ulen)) + return CURLPX_SEND_REQUEST; } - len += proxy_user_len; - socksreq[len++] = (unsigned char) proxy_password_len; - if(sx->proxy_password && proxy_password_len) { - /* the length must fit in a single byte */ - if(proxy_password_len > 255) { - failf(data, "Excessive password length for proxy auth"); - return CURLPX_LONG_PASSWD; - } - memcpy(socksreq + len, sx->proxy_password, proxy_password_len); + buf[0] = (unsigned char) plen; + result = Curl_bufq_write(&sx->iobuf, buf, 1, &nwritten); + if(result || (nwritten != 1)) + return CURLPX_SEND_REQUEST; + if(plen) { + result = Curl_bufq_cwrite(&sx->iobuf, sx->proxy_password, plen, &nwritten); + if(result || (nwritten != plen)) + return CURLPX_SEND_REQUEST; } - len += proxy_password_len; - sxstate(sx, cf, data, CONNECT_AUTH_SEND); - DEBUGASSERT(len <= sizeof(sx->buffer)); - sx->outstanding = len; - sx->outp = socksreq; + sxstate(sx, cf, data, SOCKS5_ST_AUTH_SEND); return CURLPX_OK; } -/* - * This function logs in to a SOCKS5 proxy and sends the specifics to the final - * destination server. - */ -static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, - struct socks_state *sx, - struct Curl_easy *data) +static CURLproxycode socks5_check_auth_resp(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data) { - /* - According to the RFC1928, section "6. Replies". This is what a SOCK5 - replies: + const unsigned char *resp; + unsigned char auth_status; + size_t rlen; - +----+-----+-------+------+----------+----------+ - |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ + (void)cf; + if(!Curl_bufq_peek(&sx->iobuf, &resp, &rlen) || rlen < 2) { + failf(data, "SOCKS5 sub-negotiation response incomplete."); + return CURLPX_RECV_CONNECT; + } - Where: + /* ignore the first (VER) byte */ + auth_status = resp[1]; + Curl_bufq_reset(&sx->iobuf); - o VER protocol version: X'05' - o REP Reply field: - o X'00' succeeded - */ - struct connectdata *conn = cf->conn; - unsigned char *socksreq = sx->buffer; + if(auth_status) { + failf(data, "User was rejected by the SOCKS5 server (%d %d).", + resp[0], resp[1]); + return CURLPX_USER_REJECTED; + } + return CURLPX_OK; +} + +static CURLproxycode socks5_req1_init(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + unsigned char req[5]; + unsigned char ipbuf[16]; + const unsigned char *destination; + unsigned char desttype, destlen, hdlen; + size_t nwritten; CURLcode result; - CURLproxycode presult; - bool socks5_resolve_local = - (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5); - const size_t hostname_len = strlen(sx->hostname); - size_t len = 0; - bool allow_gssapi = FALSE; - struct Curl_dns_entry *dns = NULL; - switch(sx->state) { - case CONNECT_SOCKS_INIT: - presult = socks5_init(cf, sx, data, socks5_resolve_local, hostname_len); - if(presult || sx->outstanding) - return presult; - sxstate(sx, cf, data, CONNECT_SOCKS_READ); - goto CONNECT_SOCKS_READ_INIT; - case CONNECT_SOCKS_SEND: - presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, - "initial SOCKS5 request"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in sending state */ - return CURLPX_OK; - } - FALLTHROUGH(); - case CONNECT_SOCKS_READ_INIT: -CONNECT_SOCKS_READ_INIT: - sx->outstanding = 2; /* expect two bytes */ - sx->outp = socksreq; /* store it here */ - FALLTHROUGH(); - case CONNECT_SOCKS_READ: - presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, - "initial SOCKS5 response"); -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(data->set.socks5auth & CURLAUTH_GSSAPI) - allow_gssapi = TRUE; -#endif - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in reading state */ - return CURLPX_OK; - } - else if(socksreq[0] != 5) { - failf(data, "Received invalid version in initial SOCKS5 response."); - return CURLPX_BAD_VERSION; - } - else if(socksreq[1] == 0) { - /* DONE! No authentication needed. Send request. */ - sxstate(sx, cf, data, CONNECT_REQ_INIT); - goto CONNECT_REQ_INIT; - } - else if(socksreq[1] == 2) { - /* regular name + password authentication */ - sxstate(sx, cf, data, CONNECT_AUTH_INIT); - goto CONNECT_AUTH_INIT; - } -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - else if(allow_gssapi && (socksreq[1] == 1)) { - sxstate(sx, cf, data, CONNECT_GSSAPI_INIT); - result = Curl_SOCKS5_gssapi_negotiate(cf, data); - if(result) { - failf(data, "Unable to negotiate SOCKS5 GSS-API context."); - return CURLPX_GSSAPI; - } - } -#endif - else { - /* error */ - if(!allow_gssapi && (socksreq[1] == 1)) { - failf(data, - "SOCKS5 GSSAPI per-message authentication is not supported."); - return CURLPX_GSSAPI_PERMSG; - } - else if(socksreq[1] == 255) { - failf(data, "No authentication method was acceptable."); - return CURLPX_NO_AUTH; - } - } - failf(data, - "Undocumented SOCKS5 mode attempted to be used by server."); - return CURLPX_UNKNOWN_MODE; -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - case CONNECT_GSSAPI_INIT: - /* GSSAPI stuff done non-blocking */ - break; + req[0] = 5; /* version (SOCKS5) */ + req[1] = 1; /* connect */ + req[2] = 0; /* must be zero */ + if(sx->resolve_local) { + /* rest of request is added after resolving */ + result = Curl_bufq_write(&sx->iobuf, req, 3, &nwritten); + if(result || (nwritten != 3)) + return CURLPX_SEND_REQUEST; + return CURLPX_OK; + } + + /* remote resolving, send what type+addr/string to resolve */ +#ifdef USE_IPV6 + if(cf->conn->bits.ipv6_ip) { + desttype = 4; + destination = ipbuf; + destlen = 16; + if(curlx_inet_pton(AF_INET6, sx->hostname, ipbuf) != 1) + return CURLPX_BAD_ADDRESS_TYPE; + } + else #endif + if(curlx_inet_pton(AF_INET, sx->hostname, ipbuf) == 1) { + desttype = 1; + destination = ipbuf; + destlen = 4; + } + else { + const size_t hostname_len = strlen(sx->hostname); + desttype = 3; + destination = (const unsigned char *)sx->hostname; + destlen = (unsigned char) hostname_len; /* one byte length */ + } - default: /* do nothing! */ - break; + req[3] = desttype; + req[4] = destlen; + hdlen = (desttype == 3) ? 5 : 4; /* no length byte for ip addresses */ + result = Curl_bufq_write(&sx->iobuf, req, hdlen, &nwritten); + if(result || (nwritten != hdlen)) + return CURLPX_SEND_REQUEST; + result = Curl_bufq_write(&sx->iobuf, destination, destlen, &nwritten); + if(result || (nwritten != destlen)) + return CURLPX_SEND_REQUEST; + /* PORT MSB+LSB */ + req[0] = (unsigned char)((sx->remote_port >> 8) & 0xff); + req[1] = (unsigned char)(sx->remote_port & 0xff); + result = Curl_bufq_write(&sx->iobuf, req, 2, &nwritten); + if(result || (nwritten != 2)) + return CURLPX_SEND_REQUEST; + CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%d (remotely resolved)", + sx->hostname, sx->remote_port); + return CURLPX_OK; +} -CONNECT_AUTH_INIT: - case CONNECT_AUTH_INIT: - presult = socks5_auth_init(cf, sx, data); - if(presult) - return presult; - FALLTHROUGH(); - case CONNECT_AUTH_SEND: - presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH, - "SOCKS5 sub-negotiation request"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in sending state */ - return CURLPX_OK; - } - sx->outp = socksreq; - sx->outstanding = 2; - sxstate(sx, cf, data, CONNECT_AUTH_READ); - FALLTHROUGH(); - case CONNECT_AUTH_READ: - presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH, - "SOCKS5 sub-negotiation response"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in reading state */ - return CURLPX_OK; - } - /* ignore the first (VER) byte */ - else if(socksreq[1]) { /* status */ - failf(data, "User was rejected by the SOCKS5 server (%d %d).", - socksreq[0], socksreq[1]); - return CURLPX_USER_REJECTED; - } +static CURLproxycode socks5_resolving(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + struct Curl_dns_entry *dns = NULL; + struct Curl_addrinfo *hp = NULL; + char dest[MAX_IPADR_LEN]; /* printable address */ + unsigned char *destination = NULL; + unsigned char desttype = 1, destlen = 4; + unsigned char req[2]; + CURLcode result; + CURLproxycode presult = CURLPX_OK; + size_t nwritten; - /* Everything is good so far, user was authenticated! */ - sxstate(sx, cf, data, CONNECT_REQ_INIT); - FALLTHROUGH(); - case CONNECT_REQ_INIT: -CONNECT_REQ_INIT: - if(socks5_resolve_local) { - result = Curl_resolv(data, sx->hostname, sx->remote_port, - cf->conn->ip_version, TRUE, &dns); - - if(result == CURLE_AGAIN) { - sxstate(sx, cf, data, CONNECT_RESOLVING); - return CURLPX_OK; - } - else if(result) - return CURLPX_RESOLVE_HOST; - sxstate(sx, cf, data, CONNECT_RESOLVED); - goto CONNECT_RESOLVED; - } - goto CONNECT_RESOLVE_REMOTE; + *done = FALSE; + if(sx->start_resolving) { + /* need to resolve hostname to add destination address */ + sx->start_resolving = FALSE; - case CONNECT_RESOLVING: + result = Curl_resolv(data, sx->hostname, sx->remote_port, + cf->conn->ip_version, TRUE, &dns); + if(result == CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "SOCKS5 non-blocking resolve of %s", + sx->hostname); + return CURLPX_OK; + } + else if(result) + return CURLPX_RESOLVE_HOST; + } + else { /* check if we have the name resolved by now */ result = Curl_resolv_check(data, &dns); - if(!dns) { - if(result) - return CURLPX_RESOLVE_HOST; + if(!result && !dns) return CURLPX_OK; - } - FALLTHROUGH(); - case CONNECT_RESOLVED: -CONNECT_RESOLVED: - { - char dest[MAX_IPADR_LEN]; /* printable address */ - struct Curl_addrinfo *hp = NULL; - if(dns) - hp = dns->addr; + } + + if(result || !dns) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + sx->hostname); + presult = CURLPX_RESOLVE_HOST; + goto out; + } + + if(dns) + hp = dns->addr; #ifdef USE_IPV6 - if(data->set.ipver != CURL_IPRESOLVE_WHATEVER) { - int wanted_family = data->set.ipver == CURL_IPRESOLVE_V4 ? - AF_INET : AF_INET6; - /* scan for the first proper address */ - while(hp && (hp->ai_family != wanted_family)) - hp = hp->ai_next; - } + if(data->set.ipver != CURL_IPRESOLVE_WHATEVER) { + int wanted_family = data->set.ipver == CURL_IPRESOLVE_V4 ? + AF_INET : AF_INET6; + /* scan for the first proper address */ + while(hp && (hp->ai_family != wanted_family)) + hp = hp->ai_next; + } #endif - if(!hp) { - failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", - sx->hostname); - return CURLPX_RESOLVE_HOST; - } + if(!hp) { + failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", + sx->hostname); + presult = CURLPX_RESOLVE_HOST; + goto out; + } - Curl_printable_address(hp, dest, sizeof(dest)); + Curl_printable_address(hp, dest, sizeof(dest)); - len = 0; - socksreq[len++] = 5; /* version (SOCKS5) */ - socksreq[len++] = 1; /* connect */ - socksreq[len++] = 0; /* must be zero */ - if(hp->ai_family == AF_INET) { - int i; - struct sockaddr_in *saddr_in; - socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ + if(hp->ai_family == AF_INET) { + struct sockaddr_in *saddr_in; + desttype = 1; /* ATYP: IPv4 = 1 */ + destlen = 4; + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + destination = (unsigned char *)&saddr_in->sin_addr.s_addr; + CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%d (locally resolved)", + dest, sx->remote_port); + } +#ifdef USE_IPV6 + else if(hp->ai_family == AF_INET6) { + struct sockaddr_in6 *saddr_in6; + desttype = 4; /* ATYP: IPv6 = 4 */ + destlen = 16; + saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; + destination = (unsigned char *)&saddr_in6->sin6_addr.s6_addr; + CURL_TRC_CF(data, cf, "SOCKS5 connect to [%s]:%d (locally resolved)", + dest, sx->remote_port); + } +#endif - saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; - for(i = 0; i < 4; i++) { - socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; - } + if(!destination) { + failf(data, "SOCKS5 connection to %s not supported", dest); + presult = CURLPX_RESOLVE_HOST; + goto out; + } - CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%d (locally resolved)", - dest, sx->remote_port); - } -#ifdef USE_IPV6 - else if(hp->ai_family == AF_INET6) { - int i; - struct sockaddr_in6 *saddr_in6; - socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ - - saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; - for(i = 0; i < 16; i++) { - socksreq[len++] = - ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; - } + req[0] = desttype; + result = Curl_bufq_write(&sx->iobuf, req, 1, &nwritten); + if(result || (nwritten != 1)) { + presult = CURLPX_SEND_REQUEST; + goto out; + } + result = Curl_bufq_write(&sx->iobuf, destination, destlen, &nwritten); + if(result || (nwritten != destlen)) { + presult = CURLPX_SEND_REQUEST; + goto out; + } + /* PORT MSB+LSB */ + req[0] = (unsigned char)((sx->remote_port >> 8) & 0xffu); + req[1] = (unsigned char)(sx->remote_port & 0xffu); + result = Curl_bufq_write(&sx->iobuf, req, 2, &nwritten); + if(result || (nwritten != 2)) { + presult = CURLPX_SEND_REQUEST; + goto out; + } - CURL_TRC_CF(data, cf, "SOCKS5 connect to [%s]:%d (locally resolved)", - dest, sx->remote_port); - } -#endif - else { - hp = NULL; /* fail! */ - failf(data, "SOCKS5 connection to %s not supported", dest); +out: + if(dns) + Curl_resolv_unlink(data, &dns); + *done = (presult == CURLPX_OK); + return presult; +} + +static CURLproxycode socks5_recv_resp1(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + const unsigned char *resp; + size_t rlen, resp_len = 8; /* minimum response length */ + CURLproxycode presult; + + presult = socks_recv(sx, cf, data, resp_len, done); + if(presult) + return presult; + else if(!*done) + return CURLPX_OK; + + if(!Curl_bufq_peek(&sx->iobuf, &resp, &rlen) || rlen < resp_len) { + failf(data, "SOCKS5 response is incomplete."); + return CURLPX_RECV_CONNECT; + } + + /* Response packet includes BND.ADDR is variable length parameter by RFC + 1928, so the response packet MUST be read until the end to avoid errors + at subsequent protocol level. + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ + + ATYP: + o IP v4 address: X'01', BND.ADDR = 4 byte + o domain name: X'03', BND.ADDR = [ 1 byte length, string ] + o IP v6 address: X'04', BND.ADDR = 16 byte + */ + if(resp[0] != 5) { /* version */ + failf(data, "SOCKS5 reply has wrong version, version should be 5."); + return CURLPX_BAD_VERSION; + } + else if(resp[1]) { /* Anything besides 0 is an error */ + CURLproxycode rc = CURLPX_REPLY_UNASSIGNED; + int code = resp[1]; + failf(data, "cannot complete SOCKS5 connection to %s. (%d)", + sx->hostname, code); + if(code < 9) { + /* RFC 1928 section 6 lists: */ + static const CURLproxycode lookup[] = { + CURLPX_OK, + CURLPX_REPLY_GENERAL_SERVER_FAILURE, + CURLPX_REPLY_NOT_ALLOWED, + CURLPX_REPLY_NETWORK_UNREACHABLE, + CURLPX_REPLY_HOST_UNREACHABLE, + CURLPX_REPLY_CONNECTION_REFUSED, + CURLPX_REPLY_TTL_EXPIRED, + CURLPX_REPLY_COMMAND_NOT_SUPPORTED, + CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, + }; + rc = lookup[code]; } + return rc; + } - Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ - goto CONNECT_REQ_SEND; + /* Calculate real packet size */ + switch(resp[3]) { + case 1: /* IPv4 */ + resp_len = 4 + 4 + 2; + break; + case 3: /* domain name */ + resp_len = 4 + 1 + resp[4] + 2; /* header, var length, var bytes, port */ + break; + case 4: /* IPv6 */ + resp_len = 4 + 16 + 2; + break; + default: + failf(data, "SOCKS5 reply has wrong address type."); + return CURLPX_BAD_ADDRESS_TYPE; } -CONNECT_RESOLVE_REMOTE: - case CONNECT_RESOLVE_REMOTE: - /* Authentication is complete, now specify destination to the proxy */ - len = 0; - socksreq[len++] = 5; /* version (SOCKS5) */ - socksreq[len++] = 1; /* connect */ - socksreq[len++] = 0; /* must be zero */ - - if(!socks5_resolve_local) { - /* ATYP: domain name = 3, - IPv6 == 4, - IPv4 == 1 */ - unsigned char ip4[4]; -#ifdef USE_IPV6 - if(conn->bits.ipv6_ip) { - char ip6[16]; - if(curlx_inet_pton(AF_INET6, sx->hostname, ip6) != 1) - return CURLPX_BAD_ADDRESS_TYPE; - socksreq[len++] = 4; - memcpy(&socksreq[len], ip6, sizeof(ip6)); - len += sizeof(ip6); - } - else -#endif - if(curlx_inet_pton(AF_INET, sx->hostname, ip4) == 1) { - socksreq[len++] = 1; - memcpy(&socksreq[len], ip4, sizeof(ip4)); - len += sizeof(ip4); - } - else { - socksreq[len++] = 3; - socksreq[len++] = (unsigned char) hostname_len; /* one byte length */ - memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */ - len += hostname_len; - } - CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%d (remotely resolved)", + + /* receive the rest of the response */ + presult = socks_recv(sx, cf, data, resp_len, done); + if(presult) + return presult; + else if(!*done) + return CURLPX_OK; + + if(!Curl_bufq_peek(&sx->iobuf, &resp, &rlen) || rlen < resp_len) { + failf(data, "SOCKS5 response is incomplete."); + return CURLPX_RECV_CONNECT; + } + /* got it all */ + *done = TRUE; + return CURLPX_OK; +} + +/* + * This function logs in to a SOCKS5 proxy and sends the specifics to the final + * destination server. + */ +static CURLproxycode socks5_connect(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + CURLproxycode presult; + bool done; + +process_state: + switch(sx->state) { + case SOCKS_ST_INIT: + sx->version = 5; + sx->resolve_local = (cf->conn->socks_proxy.proxytype == CURLPROXY_SOCKS5); + sxstate(sx, cf, data, SOCKS5_ST_START); + FALLTHROUGH(); + + case SOCKS5_ST_START: + if(cf->conn->bits.httpproxy) + CURL_TRC_CF(data, cf, "SOCKS5: connecting to HTTP proxy %s port %d", sx->hostname, sx->remote_port); - } + presult = socks5_req0_init(cf, sx, data); + if(presult) + return socks_failed(sx, cf, data, presult); + sxstate(sx, cf, data, SOCKS5_ST_REQ0_SEND); FALLTHROUGH(); - case CONNECT_REQ_SEND: -CONNECT_REQ_SEND: - /* PORT MSB */ - socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff); - /* PORT LSB */ - socksreq[len++] = (unsigned char)(sx->remote_port & 0xff); + case SOCKS5_ST_REQ0_SEND: + presult = socks_flush(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) + return CURLPX_OK; + /* done sending! */ + sxstate(sx, cf, data, SOCKS5_ST_RESP0_RECV); + FALLTHROUGH(); + + case SOCKS5_ST_RESP0_RECV: + presult = socks_recv(sx, cf, data, 2, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) + return CURLPX_OK; + presult = socks5_check_resp0(sx, cf, data); + if(presult) + return socks_failed(sx, cf, data, presult); + /* socks5_check_resp0() sets next socks state */ + goto process_state; + case SOCKS5_ST_GSSAPI_INIT: { #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(conn->socks5_gssapi_enctype) { - failf(data, "SOCKS5 GSS-API protection not yet implemented."); - return CURLPX_GSSAPI_PROTECTION; + /* GSSAPI stuff done non-blocking */ + CURLcode result = Curl_SOCKS5_gssapi_negotiate(cf, data); + if(result) { + failf(data, "Unable to negotiate SOCKS5 GSS-API context."); + return CURLPX_GSSAPI; } + sxstate(sx, cf, data, SOCKS5_ST_REQ1_INIT); + goto process_state; +#else + failf(data, + "SOCKS5 GSSAPI per-message authentication is not supported."); + return socks_failed(sx, cf, data, CURLPX_GSSAPI_PERMSG); #endif - sx->outp = socksreq; - DEBUGASSERT(len <= sizeof(sx->buffer)); - sx->outstanding = len; - sxstate(sx, cf, data, CONNECT_REQ_SENDING); + } + + case SOCKS5_ST_AUTH_INIT: + presult = socks5_auth_init(cf, sx, data); + if(presult) + return socks_failed(sx, cf, data, presult); + sxstate(sx, cf, data, SOCKS5_ST_AUTH_SEND); FALLTHROUGH(); - case CONNECT_REQ_SENDING: - presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST, - "SOCKS5 connect request"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in send state */ + + case SOCKS5_ST_AUTH_SEND: + presult = socks_flush(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) return CURLPX_OK; - } -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(conn->socks5_gssapi_enctype) { - failf(data, "SOCKS5 GSS-API protection not yet implemented."); - return CURLPX_GSSAPI_PROTECTION; - } -#endif - sx->outstanding = 10; /* minimum packet size is 10 */ - sx->outp = socksreq; - sxstate(sx, cf, data, CONNECT_REQ_READ); + sxstate(sx, cf, data, SOCKS5_ST_AUTH_RECV); FALLTHROUGH(); - case CONNECT_REQ_READ: - presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK, - "SOCKS5 connect request ack"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in reading state */ + + case SOCKS5_ST_AUTH_RECV: + presult = socks_recv(sx, cf, data, 2, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) return CURLPX_OK; - } - else if(socksreq[0] != 5) { /* version */ - failf(data, - "SOCKS5 reply has wrong version, version should be 5."); - return CURLPX_BAD_VERSION; - } - else if(socksreq[1]) { /* Anything besides 0 is an error */ - CURLproxycode rc = CURLPX_REPLY_UNASSIGNED; - int code = socksreq[1]; - failf(data, "cannot complete SOCKS5 connection to %s. (%d)", - sx->hostname, (unsigned char)socksreq[1]); - if(code < 9) { - /* RFC 1928 section 6 lists: */ - static const CURLproxycode lookup[] = { - CURLPX_OK, - CURLPX_REPLY_GENERAL_SERVER_FAILURE, - CURLPX_REPLY_NOT_ALLOWED, - CURLPX_REPLY_NETWORK_UNREACHABLE, - CURLPX_REPLY_HOST_UNREACHABLE, - CURLPX_REPLY_CONNECTION_REFUSED, - CURLPX_REPLY_TTL_EXPIRED, - CURLPX_REPLY_COMMAND_NOT_SUPPORTED, - CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, - }; - rc = lookup[code]; - } - return rc; - } + presult = socks5_check_auth_resp(sx, cf, data); + if(presult) + return socks_failed(sx, cf, data, presult); + /* Everything is good so far, user was authenticated! */ + sxstate(sx, cf, data, SOCKS5_ST_REQ1_INIT); + FALLTHROUGH(); - /* Fix: in general, returned BND.ADDR is variable length parameter by RFC - 1928, so the reply packet should be read until the end to avoid errors - at subsequent protocol level. - - +----+-----+-------+------+----------+----------+ - |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ - - ATYP: - o IP v4 address: X'01', BND.ADDR = 4 byte - o domain name: X'03', BND.ADDR = [ 1 byte length, string ] - o IP v6 address: X'04', BND.ADDR = 16 byte - */ - - /* Calculate real packet size */ - if(socksreq[3] == 3) { - /* domain name */ - int addrlen = (int) socksreq[4]; - len = 5 + addrlen + 2; - } - else if(socksreq[3] == 4) { - /* IPv6 */ - len = 4 + 16 + 2; - } - else if(socksreq[3] == 1) { - len = 4 + 4 + 2; - } - else { - failf(data, "SOCKS5 reply has wrong address type."); - return CURLPX_BAD_ADDRESS_TYPE; + case SOCKS5_ST_REQ1_INIT: + presult = socks5_req1_init(sx, cf, data); + if(presult) + return socks_failed(sx, cf, data, presult); + if(!sx->resolve_local) { + /* we do not resolve, request is complete */ + sxstate(sx, cf, data, SOCKS5_ST_REQ1_SEND); + goto process_state; } + sx->start_resolving = TRUE; + sxstate(sx, cf, data, SOCKS5_ST_RESOLVING); + FALLTHROUGH(); - /* At this point we already read first 10 bytes */ -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(!conn->socks5_gssapi_enctype) { - /* decrypt_gssapi_blockread already read the whole packet */ -#endif - if(len > 10) { - DEBUGASSERT(len <= sizeof(sx->buffer)); - sx->outstanding = len - 10; /* get the rest */ - sx->outp = &socksreq[10]; - sxstate(sx, cf, data, CONNECT_REQ_READ_MORE); - } - else { - sxstate(sx, cf, data, CONNECT_DONE); - break; - } + case SOCKS5_ST_RESOLVING: + presult = socks5_resolving(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + if(!done) + return CURLPX_OK; + sxstate(sx, cf, data, SOCKS5_ST_REQ1_SEND); + FALLTHROUGH(); + + case SOCKS5_ST_REQ1_SEND: + presult = socks_flush(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + else if(!done) + return CURLPX_OK; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(cf->conn->socks5_gssapi_enctype) { + failf(data, "SOCKS5 GSS-API protection not yet implemented."); + return CURLPX_GSSAPI_PROTECTION; } #endif + sxstate(sx, cf, data, SOCKS5_ST_RESP1_RECV); FALLTHROUGH(); - case CONNECT_REQ_READ_MORE: - presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS, - "SOCKS5 connect request address"); - if(CURLPX_OK != presult) - return presult; - else if(sx->outstanding) { - /* remain in reading state */ - return CURLPX_OK; - } - sxstate(sx, cf, data, CONNECT_DONE); - } - CURL_TRC_CF(data, cf, "SOCKS5 request granted."); - return CURLPX_OK; /* Proxy was successful! */ -} - -static CURLcode connect_SOCKS(struct Curl_cfilter *cf, - struct socks_state *sxstate, - struct Curl_easy *data) -{ - CURLcode result = CURLE_OK; - CURLproxycode pxresult = CURLPX_OK; - struct connectdata *conn = cf->conn; + case SOCKS5_ST_RESP1_RECV: + presult = socks5_recv_resp1(sx, cf, data, &done); + if(presult) + return socks_failed(sx, cf, data, presult); + if(!done) + return CURLPX_OK; + CURL_TRC_CF(data, cf, "SOCKS5 request granted."); + sxstate(sx, cf, data, SOCKS_ST_SUCCESS); + FALLTHROUGH(); - switch(conn->socks_proxy.proxytype) { - case CURLPROXY_SOCKS5: - case CURLPROXY_SOCKS5_HOSTNAME: - pxresult = do_SOCKS5(cf, sxstate, data); - break; + case SOCKS_ST_SUCCESS: + return CURLPX_OK; - case CURLPROXY_SOCKS4: - case CURLPROXY_SOCKS4A: - pxresult = do_SOCKS4(cf, sxstate, data); - break; + case SOCKS_ST_FAILED: + DEBUGASSERT(sx->presult); + return sx->presult; default: - failf(data, "unknown proxytype option given"); - result = CURLE_COULDNT_CONNECT; - } /* switch proxytype */ - if(pxresult) { - result = CURLE_PROXY; - data->info.pxcode = pxresult; + DEBUGASSERT(0); + return socks_failed(sx, cf, data, CURLPX_SEND_REQUEST); } - - return result; } static void socks_proxy_cf_free(struct Curl_cfilter *cf) { struct socks_state *sxstate = cf->ctx; if(sxstate) { + Curl_bufq_free(&sxstate->iobuf); free(sxstate); cf->ctx = NULL; } @@ -1117,6 +1225,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, struct connectdata *conn = cf->conn; int sockindex = cf->sockindex; struct socks_state *sx = cf->ctx; + CURLproxycode pxresult = CURLPX_OK; if(cf->connected) { *done = TRUE; @@ -1128,17 +1237,13 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, return result; if(!sx) { - sx = calloc(1, sizeof(*sx)); + cf->ctx = sx = calloc(1, sizeof(*sx)); if(!sx) return CURLE_OUT_OF_MEMORY; - cf->ctx = sx; - } - if(sx->state == CONNECT_INIT) { /* for the secondary socket (FTP), use the "connect to host" * but ignore the "connect to port" (use the secondary port) */ - sxstate(sx, cf, data, CONNECT_SOCKS_INIT); sx->hostname = conn->bits.httpproxy ? conn->http_proxy.host.name : @@ -1153,29 +1258,54 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, conn->remote_port; sx->proxy_user = conn->socks_proxy.user; sx->proxy_password = conn->socks_proxy.passwd; + Curl_bufq_init2(&sx->iobuf, SOCKS_CHUNK_SIZE, SOCKS_CHUNKS, + BUFQ_OPT_SOFT_LIMIT); + } + + switch(conn->socks_proxy.proxytype) { + case CURLPROXY_SOCKS5: + case CURLPROXY_SOCKS5_HOSTNAME: + pxresult = socks5_connect(cf, sx, data); + break; + + case CURLPROXY_SOCKS4: + case CURLPROXY_SOCKS4A: + pxresult = socks4_connect(cf, sx, data); + break; + + default: + failf(data, "unknown proxytype option given"); + result = CURLE_COULDNT_CONNECT; + goto out; + } + + if(pxresult) { + result = CURLE_PROXY; + data->info.pxcode = pxresult; + goto out; } + else if(sx->state != SOCKS_ST_SUCCESS) + goto out; - result = connect_SOCKS(cf, sx, data); - if(!result && sx->state == CONNECT_DONE) { - cf->connected = TRUE; #ifndef CURL_DISABLE_VERBOSE_STRINGS - if(Curl_trc_is_verbose(data)) { - struct ip_quadruple ipquad; - bool is_ipv6; - result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad); - if(result) - return result; - infof(data, "Opened %sSOCKS connection from %s port %u to %s port %u " - "(via %s port %u)", - (sockindex == SECONDARYSOCKET) ? "2nd " : "", - ipquad.local_ip, ipquad.local_port, - sx->hostname, sx->remote_port, - ipquad.remote_ip, ipquad.remote_port); - } -#endif - socks_proxy_cf_free(cf); + if(Curl_trc_is_verbose(data)) { + struct ip_quadruple ipquad; + bool is_ipv6; + result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad); + if(result) + return result; + infof(data, "Opened %sSOCKS connection from %s port %u to %s port %u " + "(via %s port %u)", + (sockindex == SECONDARYSOCKET) ? "2nd " : "", + ipquad.local_ip, ipquad.local_port, + sx->hostname, sx->remote_port, + ipquad.remote_ip, ipquad.remote_port); } +#endif + socks_proxy_cf_free(cf); + cf->connected = TRUE; +out: *done = cf->connected; return result; } @@ -1192,15 +1322,16 @@ static CURLcode socks_cf_adjust_pollset(struct Curl_cfilter *cf, * to wait on, we determine what to wait for. */ curl_socket_t sock = Curl_conn_cf_get_socket(cf, data); switch(sx->state) { - case CONNECT_RESOLVING: - case CONNECT_SOCKS_READ: - case CONNECT_AUTH_READ: - case CONNECT_REQ_READ: - case CONNECT_REQ_READ_MORE: - result = Curl_pollset_set_in_only(data, ps, sock); + case SOCKS4_ST_SEND: + case SOCKS5_ST_REQ0_SEND: + case SOCKS5_ST_AUTH_SEND: + case SOCKS5_ST_REQ1_SEND: + CURL_TRC_CF(data, cf, "adjust pollset out (%d)", sx->state); + result = Curl_pollset_set_out_only(data, ps, sock); break; default: - result = Curl_pollset_set_out_only(data, ps, sock); + CURL_TRC_CF(data, cf, "adjust pollset in (%d)", sx->state); + result = Curl_pollset_set_in_only(data, ps, sock); break; } } diff --git a/tests/libtest/lib564.c b/tests/libtest/lib564.c index 86e4f9ed06c3..3fc86015044b 100644 --- a/tests/libtest/lib564.c +++ b/tests/libtest/lib564.c @@ -23,6 +23,7 @@ ***************************************************************************/ #include "first.h" +#include "testtrace.h" #include "memdebug.h" static CURLcode test_lib564(const char *URL) @@ -32,6 +33,9 @@ static CURLcode test_lib564(const char *URL) int running; CURLM *m = NULL; + debug_config.nohex = TRUE; + debug_config.tracetime = TRUE; + start_test_timing(); global_init(CURL_GLOBAL_ALL); @@ -39,6 +43,8 @@ static CURLcode test_lib564(const char *URL) easy_init(curl); easy_setopt(curl, CURLOPT_URL, URL); + easy_setopt(curl, CURLOPT_DEBUGDATA, &debug_config); + easy_setopt(curl, CURLOPT_DEBUGFUNCTION, libtest_debug_cb); easy_setopt(curl, CURLOPT_VERBOSE, 1L); easy_setopt(curl, CURLOPT_PROXY, libtest_arg2); easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); From cbc30d4ed2720a18ccf86a24eb3659a9cff74a1b Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 11:15:15 +0200 Subject: [PATCH 167/465] vtls: alpn setting, check proto parameter When setting the negotiated alpn protocol, either then length must be 0 or a pointer must be passed. Reported in Joshua's sarif data Closes #18717 --- lib/vtls/vtls.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index bfec585ce210..9872e4c24d42 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1993,6 +1993,11 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, result = CURLE_SSL_CONNECT_ERROR; goto out; } + else if(!proto) { + DEBUGASSERT(0); /* with length, we need a pointer */ + result = CURLE_SSL_CONNECT_ERROR; + goto out; + } else if((strlen(connssl->negotiated.alpn) != proto_len) || memcmp(connssl->negotiated.alpn, proto, proto_len)) { failf(data, "ALPN: asked for '%s' from previous session, but server " From 9e8b05fb995ed36dee08e19953faa2ab48d9304b Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 11:25:17 +0200 Subject: [PATCH 168/465] wolfssl: check BIO read parameters Check parameters passed more thoroughly and assure that current 'data' also exists. Reported in Joshua's sarif data Closes #18718 --- lib/vtls/wolfssl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 693cbdc92e21..0cf6e0e4a57a 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -362,8 +362,11 @@ static int wssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) CURLcode result = CURLE_OK; DEBUGASSERT(data); - /* OpenSSL catches this case, so should we. */ - if(!buf) + if(!data || (blen < 0)) { + wssl->io_result = CURLE_FAILED_INIT; + return -1; + } + if(!buf || !blen) return 0; if((connssl->connecting_state == ssl_connect_2) && From b0f65932191df13148032fed307c15557723da48 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 11:49:45 +0200 Subject: [PATCH 169/465] openssl-quic: check results better Fail on errors from SSL_handle_events(). Force quit Caddy test instance that is left hanging longer with openssl-quic tests for unknown reasons. Reported in Joshua's sarif data Closes #18720 --- lib/vquic/curl_osslq.c | 6 +++++- tests/http/testenv/caddy.py | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 5e9b0727360b..b4cc052ec243 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -1421,12 +1421,16 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, if(!snew) break; - (void)cf_osslq_h3conn_add_stream(&ctx->h3, snew, cf, data); + result = cf_osslq_h3conn_add_stream(&ctx->h3, snew, cf, data); + if(result) + goto out; } if(!SSL_handle_events(ctx->tls.ossl.ssl)) { int detail = SSL_get_error(ctx->tls.ossl.ssl, 0); result = cf_osslq_ssl_err(cf, data, detail, CURLE_RECV_ERROR); + if(result) + goto out; } if(ctx->h3.conn) { diff --git a/tests/http/testenv/caddy.py b/tests/http/testenv/caddy.py index ad56ce13c86b..d7f6a0d7291a 100644 --- a/tests/http/testenv/caddy.py +++ b/tests/http/testenv/caddy.py @@ -117,7 +117,10 @@ def stop(self, wait_dead=True): self._mkpath(self._tmp_dir) if self._process: self._process.terminate() - self._process.wait(timeout=2) + try: + self._process.wait(timeout=1) + except Exception: + self._process.kill() self._process = None return not wait_dead or self.wait_dead(timeout=timedelta(seconds=5)) return True From 5f4f70e06d688e34a6079a81db1794d76c465fdb Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:07:25 +0200 Subject: [PATCH 170/465] ngtcp2: fix early return On a failed tls handshake, the receive function returned without restoring the current data. Reported in Joshua's sarif data Closes #18723 --- lib/vquic/curl_ngtcp2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 0e05694992a0..4998400d96aa 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -1303,8 +1303,10 @@ static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, *pnread = 0; /* handshake verification failed in callback, do not recv anything */ - if(ctx->tls_vrfy_result) - return ctx->tls_vrfy_result; + if(ctx->tls_vrfy_result) { + result = ctx->tls_vrfy_result; + goto out; + } pktx_init(&pktx, cf, data); From 887b863b00b9893c20eb9e1f3987ceaeade1f774 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:11:15 +0200 Subject: [PATCH 171/465] openssl: clear retry flag on x509 error When loading the trust anchors and encountering an error, clear a possibly set retry flag. Reported in Joshua's sarif data Closes #18724 --- lib/vtls/openssl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 4d37f5e77f20..1048bf5751c1 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -741,6 +741,7 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen) if(!octx->x509_store_setup) { r2 = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx); if(r2) { + BIO_clear_retry_flags(bio); octx->io_result = r2; return -1; } From ee2dd2d6cb9b50dbf7ffd3ada106ba5c09229fa5 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:38:02 +0200 Subject: [PATCH 172/465] openssl-quic: handle error in SSL_get_stream_read_error_code The return code of SSL_get_stream_read_error_code() was not checked in one location, but others. Make that consistent. Reported in Joshua's sarif data Closes #18725 --- lib/vquic/curl_osslq.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index b4cc052ec243..e6278ad961a9 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -1264,12 +1264,16 @@ static CURLcode h3_quic_recv(void *reader_ctx, else if(SSL_get_stream_read_state(x->s->ssl) == SSL_STREAM_STATE_RESET_REMOTE) { uint64_t app_error_code = NGHTTP3_H3_NO_ERROR; - SSL_get_stream_read_error_code(x->s->ssl, &app_error_code); - CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> RESET, " - "rv=%d, app_err=%" FMT_PRIu64, - x->s->id, rv, (curl_uint64_t)app_error_code); - if(app_error_code != NGHTTP3_H3_NO_ERROR) { + if(!SSL_get_stream_read_error_code(x->s->ssl, &app_error_code)) { x->s->reset = TRUE; + return CURLE_RECV_ERROR; + } + else { + CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> RESET, " + "rv=%d, app_err=%" FMT_PRIu64, + x->s->id, rv, (curl_uint64_t)app_error_code); + if(app_error_code != NGHTTP3_H3_NO_ERROR) + x->s->reset = TRUE; } x->s->recvd_eos = TRUE; return CURLE_OK; From 36eb26381c1c46098a7c0e4b8a12e7102001c721 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:46:09 +0200 Subject: [PATCH 173/465] quiche: fix verbose message when ip quadruple cannot be obtained. Reported in Joshua's sarif data Closes #18726 --- lib/vquic/curl_quiche.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 523f04e33bd9..e096c63fe98f 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1432,9 +1432,11 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, if(result && result != CURLE_AGAIN) { struct ip_quadruple ip; - Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); - infof(data, "connect to %s port %u failed: %s", - ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); + if(!Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip)) + infof(data, "connect to %s port %u failed: %s", + ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); + else + infof(data, "connect failed: %s", curl_easy_strerror(result)); } #endif return result; From e02cbe94ff92310b2bb4ba3ad622063b0d34ce0a Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:53:37 +0200 Subject: [PATCH 174/465] mbedtls: check result of setting ALPN The result of setting the negotiated ALPN was not checked, leading to reporting success when it should not have. Reported in Joshua's sarif data Closes #18727 --- lib/vtls/mbedtls.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 0a62da2b58bf..aa7e8d67ef4d 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -918,6 +918,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) static CURLcode mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) { + CURLcode result; int ret; struct ssl_connect_data *connssl = cf->ctx; struct mbed_ssl_backend_data *backend = @@ -968,7 +969,6 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) if(pinnedpubkey) { int size; - CURLcode result; const mbedtls_x509_crt *peercert; mbedtls_x509_crt *p = NULL; unsigned char *pubkey = NULL; @@ -1018,17 +1018,19 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) mbedtls_x509_crt_free(p); free(p); free(pubkey); - if(result) { + if(result) return result; - } } #ifdef HAS_ALPN_MBEDTLS if(connssl->alpn) { const char *proto = mbedtls_ssl_get_alpn_protocol(&backend->ssl); - Curl_alpn_set_negotiated(cf, data, connssl, (const unsigned char *)proto, - proto ? strlen(proto) : 0); + result = Curl_alpn_set_negotiated(cf, data, connssl, + (const unsigned char *)proto, + proto ? strlen(proto) : 0); + if(result) + return result; } #endif From 15b4b9618879318ffcd7d8b95f9b2692b14c8e8b Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:59:36 +0200 Subject: [PATCH 175/465] rustls: fix comment describing cr_recv() The comments on `cf_recv()` function were outdated and described calling conventions that no longer are true. Reported in Joshua's sarif data Closes #18728 --- lib/vtls/rustls.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index e081c4651ac8..a6d8a4652d88 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -188,16 +188,8 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf, } /* - * On each run: - * - Read a chunk of bytes from the socket into Rustls' TLS input buffer. - * - Tell Rustls to process any new packets. - * - Read out as many plaintext bytes from Rustls as possible, until hitting - * error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up. - * - * it is okay to call this function with plainbuf == NULL and plainlen == 0. In - * that case, it will copy bytes from the socket into Rustls' TLS input - * buffer, and process packets, but will not consume bytes from Rustls' - * plaintext output buffer. + * Filter receive method implementation. `plainbuf` and `plainlen` + * are always not NULL/0. */ static CURLcode cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, From dec661c81cb0bc55e089b67112ab995eeba350eb Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 13:11:58 +0200 Subject: [PATCH 176/465] wolfssl: fix error check in shutdown When trying to send the TLS shutdown, use the return code to check for the cause. Reported in Joshua's sarif data Closes #18729 --- lib/vtls/wolfssl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 0cf6e0e4a57a..ed024356766e 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -1921,7 +1921,8 @@ static CURLcode wssl_shutdown(struct Curl_cfilter *cf, * was not complete, we are lacking the close notify from the server. */ if(send_shutdown) { wolfSSL_ERR_clear_error(); - if(wolfSSL_shutdown(wctx->ssl) == 1) { + nread = wolfSSL_shutdown(wctx->ssl); + if(nread == 1) { CURL_TRC_CF(data, cf, "SSL shutdown finished"); *done = TRUE; goto out; From 771dd9d9e7cda15be4d99a4c50a04b4d6c46b765 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 13:17:48 +0200 Subject: [PATCH 177/465] quiche: when ingress processing fails, return that error code Instead of a general CURLE_RECV_ERROR. Reported in Joshua's sarif data Closes #18730 --- lib/vquic/curl_quiche.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index e096c63fe98f..5fb67f69f42c 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -865,9 +865,9 @@ static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data, goto out; } - if(cf_process_ingress(cf, data)) { + result = cf_process_ingress(cf, data); + if(result) { CURL_TRC_CF(data, cf, "cf_recv, error on ingress"); - result = CURLE_RECV_ERROR; goto out; } From 221b7dda3837940532b03fbc5f7c54d8a6edd266 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 13:25:29 +0200 Subject: [PATCH 178/465] transfer: avoid busy loop with tiny speed limit When a transfer has a speed limit less than 4, the receive loop early exits without receiving anything, causing a busy loop for that transfer. Perform that check only after the first receive has been done. Reported in Joshua's sarif data Closes #18732 --- lib/transfer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/transfer.c b/lib/transfer.c index 1297a3e82d26..62528d227577 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -283,7 +283,7 @@ static CURLcode sendrecv_dl(struct Curl_easy *data, * a quarter of the quota, break out. We want to stutter a bit * to keep in the limit, but too small receives will just cost * cpu unnecessarily. */ - if(total_received >= (data->set.max_recv_speed / 4)) + if(total_received && (total_received >= (data->set.max_recv_speed / 4))) break; if(data->set.max_recv_speed < (curl_off_t)bytestoread) bytestoread = (size_t)data->set.max_recv_speed; From 442943fb8e9a0e7bd9ae0e5976e4e52792af9739 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 13:31:17 +0200 Subject: [PATCH 179/465] openssl: set io_need always When OpenSSL reports SSL_ERROR_WANT_READ, set the io_need explicitly. It should have already been set by the BIO, but be safe. Reported in Joshua's sarif data Closes #18733 --- lib/vtls/openssl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 1048bf5751c1..d07c1bf773da 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -5369,6 +5369,7 @@ static CURLcode ossl_recv(struct Curl_cfilter *cf, connclose(conn, "TLS close_notify"); break; case SSL_ERROR_WANT_READ: + connssl->io_need = CURL_SSL_IO_NEED_RECV; result = CURLE_AGAIN; goto out; case SSL_ERROR_WANT_WRITE: From e08211b1ca35b9d6fbc5e4a898af0738516ad1ec Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 13:14:36 +0200 Subject: [PATCH 180/465] GHA: bump pip `cryptography`, relax `impacket` version requirement Bump `cryptography` to a newer version that fixes two known OpenSSL vulnerabilities reported by Dependabot. To make it work, also allow `impacket` 0.11.0, because it allows any pyOpenSSL version, while 0.12.0 pinned it to a single version that happens to be incompatible with the bugfixed `cryptography` version. Also: drop spaces from `requirements.txt` files. Bots don't add them, though they seem to be preferred in the official documentation: https://pip.pypa.io/en/stable/reference/requirements-file-format/ https://github.com/fortra/impacket/blob/impacket_0_11_0/requirements.txt https://github.com/fortra/impacket/blob/impacket_0_12_0/requirements.txt Follow-up to 7d5f8be532c19ec73063aaa4f27057047bdae5ac #18708 Closes #18731 --- .github/scripts/requirements.txt | 10 +++++----- tests/http/requirements.txt | 12 ++++++------ tests/requirements.txt | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 5e876b0cb2b8..ac858451d59f 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -2,8 +2,8 @@ # # SPDX-License-Identifier: curl -cmakelang == 0.6.13 -codespell == 2.4.1 -pytype == 2024.10.11 -reuse == 5.1.1 -ruff == 0.13.1 +cmakelang==0.6.13 +codespell==2.4.1 +pytype==2024.10.11 +reuse==5.1.1 +ruff==0.13.1 diff --git a/tests/http/requirements.txt b/tests/http/requirements.txt index 8dddcd1e1c24..6a98723ac208 100644 --- a/tests/http/requirements.txt +++ b/tests/http/requirements.txt @@ -2,9 +2,9 @@ # # SPDX-License-Identifier: curl -cryptography == 42.0.8 -filelock == 3.19.1 -psutil == 7.1.0 -pytest == 8.4.2 -pytest-xdist == 3.8.0 -websockets == 15.0.1 +cryptography==44.0.1 +filelock==3.19.1 +psutil==7.1.0 +pytest==8.4.2 +pytest-xdist==3.8.0 +websockets==15.0.1 diff --git a/tests/requirements.txt b/tests/requirements.txt index dab4784c5fa1..501c1fc69359 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -2,4 +2,4 @@ # # SPDX-License-Identifier: curl -impacket == 0.12.0 +impacket>=0.11.0,<=0.12.0 From 882293cc81c0c384c30288c24111e45e6de4cd39 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 13:40:54 +0200 Subject: [PATCH 181/465] KNOWN_BUGS: telnet code does not handle partial writes properly Reported in Joshua's sarif data Closes #18735 --- docs/KNOWN_BUGS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 3785d73aa49e..5b7df42bdab9 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -86,6 +86,7 @@ problems may have been fixed or changed somewhat since this was written. 12.4 LDAPS requests to ActiveDirectory server hang 13. TCP/IP + 13.1 telnet code does not handle partial writes properly 13.2 Trying local ports fails on Windows 15. CMake @@ -547,6 +548,11 @@ problems may have been fixed or changed somewhat since this was written. 13. TCP/IP +13.1 telnet code does not handle partial writes properly + + It probably does not happen too easily because of how slow and infrequent + sends are normally performed. + 13.2 Trying local ports fails on Windows This makes '--local-port [range]' to not work since curl cannot properly From 5b8c80684b5b39c4d4fde2a7c4f2e3247c391fac Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 14:34:46 +0200 Subject: [PATCH 182/465] GHA/checksrc: drop no longer used `DEBIAN_FRONTEND` env Follow-up to 7d5f8be532c19ec73063aaa4f27057047bdae5ac #18708 Cherry-picked from #18736 --- .github/workflows/checksrc.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 59fc930fa76d..0e7d4ed326c8 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -52,8 +52,6 @@ jobs: persist-credentials: false - name: 'install' - env: - DEBIAN_FRONTEND: noninteractive run: | python3 -m venv ~/venv ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary \ From edbf610c6a55ee9776f85352f9ad182cd52559b0 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 14:38:48 +0200 Subject: [PATCH 183/465] GHA: set `HOMEBREW_NO_AUTO_UPDATE=1` for Linuxbrew In an attempt to make `brew install` commands initialize faster. Often this command started with 20-50 seconds of delay before this patch. This is an attempt to make it launch faster. Cherry-picked from #18736 --- .github/workflows/checksrc.yml | 4 ++-- .github/workflows/codeql.yml | 2 +- .github/workflows/linux.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 0e7d4ed326c8..b101a822c545 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -72,7 +72,7 @@ jobs: - name: 'typos' run: | - /home/linuxbrew/.linuxbrew/bin/brew install typos-cli + HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install typos-cli eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" typos --version .github/scripts/typos.sh @@ -118,7 +118,7 @@ jobs: timeout-minutes: 5 steps: - name: 'install prereqs' - run: /home/linuxbrew/.linuxbrew/bin/brew install shellcheck zizmor + run: HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install shellcheck zizmor - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8cc7e9f48c2c..f271d26b149b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -77,7 +77,7 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libssh-dev \ libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev - /home/linuxbrew/.linuxbrew/bin/brew install c-ares gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi + HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install c-ares gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 556ff8df1ec9..2724901324cf 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -322,7 +322,7 @@ jobs: ${INSTALL_PACKAGES} \ ${MATRIX_INSTALL_PACKAGES} if [ -n "${INSTALL_PACKAGES_BREW}" ]; then - /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} + HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} fi - name: 'install prereqs' From bebc8df0f733468377fbb5cc2a68dbb1239a4b73 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 14:52:38 +0200 Subject: [PATCH 184/465] schannel_verify: use more human friendly error messages Closes #18737 --- lib/vtls/schannel_verify.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index b19e1757d452..f73d758ba196 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -889,7 +889,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, NULL, &pChainContext)) { char buffer[WINAPI_ERROR_LEN]; - failf(data, "schannel: CertGetCertificateChain failed: %s", + failf(data, "schannel: failed to get the certificate chain: %s", curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); pChainContext = NULL; result = CURLE_PEER_FAILED_VERIFICATION; @@ -910,23 +910,20 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, if(dwTrustErrorMask) { if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_REVOKED"); + failf(data, "schannel: trust for this certificate or one of " + "the certificates in the certificate chain has been revoked"); else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_PARTIAL_CHAIN"); + failf(data, "schannel: the certificate chain is incomplete"); else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_UNTRUSTED_ROOT"); + failf(data, "schannel: the certificate or certificate chain is " + "based on an untrusted root"); else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_IS_NOT_TIME_VALID"); + failf(data, "schannel: this certificate or one of the certificates " + "in the certificate chain is not time valid"); else if(dwTrustErrorMask & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) - failf(data, "schannel: CertGetCertificateChain trust error" - " CERT_TRUST_REVOCATION_STATUS_UNKNOWN"); + failf(data, "schannel: the revocation status is unknown"); else - failf(data, "schannel: CertGetCertificateChain error mask: 0x%08lx", - dwTrustErrorMask); + failf(data, "schannel: error 0x%08lx", dwTrustErrorMask); result = CURLE_PEER_FAILED_VERIFICATION; } } From 9f75603d4fefacceed2e368638a1f7f12194d3ed Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 16:19:56 +0200 Subject: [PATCH 185/465] tftp: only check address if it was stored If recvfrom() fails, it might not have stored an address. Follow-up to c4f9977c66bbb05a837a7eb03004dd79c3cc9b44 Pointed out by CodeSonar Closes #18738 --- lib/tftp.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/tftp.c b/lib/tftp.c index 736b14b67364..ad2c84e6608d 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -1106,19 +1106,21 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data, 0, (struct sockaddr *)&remote_addr, &fromlen); - if(state->remote_pinned) { - /* pinned, verify that it comes from the same address */ - if((state->remote_addrlen != fromlen) || - memcmp(&remote_addr, &state->remote_addr, fromlen)) { - failf(data, "Data received from another address"); - return CURLE_RECV_ERROR; + if(fromlen) { + if(state->remote_pinned) { + /* pinned, verify that it comes from the same address */ + if((state->remote_addrlen != fromlen) || + memcmp(&remote_addr, &state->remote_addr, fromlen)) { + failf(data, "Data received from another address"); + return CURLE_RECV_ERROR; + } + } + else { + /* pin address on first use */ + state->remote_pinned = TRUE; + state->remote_addrlen = fromlen; + memcpy(&state->remote_addr, &remote_addr, fromlen); } - } - else { - /* pin address on first use */ - state->remote_pinned = TRUE; - state->remote_addrlen = fromlen; - memcpy(&state->remote_addr, &remote_addr, fromlen); } /* Sanity check packet length */ From f5bae285f321063a3d48774915bb38187b4511ac Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 25 Sep 2025 12:00:57 +0200 Subject: [PATCH 186/465] socks: handle error in verbose trace gracefully Adjust the flow to always succeed in verbose trace of connect. Reported in Joshua's sarif data Closes #18722 --- lib/socks.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/socks.c b/lib/socks.c index 6927e32c3ecb..da974ad6d8d7 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -1291,15 +1291,16 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, if(Curl_trc_is_verbose(data)) { struct ip_quadruple ipquad; bool is_ipv6; - result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad); - if(result) - return result; - infof(data, "Opened %sSOCKS connection from %s port %u to %s port %u " - "(via %s port %u)", - (sockindex == SECONDARYSOCKET) ? "2nd " : "", - ipquad.local_ip, ipquad.local_port, - sx->hostname, sx->remote_port, - ipquad.remote_ip, ipquad.remote_port); + if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) + infof(data, "Opened %sSOCKS connection from %s port %u to %s port %u " + "(via %s port %u)", + (sockindex == SECONDARYSOCKET) ? "2nd " : "", + ipquad.local_ip, ipquad.local_port, + sx->hostname, sx->remote_port, + ipquad.remote_ip, ipquad.remote_port); + else + infof(data, "Opened %sSOCKS connection", + (sockindex == SECONDARYSOCKET) ? "2nd " : ""); } #endif socks_proxy_cf_free(cf); From e48c1ea415d5076082bd2349d066c0df16dc9993 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 14:50:15 +0200 Subject: [PATCH 187/465] GHA: use `pyspelling` directly To avoid depending on Docker Hub, an Docker image and a GitHub Action. Also to simplify running this check on a local machine. Pending question if Dependabot and Mend/Renovate will automatically pick up `requirements-docs.txt`. Also: - enable parallel spellchecking. (also to win back the time lost with installing components directly from Debian and pip.) - pin `pyspelling`. - link to official `pyspelling` docs. Closes #18736 --- .github/scripts/requirements-docs.txt | 5 +++++ .github/scripts/spellcheck.yaml | 1 + .github/workflows/checkdocs.yml | 23 ++++++++++++++++------- 3 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 .github/scripts/requirements-docs.txt diff --git a/.github/scripts/requirements-docs.txt b/.github/scripts/requirements-docs.txt new file mode 100644 index 000000000000..bd50e5010efb --- /dev/null +++ b/.github/scripts/requirements-docs.txt @@ -0,0 +1,5 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +pyspelling==2.11 diff --git a/.github/scripts/spellcheck.yaml b/.github/scripts/spellcheck.yaml index 05ddf0d937f1..8e26b76189bc 100644 --- a/.github/scripts/spellcheck.yaml +++ b/.github/scripts/spellcheck.yaml @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: curl # +# Docs: https://facelessuser.github.io/pyspelling/configuration/ # Docs: https://github.com/UnicornGlobal/spellcheck-github-actions matrix: - name: Markdown diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index f236ebc85013..a34a341a636f 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -113,13 +113,22 @@ jobs: # shellcheck disable=SC2046 .github/scripts/cleancmd.pl $(find docs -name '*.md') - - name: 'setup the custom wordlist' - run: grep -v '^#' .github/scripts/spellcheck.words > wordlist.txt - - - name: 'check Spelling' - uses: rojopolis/spellcheck-github-actions@739a1e3ceb79a98a5d4a9bf76f351137f9d78892 # v0 - with: - config_path: .github/scripts/spellcheck.yaml + - name: 'install' + run: | + sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list + sudo apt-get -o Dpkg::Use-Pty=0 update + sudo rm -f /var/lib/man-db/auto-update + sudo apt-get -o Dpkg::Use-Pty=0 install aspell aspell-en + python3 -m venv ~/venv + ~/venv/bin/pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r .github/scripts/requirements-docs.txt + + - name: 'check spelling' + run: | + source ~/venv/bin/activate + grep -v '^#' .github/scripts/spellcheck.words > wordlist.txt + aspell --version + pyspelling --version + pyspelling --verbose --jobs 5 --config .github/scripts/spellcheck.yaml badwords-synopsis: name: 'badwords, synopsis' From 9595921b06c911af278a645be1d298cb83e32df0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 16:32:18 +0200 Subject: [PATCH 188/465] libssh: clarify myssh_block2waitfor Fixed misleading comment. Simplified the bit setup. Reported in Joshua's sarif data Closes #18739 --- lib/vssh/libssh.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 576ac3b0c042..e1e660b4b3ae 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -2392,19 +2392,16 @@ static void myssh_block2waitfor(struct connectdata *conn, struct ssh_conn *sshc, bool block) { - /* If it did not block, or nothing was returned by ssh_get_poll_flags - * have the original set */ - conn->waitfor = sshc->orig_waitfor; - if(block) { int dir = ssh_get_poll_flags(sshc->ssh_session); - conn->waitfor = 0; /* translate the libssh define bits into our own bit defines */ - if(dir & SSH_READ_PENDING) - conn->waitfor |= KEEP_RECV; - if(dir & SSH_WRITE_PENDING) - conn->waitfor |= KEEP_SEND; + conn->waitfor = + ((dir & SSH_READ_PENDING) ? KEEP_RECV : 0) | + ((dir & SSH_WRITE_PENDING) ? KEEP_SEND : 0); } + else + /* if it did not block, use the original set */ + conn->waitfor = sshc->orig_waitfor; } /* called repeatedly until done from multi.c */ From b8f10be4f205665552a2dfd276889896e0c3116b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 16:38:49 +0200 Subject: [PATCH 189/465] libssh: acknowledge SSH_AGAIN in the SFTP state machine Reported in Joshua's sarif data Closes #18740 --- lib/vssh/libssh.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index e1e660b4b3ae..0f51137e8c72 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1959,6 +1959,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_SETSTAT: rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2, sshc->quote_attrs); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); @@ -1978,6 +1980,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_SYMLINK: rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2, sshc->quote_path1); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); @@ -1994,6 +1998,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_MKDIR: rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1, (mode_t)data->set.new_directory_perms); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); failf(data, "mkdir command failed: %s", @@ -2009,6 +2015,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_RENAME: rc = sftp_rename(sshc->sftp_session, sshc->quote_path1, sshc->quote_path2); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); @@ -2024,6 +2032,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_RMDIR: rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); failf(data, "rmdir command failed: %s", @@ -2038,6 +2048,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, case SSH_SFTP_QUOTE_UNLINK: rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1); + if(rc == SSH_AGAIN) + break; if(rc && !sshc->acceptfail) { Curl_safefree(sshc->quote_path1); failf(data, "rm command failed: %s", From e27853d36b964e91baaa03d4a87802a2c4ba6eca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 15:03:08 +0000 Subject: [PATCH 190/465] GHA: update dependency ruff and github/codeql-action - update github/codeql-action digest to 303c0ae - update dependency ruff to v0.13.2 Closes #18716 Closes #18734 --- .github/scripts/requirements.txt | 2 +- .github/workflows/codeql.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index ac858451d59f..7cb10c47f866 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -6,4 +6,4 @@ cmakelang==0.6.13 codespell==2.4.1 pytype==2024.10.11 reuse==5.1.1 -ruff==0.13.1 +ruff==0.13.2 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f271d26b149b..53505673a473 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -48,13 +48,13 @@ jobs: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3 + uses: github/codeql-action/init@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 with: languages: actions, python queries: security-extended - name: 'perform analysis' - uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 + uses: github/codeql-action/analyze@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 c: name: 'C' @@ -84,7 +84,7 @@ jobs: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3 + uses: github/codeql-action/init@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 with: languages: cpp build-mode: manual @@ -129,4 +129,4 @@ jobs: fi - name: 'perform analysis' - uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3 + uses: github/codeql-action/analyze@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 From 16e0a2098d91c87ab77ce568acdeda724baf753a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 20 Sep 2025 22:32:23 +0200 Subject: [PATCH 191/465] openssl: fail the transfer if ossl_certchain() fails Since it would indicate errors to the degree that continuing would just risk hiding the earlier errors or make things weird. Inspired by a report in Joshua's sarif data Closes #18646 --- lib/vtls/openssl.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index d07c1bf773da..37cdd5574714 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -355,9 +355,8 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl) DEBUGASSERT(ssl); sk = SSL_get_peer_cert_chain(ssl); - if(!sk) { - return CURLE_OUT_OF_MEMORY; - } + if(!sk) + return CURLE_SSL_CONNECT_ERROR; numcerts = sk_X509_num(sk); @@ -4856,9 +4855,15 @@ CURLcode Curl_ossl_check_peer_cert(struct Curl_cfilter *cf, return CURLE_OUT_OF_MEMORY; } - if(data->set.ssl.certinfo) - /* asked to gather certificate info */ - (void)ossl_certchain(data, octx->ssl); + if(data->set.ssl.certinfo && !octx->reused_session) { + /* asked to gather certificate info. Reused sessions don't have cert + chains */ + result = ossl_certchain(data, octx->ssl); + if(result) { + BIO_free(mem); + return result; + } + } octx->server_cert = SSL_get1_peer_certificate(octx->ssl); if(!octx->server_cert) { From 500ea90829c825e9c19d2d4290d4d130e9ac42bd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 25 Sep 2025 23:35:31 +0200 Subject: [PATCH 192/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 63 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index da62171c7198..511be250eb03 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,7 +4,7 @@ curl and libcurl 8.17.0 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3508 + Contributors: 3509 This release includes the following changes: @@ -28,6 +28,7 @@ This release includes the following bugfixes: o build: address some `-Weverything` warnings, update picky warnings [74] o build: avoid overriding system symbols for socket functions [68] o build: show llvm/clang in platform flags and `buildinfo.txt` [126] + o cf-h2-proxy: break loop on edge case [140] o cf-socket: use the right byte order for ports in bindlocal [61] o cfilter: unlink and discard [46] o cmake: add `CURL_CODE_COVERAGE` option [78] @@ -60,10 +61,13 @@ This release includes the following bugfixes: o httpsrr: free old pointers when storing new [57] o krb5: return appropriate error on send failures [22] o ldap: do not base64 encode zero length string [42] + o lib: upgrade/multiplex handling [136] o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] o libssh2: drop two redundant null-terminations [26] o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] + o libssh: acknowledge SSH_AGAIN in the SFTP state machine [89] + o libssh: clarify myssh_block2waitfor [92] o libssh: drop two unused assignments [104] o libssh: error on bad chgrp number [71] o libssh: error on bad chown number and store the value [64] @@ -74,24 +78,43 @@ This release includes the following bugfixes: o managen: ignore version mentions < 7.66.0 [55] o managen: render better manpage references/links [54] o managen: strict protocol check [109] + o mbedtls: check result of setting ALPN [127] + o mbedtls: handle WANT_WRITE from mbedtls_ssl_read() [145] o multi.h: add CURLMINFO_LASTENTRY [51] o ngtcp2: check error code on connect failure [13] + o ngtcp2: fix early return [131] o openldap: avoid indexing the result at -1 for blank responses [44] o openldap: check ldap_get_option() return codes [119] + o openssl-quic: check results better [132] + o openssl-quic: handle error in SSL_get_stream_read_error_code [129] + o openssl: clear retry flag on x509 error [130] + o openssl: fail the transfer if ossl_certchain() fails [23] o openssl: make the asn1_object_dump name null terminated [56] + o openssl: set io_need always [99] + o OS400: fix a use-after-free/double-free case [142] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o quiche: fix verbose message when ip quadruple cannot be obtained. [128] + o quiche: when ingress processing fails, return that error code [103] o rustls: fix clang-tidy warning [107] + o rustls: fix comment describing cr_recv() [117] o rustls: typecast variable for safer trace output [69] o rustls: use %zu for size_t in failf() format string [121] o sasl: clear canceled mechanism instead of toggling it [41] o schannel: assign result before using it [62] + o schannel_verify: use more human friendly error messages [96] o setopt: accept *_SSL_VERIFYHOST set to 2L [31] o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] o smb: adjust buffer size checks [45] o smtp: check EHLO responses case insensitively [50] + o socks: handle error in verbose trace gracefully [94] o socks: make Curl_blockread_all return CURLcode [67] + o socks: rewwork, cleaning up socks state handling [135] + o socks_gssapi: make the gss_context a local variable [144] o socks_gssapi: reject too long tokens [90] + o socks_gssapi: remove superfluous releases of the gss_recv_token [139] + o socks_gssapi: remove the forced "no protection" [143] + o socks_sspi: bail out on too long fields [137] o socks_sspi: fix memory cleanup calls [40] o socks_sspi: restore non-blocking socket on error paths [48] o ssl-sessions.md: mark option experimental [12] @@ -116,10 +139,14 @@ This release includes the following bugfixes: o tool_getparam/set_rate: skip the multiplication on overflow [84] o tool_operate: improve wording in retry message [37] o tool_operate: keep the progress meter for --out-null [33] + o transfer: avoid busy loop with tiny speed limit [100] o urldata: FILE is not a list-only protocol [9] + o vtls: alpn setting, check proto parameter [134] o vtls_int.h: clarify data_pending [124] o windows: replace `_beginthreadex()` with `CreateThread()` [80] o windows: stop passing unused, optional argument for Win9x compatibility [75] + o wolfssl: check BIO read parameters [133] + o wolfssl: fix error check in shutdown [105] o ws: clarify an error message [125] o ws: reject curl_ws_recv called with NULL buffer with a buflen [118] @@ -149,9 +176,10 @@ advice from friends like these: divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, fds242 on github, Javier Blazquez, Jicea, jmaggard10 on github, Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, Marcel Raad, - Michael Osipov, Michał Petryka, Nir Azkiel, Ray Satiro, renovate[bot], - rinsuki on github, Samuel Dionne-Riel, Stefan Eissing, Viktor Szakats - (28 contributors) + Michael Osipov, Michał Petryka, Nir Azkiel, Patrick Monnerat, Ray Satiro, + renovate[bot], rinsuki on github, Samuel Dionne-Riel, Stanislav Fort, + Stefan Eissing, Viktor Szakats + (30 contributors) References to bug reports and discussions on issues: @@ -177,6 +205,7 @@ References to bug reports and discussions on issues: [20] = https://curl.se/bug/?i=18554 [21] = https://curl.se/bug/?i=18618 [22] = https://curl.se/bug/?i=18561 + [23] = https://curl.se/bug/?i=18646 [24] = https://curl.se/bug/?i=18616 [25] = https://curl.se/bug/?i=18491 [26] = https://curl.se/bug/?i=18606 @@ -241,11 +270,19 @@ References to bug reports and discussions on issues: [85] = https://curl.se/bug/?i=18612 [87] = https://curl.se/bug/?i=18707 [88] = https://curl.se/bug/?i=18680 + [89] = https://curl.se/bug/?i=18740 [90] = https://curl.se/bug/?i=18681 [91] = https://curl.se/bug/?i=18251 + [92] = https://curl.se/bug/?i=18739 + [94] = https://curl.se/bug/?i=18722 + [96] = https://curl.se/bug/?i=18737 + [99] = https://curl.se/bug/?i=18733 + [100] = https://curl.se/bug/?i=18732 [101] = https://curl.se/bug/?i=18689 [102] = https://curl.se/bug/?i=18688 + [103] = https://curl.se/bug/?i=18730 [104] = https://curl.se/bug/?i=18684 + [105] = https://curl.se/bug/?i=18729 [106] = https://curl.se/bug/?i=18671 [107] = https://curl.se/bug/?i=18670 [108] = https://curl.se/bug/?i=18633 @@ -257,6 +294,7 @@ References to bug reports and discussions on issues: [114] = https://curl.se/bug/?i=18666 [115] = https://curl.se/bug/?i=18664 [116] = https://curl.se/bug/?i=18659 + [117] = https://curl.se/bug/?i=18728 [118] = https://curl.se/bug/?i=18656 [119] = https://curl.se/bug/?i=18653 [120] = https://curl.se/bug/?i=18652 @@ -266,3 +304,20 @@ References to bug reports and discussions on issues: [124] = https://curl.se/bug/?i=18644 [125] = https://curl.se/bug/?i=18654 [126] = https://curl.se/bug/?i=18645 + [127] = https://curl.se/bug/?i=18727 + [128] = https://curl.se/bug/?i=18726 + [129] = https://curl.se/bug/?i=18725 + [130] = https://curl.se/bug/?i=18724 + [131] = https://curl.se/bug/?i=18723 + [132] = https://curl.se/bug/?i=18720 + [133] = https://curl.se/bug/?i=18718 + [134] = https://curl.se/bug/?i=18717 + [135] = https://curl.se/bug/?i=18401 + [136] = https://curl.se/bug/?i=18227 + [137] = https://curl.se/bug/?i=18719 + [139] = https://curl.se/bug/?i=18714 + [140] = https://curl.se/bug/?i=18715 + [142] = https://curl.se/bug/?i=18713 + [143] = https://curl.se/bug/?i=18712 + [144] = https://curl.se/bug/?i=18711 + [145] = https://curl.se/bug/?i=18682 From 061e265502fc2f605f0d87453b8b1167ba16839d Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 22 Sep 2025 15:48:07 +0200 Subject: [PATCH 193/465] http: handle user-defined connection headers When there is more than one user-supplied 'Connection: ' header, add values that curl needs internally to the first one and emit all subsequent ones thereafter. Fixes #18662 Reported-by: Evgeny Grin (Karlson2k) Closes #18686 --- docs/libcurl/opts/CURLOPT_HTTPHEADER.md | 4 ++ lib/http.c | 64 +++++++++++++++++---- tests/data/Makefile.am | 2 +- tests/data/test1617 | 75 +++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 tests/data/test1617 diff --git a/docs/libcurl/opts/CURLOPT_HTTPHEADER.md b/docs/libcurl/opts/CURLOPT_HTTPHEADER.md index 4440b4ec4b61..c7a705bedc82 100644 --- a/docs/libcurl/opts/CURLOPT_HTTPHEADER.md +++ b/docs/libcurl/opts/CURLOPT_HTTPHEADER.md @@ -55,6 +55,10 @@ without content (no data on the right side of the colon) as in `Accept:`, the internally used header is removed. To forcibly add a header without content (nothing after the colon), use the form `name;` (using a trailing semicolon). +There are exceptions when suppressing headers. The `Connection:` header in +HTTP/1.1 cannot be overridden. You can provide values for it, but should a +request require specific ones, they are always added to your own. + The headers included in the linked list **must not** be CRLF-terminated, since libcurl adds CRLF after each header item itself. Failure to comply with this might result in strange behavior. libcurl passes on the verbatim strings you diff --git a/lib/http.c b/lib/http.c index ce31e6dff005..3479bb4ec976 100644 --- a/lib/http.c +++ b/lib/http.c @@ -263,6 +263,19 @@ char *Curl_checkProxyheaders(struct Curl_easy *data, #define Curl_checkProxyheaders(x,y,z,a) NULL #endif +static bool http_header_is_empty(const char *header) +{ + struct Curl_str out; + + if(!curlx_str_cspn(&header, &out, ";:") && + (!curlx_str_single(&header, ':') || !curlx_str_single(&header, ';'))) { + curlx_str_untilnl(&header, &out, MAX_HTTP_RESP_HEADER_SIZE); + curlx_str_trimblanks(&out); + return curlx_strlen(&out) == 0; + } + return TRUE; /* invalid head format, treat as empty */ +} + /* * Strip off leading and trailing whitespace from the value in the given HTTP * header line and return a strdup()ed copy. Returns NULL in case of @@ -1702,7 +1715,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, curlx_str_casecompare(&name, "Content-Length")) ; else if(curlx_str_casecompare(&name, "Connection")) - /* Normal Connection: header generation takes care of this */ + /* Connection headers are handled specially */ ; else if((httpversion >= 20) && curlx_str_casecompare(&name, "Transfer-Encoding")) @@ -2636,17 +2649,29 @@ static CURLcode http_check_new_conn(struct Curl_easy *data) static CURLcode http_add_connection_hd(struct Curl_easy *data, struct dynbuf *req) { - char *custom = Curl_checkheaders(data, STRCONST("Connection")); - char *custom_val = custom ? Curl_copy_header_value(custom) : NULL; - const char *sep = (custom_val && *custom_val) ? ", " : "Connection: "; + struct curl_slist *head; + const char *sep = "Connection: "; CURLcode result = CURLE_OK; size_t rlen = curlx_dyn_len(req); + char *value; + bool skip; + + /* Add the 1st custom "Connection: " header, if there is one */ + for(head = data->set.headers; head; head = head->next) { + if(curl_strnequal(head->data, "Connection", 10) && + Curl_headersep(head->data[10]) && + !http_header_is_empty(head->data)) { + value = Curl_copy_header_value(head->data); + if(!value) + return CURLE_OUT_OF_MEMORY; + result = curlx_dyn_addf(req, "%s%s", sep, value); + sep = ", "; + free(value); + break; /* leave, having added 1st one */ + } + } - if(custom && !custom_val) - return CURLE_OUT_OF_MEMORY; - - if(custom_val && *custom_val) - result = curlx_dyn_addf(req, "Connection: %s", custom_val); + /* add our internal Connection: header values, if we have any */ if(!result && data->state.http_hd_te) { result = curlx_dyn_addf(req, "%s%s", sep, "TE"); sep = ", "; @@ -2660,9 +2685,26 @@ static CURLcode http_add_connection_hd(struct Curl_easy *data, } if(!result && (rlen < curlx_dyn_len(req))) result = curlx_dyn_addn(req, STRCONST("\r\n")); + if(result) + return result; - free(custom_val); - return result; + /* Add all user-defined Connection: headers after the first */ + skip = TRUE; + for(head = data->set.headers; head; head = head->next) { + if(curl_strnequal(head->data, "Connection", 10) && + Curl_headersep(head->data[10]) && + !http_header_is_empty(head->data)) { + if(skip) { + skip = FALSE; + continue; + } + result = curlx_dyn_addf(req, "%s\r\n", head->data); + if(result) + return result; + } + } + + return CURLE_OK; } /* Header identifier in order we send them by default */ diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 854791fba0e9..5063e0210f42 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -214,7 +214,7 @@ test1580 test1581 \ test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \ test1598 test1599 test1600 test1601 test1602 test1603 test1604 test1605 \ test1606 test1607 test1608 test1609 test1610 test1611 test1612 test1613 \ -test1614 test1615 test1616 \ +test1614 test1615 test1616 test1617 \ test1620 test1621 \ \ test1630 test1631 test1632 test1633 test1634 test1635 \ diff --git a/tests/data/test1617 b/tests/data/test1617 new file mode 100644 index 000000000000..0fe967bd27a7 --- /dev/null +++ b/tests/data/test1617 @@ -0,0 +1,75 @@ + + + +HTTP +HTTP GET +compressed +Transfer-Encoding + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Mon, 29 Nov 2004 21:56:53 GMT +Server: Apache/1.3.31 (Debian GNU/Linux) mod_gzip/1.3.26.1a PHP/4.3.9-1 mod_ssl/2.8.20 OpenSSL/0.9.7d mod_perl/1.29 +Vary: Accept-Encoding +Content-Type: text/html; charset=ISO-8859-1 +Transfer-Encoding: gzip, chunked + +2c +%hex[%1f%8b%08%08%79%9e%ab%41%00%03%6c%61%6c%61%6c%61%00%cb%c9%cc%4b%55%30%e4%52%c8%01%d1%46%5c]hex% +%hex[%10%86%31%17%00]hex% +%hex[%02%71%60%18%00%00%00]hex% +0 + + + + +HTTP/1.1 200 OK +Date: Mon, 29 Nov 2004 21:56:53 GMT +Server: Apache/1.3.31 (Debian GNU/Linux) mod_gzip/1.3.26.1a PHP/4.3.9-1 mod_ssl/2.8.20 OpenSSL/0.9.7d mod_perl/1.29 +Vary: Accept-Encoding +Content-Type: text/html; charset=ISO-8859-1 +Transfer-Encoding: gzip, chunked + +line 1 + line 2 + line 3 + + + + +# +# Client-side + + +libz + + +http + + +HTTP GET transfer-encoding with two user Connection: headers + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --tr-encoding -H "Connection: this" -H "Connection: that" + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* +TE: gzip +Connection: this, TE +Connection: that + + + + From 84d96275319869e1f0e6c374e39b54a7d892d146 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 26 Sep 2025 09:43:19 +0200 Subject: [PATCH 194/465] tool_progress: handle possible integer overflows The progress meters max out at 2^63 bytes. Reported-by: BobodevMm on github Fixes #18744 Closes #18746 --- src/tool_progress.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/tool_progress.c b/src/tool_progress.c index 666fe9869cd7..aae2ff68b184 100644 --- a/src/tool_progress.c +++ b/src/tool_progress.c @@ -144,6 +144,15 @@ static unsigned int speedindex; static bool indexwrapped; static struct speedcount speedstore[SPEEDCNT]; +static void add_offt(curl_off_t *val, curl_off_t add) +{ + if(CURL_OFF_T_MAX - *val < add) + /* maxed out! */ + *val = CURL_OFF_T_MAX; + else + *val += add; +} + /* |DL% UL% Dled Uled Xfers Live Total Current Left Speed | 6 -- 9.9G 0 2 2 0:00:40 0:00:02 0:00:37 4087M @@ -189,24 +198,24 @@ bool progress_meter(CURLM *multi, stamp = now; /* first add the amounts of the already completed transfers */ - all_dlnow += all_dlalready; - all_ulnow += all_ulalready; + add_offt(&all_dlnow, all_dlalready); + add_offt(&all_ulnow, all_ulalready); for(per = transfers; per; per = per->next) { - all_dlnow += per->dlnow; - all_ulnow += per->ulnow; + add_offt(&all_dlnow, per->dlnow); + add_offt(&all_ulnow, per->ulnow); if(!per->dltotal) dlknown = FALSE; else if(!per->dltotal_added) { /* only add this amount once */ - all_dltotal += per->dltotal; + add_offt(&all_dltotal, per->dltotal); per->dltotal_added = TRUE; } if(!per->ultotal) ulknown = FALSE; else if(!per->ultotal_added) { /* only add this amount once */ - all_ultotal += per->ultotal; + add_offt(&all_ultotal, per->ultotal); per->ultotal_added = TRUE; } } @@ -306,14 +315,14 @@ bool progress_meter(CURLM *multi, void progress_finalize(struct per_transfer *per) { /* get the numbers before this transfer goes away */ - all_dlalready += per->dlnow; - all_ulalready += per->ulnow; + add_offt(&all_dlalready, per->dlnow); + add_offt(&all_ulalready, per->ulnow); if(!per->dltotal_added) { - all_dltotal += per->dltotal; + add_offt(&all_dltotal, per->dltotal); per->dltotal_added = TRUE; } if(!per->ultotal_added) { - all_ultotal += per->ultotal; + add_offt(&all_ultotal, per->ultotal); per->ultotal_added = TRUE; } } From 72f72f678d1669d9758ad3f948321ee4dfc71330 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 26 Sep 2025 13:53:04 +0200 Subject: [PATCH 195/465] openldap: check ber_sockbuf_add_io() return code The man page says nothing about what the return code means but Howard Chu tells me it is 0 on success, -1 on fail. Help-by: Howard Chu Closes #18747 --- lib/openldap.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/lib/openldap.c b/lib/openldap.c index 7d25d1842112..6aa74e028f8b 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -531,19 +531,19 @@ static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate) if(!li) return CURLE_FAILED_INIT; result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); - if(!result) { - oldap_state(data, li, newstate); + if(result) + return result; + oldap_state(data, li, newstate); - if(ssldone) { - Sockbuf *sb; + if(ssldone) { + Sockbuf *sb; - /* Install the libcurl SSL handlers into the sockbuf. */ - if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) - return CURLE_FAILED_INIT; - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); - li->recv = conn->recv[FIRSTSOCKET]; - li->send = conn->send[FIRSTSOCKET]; - } + /* Install the libcurl SSL handlers into the sockbuf. */ + if((ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) || + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data)) + return CURLE_FAILED_INIT; + li->recv = conn->recv[FIRSTSOCKET]; + li->send = conn->send[FIRSTSOCKET]; } return result; @@ -947,19 +947,18 @@ static CURLcode oldap_disconnect(struct Curl_easy *data, (void)data; #endif - if(li) { - if(li->ld) { + if(li && li->ld) { #ifdef USE_SSL - if(ssl_installed(conn)) { - Sockbuf *sb; - if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) - return CURLE_FAILED_INIT; - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); - } -#endif - ldap_unbind_ext(li->ld, NULL, NULL); - li->ld = NULL; + if(ssl_installed(conn)) { + Sockbuf *sb; + if((ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) + || + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data)) + return CURLE_FAILED_INIT; } +#endif + ldap_unbind_ext(li->ld, NULL, NULL); + li->ld = NULL; } return CURLE_OK; } @@ -988,9 +987,9 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done) if(ssl_installed(conn)) { Sockbuf *sb; /* re-install the libcurl SSL handlers into the sockbuf. */ - if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) + if((ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) || + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data)) return CURLE_FAILED_INIT; - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); } #endif From 34b1e146e42f2dbac5c89414a2a0458a8729a255 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 25 Sep 2025 01:54:28 +0200 Subject: [PATCH 196/465] perlcheck: add script, run in CI, fix fallouts Add script to run all Perl sources through `perl -c` to ensure no issues, and run this script via GHA/checksrc in CI. Fallouts: - fix two repeated declarations. - move `shell_quote()` from `testutil.pm` to `pathhelp.pm`, to avoid circular dependency in `globalconfig.pm`. Closes #18745 --- .github/workflows/checksrc.yml | 4 +++ scripts/Makefile.am | 3 ++- scripts/perlcheck.sh | 47 ++++++++++++++++++++++++++++++++++ tests/globalconfig.pm | 4 +-- tests/pathhelp.pm | 20 +++++++++++++++ tests/runner.pm | 2 +- tests/runtests.pl | 1 + tests/servers.pm | 2 +- tests/test745.pl | 5 ++-- tests/testcurl.pl | 6 +++-- tests/testutil.pm | 20 --------------- 11 files changed, 84 insertions(+), 30 deletions(-) create mode 100755 scripts/perlcheck.sh diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index b101a822c545..71ee031d68a8 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -82,6 +82,10 @@ jobs: source ~/venv/bin/activate scripts/cmakelint.sh + - name: 'perlcheck' + run: | + scripts/perlcheck.sh + - name: 'pytype' run: | source ~/venv/bin/activate diff --git a/scripts/Makefile.am b/scripts/Makefile.am index cfa3d3e740a9..a52581155d46 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -25,7 +25,8 @@ EXTRA_DIST = coverage.sh completion.pl firefox-db2pem.sh checksrc.pl checksrc-all.pl \ mk-ca-bundle.pl mk-unity.pl schemetable.c cd2nroff nroff2cd cdall cd2cd managen \ dmaketgz maketgz release-tools.sh verify-release cmakelint.sh mdlinkcheck \ - CMakeLists.txt pythonlint.sh randdisable wcurl top-complexity extract-unit-protos + CMakeLists.txt perlcheck.sh pythonlint.sh randdisable wcurl top-complexity \ + extract-unit-protos dist_bin_SCRIPTS = wcurl diff --git a/scripts/perlcheck.sh b/scripts/perlcheck.sh new file mode 100755 index 000000000000..be0c0e1c870f --- /dev/null +++ b/scripts/perlcheck.sh @@ -0,0 +1,47 @@ +#!/bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) Dan Fandrich, , Viktor Szakats, 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 xargs invocation is portable, but does not preserve spaces in file names. +# If such a file is ever added, then this can be portably fixed by switching to +# "xargs -I{}" and appending {} to the end of the xargs arguments (which will +# call cmakelint once per file) or by using the GNU extension "xargs -d'\n'". + +set -eu + +cd "$(dirname "$0")"/.. + +{ + if [ -n "${1:-}" ]; then + for A in "$@"; do printf "%s\n" "$A"; done + elif git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + { + git ls-files | grep -E '\.(pl|pm)$' + git grep -l -E '^#!/usr/bin/env perl' + } | sort -u + else + # strip off the leading ./ to make the grep regexes work properly + find . -type f \( -name '*.pl' -o -name '*.pm' \) | sed 's@^\./@@' + fi +} | xargs -n 1 perl -c -Itests diff --git a/tests/globalconfig.pm b/tests/globalconfig.pm index de9abab34c2a..8635dea55b58 100644 --- a/tests/globalconfig.pm +++ b/tests/globalconfig.pm @@ -78,11 +78,9 @@ BEGIN { use pathhelp qw( exe_ext dirsepadd - ); -use Cwd qw(getcwd); -use testutil qw( shell_quote ); +use Cwd qw(getcwd); use File::Spec; diff --git a/tests/pathhelp.pm b/tests/pathhelp.pm index 169582518848..49987f745388 100644 --- a/tests/pathhelp.pm +++ b/tests/pathhelp.pm @@ -60,6 +60,7 @@ BEGIN { os_is_win exe_ext dirsepadd + shell_quote sys_native_abs_path sys_native_current_path build_sys_abs_path @@ -192,4 +193,23 @@ sub dirsepadd { return $dir . '/'; } +####################################################################### +# Quote an argument for passing safely to a Bourne shell +# This does the same thing as String::ShellQuote but doesn't need a package. +# +sub shell_quote { + my ($s)=@_; + if($^O eq 'MSWin32') { + $s = '"' . $s . '"'; + } + else { + if($s !~ m/^[-+=.,_\/:a-zA-Z0-9]+$/) { + # string contains a "dangerous" character--quote it + $s =~ s/'/'"'"'/g; + $s = "'" . $s . "'"; + } + } + return $s; +} + 1; # End of module diff --git a/tests/runner.pm b/tests/runner.pm index 62f722f319bc..1eef1f5b9d3f 100644 --- a/tests/runner.pm +++ b/tests/runner.pm @@ -84,6 +84,7 @@ use Storable qw( use pathhelp qw( exe_ext + shell_quote ); use servers qw( checkcmd @@ -100,7 +101,6 @@ use testutil qw( logmsg runclient exerunner - shell_quote subbase64 subsha256base64file substrippemfile diff --git a/tests/runtests.pl b/tests/runtests.pl index 6b6e5b076191..d836841a296d 100755 --- a/tests/runtests.pl +++ b/tests/runtests.pl @@ -91,6 +91,7 @@ BEGIN use pathhelp qw( exe_ext sys_native_current_path + shell_quote ); use appveyor; diff --git a/tests/servers.pm b/tests/servers.pm index e62505887076..e5505886f6af 100644 --- a/tests/servers.pm +++ b/tests/servers.pm @@ -105,6 +105,7 @@ use pathhelp qw( os_is_win build_sys_abs_path sys_native_abs_path + shell_quote ); use processhelp; @@ -114,7 +115,6 @@ use testutil qw( runclient runclientoutput exerunner - shell_quote ); diff --git a/tests/test745.pl b/tests/test745.pl index faddda429f39..4395eb9681ab 100755 --- a/tests/test745.pl +++ b/tests/test745.pl @@ -45,7 +45,8 @@ sub gettypecheck { } sub getinclude { - open(my $f, "<", "$root/include/curl/curl.h") + my $f; + open($f, "<", "$root/include/curl/curl.h") || die "no curl.h"; while(<$f>) { if($_ =~ /\((CURLOPT[^,]*), (CURLOPTTYPE_[^,]*)/) { @@ -61,7 +62,7 @@ sub getinclude { $enum{"CURLOPT_CONV_TO_NETWORK_FUNCTION"}++; close($f); - open(my $f, "<", "$root/include/curl/multi.h") + open($f, "<", "$root/include/curl/multi.h") || die "no curl.h"; while(<$f>) { if($_ =~ /\((CURLMOPT[^,]*), (CURLOPTTYPE_[^,]*)/) { diff --git a/tests/testcurl.pl b/tests/testcurl.pl index 8d6183102bbf..4f3eade70347 100755 --- a/tests/testcurl.pl +++ b/tests/testcurl.pl @@ -584,8 +584,10 @@ sub findinpath { } } +my $f; + logit_spaced "display lib/$confheader"; -open(my $f, "<", "lib/$confheader") or die "lib/$confheader: $!"; +open($f, "<", "lib/$confheader") or die "lib/$confheader: $!"; while(<$f>) { print if /^ *#/; } @@ -660,7 +662,7 @@ sub findinpath { my $mkcmd = "$make -i" . ($targetos && !$configurebuild ? " $targetos" : ""); logit "$mkcmd"; -open(my $f, "-|", "$mkcmd 2>&1") or die; +open($f, "-|", "$mkcmd 2>&1") or die; while(<$f>) { s/$pwd//g; print; diff --git a/tests/testutil.pm b/tests/testutil.pm index e84cc45fde2c..3477d5bb57f8 100644 --- a/tests/testutil.pm +++ b/tests/testutil.pm @@ -38,7 +38,6 @@ BEGIN { runclientoutput setlogfunc exerunner - shell_quote subbase64 subnewlines subsha256base64file @@ -219,25 +218,6 @@ sub exerunner { return ''; } -####################################################################### -# Quote an argument for passing safely to a Bourne shell -# This does the same thing as String::ShellQuote but doesn't need a package. -# -sub shell_quote { - my ($s)=@_; - if($^O eq 'MSWin32') { - $s = '"' . $s . '"'; - } - else { - if($s !~ m/^[-+=.,_\/:a-zA-Z0-9]+$/) { - # string contains a "dangerous" character--quote it - $s =~ s/'/'"'"'/g; - $s = "'" . $s . "'"; - } - } - return $s; -} - sub get_sha256_base64 { my ($file_path) = @_; return encode_base64(sha256(do { local $/; open my $fh, '<:raw', $file_path or die $!; <$fh> }), ""); From b5ffe30e5b7e79d51ec96c266538eb5586c6a0dd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 26 Sep 2025 16:30:34 +0200 Subject: [PATCH 197/465] cf-ip-happy: mention unix domain path, not port number In the connect error message if a unix domain socket was used. Reported-by: kuchara on github Ref: #18748 Closes #18749 --- lib/cf-ip-happy.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index 5e4c20444e79..0a1364e4b3f5 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -627,26 +627,35 @@ static CURLcode is_connected(struct Curl_cfilter *cf, { const char *hostname, *proxy_name = NULL; - int port; + char viamsg[160]; #ifndef CURL_DISABLE_PROXY if(conn->bits.socksproxy) proxy_name = conn->socks_proxy.host.name; else if(conn->bits.httpproxy) proxy_name = conn->http_proxy.host.name; #endif - hostname = conn->bits.conn_to_host ? - conn->conn_to_host.name : conn->host.name; + hostname = conn->bits.conn_to_host ? conn->conn_to_host.name : + conn->host.name; - if(cf->sockindex == SECONDARYSOCKET) - port = conn->secondary_port; - else if(cf->conn->bits.conn_to_port) - port = conn->conn_to_port; +#ifdef USE_UNIX_SOCKETS + if(conn->unix_domain_socket) + msnprintf(viamsg, sizeof(viamsg), "over %s", conn->unix_domain_socket); else - port = conn->remote_port; +#endif + { + int port; + if(cf->sockindex == SECONDARYSOCKET) + port = conn->secondary_port; + else if(cf->conn->bits.conn_to_port) + port = conn->conn_to_port; + else + port = conn->remote_port; + msnprintf(viamsg, sizeof(viamsg), "port %u", port); + } - failf(data, "Failed to connect to %s port %u %s%s%safter " + failf(data, "Failed to connect to %s %s %s%s%safter " "%" FMT_TIMEDIFF_T " ms: %s", - hostname, port, + hostname, viamsg, proxy_name ? "via " : "", proxy_name ? proxy_name : "", proxy_name ? " " : "", From 8538856662460fdcb38bafde3218ee3022e64807 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 26 Sep 2025 20:57:16 +0200 Subject: [PATCH 198/465] perlcheck: parallelize Follow-up to 34b1e146e42f2dbac5c89414a2a0458a8729a255 #18745 Closes #18750 --- scripts/perlcheck.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/perlcheck.sh b/scripts/perlcheck.sh index be0c0e1c870f..7de0f6dbb559 100755 --- a/scripts/perlcheck.sh +++ b/scripts/perlcheck.sh @@ -32,6 +32,10 @@ set -eu cd "$(dirname "$0")"/.. +procs=6 +command -v nproc >/dev/null && procs="$(nproc)" +echo "parallel: ${procs}" + { if [ -n "${1:-}" ]; then for A in "$@"; do printf "%s\n" "$A"; done @@ -44,4 +48,4 @@ cd "$(dirname "$0")"/.. # strip off the leading ./ to make the grep regexes work properly find . -type f \( -name '*.pl' -o -name '*.pm' \) | sed 's@^\./@@' fi -} | xargs -n 1 perl -c -Itests +} | xargs -n 1 -P "${procs}" perl -c -Itests From 95e50ad69473d8229b85478a3f2138b7e632fbe8 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 16 Sep 2025 19:28:27 +0200 Subject: [PATCH 199/465] tidy-up: miscellaneous - GHA/checkdocs: rename `spellcheck` job to `pyspelling` to say the exact tool used. - GHA/checkdocs: restore a comment. - GHA/linux: add `-B .` to a cmake configure to avoid warning, and future breakage. - autotools: use correct casing for `Schannel`. - doh: update RFC URL. - drop redundant parenthesis. - fix indentation, whitespace. Closes #18756 --- .github/workflows/checkdocs.yml | 5 +++-- configure.ac | 6 +++--- docs/libcurl/libcurl.m4 | 2 +- lib/curl_threads.c | 1 - lib/curlx/version_win32.c | 2 +- lib/doh.c | 2 +- lib/system_win32.c | 6 +++--- lib/telnet.c | 22 +++++++++------------- lib/vtls/openssl.c | 2 +- lib/vtls/schannel.c | 4 ++-- lib/ws.c | 12 ++++++------ 11 files changed, 30 insertions(+), 34 deletions(-) diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index a34a341a636f..3f802b5c4edc 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -100,8 +100,8 @@ jobs: - name: 'mdlinkcheck' run: ./scripts/mdlinkcheck - spellcheck: - name: 'spellcheck' + pyspelling: + name: 'pyspelling' runs-on: ubuntu-latest steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 @@ -125,6 +125,7 @@ jobs: - name: 'check spelling' run: | source ~/venv/bin/activate + # setup the custom wordlist grep -v '^#' .github/scripts/spellcheck.words > wordlist.txt aspell --version pyspelling --version diff --git a/configure.ac b/configure.ac index 56ac66de2369..fddae6a630d1 100644 --- a/configure.ac +++ b/configure.ac @@ -208,7 +208,7 @@ OPT_SCHANNEL=no AC_ARG_WITH(schannel,dnl AS_HELP_STRING([--with-schannel],[enable Windows native SSL/TLS]), OPT_SCHANNEL=$withval - TLSCHOICE="schannel") + TLSCHOICE="Schannel") OPT_AMISSL=no AC_ARG_WITH(amissl,dnl @@ -5033,8 +5033,8 @@ if test "x$want_ech" != "xno"; then ECH_ENABLED_WOLFSSL=1) fi if test "x$RUSTLS_ENABLED" = "x1"; then - ECH_SUPPORT="$ECH_SUPPORT rustls-ffi" - ECH_ENABLED_RUSTLS=1 + ECH_SUPPORT="$ECH_SUPPORT rustls-ffi" + ECH_ENABLED_RUSTLS=1 fi dnl now deal with whatever we found diff --git a/docs/libcurl/libcurl.m4 b/docs/libcurl/libcurl.m4 index 4c89511f06ce..973493f03af5 100644 --- a/docs/libcurl/libcurl.m4 +++ b/docs/libcurl/libcurl.m4 @@ -178,7 +178,7 @@ AC_DEFUN([LIBCURL_CHECK_CONFIG], x=CURLOPT_ERRORBUFFER; x=CURLOPT_STDERR; x=CURLOPT_VERBOSE; - if (x) {;} + if(x) {;} ]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) CPPFLAGS=$_libcurl_save_cppflags diff --git a/lib/curl_threads.c b/lib/curl_threads.c index 94425d19fe8a..a585d26d3fac 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -134,7 +134,6 @@ int Curl_thread_join(curl_thread_t *hnd) Curl_thread_destroy(hnd); - return ret; } diff --git a/lib/curlx/version_win32.c b/lib/curlx/version_win32.c index 4efe62b111ca..7e415dfe89d9 100644 --- a/lib/curlx/version_win32.c +++ b/lib/curlx/version_win32.c @@ -139,7 +139,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, #pragma clang diagnostic ignored "-Wcast-function-type-strict" #endif pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN, - (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo"))); + GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")); #if defined(__clang__) && __clang_major__ >= 16 #pragma clang diagnostic pop #endif diff --git a/lib/doh.c b/lib/doh.c index 069d5387eaf0..a76f42207d60 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -1062,7 +1062,7 @@ UNITTEST void de_cleanup(struct dohentry *d) * @return is 1 for success, error otherwise * * The encoding here is defined in - * https://tools.ietf.org/html/rfc1035#section-3.1 + * https://datatracker.ietf.org/doc/html/rfc1035#section-3.1 * * The input buffer pointer will be modified so it points to * just after the end of the DNS name encoding on output. (And diff --git a/lib/system_win32.c b/lib/system_win32.c index a890a0ea9896..cd01fd2ebfe3 100644 --- a/lib/system_win32.c +++ b/lib/system_win32.c @@ -106,8 +106,8 @@ CURLcode Curl_win32_init(long flags) #endif IF_NAMETOINDEX_FN pIfNameToIndex = CURLX_FUNCTION_CAST(IF_NAMETOINDEX_FN, - (GetProcAddress(s_hIpHlpApiDll, - CURL_TEXT("if_nametoindex")))); + GetProcAddress(s_hIpHlpApiDll, + CURL_TEXT("if_nametoindex"))); if(pIfNameToIndex) Curl_if_nametoindex = pIfNameToIndex; @@ -202,7 +202,7 @@ static HMODULE curl_load_library(LPCTSTR filename) and above */ pLoadLibraryEx = CURLX_FUNCTION_CAST(LOADLIBRARYEX_FN, - (GetProcAddress(hKernel32, LOADLIBARYEX))); + GetProcAddress(hKernel32, LOADLIBARYEX)); /* Detect if there is already a path in the filename and load the library if there is. Note: Both back slashes and forward slashes have been supported diff --git a/lib/telnet.c b/lib/telnet.c index f2226a7f7dd8..66585d6f2a30 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -108,15 +108,15 @@ */ typedef enum { - CURL_TS_DATA = 0, - CURL_TS_IAC, - CURL_TS_WILL, - CURL_TS_WONT, - CURL_TS_DO, - CURL_TS_DONT, - CURL_TS_CR, - CURL_TS_SB, /* sub-option collection */ - CURL_TS_SE /* looking for sub-option end */ + CURL_TS_DATA = 0, + CURL_TS_IAC, + CURL_TS_WILL, + CURL_TS_WONT, + CURL_TS_DO, + CURL_TS_DONT, + CURL_TS_CR, + CURL_TS_SB, /* sub-option collection */ + CURL_TS_SE /* looking for sub-option end */ } TelnetReceive; struct TELNET { @@ -939,7 +939,6 @@ static bool bad_option(const char *data) * Look at the sub-option buffer, and try to be helpful to the other * side. */ - static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) { struct curl_slist *v; @@ -1023,13 +1022,11 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) return CURLE_OK; } - /* * sendsuboption() * * Send suboption information to the server side. */ - static void sendsuboption(struct Curl_easy *data, struct TELNET *tn, int option) { @@ -1084,7 +1081,6 @@ static void sendsuboption(struct Curl_easy *data, } } - static CURLcode telrcv(struct Curl_easy *data, struct TELNET *tn, diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 37cdd5574714..36818daa9e17 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -125,7 +125,7 @@ static void ossl_provider_cleanup(struct Curl_easy *data); * X509_V_ERR_EC_KEY_EXPLICIT_PARAMS. */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) && \ - (!defined(OPENSSL_IS_AWSLC) || (defined(X509_V_ERR_EC_KEY_EXPLICIT_PARAMS))) + (!defined(OPENSSL_IS_AWSLC) || defined(X509_V_ERR_EC_KEY_EXPLICIT_PARAMS)) #define HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN 1 #endif diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 8b7f1d9306c1..8ff8029e3b3e 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -2558,8 +2558,8 @@ static int schannel_init(void) #endif WINE_GET_VERSION_FN p_wine_get_version = CURLX_FUNCTION_CAST(WINE_GET_VERSION_FN, - (GetProcAddress(GetModuleHandleA("ntdll"), - "wine_get_version"))); + GetProcAddress(GetModuleHandleA("ntdll"), + "wine_get_version")); #if defined(__clang__) && __clang_major__ >= 16 #pragma clang diagnostic pop #endif diff --git a/lib/ws.c b/lib/ws.c index 6a265fccc700..36c9c91f6542 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -545,7 +545,7 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec, const unsigned char tmp = '\0'; /* special case of a 0 length frame, need to write once */ result = write_cb(&tmp, 0, dec->frame_age, dec->frame_flags, - 0, 0, write_ctx, &nwritten); + 0, 0, write_ctx, &nwritten); if(result) return result; dec->state = WS_DEC_INIT; @@ -680,8 +680,8 @@ static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen, payload_len, buflen); result = Curl_cwriter_write(data, ctx->next_writer, - (ctx->cw_type | CLIENTWRITE_0LEN), - (const char *)buf, buflen); + (ctx->cw_type | CLIENTWRITE_0LEN), + (const char *)buf, buflen); if(result) return result; } @@ -1579,9 +1579,9 @@ CURLcode curl_ws_recv(CURL *d, void *buffer, *metap = &ws->recvframe; *nread = ws->recvframe.len; CURL_TRC_WS(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %" - FMT_OFF_T ", %" FMT_OFF_T " left)", - buflen, *nread, ws->recvframe.offset, - ws->recvframe.bytesleft); + FMT_OFF_T ", %" FMT_OFF_T " left)", + buflen, *nread, ws->recvframe.offset, + ws->recvframe.bytesleft); /* all's well, try to send any pending control. we do not know * when the application will call `curl_ws_send()` again. */ if(!data->set.ws_raw_mode && ws->pending.type) { From 16f721443aee235014f3d17e623c5c5eeb24b83e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 27 Sep 2025 13:02:12 +0200 Subject: [PATCH 200/465] GHA/linux: tidy up AWS-LC local build To sync with other builds and to use `-B` to avoid a cmake warning and future breakage. Closes #18757 --- .github/workflows/linux.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 2724901324cf..463ea7eb58a4 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -503,9 +503,8 @@ jobs: run: | curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ --location "https://github.com/awslabs/aws-lc/archive/refs/tags/v${AWSLC_VERSION}.tar.gz" | tar -xz - mkdir "aws-lc-${AWSLC_VERSION}-build" - cd "aws-lc-${AWSLC_VERSION}-build" - cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/home/runner/awslc "../aws-lc-${AWSLC_VERSION}" -DBUILD_TOOL=OFF -DBUILD_TESTING=OFF + cd "aws-lc-${AWSLC_VERSION}" + cmake -B . -G Ninja -DCMAKE_INSTALL_PREFIX=/home/runner/awslc -DBUILD_TOOL=OFF -DBUILD_TESTING=OFF cmake --build . cmake --install . From b5c9c858d53072ae6e5a2388d488d2f691f7cd32 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 21:53:21 +0000 Subject: [PATCH 201/465] GHA: update dependency awslabs/aws-lc to v1.61.4 Closes #18752 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 019790b68e5d..6ed393465ebf 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -46,7 +46,7 @@ env: # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com LIBRESSL_VERSION: 4.1.0 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com - AWSLC_VERSION: 1.61.3 + AWSLC_VERSION: 1.61.4 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # renovate: datasource=github-tags depName=gnutls/gnutls versioning=semver registryUrl=https://github.com diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 463ea7eb58a4..dd1e88ed0cd8 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -44,7 +44,7 @@ env: # renovate: datasource=github-tags depName=Mbed-TLS/mbedtls versioning=semver registryUrl=https://github.com MBEDTLS_VERSION: 3.6.4 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com - AWSLC_VERSION: 1.61.3 + AWSLC_VERSION: 1.61.4 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # handled in renovate.json From 75d5424979a8effac331c4924edb1a8be458cdce Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 27 Sep 2025 17:58:29 +0200 Subject: [PATCH 202/465] GHA/windows: tidy up Cygwin jobs - drop unnecessary installed packages. - sync built type name with other jobs. Closes #18758 --- .github/workflows/windows.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e5d66ccc87fc..b866bdacd622 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -110,8 +110,8 @@ jobs: strategy: matrix: include: - - { build: 'automake', platform: 'x86_64', tflags: 'skiprun', config: '--with-openssl', install: 'libssl-devel libssh2-devel', name: 'openssl R' } - - { build: 'cmake' , platform: 'x86_64', tflags: '' , config: '-DENABLE_DEBUG=ON -DCURL_USE_OPENSSL=ON -DENABLE_THREADED_RESOLVER=OFF', install: 'libssl-devel libssh2-devel', name: 'openssl' } + - { build: 'autotools', platform: 'x86_64', tflags: 'skiprun', config: '--with-openssl', install: 'libssl-devel libssh2-devel', name: 'openssl R' } + - { build: 'cmake' , platform: 'x86_64', tflags: '' , config: '-DENABLE_DEBUG=ON -DCURL_USE_OPENSSL=ON -DENABLE_THREADED_RESOLVER=OFF', install: 'libssl-devel libssh2-devel', name: 'openssl' } fail-fast: false steps: - run: git config --global core.autocrlf input @@ -123,8 +123,8 @@ jobs: work-vol: 'D:' # https://cygwin.com/cgi-bin2/package-grep.cgi packages: >- - autoconf libtool gcc-core gcc-g++ binutils - ${{ matrix.build }} make ninja + ${{ matrix.build == 'autotools' && 'autoconf automake libtool make' || 'cmake ninja' }} + gcc-core binutils perl openssh libpsl-devel zlib-devel @@ -138,7 +138,7 @@ jobs: persist-credentials: false - name: 'autoreconf' - if: ${{ matrix.build == 'automake' }} + if: ${{ matrix.build == 'autotools' }} timeout-minutes: 2 run: | PATH=/usr/bin From 660d915ebda4ea44c4422a647e09693d6fb6a9ee Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 27 Sep 2025 23:51:46 +0200 Subject: [PATCH 203/465] ci: use `--enable-option-checking=fatal` in autotools jobs To avoid typos and non-existing options passed to `./configure` in CI builds. Also delete obsolete option `--enable-test-bundles` from Circle CI jobs. Closes #18759 --- .circleci/config.yml | 12 ++++++------ .github/workflows/distcheck.yml | 10 +++++----- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- .github/workflows/macos.yml | 6 +++--- .github/workflows/non-native.yml | 4 ++-- .github/workflows/windows.yml | 6 +++--- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1603e7f7d0f0..21b88054d5d3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -66,7 +66,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror --enable-warnings \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror --enable-warnings \ --with-openssl \ || { tail -1000 config.log; false; } @@ -75,7 +75,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror \ --with-openssl --disable-verbose \ || { tail -1000 config.log; false; } @@ -84,7 +84,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror \ --with-openssl --disable-proxy \ || { tail -1000 config.log; false; } @@ -93,7 +93,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror --enable-warnings \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror --enable-warnings \ --with-openssl --with-libssh \ || { tail -1000 config.log; false; } @@ -102,7 +102,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror --enable-warnings \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror --enable-warnings \ --with-openssl --enable-ares \ || { tail -1000 config.log; false; } @@ -111,7 +111,7 @@ commands: - run: command: | autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror --enable-debug \ + ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror --enable-debug \ --with-openssl --enable-ares \ || { tail -1000 config.log; false; } diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index da65bf4bd0cf..7a1a4dad844f 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -60,7 +60,7 @@ jobs: echo "::stop-commands::$(uuidgen)" tar xvf curl-99.98.97.tar.gz pushd curl-99.98.97 - ./configure --prefix="$HOME"/temp --enable-werror --without-ssl --without-libpsl + ./configure --prefix="$HOME"/temp --enable-option-checking=fatal --enable-werror --without-ssl --without-libpsl make make test-ci make install @@ -86,7 +86,7 @@ jobs: touch curl-99.98.97/docs/{cmdline-opts,libcurl}/Makefile.inc mkdir build pushd build - ../curl-99.98.97/configure --enable-werror --without-ssl --without-libpsl + ../curl-99.98.97/configure --enable-option-checking=fatal --enable-werror --without-ssl --without-libpsl make make test-ci popd @@ -110,7 +110,7 @@ jobs: pushd curl-99.98.97 mkdir build pushd build - ../configure --prefix="$PWD"/curl-install --enable-werror --without-ssl --enable-debug --without-libpsl + ../configure --prefix="$PWD"/curl-install --enable-option-checking=fatal --enable-werror --without-ssl --enable-debug --without-libpsl make make test-ci make install @@ -136,7 +136,7 @@ jobs: pushd curl-99.98.97 mkdir build pushd build - ../configure --prefix="$PWD"/curl-install --enable-werror --without-ssl --without-libpsl ac_cv_path_PERL= + ../configure --prefix="$PWD"/curl-install --enable-option-checking=fatal --enable-werror --without-ssl --without-libpsl ac_cv_path_PERL= make make install curl-install/bin/curl --disable --version @@ -158,7 +158,7 @@ jobs: echo "::stop-commands::$(uuidgen)" tar xvf curl-99.98.97.tar.gz pushd curl-99.98.97 - ./configure --prefix="$PWD"/curl-install --enable-werror --without-ssl --without-libpsl ac_cv_path_PERL= + ./configure --prefix="$PWD"/curl-install --enable-option-checking=fatal --enable-werror --without-ssl --without-libpsl ac_cv_path_PERL= make make install curl-install/bin/curl --disable --version diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 6ed393465ebf..05d71b6f107a 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -686,7 +686,7 @@ jobs: mkdir bld && cd bld && ../configure --enable-warnings --enable-werror --enable-debug \ --with-libuv \ --with-test-nghttpx=/home/runner/nghttp2/build/bin/nghttpx \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ ${MATRIX_CONFIGURE} fi diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index dd1e88ed0cd8..1d38c50db64d 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -595,7 +595,7 @@ jobs: mkdir bld && cd bld && \ ${MATRIX_CONFIGURE_PREFIX} \ ../configure --prefix="$HOME"/curl-install --enable-unity --enable-warnings --enable-werror \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ ${MATRIX_CONFIGURE} fi diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 88b7ee880062..6777f3aa924f 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -160,7 +160,7 @@ jobs: ${MATRIX_GENERATE} ${options} else mkdir bld && cd bld && ../configure --enable-unity --enable-warnings --enable-werror \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ CFLAGS="-isysroot $(xcrun --sdk iphoneos --show-sdk-path 2>/dev/null)" \ --host=aarch64-apple-darwin \ --with-apple-idn \ @@ -440,7 +440,7 @@ jobs: [ -n "${MATRIX_MACOS_VERSION_MIN}" ] && CFLAGS+=" -mmacosx-version-min=${MATRIX_MACOS_VERSION_MIN}" [[ "${MATRIX_INSTALL_STEPS}" = *'pytest'* ]] && options+=' --with-test-vsftpd=no' # Skip ~20 tests that stretch run time by 7x on macOS mkdir bld && cd bld && ../configure --prefix="$PWD"/curl-install --enable-unity --enable-warnings --enable-werror \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ --with-libpsl=/opt/homebrew/opt/libpsl \ ${MATRIX_CONFIGURE} ${options} fi @@ -706,7 +706,7 @@ jobs: [ -n "${MATRIX_MACOS_VERSION_MIN}" ] && CFLAGS+=" -mmacosx-version-min=${MATRIX_MACOS_VERSION_MIN}" # would pick up nghttp2, libidn2, but libssh2 is disabled by default mkdir bld && cd bld && ../configure --enable-unity --enable-warnings --enable-werror \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ --disable-docs --disable-manual \ --with-openssl="$(brew --prefix openssl)" \ --without-nghttp2 --without-libidn2 \ diff --git a/.github/workflows/non-native.yml b/.github/workflows/non-native.yml index 2670c39078fd..03abced26eb4 100644 --- a/.github/workflows/non-native.yml +++ b/.github/workflows/non-native.yml @@ -192,7 +192,7 @@ jobs: --prefix="$HOME"/curl-install \ --with-openssl \ --with-brotli --enable-ldap --enable-ldaps --with-libidn2 --with-libssh2 --with-nghttp2 --with-gssapi \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ ${options} \ ${MATRIX_OPTIONS} \ || { tail -n 1000 config.log; false; } @@ -284,7 +284,7 @@ jobs: ${MATRIX_OPTIONS} else TOOLCHAIN="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64" - mkdir bld && cd bld && ../configure --disable-dependency-tracking --enable-unity --enable-warnings --enable-werror \ + mkdir bld && cd bld && ../configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-warnings --enable-werror \ CC="$TOOLCHAIN/bin/aarch64-linux-android${MATRIX_PLATFORM}-clang" \ AR="$TOOLCHAIN/bin/llvm-ar" \ RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \ diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index b866bdacd622..e1219dfadc48 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -160,7 +160,7 @@ jobs: mkdir bld && cd bld && ../configure --enable-unity --enable-warnings --enable-werror \ --prefix="$HOME"/curl-install \ --with-libssh2 \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ ${MATRIX_CONFIG} fi @@ -367,7 +367,7 @@ jobs: mkdir bld && cd bld && ../configure --enable-unity --enable-warnings --enable-werror \ --prefix="$HOME"/curl-install \ --with-libssh2 \ - --disable-dependency-tracking \ + --disable-dependency-tracking --enable-option-checking=fatal \ ${MATRIX_CONFIG} fi @@ -756,7 +756,7 @@ jobs: --host="${TRIPLET}" \ --with-schannel --with-winidn \ --without-libpsl \ - --disable-dependency-tracking + --disable-dependency-tracking --enable-option-checking=fatal fi - name: 'configure log' From a6182865d0c8cfb9dbfe8d6444b428d17ecc677c Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 28 Sep 2025 00:32:49 +0200 Subject: [PATCH 204/465] CI: make pip use `tests/requirements.txt` in Circle CI Also sync `pip` options with those used in GHA. Closes #18760 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 21b88054d5d3..39201708e81b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,7 +45,7 @@ commands: - run: command: | sudo apt-get update && sudo apt-get install -y libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev python3-pip libpsl-dev - sudo python3 -m pip install impacket + sudo python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt install-wolfssl: steps: From 81a9197102472a03a873c0d59d150223f5ed8840 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 28 Sep 2025 11:54:57 +0200 Subject: [PATCH 205/465] GHA/linux-old: make one cmake v3.7.2 job verbose To show the details in cmake builds using the oldest supported version. Use a legacy method. `--verbose` became supported later, in 3.14. Closes #18764 --- .github/workflows/linux-old.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index 7e25cd213911..e7aad3c3e73a 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -86,7 +86,7 @@ jobs: cd bld-1 cmake .. -DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON -DBUILD_SHARED_LIBS=ON \ -DCURL_USE_GNUTLS=ON -DENABLE_ARES=OFF -DCURL_ZSTD=OFF -DCURL_USE_GSSAPI=OFF -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=OFF -DUSE_LIBRTMP=ON - make install + VERBOSE=1 make install src/curl --disable --version - name: 'cmake build-only curl_config.h' From e17aa98bfe3799723cec978661cad4079bfa4dd7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 28 Sep 2025 02:34:13 +0200 Subject: [PATCH 206/465] cmake: use more `COMPILER_OPTIONS`, `LINK_OPTIONS` / `LINK_FLAGS` - replace `COMPILE_FLAGS` with `COMPILE_OPTIONS` that superceded it. Follow-up to 6140dfcf3e7845f11dee755de6865379aa96dab7 https://cmake.org/cmake/help/v4.1/prop_sf/COMPILE_FLAGS.html - replace `target_link_libraries()` with `LINK_FLAGS` property for CMake <=3.12, because we are passing linker options (not libs). Follow-up to 91720b620e802748d2e1629f43e29b76736542f9 #18468 Follow-up to 548873921cde197aa1d40216c594c76738031374 #17670 Follow-up to 95aea798dbd785c4daee2b2e24f2c8c94f3e3cf4 #5843 https://cmake.org/cmake/help/v3.7/command/target_link_libraries.html https://cmake.org/cmake/help/v3.7/prop_tgt/LINK_FLAGS.html - replace `target_link_options()` with `LINK_OPTIONS` propery for CMake 3.13+, to use the modern style. Follow-up to 91720b620e802748d2e1629f43e29b76736542f9 #18468 Follow-up to 548873921cde197aa1d40216c594c76738031374 #17670 https://cmake.org/cmake/help/v3.13/command/target_link_options.html https://cmake.org/cmake/help/v3.13/prop_tgt/LINK_OPTIONS.html Also: - fix to append to, not override, previously set linker options when using `CURL_LIBCURL_VERSIONED_SYMBOLS=ON`. Before this patch, it was overwriting linker options when using `CURL_CODE_COVERAGE=ON`. Follow-up to 91720b620e802748d2e1629f43e29b76736542f9 #18468 Closes #18762 --- lib/CMakeLists.txt | 14 +++++++------- src/CMakeLists.txt | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 7dce3aea8770..d9857a50c27f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -112,7 +112,7 @@ if(SHARE_LIB_OBJECT AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) set_target_properties(${LIB_OBJECT} PROPERTIES POSITION_INDEPENDENT_CODE ON) if(CURL_HIDES_PRIVATE_SYMBOLS) - set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}") set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") endif() if(CURL_HAS_LTO) @@ -154,7 +154,7 @@ if(BUILD_STATIC_LIBS) INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB" INTERFACE_LINK_DIRECTORIES "${CURL_LIBDIRS}") if(CURL_HIDES_PRIVATE_SYMBOLS) - set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}") set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") endif() if(CURL_HAS_LTO) @@ -194,7 +194,7 @@ if(BUILD_SHARED_LIBS) IMPORT_PREFIX "" IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}" POSITION_INDEPENDENT_CODE ON) if(CURL_HIDES_PRIVATE_SYMBOLS) - set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}") + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}") set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") endif() if(CURL_HAS_LTO) @@ -210,9 +210,9 @@ if(BUILD_SHARED_LIBS) set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) - target_link_options(${LIB_SHARED} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_OPTIONS ${CURL_COVERAGE_LDFLAGS}) else() - target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_FLAGS ${CURL_COVERAGE_LDFLAGS}) endif() endif() @@ -289,9 +289,9 @@ if(BUILD_SHARED_LIBS) check_c_source_compiles("int main(void) { return 0; }" HAVE_VERSIONED_SYMBOLS) if(HAVE_VERSIONED_SYMBOLS) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) - set_target_properties(${LIB_SHARED} PROPERTIES LINK_OPTIONS "${CMAKE_REQUIRED_LINK_OPTIONS}") + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_OPTIONS "${CMAKE_REQUIRED_LINK_OPTIONS}") else() - set_target_properties(${LIB_SHARED} PROPERTIES LINK_FLAGS "${CMAKE_REQUIRED_LINK_OPTIONS}") + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_FLAGS "${CMAKE_REQUIRED_LINK_OPTIONS}") endif() else() message(WARNING "Versioned symbols requested, but not supported by the toolchain.") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c4b8ebb9346d..a70c96b7650f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,9 +123,9 @@ endif() if(ENABLE_UNICODE AND MINGW AND NOT MINGW32CE) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) - target_link_options(${EXE_NAME} PRIVATE "-municode") + set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_OPTIONS "-municode") else() - target_link_libraries(${EXE_NAME} PRIVATE "-municode") + set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_FLAGS "-municode") endif() endif() @@ -133,9 +133,9 @@ if(CURL_CODE_COVERAGE) set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS}) set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS}) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) - target_link_options(${EXE_NAME} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_OPTIONS ${CURL_COVERAGE_LDFLAGS}) else() - target_link_libraries(${EXE_NAME} PRIVATE ${CURL_COVERAGE_LDFLAGS}) + set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_FLAGS ${CURL_COVERAGE_LDFLAGS}) endif() endif() From 10bac43b873fe45869e15b36aac1c1e5bc89b6e0 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 29 Sep 2025 22:48:55 +0200 Subject: [PATCH 207/465] tests/server: drop unsafe `open()` override in signal handler (Windows) Turns out the signal handler on Windows still wasn't signal safe after the previous round of fix. There is an `open()` call made from there, and `open` happens to be unconditionally overridden via `curl_setup.h` on Windows, to its local implementation (`curlx_win32_open()`), which does memory allocations and potentially other things that are not signal safe. This is a temporary fix, till avoiding the override of system symbols `open` and `stat` on Windows. FTR this did not fix the CI 2304 errors, diskspace fail or job hangs due to 0xC0000142 fork failure (it's rare all three occurs in the same run): https://github.com/curl/curl/actions/runs/18110523584?pr=18774 Ref: #18634 Follow-up e95f509c66abdd88ae02e3243cdc217f19c4a330 #16852 Closes #18774 --- tests/server/util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/server/util.c b/tests/server/util.c index 052effa89583..41f42ca42e09 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -373,12 +373,12 @@ static void exit_signal_handler(int signum) (void)!write(STDERR_FILENO, msg, sizeof(msg) - 1); } else { + int fd; #ifdef _WIN32 -#define OPENMODE S_IREAD | S_IWRITE + fd = _open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, S_IREAD | S_IWRITE); #else -#define OPENMODE S_IRUSR | S_IWUSR + fd = open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR | S_IWUSR); #endif - int fd = open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, OPENMODE); if(fd != -1) { static const char msg[] = "exit_signal_handler: called\n"; (void)!write(fd, msg, sizeof(msg) - 1); From 20142f5d06f7120ba94cbcc25c998e8d81aec85b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 14 Sep 2025 15:34:18 +0200 Subject: [PATCH 208/465] build: avoid overriding system symbols for fopen functions By introducing wrappers for them in the curlx namespace: `curlx_fopen()`, `curlx_fdopen()`, `curlx_fclose()`. The undefine/redefine/`(function)()` methods broke on systems implementing these functions as macros. E.g. AIX 32-bit's `fopen()`. Also: - rename `lib/fopen.*` to `lib/curl_fopen.*` (for `Curl_fopen()`) to make room for the newly added `curlx/fopen.h`. - curlx: move file-related functions from `multibyte.c` to `fopen.c`. - tests/server: stop using the curl-specific `fopen()` implementation on Windows. Unicode isn't used by runtests, and it isn't critical to run tests on longs path. It can be re-enabled if this becomes necessary, or if the wrapper receives a feature that's critical for test servers. Reported-by: Andrew Kirillov Bug: https://github.com/curl/curl/issues/18510#issuecomment-3274393640 Follow-up to bf7375ecc50e857760b0d0a668c436e208a400bd #18503 Follow-up to 9863599d69b79d290928a89bf9160f4e4e023d4e #18502 Follow-up to 3bb5e58c105d7be450b667858d1b8e7ae3ded555 #17827 Closes #18634 --- .github/scripts/verify-examples.pl | 4 +- docs/examples/.checksrc | 3 + docs/internals/CHECKSRC.md | 2 +- lib/Makefile.inc | 6 +- lib/altsvc.c | 8 +- lib/cookie.c | 10 +- lib/{fopen.c => curl_fopen.c} | 8 +- lib/{fopen.h => curl_fopen.h} | 2 + lib/curl_mem_undef.h | 11 - lib/curl_setup.h | 3 - lib/curlx/curlx.h | 3 + lib/curlx/fopen.c | 310 +++++++++++++++++++++++++++++ lib/curlx/fopen.h | 48 +++++ lib/curlx/multibyte.c | 273 ------------------------- lib/hsts.c | 8 +- lib/memdebug.c | 24 +-- lib/memdebug.h | 7 - lib/mime.c | 15 +- lib/netrc.c | 5 +- lib/vtls/gtls.c | 5 +- lib/vtls/keylog.c | 7 +- lib/vtls/rustls.c | 7 +- lib/vtls/schannel.c | 5 +- lib/vtls/vtls.c | 5 +- scripts/checksrc.pl | 7 +- src/Makefile.inc | 2 + src/tool_cb_dbg.c | 2 +- src/tool_cb_wrt.c | 4 +- src/tool_cfgable.c | 2 +- src/tool_easysrc.c | 4 +- src/tool_formparse.c | 4 +- src/tool_getparam.c | 24 +-- src/tool_ipfs.c | 6 +- src/tool_operate.c | 34 ++-- src/tool_parsecfg.c | 6 +- src/tool_ssls.c | 8 +- src/tool_stderr.c | 4 +- src/tool_util.c | 2 +- src/tool_writeout.c | 12 +- src/var.c | 4 +- tests/data/test1185 | 4 +- tests/libtest/Makefile.inc | 1 + tests/libtest/cli_h2_serverpush.c | 10 +- tests/libtest/cli_hx_download.c | 4 +- tests/libtest/cli_hx_upload.c | 4 +- tests/libtest/lib500.c | 4 +- tests/libtest/lib505.c | 16 +- tests/libtest/lib518.c | 4 +- tests/libtest/lib525.c | 8 +- tests/libtest/lib537.c | 4 +- tests/libtest/lib541.c | 12 +- tests/libtest/lib566.c | 4 +- tests/libtest/lib568.c | 6 +- tests/libtest/lib569.c | 8 +- tests/libtest/lib571.c | 8 +- tests/libtest/lib572.c | 6 +- tests/libtest/lib578.c | 4 +- tests/libtest/lib579.c | 8 +- tests/libtest/lib582.c | 8 +- tests/libtest/lib591.c | 6 +- tests/libtest/lib599.c | 4 +- tests/libtest/lib678.c | 4 +- tests/server/.checksrc | 2 + tests/server/Makefile.inc | 1 + tests/unit/unit3200.c | 8 +- 65 files changed, 568 insertions(+), 484 deletions(-) rename lib/{fopen.c => curl_fopen.c} (96%) rename lib/{fopen.h => curl_fopen.h} (97%) create mode 100644 lib/curlx/fopen.c create mode 100644 lib/curlx/fopen.h diff --git a/.github/scripts/verify-examples.pl b/.github/scripts/verify-examples.pl index 27c4de6db855..a8dd08d1827a 100755 --- a/.github/scripts/verify-examples.pl +++ b/.github/scripts/verify-examples.pl @@ -63,9 +63,9 @@ sub extract { elsif($syn == 1) { if(/^~~~/) { $syn++; - print O "/* !checksrc! disable UNUSEDIGNORE all */\n"; + print O "/* !checksrc! disable BANNEDFUNC all */\n"; # for fopen() print O "/* !checksrc! disable COPYRIGHT all */\n"; - print O "/* !checksrc! disable FOPENMODE all */\n"; + print O "/* !checksrc! disable UNUSEDIGNORE all */\n"; printf O "#line %d \"$f\"\n", $iline+1; } } diff --git a/docs/examples/.checksrc b/docs/examples/.checksrc index 0b626e65703d..e0b6c43da939 100644 --- a/docs/examples/.checksrc +++ b/docs/examples/.checksrc @@ -1,3 +1,6 @@ +allowfunc fclose +allowfunc fdopen +allowfunc fopen allowfunc gmtime allowfunc localtime allowfunc socket diff --git a/docs/internals/CHECKSRC.md b/docs/internals/CHECKSRC.md index 16eb96c75bfc..9c4f1428791e 100644 --- a/docs/internals/CHECKSRC.md +++ b/docs/internals/CHECKSRC.md @@ -76,7 +76,7 @@ warnings are: - `EXCLAMATIONSPACE`: space found after exclamations mark -- `FOPENMODE`: `fopen()` needs a macro for the mode string, use it +- `FOPENMODE`: `curlx_fopen()` needs a macro for the mode string, use it - `INDENTATION`: detected a wrong start column for code. Note that this warning only checks some specific places and can certainly miss many bad diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 6391eb2c4351..1447e53a1e5b 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -26,6 +26,7 @@ LIB_CURLX_CFILES = \ curlx/base64.c \ curlx/dynbuf.c \ + curlx/fopen.c \ curlx/inet_ntop.c \ curlx/inet_pton.c \ curlx/multibyte.c \ @@ -43,6 +44,7 @@ LIB_CURLX_HFILES = \ curlx/base64.h \ curlx/curlx.h \ curlx/dynbuf.h \ + curlx/fopen.h \ curlx/inet_ntop.h \ curlx/inet_pton.h \ curlx/multibyte.h \ @@ -157,6 +159,7 @@ LIB_CFILES = \ curl_des.c \ curl_endian.c \ curl_fnmatch.c \ + curl_fopen.c \ curl_get_line.c \ curl_gethostname.c \ curl_gssapi.c \ @@ -181,7 +184,6 @@ LIB_CFILES = \ fake_addrinfo.c \ file.c \ fileinfo.c \ - fopen.c \ formdata.c \ ftp.c \ ftplistparser.c \ @@ -286,6 +288,7 @@ LIB_HFILES = \ curl_des.h \ curl_endian.h \ curl_fnmatch.h \ + curl_fopen.h \ curl_get_line.h \ curl_gethostname.h \ curl_gssapi.h \ @@ -320,7 +323,6 @@ LIB_HFILES = \ fake_addrinfo.h \ file.h \ fileinfo.h \ - fopen.h \ formdata.h \ ftp.h \ ftplistparser.h \ diff --git a/lib/altsvc.c b/lib/altsvc.c index c7448692fb56..7e4c4b5c25a7 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -31,11 +31,11 @@ #include #include "urldata.h" #include "altsvc.h" +#include "curl_fopen.h" #include "curl_get_line.h" #include "parsedate.h" #include "sendf.h" #include "curlx/warnless.h" -#include "fopen.h" #include "rename.h" #include "strdup.h" #include "curlx/inet_pton.h" @@ -227,7 +227,7 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file) if(!asi->filename) return CURLE_OUT_OF_MEMORY; - fp = fopen(file, FOPEN_READTEXT); + fp = curlx_fopen(file, FOPEN_READTEXT); if(fp) { struct dynbuf buf; curlx_dyn_init(&buf, MAX_ALTSVC_LINE); @@ -238,7 +238,7 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file) altsvc_add(asi, lineptr); } curlx_dyn_free(&buf); /* free the line buffer */ - fclose(fp); + curlx_fclose(fp); } return result; } @@ -391,7 +391,7 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data, if(result) break; } - fclose(out); + curlx_fclose(out); if(!result && tempstore && Curl_rename(tempstore, file)) result = CURLE_WRITE_ERROR; diff --git a/lib/cookie.c b/lib/cookie.c index 90d375a7611b..c5fbe1344dd6 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -80,11 +80,11 @@ Example set of cookies: #include "slist.h" #include "share.h" #include "strcase.h" +#include "curl_fopen.h" #include "curl_get_line.h" #include "curl_memrchr.h" #include "parsedate.h" #include "rename.h" -#include "fopen.h" #include "strdup.h" #include "llist.h" #include "curlx/strparse.h" @@ -1195,7 +1195,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, if(!strcmp(file, "-")) fp = stdin; else { - fp = fopen(file, "rb"); + fp = curlx_fopen(file, "rb"); if(!fp) infof(data, "WARNING: failed to open cookie file \"%s\"", file); else @@ -1228,7 +1228,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, remove_expired(ci); if(handle) - fclose(handle); + curlx_fclose(handle); } data->state.cookie_engine = TRUE; } @@ -1583,7 +1583,7 @@ static CURLcode cookie_output(struct Curl_easy *data, } if(!use_stdout) { - fclose(out); + curlx_fclose(out); out = NULL; if(tempstore && Curl_rename(tempstore, filename)) { unlink(tempstore); @@ -1602,7 +1602,7 @@ static CURLcode cookie_output(struct Curl_easy *data, error: if(out && !use_stdout) - fclose(out); + curlx_fclose(out); free(tempstore); return error; } diff --git a/lib/fopen.c b/lib/curl_fopen.c similarity index 96% rename from lib/fopen.c rename to lib/curl_fopen.c index b28977317a8b..13acd299c0dd 100644 --- a/lib/fopen.c +++ b/lib/curl_fopen.c @@ -33,7 +33,7 @@ #include "urldata.h" #include "rand.h" -#include "fopen.h" +#include "curl_fopen.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -102,7 +102,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, char *dir = NULL; *tempname = NULL; - *fh = fopen(filename, FOPEN_WRITETEXT); + *fh = curlx_fopen(filename, FOPEN_WRITETEXT); if(!*fh) goto fail; if( @@ -114,7 +114,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, || !S_ISREG(sb.st_mode)) { return CURLE_OK; } - fclose(*fh); + curlx_fclose(*fh); *fh = NULL; result = Curl_rand_alnum(data, randbuf, sizeof(randbuf)); @@ -144,7 +144,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, if(fd == -1) goto fail; - *fh = fdopen(fd, FOPEN_WRITETEXT); + *fh = curlx_fdopen(fd, FOPEN_WRITETEXT); if(!*fh) goto fail; diff --git a/lib/fopen.h b/lib/curl_fopen.h similarity index 97% rename from lib/fopen.h rename to lib/curl_fopen.h index e3a919d07367..a3dc1382bca8 100644 --- a/lib/fopen.h +++ b/lib/curl_fopen.h @@ -24,6 +24,8 @@ * ***************************************************************************/ +#include "curlx/fopen.h" + CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, FILE **fh, char **tempname); diff --git a/lib/curl_mem_undef.h b/lib/curl_mem_undef.h index a70a9fcf5379..2be114cbd5e6 100644 --- a/lib/curl_mem_undef.h +++ b/lib/curl_mem_undef.h @@ -33,16 +33,5 @@ #undef Curl_tcsdup #endif -#ifdef CURLDEBUG - -#undef fopen -#ifdef CURL_FOPEN -#define fopen(fname, mode) CURL_FOPEN(fname, mode) -#endif -#undef fdopen -#undef fclose - -#endif /* CURLDEBUG */ - #undef HEADER_CURL_MEMORY_H #undef HEADER_CURL_MEMDEBUG_H diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 55c65c99f696..b3c19a95efb5 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -509,11 +509,8 @@ # ifndef UNDER_CE int curlx_win32_stat(const char *path, struct_stat *buffer); int curlx_win32_open(const char *filename, int oflag, ...); - FILE *curlx_win32_fopen(const char *filename, const char *mode); # define stat(fname, stp) curlx_win32_stat(fname, stp) # define open curlx_win32_open -# define CURL_FOPEN(fname, mode) curlx_win32_fopen(fname, mode) -# define fopen(fname, mode) CURL_FOPEN(fname, mode) # endif #elif defined(__DJGPP__) /* Requires DJGPP 2.04 */ diff --git a/lib/curlx/curlx.h b/lib/curlx/curlx.h index 9f7bd3a975ea..33ac72e8e19b 100644 --- a/lib/curlx/curlx.h +++ b/lib/curlx/curlx.h @@ -64,6 +64,9 @@ #include "dynbuf.h" /* The curlx_dyn_* functions */ +#include "fopen.h" +/* The curlx_f* functions */ + #include "base64.h" #include "timeval.h" #include "timediff.h" diff --git a/lib/curlx/fopen.c b/lib/curlx/fopen.c new file mode 100644 index 000000000000..22c7259c70dd --- /dev/null +++ b/lib/curlx/fopen.c @@ -0,0 +1,310 @@ +/*************************************************************************** + * _ _ ____ _ + * 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 + * + ***************************************************************************/ + +/* + * This file is 'mem-include-scan' clean, which means its memory allocations + * are not tracked by the curl memory tracker memdebug, so they must not use + * `CURLDEBUG` macro replacements in memdebug.h for free, malloc, etc. To avoid + * these macro replacements, wrap the names in parentheses to call the original + * versions: `ptr = (malloc)(123)`, `(free)(ptr)`, etc. + */ + +#include "../curl_setup.h" + +#if defined(_WIN32) && !defined(UNDER_CE) + +#include "fopen.h" +#include "multibyte.h" + +/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */ +#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \ + (_WIN32_WINNT < _WIN32_WINNT_WIN10) +WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *); +#endif + +/* Fix excessive paths (paths that exceed MAX_PATH length of 260). + * + * This is a helper function to fix paths that would exceed the MAX_PATH + * limitation check done by Windows APIs. It does so by normalizing the passed + * in filename or path 'in' to its full canonical path, and if that path is + * longer than MAX_PATH then setting 'out' to "\\?\" prefix + that full path. + * + * For example 'in' filename255chars in current directory C:\foo\bar is + * fixed as \\?\C:\foo\bar\filename255chars for 'out' which will tell Windows + * it is ok to access that filename even though the actual full path is longer + * than 260 chars. + * + * For non-Unicode builds this function may fail sometimes because only the + * Unicode versions of some Windows API functions can access paths longer than + * MAX_PATH, for example GetFullPathNameW which is used in this function. When + * the full path is then converted from Unicode to multibyte that fails if any + * directories in the path contain characters not in the current codepage. + */ +static bool fix_excessive_path(const TCHAR *in, TCHAR **out) +{ + size_t needed, count; + const wchar_t *in_w; + wchar_t *fbuf = NULL; + + /* MS documented "approximate" limit for the maximum path length */ + const size_t max_path_len = 32767; + +#ifndef _UNICODE + wchar_t *ibuf = NULL; + char *obuf = NULL; +#endif + + *out = NULL; + + /* skip paths already normalized */ + if(!_tcsncmp(in, _T("\\\\?\\"), 4)) + goto cleanup; + +#ifndef _UNICODE + /* convert multibyte input to unicode */ + needed = mbstowcs(NULL, in, 0); + if(needed == (size_t)-1 || needed >= max_path_len) + goto cleanup; + ++needed; /* for NUL */ + ibuf = (malloc)(needed * sizeof(wchar_t)); + if(!ibuf) + goto cleanup; + count = mbstowcs(ibuf, in, needed); + if(count == (size_t)-1 || count >= needed) + goto cleanup; + in_w = ibuf; +#else + in_w = in; +#endif + + /* GetFullPathNameW returns the normalized full path in unicode. It converts + forward slashes to backslashes, processes .. to remove directory segments, + etc. Unlike GetFullPathNameA it can process paths that exceed MAX_PATH. */ + needed = (size_t)GetFullPathNameW(in_w, 0, NULL, NULL); + if(!needed || needed > max_path_len) + goto cleanup; + /* skip paths that are not excessive and do not need modification */ + if(needed <= MAX_PATH) + goto cleanup; + fbuf = (malloc)(needed * sizeof(wchar_t)); + if(!fbuf) + goto cleanup; + count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL); + if(!count || count >= needed) + goto cleanup; + + /* prepend \\?\ or \\?\UNC\ to the excessively long path. + * + * c:\longpath ---> \\?\c:\longpath + * \\.\c:\longpath ---> \\?\c:\longpath + * \\?\c:\longpath ---> \\?\c:\longpath (unchanged) + * \\server\c$\longpath ---> \\?\UNC\server\c$\longpath + * + * https://learn.microsoft.com/dotnet/standard/io/file-path-formats + */ + if(!wcsncmp(fbuf, L"\\\\?\\", 4)) + ; /* do nothing */ + else if(!wcsncmp(fbuf, L"\\\\.\\", 4)) + fbuf[2] = '?'; + else if(!wcsncmp(fbuf, L"\\\\.", 3) || !wcsncmp(fbuf, L"\\\\?", 3)) { + /* Unexpected, not UNC. The formatting doc doesn't allow this AFAICT. */ + goto cleanup; + } + else { + wchar_t *temp; + + if(!wcsncmp(fbuf, L"\\\\", 2)) { + /* "\\?\UNC\" + full path without "\\" + null */ + needed = 8 + (count - 2) + 1; + if(needed > max_path_len) + goto cleanup; + + temp = (malloc)(needed * sizeof(wchar_t)); + if(!temp) + goto cleanup; + + wcsncpy(temp, L"\\\\?\\UNC\\", 8); + wcscpy(temp + 8, fbuf + 2); + } + else { + /* "\\?\" + full path + null */ + needed = 4 + count + 1; + if(needed > max_path_len) + goto cleanup; + + temp = (malloc)(needed * sizeof(wchar_t)); + if(!temp) + goto cleanup; + + wcsncpy(temp, L"\\\\?\\", 4); + wcscpy(temp + 4, fbuf); + } + + (free)(fbuf); + fbuf = temp; + } + +#ifndef _UNICODE + /* convert unicode full path to multibyte output */ + needed = wcstombs(NULL, fbuf, 0); + if(needed == (size_t)-1 || needed >= max_path_len) + goto cleanup; + ++needed; /* for NUL */ + obuf = (malloc)(needed); + if(!obuf) + goto cleanup; + count = wcstombs(obuf, fbuf, needed); + if(count == (size_t)-1 || count >= needed) + goto cleanup; + *out = obuf; + obuf = NULL; +#else + *out = fbuf; + fbuf = NULL; +#endif + +cleanup: + (free)(fbuf); +#ifndef _UNICODE + (free)(ibuf); + (free)(obuf); +#endif + return *out ? true : false; +} + +int curlx_win32_open(const char *filename, int oflag, ...) +{ + int pmode = 0; + int result = -1; + TCHAR *fixed = NULL; + const TCHAR *target = NULL; + +#ifdef _UNICODE + wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); +#endif + + va_list param; + va_start(param, oflag); + if(oflag & O_CREAT) + pmode = va_arg(param, int); + va_end(param); + +#ifdef _UNICODE + if(filename_w) { + if(fix_excessive_path(filename_w, &fixed)) + target = fixed; + else + target = filename_w; + result = _wopen(target, oflag, pmode); + curlx_unicodefree(filename_w); + } + else + /* !checksrc! disable ERRNOVAR 1 */ + CURL_SETERRNO(EINVAL); +#else + if(fix_excessive_path(filename, &fixed)) + target = fixed; + else + target = filename; + result = _open(target, oflag, pmode); +#endif + + (free)(fixed); + return result; +} + +FILE *curlx_win32_fopen(const char *filename, const char *mode) +{ + FILE *result = NULL; + TCHAR *fixed = NULL; + const TCHAR *target = NULL; + +#ifdef _UNICODE + wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); + wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode); + if(filename_w && mode_w) { + if(fix_excessive_path(filename_w, &fixed)) + target = fixed; + else + target = filename_w; + result = _wfopen(target, mode_w); + } + else + /* !checksrc! disable ERRNOVAR 1 */ + CURL_SETERRNO(EINVAL); + curlx_unicodefree(filename_w); + curlx_unicodefree(mode_w); +#else + if(fix_excessive_path(filename, &fixed)) + target = fixed; + else + target = filename; + /* !checksrc! disable BANNEDFUNC 1 */ + result = fopen(target, mode); +#endif + + (free)(fixed); + return result; +} + +int curlx_win32_stat(const char *path, struct_stat *buffer) +{ + int result = -1; + TCHAR *fixed = NULL; + const TCHAR *target = NULL; + +#ifdef _UNICODE + wchar_t *path_w = curlx_convert_UTF8_to_wchar(path); + if(path_w) { + if(fix_excessive_path(path_w, &fixed)) + target = fixed; + else + target = path_w; +#ifndef USE_WIN32_LARGE_FILES + result = _wstat(target, buffer); +#else + result = _wstati64(target, buffer); +#endif + curlx_unicodefree(path_w); + } + else + /* !checksrc! disable ERRNOVAR 1 */ + CURL_SETERRNO(EINVAL); +#else + if(fix_excessive_path(path, &fixed)) + target = fixed; + else + target = path; +#ifndef USE_WIN32_LARGE_FILES + result = _stat(target, buffer); +#else + result = _stati64(target, buffer); +#endif +#endif + + (free)(fixed); + return result; +} + +#endif /* _WIN32 && !UNDER_CE */ diff --git a/lib/curlx/fopen.h b/lib/curlx/fopen.h new file mode 100644 index 000000000000..2a2b07963789 --- /dev/null +++ b/lib/curlx/fopen.h @@ -0,0 +1,48 @@ +#ifndef HEADER_CURLX_FOPEN_H +#define HEADER_CURLX_FOPEN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "../curl_setup.h" + +#include "multibyte.h" + +#if defined(_WIN32) && !defined(UNDER_CE) +FILE *curlx_win32_fopen(const char *filename, const char *mode); +#define CURLX_FOPEN_LOW(fname, mode) curlx_win32_fopen(fname, mode) +#else +#define CURLX_FOPEN_LOW fopen +#endif + +#ifdef CURLDEBUG +#define curlx_fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) +#define curlx_fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__) +#define curlx_fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__) +#else +#define curlx_fopen CURLX_FOPEN_LOW +#define curlx_fdopen fdopen +#define curlx_fclose fclose +#endif + +#endif /* HEADER_CURLX_FOPEN_H */ diff --git a/lib/curlx/multibyte.c b/lib/curlx/multibyte.c index 1c81a71ec5b4..9e60edf7e3e2 100644 --- a/lib/curlx/multibyte.c +++ b/lib/curlx/multibyte.c @@ -84,277 +84,4 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w) return str_utf8; } -#ifndef UNDER_CE - -/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */ -#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \ - (_WIN32_WINNT < _WIN32_WINNT_WIN10) -WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *); -#endif - -/* Fix excessive paths (paths that exceed MAX_PATH length of 260). - * - * This is a helper function to fix paths that would exceed the MAX_PATH - * limitation check done by Windows APIs. It does so by normalizing the passed - * in filename or path 'in' to its full canonical path, and if that path is - * longer than MAX_PATH then setting 'out' to "\\?\" prefix + that full path. - * - * For example 'in' filename255chars in current directory C:\foo\bar is - * fixed as \\?\C:\foo\bar\filename255chars for 'out' which will tell Windows - * it is ok to access that filename even though the actual full path is longer - * than 260 chars. - * - * For non-Unicode builds this function may fail sometimes because only the - * Unicode versions of some Windows API functions can access paths longer than - * MAX_PATH, for example GetFullPathNameW which is used in this function. When - * the full path is then converted from Unicode to multibyte that fails if any - * directories in the path contain characters not in the current codepage. - */ -static bool fix_excessive_path(const TCHAR *in, TCHAR **out) -{ - size_t needed, count; - const wchar_t *in_w; - wchar_t *fbuf = NULL; - - /* MS documented "approximate" limit for the maximum path length */ - const size_t max_path_len = 32767; - -#ifndef _UNICODE - wchar_t *ibuf = NULL; - char *obuf = NULL; -#endif - - *out = NULL; - - /* skip paths already normalized */ - if(!_tcsncmp(in, _T("\\\\?\\"), 4)) - goto cleanup; - -#ifndef _UNICODE - /* convert multibyte input to unicode */ - needed = mbstowcs(NULL, in, 0); - if(needed == (size_t)-1 || needed >= max_path_len) - goto cleanup; - ++needed; /* for NUL */ - ibuf = (malloc)(needed * sizeof(wchar_t)); - if(!ibuf) - goto cleanup; - count = mbstowcs(ibuf, in, needed); - if(count == (size_t)-1 || count >= needed) - goto cleanup; - in_w = ibuf; -#else - in_w = in; -#endif - - /* GetFullPathNameW returns the normalized full path in unicode. It converts - forward slashes to backslashes, processes .. to remove directory segments, - etc. Unlike GetFullPathNameA it can process paths that exceed MAX_PATH. */ - needed = (size_t)GetFullPathNameW(in_w, 0, NULL, NULL); - if(!needed || needed > max_path_len) - goto cleanup; - /* skip paths that are not excessive and do not need modification */ - if(needed <= MAX_PATH) - goto cleanup; - fbuf = (malloc)(needed * sizeof(wchar_t)); - if(!fbuf) - goto cleanup; - count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL); - if(!count || count >= needed) - goto cleanup; - - /* prepend \\?\ or \\?\UNC\ to the excessively long path. - * - * c:\longpath ---> \\?\c:\longpath - * \\.\c:\longpath ---> \\?\c:\longpath - * \\?\c:\longpath ---> \\?\c:\longpath (unchanged) - * \\server\c$\longpath ---> \\?\UNC\server\c$\longpath - * - * https://learn.microsoft.com/dotnet/standard/io/file-path-formats - */ - if(!wcsncmp(fbuf, L"\\\\?\\", 4)) - ; /* do nothing */ - else if(!wcsncmp(fbuf, L"\\\\.\\", 4)) - fbuf[2] = '?'; - else if(!wcsncmp(fbuf, L"\\\\.", 3) || !wcsncmp(fbuf, L"\\\\?", 3)) { - /* Unexpected, not UNC. The formatting doc doesn't allow this AFAICT. */ - goto cleanup; - } - else { - wchar_t *temp; - - if(!wcsncmp(fbuf, L"\\\\", 2)) { - /* "\\?\UNC\" + full path without "\\" + null */ - needed = 8 + (count - 2) + 1; - if(needed > max_path_len) - goto cleanup; - - temp = (malloc)(needed * sizeof(wchar_t)); - if(!temp) - goto cleanup; - - wcsncpy(temp, L"\\\\?\\UNC\\", 8); - wcscpy(temp + 8, fbuf + 2); - } - else { - /* "\\?\" + full path + null */ - needed = 4 + count + 1; - if(needed > max_path_len) - goto cleanup; - - temp = (malloc)(needed * sizeof(wchar_t)); - if(!temp) - goto cleanup; - - wcsncpy(temp, L"\\\\?\\", 4); - wcscpy(temp + 4, fbuf); - } - - (free)(fbuf); - fbuf = temp; - } - -#ifndef _UNICODE - /* convert unicode full path to multibyte output */ - needed = wcstombs(NULL, fbuf, 0); - if(needed == (size_t)-1 || needed >= max_path_len) - goto cleanup; - ++needed; /* for NUL */ - obuf = (malloc)(needed); - if(!obuf) - goto cleanup; - count = wcstombs(obuf, fbuf, needed); - if(count == (size_t)-1 || count >= needed) - goto cleanup; - *out = obuf; - obuf = NULL; -#else - *out = fbuf; - fbuf = NULL; -#endif - -cleanup: - (free)(fbuf); -#ifndef _UNICODE - (free)(ibuf); - (free)(obuf); -#endif - return *out ? true : false; -} - -int curlx_win32_open(const char *filename, int oflag, ...) -{ - int pmode = 0; - int result = -1; - TCHAR *fixed = NULL; - const TCHAR *target = NULL; - -#ifdef _UNICODE - wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); -#endif - - va_list param; - va_start(param, oflag); - if(oflag & O_CREAT) - pmode = va_arg(param, int); - va_end(param); - -#ifdef _UNICODE - if(filename_w) { - if(fix_excessive_path(filename_w, &fixed)) - target = fixed; - else - target = filename_w; - result = _wopen(target, oflag, pmode); - curlx_unicodefree(filename_w); - } - else - /* !checksrc! disable ERRNOVAR 1 */ - CURL_SETERRNO(EINVAL); -#else - if(fix_excessive_path(filename, &fixed)) - target = fixed; - else - target = filename; - result = _open(target, oflag, pmode); -#endif - - (free)(fixed); - return result; -} - -FILE *curlx_win32_fopen(const char *filename, const char *mode) -{ - FILE *result = NULL; - TCHAR *fixed = NULL; - const TCHAR *target = NULL; - -#ifdef _UNICODE - wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename); - wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode); - if(filename_w && mode_w) { - if(fix_excessive_path(filename_w, &fixed)) - target = fixed; - else - target = filename_w; - result = _wfopen(target, mode_w); - } - else - /* !checksrc! disable ERRNOVAR 1 */ - CURL_SETERRNO(EINVAL); - curlx_unicodefree(filename_w); - curlx_unicodefree(mode_w); -#else - if(fix_excessive_path(filename, &fixed)) - target = fixed; - else - target = filename; - result = (fopen)(target, mode); -#endif - - (free)(fixed); - return result; -} - -int curlx_win32_stat(const char *path, struct_stat *buffer) -{ - int result = -1; - TCHAR *fixed = NULL; - const TCHAR *target = NULL; - -#ifdef _UNICODE - wchar_t *path_w = curlx_convert_UTF8_to_wchar(path); - if(path_w) { - if(fix_excessive_path(path_w, &fixed)) - target = fixed; - else - target = path_w; -#ifndef USE_WIN32_LARGE_FILES - result = _wstat(target, buffer); -#else - result = _wstati64(target, buffer); -#endif - curlx_unicodefree(path_w); - } - else - /* !checksrc! disable ERRNOVAR 1 */ - CURL_SETERRNO(EINVAL); -#else - if(fix_excessive_path(path, &fixed)) - target = fixed; - else - target = path; -#ifndef USE_WIN32_LARGE_FILES - result = _stat(target, buffer); -#else - result = _stati64(target, buffer); -#endif -#endif - - (free)(fixed); - return result; -} - -#endif /* UNDER_CE */ - #endif /* _WIN32 */ diff --git a/lib/hsts.c b/lib/hsts.c index 9525158bcc7c..b84a470f90dc 100644 --- a/lib/hsts.c +++ b/lib/hsts.c @@ -32,10 +32,10 @@ #include "urldata.h" #include "llist.h" #include "hsts.h" +#include "curl_fopen.h" #include "curl_get_line.h" #include "sendf.h" #include "parsedate.h" -#include "fopen.h" #include "rename.h" #include "share.h" #include "strdup.h" @@ -379,7 +379,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, if(result) break; } - fclose(out); + curlx_fclose(out); if(!result && tempstore && Curl_rename(tempstore, file)) result = CURLE_WRITE_ERROR; @@ -524,7 +524,7 @@ static CURLcode hsts_load(struct hsts *h, const char *file) if(!h->filename) return CURLE_OUT_OF_MEMORY; - fp = fopen(file, FOPEN_READTEXT); + fp = curlx_fopen(file, FOPEN_READTEXT); if(fp) { struct dynbuf buf; curlx_dyn_init(&buf, MAX_HSTS_LINE); @@ -542,7 +542,7 @@ static CURLcode hsts_load(struct hsts *h, const char *file) hsts_add(h, lineptr); } curlx_dyn_free(&buf); /* free the line buffer */ - fclose(fp); + curlx_fclose(fp); } return result; } diff --git a/lib/memdebug.c b/lib/memdebug.c index cffd4b2cf61b..0c9d15671583 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -29,6 +29,7 @@ #include #include "urldata.h" +#include "curlx/fopen.h" /* for CURLX_FOPEN_LOW() */ /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -68,7 +69,8 @@ static void curl_dbg_cleanup(void) if(curl_dbg_logfile && curl_dbg_logfile != stderr && curl_dbg_logfile != stdout) { - (fclose)(curl_dbg_logfile); + /* !checksrc! disable BANNEDFUNC 1 */ + fclose(curl_dbg_logfile); } curl_dbg_logfile = NULL; } @@ -78,11 +80,7 @@ void curl_dbg_memdebug(const char *logname) { if(!curl_dbg_logfile) { if(logname && *logname) -#ifdef CURL_FOPEN - curl_dbg_logfile = CURL_FOPEN(logname, FOPEN_WRITETEXT); -#else - curl_dbg_logfile = (fopen)(logname, FOPEN_WRITETEXT); -#endif + curl_dbg_logfile = CURLX_FOPEN_LOW(logname, FOPEN_WRITETEXT); else curl_dbg_logfile = stderr; #ifdef MEMDEBUG_LOG_SYNC @@ -424,13 +422,7 @@ ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode, int line, const char *source) { - FILE *res; -#ifdef CURL_FOPEN - res = CURL_FOPEN(file, mode); -#else - res = (fopen)(file, mode); -#endif - + FILE *res = CURLX_FOPEN_LOW(file, mode); if(source) curl_dbg_log("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", source, line, file, mode, (void *)res); @@ -442,7 +434,8 @@ ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode, int line, const char *source) { - FILE *res = (fdopen)(filedes, mode); + /* !checksrc! disable BANNEDFUNC 1 */ + FILE *res = fdopen(filedes, mode); if(source) curl_dbg_log("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n", source, line, filedes, mode, (void *)res); @@ -459,7 +452,8 @@ int curl_dbg_fclose(FILE *file, int line, const char *source) curl_dbg_log("FILE %s:%d fclose(%p)\n", source, line, (void *)file); - res = (fclose)(file); + /* !checksrc! disable BANNEDFUNC 1 */ + res = fclose(file); return res; } diff --git a/lib/memdebug.h b/lib/memdebug.h index 96ceb61759e5..c2b7fad9528b 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -52,12 +52,5 @@ #endif #endif /* _WIN32 */ -#undef fopen -#define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) -#undef fdopen -#define fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__) -#undef fclose -#define fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__) - #endif /* CURLDEBUG */ #endif /* HEADER_CURL_MEMDEBUG_H */ diff --git a/lib/mime.c b/lib/mime.c index 894413be17f2..6ec7f6904671 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -34,6 +34,7 @@ struct Curl_easy; #include "sendf.h" #include "transfer.h" #include "strdup.h" +#include "curlx/fopen.h" #include "curlx/base64.h" #if !defined(CURL_DISABLE_MIME) && \ @@ -131,7 +132,7 @@ static const char aschex[] = #ifndef __VMS #define filesize(name, stat_data) (stat_data.st_size) -#define fopen_read fopen +#define fopen_read curlx_fopen #else @@ -154,7 +155,7 @@ curl_off_t VmsRealFileSize(const char *name, int ret_stat; FILE * file; - file = fopen(name, FOPEN_READTEXT); /* VMS */ + file = curlx_fopen(name, FOPEN_READTEXT); /* VMS */ if(!file) return 0; @@ -165,7 +166,7 @@ curl_off_t VmsRealFileSize(const char *name, if(ret_stat) count += ret_stat; } - fclose(file); + curlx_fclose(file); return count; } @@ -210,10 +211,10 @@ static FILE * vmsfopenread(const char *file, const char *mode) case FAB$C_VAR: case FAB$C_VFC: case FAB$C_STMCR: - return fopen(file, FOPEN_READTEXT); /* VMS */ + return curlx_fopen(file, FOPEN_READTEXT); /* VMS */ break; default: - return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); + return curlx_fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); } } @@ -745,7 +746,7 @@ static void mime_file_free(void *ptr) curl_mimepart *part = (curl_mimepart *) ptr; if(part->fp) { - fclose(part->fp); + curlx_fclose(part->fp); part->fp = NULL; } Curl_safefree(part->data); @@ -967,7 +968,7 @@ static size_t readback_part(curl_mimepart *part, mimesetstate(&part->state, MIMESTATE_END, NULL); /* Try sparing open file descriptors. */ if(part->kind == MIMEKIND_FILE && part->fp) { - fclose(part->fp); + curlx_fclose(part->fp); part->fp = NULL; } FALLTHROUGH(); diff --git a/lib/netrc.c b/lib/netrc.c index 447ee095852d..a227ffefcd95 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -39,6 +39,7 @@ #include "netrc.h" #include "strcase.h" #include "curl_get_line.h" +#include "curlx/fopen.h" #include "curlx/strparse.h" /* The last 3 #include files should be in this order */ @@ -76,7 +77,7 @@ enum found_state { static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf) { NETRCcode ret = NETRC_FILE_MISSING; /* if it cannot open the file */ - FILE *file = fopen(filename, FOPEN_READTEXT); + FILE *file = curlx_fopen(filename, FOPEN_READTEXT); struct dynbuf linebuf; curlx_dyn_init(&linebuf, MAX_NETRC_LINE); @@ -99,7 +100,7 @@ static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf) done: curlx_dyn_free(&linebuf); if(file) - fclose(file); + curlx_fclose(file); return ret; } diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index e9252ec2a1d5..2db73ca2d5d1 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -54,6 +54,7 @@ #include "../progress.h" #include "../select.h" #include "../strdup.h" +#include "../curlx/fopen.h" #include "../curlx/warnless.h" #include "x509asn1.h" #include "../multiif.h" @@ -211,7 +212,7 @@ static gnutls_datum_t load_file(const char *file) long filelen; void *ptr; - f = fopen(file, "rb"); + f = curlx_fopen(file, "rb"); if(!f) return loaded_file; if(fseek(f, 0, SEEK_END) != 0 @@ -227,7 +228,7 @@ static gnutls_datum_t load_file(const char *file) loaded_file.data = ptr; loaded_file.size = (unsigned int)filelen; out: - fclose(f); + curlx_fclose(f); return loaded_file; } diff --git a/lib/vtls/keylog.c b/lib/vtls/keylog.c index 2fd25089d97b..9179d38fe76f 100644 --- a/lib/vtls/keylog.c +++ b/lib/vtls/keylog.c @@ -33,6 +33,7 @@ #include "keylog.h" #include #include "../escape.h" +#include "../curlx/fopen.h" /* The last #include files should be: */ #include "../curl_memory.h" @@ -49,7 +50,7 @@ Curl_tls_keylog_open(void) if(!keylog_file_fp) { keylog_file_name = curl_getenv("SSLKEYLOGFILE"); if(keylog_file_name) { - keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); + keylog_file_fp = curlx_fopen(keylog_file_name, FOPEN_APPENDTEXT); if(keylog_file_fp) { #ifdef _WIN32 if(setvbuf(keylog_file_fp, NULL, _IONBF, 0)) @@ -57,7 +58,7 @@ Curl_tls_keylog_open(void) if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) #endif { - fclose(keylog_file_fp); + curlx_fclose(keylog_file_fp); keylog_file_fp = NULL; } } @@ -70,7 +71,7 @@ void Curl_tls_keylog_close(void) { if(keylog_file_fp) { - fclose(keylog_file_fp); + curlx_fclose(keylog_file_fp); keylog_file_fp = NULL; } } diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index a6d8a4652d88..70e109212d36 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -32,6 +32,7 @@ #include +#include "../curlx/fopen.h" #include "../curlx/inet_pton.h" #include "../urldata.h" #include "../sendf.h" @@ -397,7 +398,7 @@ static int read_file_into(const char *filename, struct dynbuf *out) { - FILE *f = fopen(filename, FOPEN_READTEXT); + FILE *f = curlx_fopen(filename, FOPEN_READTEXT); if(!f) { return 0; } @@ -407,14 +408,14 @@ read_file_into(const char *filename, const size_t rr = fread(buf, 1, sizeof(buf), f); if(rr == 0 || CURLE_OK != curlx_dyn_addn(out, buf, rr)) { - fclose(f); + curlx_fclose(f); return 0; } if(rr < sizeof(buf)) break; } - return fclose(f) == 0; + return curlx_fclose(f) == 0; } static void diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 8ff8029e3b3e..bf68321afe96 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -47,6 +47,7 @@ #include "../strdup.h" #include "../strerror.h" #include "../select.h" /* for the socket readiness */ +#include "../curlx/fopen.h" #include "../curlx/inet_pton.h" /* for IP addr SNI check */ #include "../curlx/multibyte.h" #include "../curlx/warnless.h" @@ -563,7 +564,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, &cert_store_path, &cert_thumbprint_str); if(result && (data->set.ssl.primary.clientcert[0]!='\0')) - fInCert = fopen(data->set.ssl.primary.clientcert, "rb"); + fInCert = curlx_fopen(data->set.ssl.primary.clientcert, "rb"); if(result && !fInCert) { failf(data, "schannel: Failed to get certificate location" @@ -611,7 +612,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, if((!certdata) || ((int) fread(certdata, certsize, 1, fInCert) != 1)) continue_reading = FALSE; - fclose(fInCert); + curlx_fclose(fInCert); if(!continue_reading) { failf(data, "schannel: Failed to read cert file %s", data->set.ssl.primary.clientcert); diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 9872e4c24d42..9e3870e47005 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -68,6 +68,7 @@ #include "../progress.h" #include "../share.h" #include "../multiif.h" +#include "../curlx/fopen.h" #include "../curlx/timeval.h" #include "../curl_md5.h" #include "../curl_sha256.h" @@ -803,7 +804,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, struct dynbuf buf; char unsigned *pem_ptr = NULL; size_t left; - FILE *fp = fopen(pinnedpubkey, "rb"); + FILE *fp = curlx_fopen(pinnedpubkey, "rb"); if(!fp) return result; @@ -865,7 +866,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, end: curlx_dyn_free(&buf); Curl_safefree(pem_ptr); - fclose(fp); + curlx_fclose(fp); } return result; diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 0012ccdae1ad..b737961899f1 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -88,6 +88,9 @@ "send" => 1, "socket" => 1, "socketpair" => 1, + "fclose" => 1, + "fdopen" => 1, + "fopen" => 1, ); my %warnings_extended = ( @@ -919,8 +922,8 @@ sub scanfile { } # scan for use of non-binary fopen without the macro - if($l =~ /^(.*\W)fopen\s*\([^,]*, *\"([^"]*)/) { - my $mode = $2; + if($l =~ /^(.*\W)(curlx_fopen|CURLX_FOPEN_LOW)\s*\([^,]*, *\"([^"]*)/) { + my $mode = $3; if($mode !~ /b/) { checkwarn("FOPENMODE", $line, length($1), $file, $ol, diff --git a/src/Makefile.inc b/src/Makefile.inc index 1086c07febb1..35f8e6fdee84 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -36,6 +36,7 @@ CURLX_CFILES = \ ../lib/curlx/base64.c \ ../lib/curlx/multibyte.c \ ../lib/curlx/dynbuf.c \ + ../lib/curlx/fopen.c \ ../lib/curlx/nonblock.c \ ../lib/curlx/strparse.c \ ../lib/curlx/timediff.c \ @@ -49,6 +50,7 @@ CURLX_HFILES = \ ../lib/curlx/multibyte.h \ ../lib/curl_setup.h \ ../lib/curlx/dynbuf.h \ + ../lib/curlx/fopen.h \ ../lib/curlx/nonblock.h \ ../lib/curlx/strparse.h \ ../lib/curlx/timediff.h \ diff --git a/src/tool_cb_dbg.c b/src/tool_cb_dbg.c index 6a587cc1cc63..b454f5ca9bad 100644 --- a/src/tool_cb_dbg.c +++ b/src/tool_cb_dbg.c @@ -124,7 +124,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type, /* Ok, this is somewhat hackish but we do it undocumented for now */ global->trace_stream = tool_stderr; else { - global->trace_stream = fopen(global->trace_dump, FOPEN_WRITETEXT); + global->trace_stream = curlx_fopen(global->trace_dump, FOPEN_WRITETEXT); global->trace_fopened = TRUE; } } diff --git a/src/tool_cb_wrt.c b/src/tool_cb_wrt.c index 6fbf80753de3..b4ea781739a7 100644 --- a/src/tool_cb_wrt.c +++ b/src/tool_cb_wrt.c @@ -55,7 +55,7 @@ bool tool_create_output_file(struct OutStruct *outs, (config->file_clobber_mode == CLOBBER_DEFAULT && !outs->is_cd_filename)) { /* open file for writing */ - file = fopen(fname, "wb"); + file = curlx_fopen(fname, "wb"); } else { int fd; @@ -92,7 +92,7 @@ bool tool_create_output_file(struct OutStruct *outs, is not needed because we would have failed earlier, in the while loop and `fd` would now be -1 */ if(fd != -1) { - file = fdopen(fd, "wb"); + file = curlx_fdopen(fd, "wb"); if(!file) close(fd); } diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index 675f4d2d9da9..e2df7cf91f02 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -258,7 +258,7 @@ static void free_globalconfig(void) tool_safefree(global->trace_dump); if(global->trace_fopened && global->trace_stream) - fclose(global->trace_stream); + curlx_fclose(global->trace_stream); global->trace_stream = NULL; tool_safefree(global->libcurl); diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c index 223c66bdf503..bff251e6b03e 100644 --- a/src/tool_easysrc.c +++ b/src/tool_easysrc.c @@ -178,7 +178,7 @@ void dumpeasysrc(void) FILE *out; bool fopened = FALSE; if(strcmp(o, "-")) { - out = fopen(o, FOPEN_WRITETEXT); + out = curlx_fopen(o, FOPEN_WRITETEXT); fopened = TRUE; } else @@ -227,7 +227,7 @@ void dumpeasysrc(void) fprintf(out, "%s\n", c); if(fopened) - fclose(out); + curlx_fclose(out); } easysrc_free(); diff --git a/src/tool_formparse.c b/src/tool_formparse.c index b5ab10a00f80..f1f2f5b7e5c6 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -563,14 +563,14 @@ static int get_param_part(char endchar, endpos--; sep = *p; *endpos = '\0'; - fp = fopen(hdrfile, FOPEN_READTEXT); + fp = curlx_fopen(hdrfile, FOPEN_READTEXT); if(!fp) warnf("Cannot read from %s: %s", hdrfile, strerror(errno)); else { int i = read_field_headers(hdrfile, fp, &headers); - fclose(fp); + curlx_fclose(fp); if(i) { curl_slist_free_all(headers); return -1; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index d7bdadb5d6d3..eed87bb807d7 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -627,7 +627,7 @@ static ParameterError data_urlencode(const char *nextarg, CURLX_SET_BINMODE(stdin); } else { - file = fopen(p, "rb"); + file = curlx_fopen(p, "rb"); if(!file) { errorf("Failed to open %s", p); return PARAM_READ_ERROR; @@ -637,7 +637,7 @@ static ParameterError data_urlencode(const char *nextarg, err = file2memory(&postdata, &size, file); if(file && (file != stdin)) - fclose(file); + curlx_fclose(file); if(err) return err; } @@ -899,7 +899,7 @@ static ParameterError set_data(cmdline_t cmd, CURLX_SET_BINMODE(stdin); } else { - file = fopen(nextarg, "rb"); + file = curlx_fopen(nextarg, "rb"); if(!file) { errorf("Failed to open %s", nextarg); return PARAM_READ_ERROR; @@ -917,7 +917,7 @@ static ParameterError set_data(cmdline_t cmd, } if(file && (file != stdin)) - fclose(file); + curlx_fclose(file); if(err) return err; @@ -1094,7 +1094,7 @@ static ParameterError parse_url(struct OperationConfig *config, if(fromstdin) f = stdin; else - f = fopen(&nextarg[1], FOPEN_READTEXT); + f = curlx_fopen(&nextarg[1], FOPEN_READTEXT); if(f) { curlx_dyn_init(&line, 8092); while(my_get_line(f, &line, &error)) { @@ -1104,7 +1104,7 @@ static ParameterError parse_url(struct OperationConfig *config, break; } if(!fromstdin) - fclose(f); + curlx_fclose(f); curlx_dyn_free(&line); if(error || err) return PARAM_READ_ERROR; @@ -1206,7 +1206,7 @@ static ParameterError parse_ech(struct OperationConfig *config, file = stdin; } else { - file = fopen(nextarg, FOPEN_READTEXT); + file = curlx_fopen(nextarg, FOPEN_READTEXT); } if(!file) { warnf("Couldn't read file \"%s\" " @@ -1216,7 +1216,7 @@ static ParameterError parse_ech(struct OperationConfig *config, } err = file2string(&tmpcfg, file); if(file != stdin) - fclose(file); + curlx_fclose(file); if(err) return err; config->ech_config = aprintf("ecl:%s",tmpcfg); @@ -1242,7 +1242,7 @@ static ParameterError parse_header(struct OperationConfig *config, if(nextarg[0] == '@') { /* read many headers from a file or stdin */ bool use_stdin = !strcmp(&nextarg[1], "-"); - FILE *file = use_stdin ? stdin : fopen(&nextarg[1], FOPEN_READTEXT); + FILE *file = use_stdin ? stdin : curlx_fopen(&nextarg[1], FOPEN_READTEXT); if(!file) { errorf("Failed to open %s", &nextarg[1]); err = PARAM_READ_ERROR; @@ -1263,7 +1263,7 @@ static ParameterError parse_header(struct OperationConfig *config, err = PARAM_READ_ERROR; curlx_dyn_free(&line); if(!use_stdin) - fclose(file); + curlx_fclose(file); } } else { @@ -1536,7 +1536,7 @@ static ParameterError parse_writeout(struct OperationConfig *config, } else { fname = nextarg; - file = fopen(fname, FOPEN_READTEXT); + file = curlx_fopen(fname, FOPEN_READTEXT); if(!file) { errorf("Failed to open %s", fname); return PARAM_READ_ERROR; @@ -1545,7 +1545,7 @@ static ParameterError parse_writeout(struct OperationConfig *config, tool_safefree(config->writeout); err = file2string(&config->writeout, file); if(file && (file != stdin)) - fclose(file); + curlx_fclose(file); if(err) return err; if(!config->writeout) diff --git a/src/tool_ipfs.c b/src/tool_ipfs.c index dd030f09bc92..c2f1b165239c 100644 --- a/src/tool_ipfs.c +++ b/src/tool_ipfs.c @@ -88,7 +88,7 @@ static char *ipfs_gateway(void) if(!gateway_composed_file_path) goto fail; - gateway_file = fopen(gateway_composed_file_path, FOPEN_READTEXT); + gateway_file = curlx_fopen(gateway_composed_file_path, FOPEN_READTEXT); tool_safefree(gateway_composed_file_path); if(gateway_file) { @@ -103,7 +103,7 @@ static char *ipfs_gateway(void) goto fail; } - fclose(gateway_file); + curlx_fclose(gateway_file); gateway_file = NULL; if(curlx_dyn_len(&dyn)) @@ -121,7 +121,7 @@ static char *ipfs_gateway(void) } fail: if(gateway_file) - fclose(gateway_file); + curlx_fclose(gateway_file); tool_safefree(gateway); tool_safefree(ipfs_path); return NULL; diff --git a/src/tool_operate.c b/src/tool_operate.c index 14eff06e0630..d5a1b2646812 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -164,7 +164,7 @@ static curl_off_t vms_realfilesize(const char *name, FILE * file; /* !checksrc! disable FOPENMODE 1 */ - file = fopen(name, "r"); /* VMS */ + file = curlx_fopen(name, "r"); /* VMS */ if(!file) { return 0; } @@ -175,7 +175,7 @@ static curl_off_t vms_realfilesize(const char *name, if(ret_stat) count += ret_stat; } - fclose(file); + curlx_fclose(file); return count; } @@ -660,7 +660,7 @@ static CURLcode post_per_transfer(struct per_transfer *per, /* Close the outs file */ if(outs->fopened && outs->stream) { - rc = fclose(outs->stream); + rc = curlx_fclose(outs->stream); if(!result && rc) { /* something went wrong in the writing process */ result = CURLE_WRITE_ERROR; @@ -696,13 +696,13 @@ static CURLcode post_per_transfer(struct per_transfer *per, /* Close function-local opened file descriptors */ if(per->heads.fopened && per->heads.stream) - fclose(per->heads.stream); + curlx_fclose(per->heads.stream); if(per->heads.alloc_filename) tool_safefree(per->heads.filename); if(per->etag_save.fopened && per->etag_save.stream) - fclose(per->etag_save.stream); + curlx_fclose(per->etag_save.stream); if(per->etag_save.alloc_filename) tool_safefree(per->etag_save.filename); @@ -800,7 +800,7 @@ static CURLcode etag_compare(struct OperationConfig *config) ParameterError pe; /* open file for reading: */ - FILE *file = fopen(config->etag_compare_file, FOPEN_READTEXT); + FILE *file = curlx_fopen(config->etag_compare_file, FOPEN_READTEXT); if(!file) warnf("Failed to open %s: %s", config->etag_compare_file, strerror(errno)); @@ -815,7 +815,7 @@ static CURLcode etag_compare(struct OperationConfig *config) if(!header) { if(file) - fclose(file); + curlx_fclose(file); errorf("Failed to allocate memory for custom etag header"); return CURLE_OUT_OF_MEMORY; } @@ -825,7 +825,7 @@ static CURLcode etag_compare(struct OperationConfig *config) tool_safefree(header); if(file) - fclose(file); + curlx_fclose(file); if(pe != PARAM_OK) result = CURLE_OUT_OF_MEMORY; return result; @@ -843,7 +843,7 @@ static CURLcode etag_store(struct OperationConfig *config, /* open file for output: */ if(strcmp(config->etag_save_file, "-")) { - FILE *newfile = fopen(config->etag_save_file, "ab"); + FILE *newfile = curlx_fopen(config->etag_save_file, "ab"); if(!newfile) { warnf("Failed creating file for saving etags: \"%s\". " "Skip this transfer", config->etag_save_file); @@ -893,11 +893,11 @@ static CURLcode setup_headerfile(struct OperationConfig *config, return result; } if(!per->prev || per->prev->config != config) { - newfile = fopen(config->headerfile, "wb"); + newfile = curlx_fopen(config->headerfile, "wb"); if(newfile) - fclose(newfile); + curlx_fclose(newfile); } - newfile = fopen(config->headerfile, "ab"); + newfile = curlx_fopen(config->headerfile, "ab"); if(!newfile) { errorf("Failed to open %s", config->headerfile); @@ -999,11 +999,11 @@ static CURLcode setup_outfile(struct OperationConfig *config, #ifdef __VMS /* open file for output, forcing VMS output format into stream mode which is needed for stat() call above to always work. */ - FILE *file = fopen(outfile, "ab", - "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0"); + FILE *file = curlx_fopen(outfile, "ab", + "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0"); #else /* open file for output: */ - FILE *file = fopen(per->outfile, "ab"); + FILE *file = curlx_fopen(per->outfile, "ab"); #endif if(!file) { errorf("cannot open '%s'", per->outfile); @@ -1193,7 +1193,7 @@ static CURLcode single_transfer(struct OperationConfig *config, if(result) { curl_easy_cleanup(curl); if(etag_first.fopened) - fclose(etag_first.stream); + curlx_fclose(etag_first.stream); return result; } per->etag_save = etag_first; /* copy the whole struct */ @@ -2004,7 +2004,7 @@ static CURLcode cacertpaths(struct OperationConfig *config) char *cacert = NULL; FILE *cafile = tool_execpath("curl-ca-bundle.crt", &cacert); if(cafile) { - fclose(cafile); + curlx_fclose(cafile); config->cacert = strdup(cacert); } #elif !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) && \ diff --git a/src/tool_parsecfg.c b/src/tool_parsecfg.c index bc22b9d5b7b5..632286530a12 100644 --- a/src/tool_parsecfg.c +++ b/src/tool_parsecfg.c @@ -93,7 +93,7 @@ int parseconfig(const char *filename) /* NULL means load .curlrc from homedir! */ char *curlrc = findfile(".curlrc", CURLRC_DOTSCORE); if(curlrc) { - file = fopen(curlrc, FOPEN_READTEXT); + file = curlx_fopen(curlrc, FOPEN_READTEXT); if(!file) { free(curlrc); return 1; @@ -115,7 +115,7 @@ int parseconfig(const char *filename) } else { if(strcmp(filename, "-")) - file = fopen(filename, FOPEN_READTEXT); + file = curlx_fopen(filename, FOPEN_READTEXT); else file = stdin; } @@ -250,7 +250,7 @@ int parseconfig(const char *filename) curlx_dyn_free(&buf); curlx_dyn_free(&pbuf); if(file != stdin) - fclose(file); + curlx_fclose(file); if(fileerror) rc = 1; } diff --git a/src/tool_ssls.c b/src/tool_ssls.c index edf8d6095a99..6fb01804554d 100644 --- a/src/tool_ssls.c +++ b/src/tool_ssls.c @@ -66,7 +66,7 @@ CURLcode tool_ssls_load(struct OperationConfig *config, bool error = FALSE; curlx_dyn_init(&buf, MAX_SSLS_LINE); - fp = fopen(filename, FOPEN_READTEXT); + fp = curlx_fopen(filename, FOPEN_READTEXT); if(!fp) { /* ok if it does not exist */ notef("SSL session file does not exist (yet?): %s", filename); goto out; @@ -122,7 +122,7 @@ CURLcode tool_ssls_load(struct OperationConfig *config, if(easy) curl_easy_cleanup(easy); if(fp) - fclose(fp); + curlx_fclose(fp); curlx_dyn_free(&buf); curl_free(shmac); curl_free(sdata); @@ -190,7 +190,7 @@ CURLcode tool_ssls_save(struct OperationConfig *config, CURLcode r = CURLE_OK; ctx.exported = 0; - ctx.fp = fopen(filename, FOPEN_WRITETEXT); + ctx.fp = curlx_fopen(filename, FOPEN_WRITETEXT); if(!ctx.fp) { warnf("Warning: Failed to create SSL session file %s", filename); @@ -207,6 +207,6 @@ CURLcode tool_ssls_save(struct OperationConfig *config, if(easy) curl_easy_cleanup(easy); if(ctx.fp) - fclose(ctx.fp); + curlx_fclose(ctx.fp); return r; } diff --git a/src/tool_stderr.c b/src/tool_stderr.c index b023d6c80202..1116c3009255 100644 --- a/src/tool_stderr.c +++ b/src/tool_stderr.c @@ -50,12 +50,12 @@ void tool_set_stderr_file(const char *filename) /* precheck that filename is accessible to lessen the chance that the subsequent freopen will fail. */ - fp = fopen(filename, FOPEN_WRITETEXT); + fp = curlx_fopen(filename, FOPEN_WRITETEXT); if(!fp) { warnf("Warning: Failed to open %s", filename); return; } - fclose(fp); + curlx_fclose(fp); /* freopen the actual stderr (stdio.h stderr) instead of tool_stderr since the latter may be set to stdout. */ diff --git a/src/tool_util.c b/src/tool_util.c index e7ab704f120b..f8415d2a1739 100644 --- a/src/tool_util.c +++ b/src/tool_util.c @@ -127,7 +127,7 @@ FILE *tool_execpath(const char *filename, char **pathp) if(strlen(filename) < remaining - 1) { curl_msnprintf(lastdirchar, remaining, "%s%s", DIR_CHAR, filename); *pathp = filebuffer; - return fopen(filebuffer, FOPEN_READTEXT); + return curlx_fopen(filebuffer, FOPEN_READTEXT); } } } diff --git a/src/tool_writeout.c b/src/tool_writeout.c index cdde28c90950..eaeec152e419 100644 --- a/src/tool_writeout.c +++ b/src/tool_writeout.c @@ -772,13 +772,13 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, break; case VAR_STDOUT: if(fclose_stream) - fclose(stream); + curlx_fclose(stream); fclose_stream = FALSE; stream = stdout; break; case VAR_STDERR: if(fclose_stream) - fclose(stream); + curlx_fclose(stream); fclose_stream = FALSE; stream = tool_stderr; break; @@ -824,12 +824,12 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, FILE *stream2; memcpy(fname, ptr, flen); fname[flen] = 0; - stream2 = fopen(fname, append ? FOPEN_APPENDTEXT : - FOPEN_WRITETEXT); + stream2 = curlx_fopen(fname, append ? FOPEN_APPENDTEXT : + FOPEN_WRITETEXT); if(stream2) { /* only change if the open worked */ if(fclose_stream) - fclose(stream); + curlx_fclose(stream); stream = stream2; fclose_stream = TRUE; } @@ -872,6 +872,6 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, } } if(fclose_stream) - fclose(stream); + curlx_fclose(stream); curlx_dyn_free(&name); } diff --git a/src/var.c b/src/var.c index 612735016c95..d279fdeb6e7c 100644 --- a/src/var.c +++ b/src/var.c @@ -455,7 +455,7 @@ ParameterError setvariable(const char *input) if(use_stdin) file = stdin; else { - file = fopen(line, "rb"); + file = curlx_fopen(line, "rb"); if(!file) { errorf("Failed to open %s: %s", line, strerror(errno)); err = PARAM_READ_ERROR; @@ -469,7 +469,7 @@ ParameterError setvariable(const char *input) } curlx_dyn_free(&fname); if(!use_stdin && file) - fclose(file); + curlx_fclose(file); if(err) return err; } diff --git a/tests/data/test1185 b/tests/data/test1185 index 8b14f4c5ffcb..43a27f087054 100644 --- a/tests/data/test1185 +++ b/tests/data/test1185 @@ -47,7 +47,7 @@ func_return() ; a = sprintf(buffer, "%s", moo); -FILE *f = fopen("filename", "r"); +FILE *f = curlx_fopen("filename", "r"); void startfunc(int a, int b) { func(); @@ -124,7 +124,7 @@ void startfunc(int a, int b) { a = sprintf(buffer, "%s", moo); ^ ./%LOGDIR/code1185.c:32:11: warning: use of non-binary fopen without FOPEN_* macro: r (FOPENMODE) - FILE *f = fopen("filename", "r"); + FILE *f = curlx_fopen("filename", "r"); ^ ./%LOGDIR/code1185.c:34:30: warning: wrongly placed open brace (BRACEPOS) void startfunc(int a, int b) { diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index 00273f9e9d6a..c316a0526925 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -34,6 +34,7 @@ UTILS_C = memptr.c testutil.c testtrace.c UTILS_H = testutil.h testtrace.h unitcheck.h CURLX_C = \ + ../../lib/curlx/fopen.c \ ../../lib/curlx/warnless.c \ ../../lib/curlx/multibyte.c \ ../../lib/curlx/timediff.c \ diff --git a/tests/libtest/cli_h2_serverpush.c b/tests/libtest/cli_h2_serverpush.c index 7b465bc61ad0..a865fdfd8f5b 100644 --- a/tests/libtest/cli_h2_serverpush.c +++ b/tests/libtest/cli_h2_serverpush.c @@ -30,7 +30,7 @@ static FILE *out_download; static int setup_h2_serverpush(CURL *hnd, const char *url) { - out_download = fopen("download_0.data", "wb"); + out_download = curlx_fopen("download_0.data", "wb"); if(!out_download) return 1; /* failed */ @@ -72,7 +72,7 @@ static int server_push_callback(CURL *parent, curl_msnprintf(filename, sizeof(filename) - 1, "push%u", count++); /* here's a new stream, save it in a new file for each new push */ - out_push = fopen(filename, "wb"); + out_push = curlx_fopen(filename, "wb"); if(!out_push) { /* if we cannot save it, deny it */ curl_mfprintf(stderr, "Failed to create output file for push\n"); @@ -129,7 +129,7 @@ static CURLcode test_cli_h2_serverpush(const char *URL) easy = curl_easy_init(); if(setup_h2_serverpush(easy, URL)) { - fclose(out_download); + curlx_fclose(out_download); curl_mfprintf(stderr, "failed\n"); return (CURLcode)1; } @@ -166,9 +166,9 @@ static CURLcode test_cli_h2_serverpush(const char *URL) curl_multi_cleanup(multi_handle); - fclose(out_download); + curlx_fclose(out_download); if(out_push) - fclose(out_push); + curlx_fclose(out_push); return CURLE_OK; } diff --git a/tests/libtest/cli_hx_download.c b/tests/libtest/cli_hx_download.c index 6394c5e25b22..7a6a48c171b5 100644 --- a/tests/libtest/cli_hx_download.c +++ b/tests/libtest/cli_hx_download.c @@ -94,7 +94,7 @@ static size_t my_write_d_cb(char *buf, size_t nitems, size_t buflen, if(!t->out) { curl_msnprintf(t->filename, sizeof(t->filename)-1, "download_%zu.data", t->idx); - t->out = fopen(t->filename, "wb"); + t->out = curlx_fopen(t->filename, "wb"); if(!t->out) return 0; } @@ -530,7 +530,7 @@ static CURLcode test_cli_hx_download(const char *URL) for(i = 0; i < transfer_count_d; ++i) { t = &transfer_d[i]; if(t->out) { - fclose(t->out); + curlx_fclose(t->out); t->out = NULL; } if(t->easy) { diff --git a/tests/libtest/cli_hx_upload.c b/tests/libtest/cli_hx_upload.c index 9c69e36787f4..40e486c41a1a 100644 --- a/tests/libtest/cli_hx_upload.c +++ b/tests/libtest/cli_hx_upload.c @@ -74,7 +74,7 @@ static size_t my_write_u_cb(char *buf, size_t nitems, size_t buflen, if(!t->out) { curl_msnprintf(t->filename, sizeof(t->filename)-1, "download_%zu.data", t->idx); - t->out = fopen(t->filename, "wb"); + t->out = curlx_fopen(t->filename, "wb"); if(!t->out) return 0; } @@ -494,7 +494,7 @@ static CURLcode test_cli_hx_upload(const char *URL) for(i = 0; i < transfer_count_u; ++i) { t = &transfer_u[i]; if(t->out) { - fclose(t->out); + curlx_fclose(t->out); t->out = NULL; } if(t->easy) { diff --git a/tests/libtest/lib500.c b/tests/libtest/lib500.c index 7081ec625d28..ffb974f4f0cb 100644 --- a/tests/libtest/lib500.c +++ b/tests/libtest/lib500.c @@ -90,7 +90,7 @@ static CURLcode test_lib500(const char *URL) if(!res) { res = curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &ipstr); if(libtest_arg2) { - FILE *moo = fopen(libtest_arg2, "wb"); + FILE *moo = curlx_fopen(libtest_arg2, "wb"); if(moo) { curl_off_t time_namelookup; curl_off_t time_connect; @@ -163,7 +163,7 @@ static CURLcode test_lib500(const char *URL) (long)(time_total % 1000000)); } - fclose(moo); + curlx_fclose(moo); } } } diff --git a/tests/libtest/lib505.c b/tests/libtest/lib505.c index 2285208e9f37..fc200945847e 100644 --- a/tests/libtest/lib505.c +++ b/tests/libtest/lib505.c @@ -51,7 +51,7 @@ static CURLcode test_lib505(const char *URL) return TEST_ERR_USAGE; } - hd_src = fopen(libtest_arg2, "rb"); + hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen failed with error (%d) %s\n", errno, strerror(errno)); @@ -70,19 +70,19 @@ static CURLcode test_lib505(const char *URL) curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", errno, strerror(errno)); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } if(!file_info.st_size) { curl_mfprintf(stderr, "File %s has zero size!\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { curl_mfprintf(stderr, "curl_global_init() failed\n"); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } @@ -91,7 +91,7 @@ static CURLcode test_lib505(const char *URL) if(!curl) { curl_mfprintf(stderr, "curl_easy_init() failed\n"); curl_global_cleanup(); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } @@ -102,7 +102,7 @@ static CURLcode test_lib505(const char *URL) curl_mfprintf(stderr, "curl_slist_append() failed\n"); curl_easy_cleanup(curl); curl_global_cleanup(); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } headerlist = curl_slist_append(hl, buf_2); @@ -111,7 +111,7 @@ static CURLcode test_lib505(const char *URL) curl_slist_free_all(hl); curl_easy_cleanup(curl); curl_global_cleanup(); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } headerlist = hl; @@ -144,7 +144,7 @@ static CURLcode test_lib505(const char *URL) curl_slist_free_all(headerlist); /* close the local file */ - fclose(hd_src); + curlx_fclose(hd_src); curl_easy_cleanup(curl); curl_global_cleanup(); diff --git a/tests/libtest/lib518.c b/tests/libtest/lib518.c index 86eddec003e9..9cf3a42554ad 100644 --- a/tests/libtest/lib518.c +++ b/tests/libtest/lib518.c @@ -77,7 +77,7 @@ static int t518_fopen_works(void) fpa[i] = NULL; } for(i = 0; i < 3; i++) { - fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT); + fpa[i] = curlx_fopen(DEV_NULL, FOPEN_READTEXT); if(!fpa[i]) { t518_store_errmsg("fopen failed", errno); curl_mfprintf(stderr, "%s\n", t518_msgbuff); @@ -87,7 +87,7 @@ static int t518_fopen_works(void) } for(i = 0; i < 3; i++) { if(fpa[i]) - fclose(fpa[i]); + curlx_fclose(fpa[i]); } return ret; } diff --git a/tests/libtest/lib525.c b/tests/libtest/lib525.c index 6c7d6503667a..007889fdc722 100644 --- a/tests/libtest/lib525.c +++ b/tests/libtest/lib525.c @@ -42,7 +42,7 @@ static CURLcode test_lib525(const char *URL) return TEST_ERR_USAGE; } - hd_src = fopen(libtest_arg2, "rb"); + hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen failed with error (%d) %s\n", errno, strerror(errno)); @@ -61,13 +61,13 @@ static CURLcode test_lib525(const char *URL) curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", errno, strerror(errno)); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_FSTAT; } res_global_init(CURL_GLOBAL_ALL); if(res) { - fclose(hd_src); + curlx_fclose(hd_src); return res; } @@ -149,7 +149,7 @@ static CURLcode test_lib525(const char *URL) } /* close the local file */ - fclose(hd_src); + curlx_fclose(hd_src); return res; } diff --git a/tests/libtest/lib537.c b/tests/libtest/lib537.c index fa03c3b9833d..90de8a2d0c75 100644 --- a/tests/libtest/lib537.c +++ b/tests/libtest/lib537.c @@ -74,7 +74,7 @@ static int t537_fopen_works(void) fpa[i] = NULL; } for(i = 0; i < 3; i++) { - fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT); + fpa[i] = curlx_fopen(DEV_NULL, FOPEN_READTEXT); if(!fpa[i]) { t537_store_errmsg("fopen failed", errno); curl_mfprintf(stderr, "%s\n", t537_msgbuff); @@ -84,7 +84,7 @@ static int t537_fopen_works(void) } for(i = 0; i < 3; i++) { if(fpa[i]) - fclose(fpa[i]); + curlx_fclose(fpa[i]); } return ret; } diff --git a/tests/libtest/lib541.c b/tests/libtest/lib541.c index 9868474d01b3..3bb64f8ac4a4 100644 --- a/tests/libtest/lib541.c +++ b/tests/libtest/lib541.c @@ -42,7 +42,7 @@ static CURLcode test_lib541(const char *URL) return TEST_ERR_USAGE; } - hd_src = fopen(libtest_arg2, "rb"); + hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen failed with error (%d) %s\n", errno, strerror(errno)); @@ -61,19 +61,19 @@ static CURLcode test_lib541(const char *URL) curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", errno, strerror(errno)); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } if(!file_info.st_size) { curl_mfprintf(stderr, "File %s has zero size!\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { curl_mfprintf(stderr, "curl_global_init() failed\n"); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } @@ -82,7 +82,7 @@ static CURLcode test_lib541(const char *URL) if(!curl) { curl_mfprintf(stderr, "curl_easy_init() failed\n"); curl_global_cleanup(); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; } @@ -110,7 +110,7 @@ static CURLcode test_lib541(const char *URL) test_cleanup: /* close the local file */ - fclose(hd_src); + curlx_fclose(hd_src); curl_easy_cleanup(curl); curl_global_cleanup(); diff --git a/tests/libtest/lib566.c b/tests/libtest/lib566.c index 15221cd0ccd8..79f48f235b2c 100644 --- a/tests/libtest/lib566.c +++ b/tests/libtest/lib566.c @@ -54,10 +54,10 @@ static CURLcode test_lib566(const char *URL) res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length); - moo = fopen(libtest_arg2, "wb"); + moo = curlx_fopen(libtest_arg2, "wb"); if(moo) { curl_mfprintf(moo, "CL %.0f\n", content_length); - fclose(moo); + curlx_fclose(moo); } } diff --git a/tests/libtest/lib568.c b/tests/libtest/lib568.c index 8e34194ef5ed..83c6fd23941c 100644 --- a/tests/libtest/lib568.c +++ b/tests/libtest/lib568.c @@ -75,7 +75,7 @@ static CURLcode test_lib568(const char *URL) fstat(sdp, &file_info); close(sdp); - sdpf = fopen(libtest_arg2, "rb"); + sdpf = curlx_fopen(libtest_arg2, "rb"); if(!sdpf) { curl_mfprintf(stderr, "can't fopen %s\n", libtest_arg2); res = TEST_ERR_MAJOR_BAD; @@ -94,7 +94,7 @@ static CURLcode test_lib568(const char *URL) goto test_cleanup; test_setopt(curl, CURLOPT_UPLOAD, 0L); - fclose(sdpf); + curlx_fclose(sdpf); sdpf = NULL; /* Make sure we can do a normal request now */ @@ -159,7 +159,7 @@ static CURLcode test_lib568(const char *URL) test_cleanup: if(sdpf) - fclose(sdpf); + curlx_fclose(sdpf); curl_free(stream_uri); diff --git a/tests/libtest/lib569.c b/tests/libtest/lib569.c index 8f340b489d59..b1a80a7b0118 100644 --- a/tests/libtest/lib569.c +++ b/tests/libtest/lib569.c @@ -38,7 +38,7 @@ static CURLcode test_lib569(const char *URL) int request = 1; int i; - FILE *idfile = fopen(libtest_arg2, "wb"); + FILE *idfile = curlx_fopen(libtest_arg2, "wb"); if(!idfile) { curl_mfprintf(stderr, "couldn't open the Session ID File\n"); return TEST_ERR_MAJOR_BAD; @@ -46,7 +46,7 @@ static CURLcode test_lib569(const char *URL) if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { curl_mfprintf(stderr, "curl_global_init() failed\n"); - fclose(idfile); + curlx_fclose(idfile); return TEST_ERR_MAJOR_BAD; } @@ -54,7 +54,7 @@ static CURLcode test_lib569(const char *URL) if(!curl) { curl_mfprintf(stderr, "curl_easy_init() failed\n"); curl_global_cleanup(); - fclose(idfile); + curlx_fclose(idfile); return TEST_ERR_MAJOR_BAD; } @@ -116,7 +116,7 @@ static CURLcode test_lib569(const char *URL) test_cleanup: if(idfile) - fclose(idfile); + curlx_fclose(idfile); curl_free(stream_uri); curl_easy_cleanup(curl); diff --git a/tests/libtest/lib571.c b/tests/libtest/lib571.c index 2cf4128e7ab5..49afc2211d2a 100644 --- a/tests/libtest/lib571.c +++ b/tests/libtest/lib571.c @@ -95,7 +95,7 @@ static CURLcode test_lib571(const char *URL) char *stream_uri = NULL; int request = 1; - FILE *protofile = fopen(libtest_arg2, "wb"); + FILE *protofile = curlx_fopen(libtest_arg2, "wb"); if(!protofile) { curl_mfprintf(stderr, "Couldn't open the protocol dump file\n"); return TEST_ERR_MAJOR_BAD; @@ -103,14 +103,14 @@ static CURLcode test_lib571(const char *URL) if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { curl_mfprintf(stderr, "curl_global_init() failed\n"); - fclose(protofile); + curlx_fclose(protofile); return TEST_ERR_MAJOR_BAD; } curl = curl_easy_init(); if(!curl) { curl_mfprintf(stderr, "curl_easy_init() failed\n"); - fclose(protofile); + curlx_fclose(protofile); curl_global_cleanup(); return TEST_ERR_MAJOR_BAD; } @@ -194,7 +194,7 @@ static CURLcode test_lib571(const char *URL) curl_free(stream_uri); if(protofile) - fclose(protofile); + curlx_fclose(protofile); curl_easy_cleanup(curl); curl_global_cleanup(); diff --git a/tests/libtest/lib572.c b/tests/libtest/lib572.c index ea9e34e06853..ef5e06602357 100644 --- a/tests/libtest/lib572.c +++ b/tests/libtest/lib572.c @@ -93,7 +93,7 @@ static CURLcode test_lib572(const char *URL) fstat(params, &file_info); close(params); - paramsf = fopen(libtest_arg2, "rb"); + paramsf = curlx_fopen(libtest_arg2, "rb"); if(!paramsf) { curl_mfprintf(stderr, "can't fopen %s\n", libtest_arg2); res = TEST_ERR_MAJOR_BAD; @@ -110,7 +110,7 @@ static CURLcode test_lib572(const char *URL) goto test_cleanup; test_setopt(curl, CURLOPT_UPLOAD, 0L); - fclose(paramsf); + curlx_fclose(paramsf); paramsf = NULL; /* Heartbeat GET_PARAMETERS */ @@ -163,7 +163,7 @@ static CURLcode test_lib572(const char *URL) test_cleanup: if(paramsf) - fclose(paramsf); + curlx_fclose(paramsf); curl_free(stream_uri); diff --git a/tests/libtest/lib578.c b/tests/libtest/lib578.c index a15c9a4f8187..b6be1600f4c9 100644 --- a/tests/libtest/lib578.c +++ b/tests/libtest/lib578.c @@ -33,7 +33,7 @@ static size_t data_size = CURL_ARRAYSIZE(t578_testdata); static int t578_progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { - FILE *moo = fopen(libtest_arg2, "wb"); + FILE *moo = curlx_fopen(libtest_arg2, "wb"); (void)clientp; (void)dltotal; @@ -45,7 +45,7 @@ static int t578_progress_callback(void *clientp, double dltotal, double dlnow, else curl_mfprintf(moo, "Progress callback called with UL %f out of %f\n", ulnow, ultotal); - fclose(moo); + curlx_fclose(moo); } return 0; } diff --git a/tests/libtest/lib579.c b/tests/libtest/lib579.c index 76ecefe4ec53..29396941cc80 100644 --- a/tests/libtest/lib579.c +++ b/tests/libtest/lib579.c @@ -35,11 +35,11 @@ static size_t last_ul_total = 0; static void progress_final_report(void) { - FILE *moo = fopen(libtest_arg2, "ab"); + FILE *moo = curlx_fopen(libtest_arg2, "ab"); curl_mfprintf(moo ? moo : stderr, "Progress: end UL %zu/%zu\n", last_ul, last_ul_total); if(moo) - fclose(moo); + curlx_fclose(moo); else curl_mfprintf(stderr, "Progress: end UL, can't open %s\n", libtest_arg2); started = FALSE; @@ -59,11 +59,11 @@ static int t579_progress_callback(void *clientp, double dltotal, double dlnow, last_ul = (size_t)ulnow; last_ul_total = (size_t)ultotal; if(!started) { - FILE *moo = fopen(libtest_arg2, "ab"); + FILE *moo = curlx_fopen(libtest_arg2, "ab"); curl_mfprintf(moo ? moo : stderr, "Progress: start UL %zu/%zu\n", last_ul, last_ul_total); if(moo) - fclose(moo); + curlx_fclose(moo); else curl_mfprintf(stderr, "Progress: start UL, can't open %s\n", libtest_arg2); diff --git a/tests/libtest/lib582.c b/tests/libtest/lib582.c index 70a9ab65dcdb..b1970632210d 100644 --- a/tests/libtest/lib582.c +++ b/tests/libtest/lib582.c @@ -243,7 +243,7 @@ static CURLcode test_lib582(const char *URL) return TEST_ERR_USAGE; } - hd_src = fopen(libtest_arg2, "rb"); + hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen() failed with error (%d) %s\n", errno, strerror(errno)); @@ -262,7 +262,7 @@ static CURLcode test_lib582(const char *URL) curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", errno, strerror(errno)); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); - fclose(hd_src); + curlx_fclose(hd_src); return TEST_ERR_FSTAT; } curl_mfprintf(stderr, "Set to upload %" CURL_FORMAT_CURL_OFF_T " bytes\n", @@ -270,7 +270,7 @@ static CURLcode test_lib582(const char *URL) res_global_init(CURL_GLOBAL_ALL); if(res != CURLE_OK) { - fclose(hd_src); + curlx_fclose(hd_src); return res; } @@ -356,7 +356,7 @@ static CURLcode test_lib582(const char *URL) curl_global_cleanup(); /* close the local file */ - fclose(hd_src); + curlx_fclose(hd_src); /* free local memory */ free(sockets.read.sockets); diff --git a/tests/libtest/lib591.c b/tests/libtest/lib591.c index 1f09fbdc4d12..77a038c7c320 100644 --- a/tests/libtest/lib591.c +++ b/tests/libtest/lib591.c @@ -39,7 +39,7 @@ static CURLcode test_lib591(const char *URL) start_test_timing(); - upload = fopen(libtest_arg3, "rb"); + upload = curlx_fopen(libtest_arg3, "rb"); if(!upload) { curl_mfprintf(stderr, "fopen() failed with error (%d) %s\n", errno, strerror(errno)); @@ -49,7 +49,7 @@ static CURLcode test_lib591(const char *URL) res_global_init(CURL_GLOBAL_ALL); if(res) { - fclose(upload); + curlx_fclose(upload); return res; } @@ -138,7 +138,7 @@ static CURLcode test_lib591(const char *URL) curl_global_cleanup(); /* close the local file */ - fclose(upload); + curlx_fclose(upload); return res; } diff --git a/tests/libtest/lib599.c b/tests/libtest/lib599.c index 5b52698a29f7..199ef90dbf8c 100644 --- a/tests/libtest/lib599.c +++ b/tests/libtest/lib599.c @@ -82,10 +82,10 @@ static CURLcode test_lib599(const char *URL) FILE *moo; res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length); - moo = fopen(libtest_arg2, "wb"); + moo = curlx_fopen(libtest_arg2, "wb"); if(moo) { curl_mfprintf(moo, "CL %.0f\n", content_length); - fclose(moo); + curlx_fclose(moo); } } diff --git a/tests/libtest/lib678.c b/tests/libtest/lib678.c index 78e03c004f98..5fdabdda9609 100644 --- a/tests/libtest/lib678.c +++ b/tests/libtest/lib678.c @@ -30,7 +30,7 @@ static int loadfile(const char *filename, void **filedata, size_t *filesize) size_t datasize = 0; void *data = NULL; if(filename) { - FILE *fInCert = fopen(filename, "rb"); + FILE *fInCert = curlx_fopen(filename, "rb"); if(fInCert) { long cert_tell = 0; @@ -48,7 +48,7 @@ static int loadfile(const char *filename, void **filedata, size_t *filesize) if((!data) || ((int)fread(data, datasize, 1, fInCert) != 1)) continue_reading = FALSE; - fclose(fInCert); + curlx_fclose(fInCert); if(!continue_reading) { free(data); datasize = 0; diff --git a/tests/server/.checksrc b/tests/server/.checksrc index be8f12cec014..670d4b800912 100644 --- a/tests/server/.checksrc +++ b/tests/server/.checksrc @@ -1,4 +1,6 @@ allowfunc accept +allowfunc fclose +allowfunc fopen allowfunc freeaddrinfo allowfunc getaddrinfo allowfunc recv diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index 2e3791c77490..be35fe7c4fd0 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -35,6 +35,7 @@ UTILS_H = CURLX_C = \ ../../lib/curlx/base64.c \ + ../../lib/curlx/fopen.c \ ../../lib/curlx/inet_pton.c \ ../../lib/curlx/inet_ntop.c \ ../../lib/curlx/multibyte.c \ diff --git a/tests/unit/unit3200.c b/tests/unit/unit3200.c index 023bf0ddb6fd..5c3e4d14ad47 100644 --- a/tests/unit/unit3200.c +++ b/tests/unit/unit3200.c @@ -84,12 +84,12 @@ static CURLcode test_unit3200(const char *arg) char *line; curlx_dyn_init(&buf, len); - fp = fopen(arg, "wb"); + fp = curlx_fopen(arg, "wb"); abort_unless(fp != NULL, "Cannot open testfile"); fwrite(filecontents[i], 1, strlen(filecontents[i]), fp); - fclose(fp); + curlx_fclose(fp); - fp = fopen(arg, "rb"); + fp = curlx_fopen(arg, "rb"); abort_unless(fp != NULL, "Cannot open testfile"); curl_mfprintf(stderr, "Test %zd...", i); @@ -158,7 +158,7 @@ static CURLcode test_unit3200(const char *arg) break; } curlx_dyn_free(&buf); - fclose(fp); + curlx_fclose(fp); curl_mfprintf(stderr, "OK\n"); } return (CURLcode)rc; From dd37d6970cfd8b4cf47ebd469f03772813b92c23 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 30 Sep 2025 01:46:33 +0200 Subject: [PATCH 209/465] checksrc: fix possible endless loop when detecting `BANNEDFUNC` If the source line had square brackets before the match, the stripping of the banned function left the original line intact, and repeated the check on it forever. E.g. with banned function `open` in `lib518.c`: ```c t518_testfd[0] = open(DEV_NULL, O_RDONLY); ``` Closes #18775 --- scripts/checksrc.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index b737961899f1..23c9ef530107 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -902,6 +902,8 @@ sub scanfile { "use of $bad is banned"); my $replace = 'x' x (length($bad) + 1); $prefix =~ s/\*/\\*/; + $prefix =~ s/\[/\\[/; + $prefix =~ s/\]/\\]/; $suff =~ s/\(/\\(/; $l =~ s/$prefix$bad$suff/$prefix$replace/; goto again; From 5b086ba18833a3970919e692865ebabc00166869 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 01:14:11 +0000 Subject: [PATCH 210/465] Dockerfile: update debian:bookworm-slim digest to 7e49091 Closes #18777 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 454df8dea964..88a356bb88c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ # $ ./scripts/maketgz 8.7.1 # To update, get the latest digest e.g. from https://hub.docker.com/_/debian/tags -FROM debian:bookworm-slim@sha256:df52e55e3361a81ac1bead266f3373ee55d29aa50cf0975d440c2be3483d8ed3 +FROM debian:bookworm-slim@sha256:7e490910eea2861b9664577a96b54ce68ea3e02ce7f51d89cb0103a6f9c386e0 RUN apt-get update -qq && apt-get install -qq -y --no-install-recommends \ build-essential make autoconf automake libtool git perl zip zlib1g-dev gawk && \ From c478c7efdf4ebbc8d768ae4cdfdcecf49b68cf94 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 30 Sep 2025 11:41:11 +0200 Subject: [PATCH 211/465] examples: fix two more cases of `stat()` TOCTOU Also: - ftpupload: bump an intermediate variable size. Follow-up to f13250edf11312ab8c0425cf39b182a31b53c6f7 #18605 Closes #18778 --- docs/examples/ftpupload.c | 32 ++++++++++++++++++++------------ docs/examples/httpput.c | 16 +++++++++++++--- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/docs/examples/ftpupload.c b/docs/examples/ftpupload.c index 6e7bece70dee..ec64f4a2cdd9 100644 --- a/docs/examples/ftpupload.c +++ b/docs/examples/ftpupload.c @@ -37,6 +37,9 @@ #include #undef stat #define stat _stat +#undef fstat +#define fstat _fstat +#define fileno _fileno #else #include #endif @@ -78,25 +81,31 @@ int main(void) CURLcode res; FILE *hd_src; struct stat file_info; - unsigned long fsize; + curl_off_t fsize; struct curl_slist *headerlist = NULL; static const char buf_1 [] = "RNFR " UPLOAD_FILE_AS; static const char buf_2 [] = "RNTO " RENAME_FILE_TO; - /* get the file size of the local file */ - if(stat(LOCAL_FILE, &file_info)) { + /* get a FILE * of the file */ + hd_src = fopen(LOCAL_FILE, "rb"); + if(!hd_src) { printf("Couldn't open '%s': %s\n", LOCAL_FILE, strerror(errno)); - return 1; + return 2; } - fsize = (unsigned long)file_info.st_size; - printf("Local file size: %lu bytes.\n", fsize); + /* to get the file size */ +#ifdef UNDER_CE + if(stat(LOCAL_FILE, &file_info) != 0) { +#else + if(fstat(fileno(hd_src), &file_info) != 0) { +#endif + fclose(hd_src); + return 1; /* cannot continue */ + } + fsize = file_info.st_size; - /* get a FILE * of the same file */ - hd_src = fopen(LOCAL_FILE, "rb"); - if(!hd_src) - return 2; + printf("Local file size: %lu bytes.\n", (unsigned long)fsize); /* In Windows, this inits the Winsock stuff */ curl_global_init(CURL_GLOBAL_ALL); @@ -127,8 +136,7 @@ int main(void) option you MUST make sure that the type of the passed-in argument is a curl_off_t. If you use CURLOPT_INFILESIZE (without _LARGE) you must make sure that to pass in a type 'long' argument. */ - curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, - (curl_off_t)fsize); + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, fsize); /* Now run off and do what you have been told! */ res = curl_easy_perform(curl); diff --git a/docs/examples/httpput.c b/docs/examples/httpput.c index 3743e1b5b9c8..ddb1b07328c6 100644 --- a/docs/examples/httpput.c +++ b/docs/examples/httpput.c @@ -33,6 +33,9 @@ #ifdef _WIN32 #undef stat #define stat _stat +#undef fstat +#define fstat _fstat +#define fileno _fileno #endif /* @@ -79,9 +82,6 @@ int main(int argc, char **argv) file = argv[1]; url = argv[2]; - /* get the file size of the local file */ - stat(file, &file_info); - /* get a FILE * of the same file, could also be made with fdopen() from the previous descriptor, but hey this is just an example! */ @@ -89,6 +89,16 @@ int main(int argc, char **argv) if(!hd_src) return 2; + /* get the file size of the local file */ +#ifdef UNDER_CE + if(stat(file, &file_info) != 0) { +#else + if(fstat(fileno(hd_src), &file_info) != 0) { +#endif + fclose(hd_src); + return 1; /* cannot continue */ + } + /* In Windows, this inits the Winsock stuff */ curl_global_init(CURL_GLOBAL_ALL); From 684f4cdd3ef0cc41c547fce0e45d8a059a3058b3 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 30 Sep 2025 12:47:01 +0200 Subject: [PATCH 212/465] checksrc: catch banned functions when preceded by `(` Also add a test case. Closes #18779 --- scripts/checksrc.pl | 4 +++- tests/data/test1185 | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 23c9ef530107..5e8434d5fabf 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -893,7 +893,8 @@ sub scanfile { # scan for use of banned functions my $bl = $l; again: - if(($l =~ /^(.*?\W)(\w+)(\s*\()/x) && $banfunc{$2}) { + if((($l =~ /^(.*?\W)(\w+)(\s*\()/x) && $banfunc{$2}) || + (($l =~ /^(.*?\()(\w+)(\s*\()/x) && $banfunc{$2})) { my $bad = $2; my $prefix = $1; my $suff = $3; @@ -904,6 +905,7 @@ sub scanfile { $prefix =~ s/\*/\\*/; $prefix =~ s/\[/\\[/; $prefix =~ s/\]/\\]/; + $prefix =~ s/\(/\\(/; $suff =~ s/\(/\\(/; $l =~ s/$prefix$bad$suff/$prefix$replace/; goto again; diff --git a/tests/data/test1185 b/tests/data/test1185 index 43a27f087054..14a23dc01ac9 100644 --- a/tests/data/test1185 +++ b/tests/data/test1185 @@ -74,6 +74,8 @@ void startfunc(int a, int b) { if(a) b++; + if(sprintf(buffer, "%s", moo)) {} + // CPP comment ? /* comment doesn't end @@ -192,7 +194,10 @@ void startfunc(int a, int b) { ./%LOGDIR/code1185.c:57:7: warning: conditional block on the same line (ONELINECONDITION) if(a) b++; ^ -./%LOGDIR/code1185.c:59:2: warning: // comment (CPPCOMMENTS) +./%LOGDIR/code1185.c:59:5: warning: use of sprintf is banned (BANNEDFUNC) + if(sprintf(buffer, "%s", moo)) {} + ^ +./%LOGDIR/code1185.c:61:2: warning: // comment (CPPCOMMENTS) // CPP comment ? ^ ./%LOGDIR/code1185.c:1:1: error: Missing copyright statement (COPYRIGHT) @@ -201,7 +206,7 @@ void startfunc(int a, int b) { ./%LOGDIR/code1185.c:1:1: error: Missing closing comment (OPENCOMMENT) ^ -checksrc: 0 errors and 39 warnings +checksrc: 0 errors and 40 warnings 5 From 9678ff5b1bfea1c847aee4f9edf023e8f01c9293 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 30 Sep 2025 01:27:10 +0200 Subject: [PATCH 213/465] build: avoid overriding system `open` and `stat` symbols Replace them by `curlx_open()` and `curlx_stat()`. To make it obvious in the source code what is being executed. Also: - tests/server: stop overriding `open()` for test servers. This is critical for the call made from the signal handler. For other calls, it's an option to use `curlx_open()`, but doesn't look important enough to do it, following the path taken with `fopen()`. Follow-up to 10bac43b873fe45869e15b36aac1c1e5bc89b6e0 #18774 Follow-up to 20142f5d06f7120ba94cbcc25c998e8d81aec85b #18634 Follow-up to bf7375ecc50e857760b0d0a668c436e208a400bd #18503 Closes #18776 --- docs/examples/.checksrc | 1 + docs/examples/anyauthput.c | 1 + docs/examples/fileupload.c | 1 + docs/examples/ftpupload.c | 1 + docs/examples/http2-upload.c | 1 + docs/examples/httpput.c | 1 + lib/config-win32.h | 1 + lib/curl_fopen.c | 11 +++++------ lib/curl_setup.h | 6 ------ lib/curlx/fopen.h | 21 +++++++++++++++------ lib/file.c | 17 +++++++---------- lib/mime.c | 4 ++-- lib/vquic/vquic.c | 9 ++++----- lib/vssh/libssh2.c | 13 +++++-------- scripts/checksrc.pl | 2 ++ src/tool_cb_wrt.c | 13 +++++-------- src/tool_doswin.c | 2 +- src/tool_filetime.c | 2 +- src/tool_findfile.c | 6 +----- src/tool_getpass.c | 6 +----- src/tool_operate.c | 21 ++++++++------------- tests/libtest/lib505.c | 1 + tests/libtest/lib518.c | 2 +- tests/libtest/lib525.c | 1 + tests/libtest/lib537.c | 2 +- tests/libtest/lib541.c | 1 + tests/libtest/lib568.c | 2 +- tests/libtest/lib572.c | 2 +- tests/libtest/lib582.c | 1 + tests/server/.checksrc | 1 + tests/server/util.c | 6 +++--- 31 files changed, 76 insertions(+), 83 deletions(-) diff --git a/docs/examples/.checksrc b/docs/examples/.checksrc index e0b6c43da939..259058cad580 100644 --- a/docs/examples/.checksrc +++ b/docs/examples/.checksrc @@ -3,4 +3,5 @@ allowfunc fdopen allowfunc fopen allowfunc gmtime allowfunc localtime +allowfunc open allowfunc socket diff --git a/docs/examples/anyauthput.c b/docs/examples/anyauthput.c index c62250dce372..505d16b217b2 100644 --- a/docs/examples/anyauthput.c +++ b/docs/examples/anyauthput.c @@ -104,6 +104,7 @@ int main(int argc, char **argv) return 2; #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ stat(file, &file_info); #else fstat(fileno(fp), &file_info); diff --git a/docs/examples/fileupload.c b/docs/examples/fileupload.c index 0860c9457bea..29c3c3c3c138 100644 --- a/docs/examples/fileupload.c +++ b/docs/examples/fileupload.c @@ -52,6 +52,7 @@ int main(void) /* to get the file size */ #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ if(stat("debugit", &file_info) != 0) { #else if(fstat(fileno(fd), &file_info) != 0) { diff --git a/docs/examples/ftpupload.c b/docs/examples/ftpupload.c index ec64f4a2cdd9..4f3b679226eb 100644 --- a/docs/examples/ftpupload.c +++ b/docs/examples/ftpupload.c @@ -96,6 +96,7 @@ int main(void) /* to get the file size */ #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ if(stat(LOCAL_FILE, &file_info) != 0) { #else if(fstat(fileno(hd_src), &file_info) != 0) { diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index d13c5e58063c..b08e8fc102eb 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -234,6 +234,7 @@ static int setup(struct input *i, int num, const char *upload) } #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ if(stat(upload, &file_info) != 0) { #else if(fstat(fileno(i->in), &file_info) != 0) { diff --git a/docs/examples/httpput.c b/docs/examples/httpput.c index ddb1b07328c6..1951cb232e8b 100644 --- a/docs/examples/httpput.c +++ b/docs/examples/httpput.c @@ -91,6 +91,7 @@ int main(int argc, char **argv) /* get the file size of the local file */ #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ if(stat(file, &file_info) != 0) { #else if(fstat(fileno(hd_src), &file_info) != 0) { diff --git a/lib/config-win32.h b/lib/config-win32.h index b7f83927a43e..408606d61179 100644 --- a/lib/config-win32.h +++ b/lib/config-win32.h @@ -484,6 +484,7 @@ #define CURL_DISABLE_LDAP 1 #ifndef _MSC_VER +/* !checksrc! disable BANNEDFUNC 1 */ extern int stat(const char *path, struct stat *buffer); #endif diff --git a/lib/curl_fopen.c b/lib/curl_fopen.c index 13acd299c0dd..5e25f0eab60e 100644 --- a/lib/curl_fopen.c +++ b/lib/curl_fopen.c @@ -27,10 +27,6 @@ #if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \ !defined(CURL_DISABLE_HSTS) -#ifdef HAVE_FCNTL_H -#include -#endif - #include "urldata.h" #include "rand.h" #include "curl_fopen.h" @@ -107,6 +103,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, goto fail; if( #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ stat(filename, &sb) == -1 #else fstat(fileno(*fh), &sb) == -1 @@ -137,9 +134,11 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, result = CURLE_WRITE_ERROR; #if (defined(ANDROID) || defined(__ANDROID__)) && \ (defined(__i386__) || defined(__arm__)) - fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, (mode_t)(0600|sb.st_mode)); + fd = curlx_open(tempstore, O_WRONLY | O_CREAT | O_EXCL, + (mode_t)(0600 | sb.st_mode)); #else - fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, 0600|sb.st_mode); + fd = curlx_open(tempstore, O_WRONLY | O_CREAT | O_EXCL, + 0600 | sb.st_mode); #endif if(fd == -1) goto fail; diff --git a/lib/curl_setup.h b/lib/curl_setup.h index b3c19a95efb5..a741abde0323 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -506,12 +506,6 @@ # endif # define LSEEK_ERROR (long)-1 # endif -# ifndef UNDER_CE - int curlx_win32_stat(const char *path, struct_stat *buffer); - int curlx_win32_open(const char *filename, int oflag, ...); -# define stat(fname, stp) curlx_win32_stat(fname, stp) -# define open curlx_win32_open -# endif #elif defined(__DJGPP__) /* Requires DJGPP 2.04 */ # include diff --git a/lib/curlx/fopen.h b/lib/curlx/fopen.h index 2a2b07963789..d1e3d127c53d 100644 --- a/lib/curlx/fopen.h +++ b/lib/curlx/fopen.h @@ -30,19 +30,28 @@ #if defined(_WIN32) && !defined(UNDER_CE) FILE *curlx_win32_fopen(const char *filename, const char *mode); +int curlx_win32_stat(const char *path, struct_stat *buffer); +int curlx_win32_open(const char *filename, int oflag, ...); #define CURLX_FOPEN_LOW(fname, mode) curlx_win32_fopen(fname, mode) +#define curlx_stat(fname, stp) curlx_win32_stat(fname, stp) +#define curlx_open curlx_win32_open #else -#define CURLX_FOPEN_LOW fopen +#ifdef HAVE_FCNTL_H +#include /* for open() */ +#endif +#define CURLX_FOPEN_LOW fopen +#define curlx_stat(fname, stp) stat(fname, stp) +#define curlx_open open #endif #ifdef CURLDEBUG -#define curlx_fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) +#define curlx_fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) #define curlx_fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__) -#define curlx_fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__) +#define curlx_fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__) #else -#define curlx_fopen CURLX_FOPEN_LOW -#define curlx_fdopen fdopen -#define curlx_fclose fclose +#define curlx_fopen CURLX_FOPEN_LOW +#define curlx_fdopen fdopen +#define curlx_fclose fclose #endif #endif /* HEADER_CURLX_FOPEN_H */ diff --git a/lib/file.c b/lib/file.c index 749759653d5a..2d5818a1db42 100644 --- a/lib/file.c +++ b/lib/file.c @@ -46,10 +46,6 @@ #include #endif -#ifdef HAVE_FCNTL_H -#include -#endif - #ifdef HAVE_SYS_TYPES_H #include #endif @@ -70,6 +66,7 @@ #include "transfer.h" #include "url.h" #include "parsedate.h" /* for the week day and month names */ +#include "curlx/fopen.h" #include "curlx/warnless.h" #include "curl_range.h" /* The last 3 #include files should be in this order */ @@ -237,7 +234,7 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done) return CURLE_URL_MALFORMAT; } - fd = open(actual_path, O_RDONLY|CURL_O_BINARY); + fd = curlx_open(actual_path, O_RDONLY | CURL_O_BINARY); file->path = actual_path; #else if(memchr(real_path, 0, real_path_len)) { @@ -261,16 +258,16 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done) extern int __unix_path_semantics; if(strchr(real_path + 1, ':')) { /* Amiga absolute path */ - fd = open(real_path + 1, O_RDONLY); + fd = curlx_open(real_path + 1, O_RDONLY); file->path++; } else if(__unix_path_semantics) { /* -lunix fallback */ - fd = open(real_path, O_RDONLY); + fd = curlx_open(real_path, O_RDONLY); } } #else - fd = open(real_path, O_RDONLY); + fd = curlx_open(real_path, O_RDONLY); file->path = real_path; #endif #endif @@ -349,9 +346,9 @@ static CURLcode file_upload(struct Curl_easy *data, #if (defined(ANDROID) || defined(__ANDROID__)) && \ (defined(__i386__) || defined(__arm__)) - fd = open(file->path, mode, (mode_t)data->set.new_file_perms); + fd = curlx_open(file->path, mode, (mode_t)data->set.new_file_perms); #else - fd = open(file->path, mode, data->set.new_file_perms); + fd = curlx_open(file->path, mode, data->set.new_file_perms); #endif if(fd < 0) { failf(data, "cannot open %s for writing", file->path); diff --git a/lib/mime.c b/lib/mime.c index 6ec7f6904671..fe632604ed9d 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -205,7 +205,7 @@ static FILE * vmsfopenread(const char *file, const char *mode) struct_stat statbuf; int result; - result = stat(file, &statbuf); + result = curlx_stat(file, &statbuf); switch(statbuf.st_fab_rfm) { case FAB$C_VAR: @@ -1412,7 +1412,7 @@ CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename) char *base; struct_stat sbuf; - if(stat(filename, &sbuf)) + if(curlx_stat(filename, &sbuf)) result = CURLE_READ_ERROR; else { part->data = strdup(filename); diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index 47fbf63af05a..c50981975211 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -27,15 +27,13 @@ #ifdef HAVE_NETINET_UDP_H #include #endif -#ifdef HAVE_FCNTL_H -#include -#endif #ifdef USE_NGHTTP3 #include #endif #include "../urldata.h" #include "../bufq.h" #include "../curlx/dynbuf.h" +#include "../curlx/fopen.h" #include "../cfilters.h" #include "../curl_trc.h" #include "curl_ngtcp2.h" @@ -665,8 +663,9 @@ CURLcode Curl_qlogdir(struct Curl_easy *data, result = curlx_dyn_add(&fname, ".sqlog"); if(!result) { - int qlogfd = open(curlx_dyn_ptr(&fname), O_WRONLY|O_CREAT|CURL_O_BINARY, - data->set.new_file_perms); + int qlogfd = curlx_open(curlx_dyn_ptr(&fname), + O_WRONLY | O_CREAT | CURL_O_BINARY, + data->set.new_file_perms); if(qlogfd != -1) *qlogfdp = qlogfd; } diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index f68e3ee168f8..0b82b568b13a 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -30,10 +30,6 @@ #include -#ifdef HAVE_FCNTL_H -#include -#endif - #ifdef HAVE_NETINET_IN_H #include #endif @@ -68,6 +64,7 @@ #include "../sockaddr.h" /* required for Curl_sockaddr_storage */ #include "../multiif.h" #include "../select.h" +#include "../curlx/fopen.h" #include "../curlx/warnless.h" #include "curl_path.h" #include "../curlx/strparse.h" @@ -1199,12 +1196,12 @@ static CURLcode ssh_state_pkey_init(struct Curl_easy *data, sshc->rsa = aprintf("%s/.ssh/id_rsa", home); if(!sshc->rsa) out_of_memory = TRUE; - else if(stat(sshc->rsa, &sbuf)) { + else if(curlx_stat(sshc->rsa, &sbuf)) { free(sshc->rsa); sshc->rsa = aprintf("%s/.ssh/id_dsa", home); if(!sshc->rsa) out_of_memory = TRUE; - else if(stat(sshc->rsa, &sbuf)) { + else if(curlx_stat(sshc->rsa, &sbuf)) { Curl_safefree(sshc->rsa); } } @@ -1213,10 +1210,10 @@ static CURLcode ssh_state_pkey_init(struct Curl_easy *data, if(!out_of_memory && !sshc->rsa) { /* Nothing found; try the current dir. */ sshc->rsa = strdup("id_rsa"); - if(sshc->rsa && stat(sshc->rsa, &sbuf)) { + if(sshc->rsa && curlx_stat(sshc->rsa, &sbuf)) { free(sshc->rsa); sshc->rsa = strdup("id_dsa"); - if(sshc->rsa && stat(sshc->rsa, &sbuf)) { + if(sshc->rsa && curlx_stat(sshc->rsa, &sbuf)) { free(sshc->rsa); /* Out of guesses. Set to the empty string to avoid * surprising info messages. */ diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 5e8434d5fabf..0907c3f9ad4c 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -91,6 +91,8 @@ "fclose" => 1, "fdopen" => 1, "fopen" => 1, + "open" => 1, + "stat" => 1, ); my %warnings_extended = ( diff --git a/src/tool_cb_wrt.c b/src/tool_cb_wrt.c index b4ea781739a7..12e4417da479 100644 --- a/src/tool_cb_wrt.c +++ b/src/tool_cb_wrt.c @@ -23,11 +23,6 @@ ***************************************************************************/ #include "tool_setup.h" -#ifdef HAVE_FCNTL_H -/* for open() */ -#include -#endif - #include "tool_cfgable.h" #include "tool_msgs.h" #include "tool_cb_wrt.h" @@ -60,7 +55,8 @@ bool tool_create_output_file(struct OutStruct *outs, else { int fd; do { - fd = open(fname, O_CREAT | O_WRONLY | O_EXCL | CURL_O_BINARY, OPENMODE); + fd = curlx_open(fname, O_CREAT | O_WRONLY | O_EXCL | CURL_O_BINARY, + OPENMODE); /* Keep retrying in the hope that it is not interrupted sometime */ /* !checksrc! disable ERRNOVAR 1 */ } while(fd == -1 && errno == EINTR); @@ -78,8 +74,9 @@ bool tool_create_output_file(struct OutStruct *outs, return FALSE; next_num++; do { - fd = open(curlx_dyn_ptr(&fbuffer), - O_CREAT | O_WRONLY | O_EXCL | CURL_O_BINARY, OPENMODE); + fd = curlx_open(curlx_dyn_ptr(&fbuffer), + O_CREAT | O_WRONLY | O_EXCL | CURL_O_BINARY, + OPENMODE); /* Keep retrying in the hope that it is not interrupted sometime */ } while(fd == -1 && errno == EINTR); } diff --git a/src/tool_doswin.c b/src/tool_doswin.c index 29f8cecbd799..51b6f341018a 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -532,7 +532,7 @@ static SANITIZEcode rename_if_reserved_dos(char **const sanitized, identify whether it is a reserved device name and not a regular filename. */ #ifdef MSDOS - if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) { + if(base && (curlx_stat(base, &st_buf) == 0) && S_ISCHR(st_buf.st_mode)) { /* Prepend a '_' */ size_t blen = strlen(base); if(blen) { diff --git a/src/tool_filetime.c b/src/tool_filetime.c index c818fe3ada20..5912a5aa9a52 100644 --- a/src/tool_filetime.c +++ b/src/tool_filetime.c @@ -75,7 +75,7 @@ int getfiletime(const char *filename, curl_off_t *stamp) } #else struct_stat statbuf; - if(stat(filename, &statbuf) != -1) { + if(curlx_stat(filename, &statbuf) != -1) { *stamp = (curl_off_t)statbuf.st_mtime; rc = 0; } diff --git a/src/tool_findfile.c b/src/tool_findfile.c index 8b2be8414214..7705ab7d926f 100644 --- a/src/tool_findfile.c +++ b/src/tool_findfile.c @@ -33,10 +33,6 @@ #endif #endif -#ifdef HAVE_FCNTL_H -#include -#endif - #include "tool_findfile.h" #include "tool_cfgable.h" @@ -77,7 +73,7 @@ static char *checkhome(const char *home, const char *fname, bool dotscore) else c = aprintf("%s" DIR_CHAR "%s", home, fname); if(c) { - int fd = open(c, O_RDONLY); + int fd = curlx_open(c, O_RDONLY); if(fd >= 0) { char *path = strdup(c); close(fd); diff --git a/src/tool_getpass.c b/src/tool_getpass.c index fc59accc07ac..a92fb7594c78 100644 --- a/src/tool_getpass.c +++ b/src/tool_getpass.c @@ -30,10 +30,6 @@ #ifndef HAVE_GETPASS_R /* this file is only for systems without getpass_r() */ -#ifdef HAVE_FCNTL_H -# include -#endif - #ifdef HAVE_TERMIOS_H # include #elif defined(HAVE_TERMIO_H) @@ -178,7 +174,7 @@ char *getpass_r(const char *prompt, /* prompt to display */ { ssize_t nread; bool disabled; - int fd = open("/dev/tty", O_RDONLY); + int fd = curlx_open("/dev/tty", O_RDONLY); if(fd == -1) fd = STDIN_FILENO; /* use stdin if the tty could not be used */ diff --git a/src/tool_operate.c b/src/tool_operate.c index d5a1b2646812..d4a6d4db4251 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -23,10 +23,6 @@ ***************************************************************************/ #include "tool_setup.h" -#ifdef HAVE_FCNTL_H -# include -#endif - #ifdef HAVE_LOCALE_H # include #endif @@ -279,22 +275,22 @@ static CURLcode pre_transfer(struct per_transfer *per) #ifdef __VMS /* Calculate the real upload size for VMS */ per->infd = -1; - if(stat(per->uploadfile, &fileinfo) == 0) { + if(curlx_stat(per->uploadfile, &fileinfo) == 0) { fileinfo.st_size = VmsSpecialSize(uploadfile, &fileinfo); switch(fileinfo.st_fab_rfm) { case FAB$C_VAR: case FAB$C_VFC: case FAB$C_STMCR: - per->infd = open(per->uploadfile, O_RDONLY | CURL_O_BINARY); + per->infd = curlx_open(per->uploadfile, O_RDONLY | CURL_O_BINARY); break; default: - per->infd = open(per->uploadfile, O_RDONLY | CURL_O_BINARY, - "rfm=stmlf", "ctx=stm"); + per->infd = curlx_open(per->uploadfile, O_RDONLY | CURL_O_BINARY, + "rfm=stmlf", "ctx=stm"); } } if(per->infd == -1) #else - per->infd = open(per->uploadfile, O_RDONLY | CURL_O_BINARY); + per->infd = curlx_open(per->uploadfile, O_RDONLY | CURL_O_BINARY); if((per->infd == -1) || fstat(per->infd, &fileinfo)) #endif { @@ -668,8 +664,7 @@ static CURLcode post_per_transfer(struct per_transfer *per, } if(result && config->rm_partial) { struct_stat st; - if(!stat(outs->filename, &st) && - S_ISREG(st.st_mode)) { + if(!curlx_stat(outs->filename, &st) && S_ISREG(st.st_mode)) { if(!unlink(outs->filename)) notef("Removed output file: %s", outs->filename); else @@ -974,7 +969,7 @@ static CURLcode setup_outfile(struct OperationConfig *config, if(config->skip_existing) { struct_stat fileinfo; - if(!stat(per->outfile, &fileinfo)) { + if(!curlx_stat(per->outfile, &fileinfo)) { /* file is present */ notef("skips transfer, \"%s\" exists locally", per->outfile); per->skip = TRUE; @@ -987,7 +982,7 @@ static CURLcode setup_outfile(struct OperationConfig *config, of the file as it is now and open it for append instead */ struct_stat fileinfo; /* VMS -- Danger, the filesize is only valid for stream files */ - if(stat(per->outfile, &fileinfo) == 0) + if(curlx_stat(per->outfile, &fileinfo) == 0) /* set offset to current file size: */ config->resume_from = fileinfo.st_size; else diff --git a/tests/libtest/lib505.c b/tests/libtest/lib505.c index fc200945847e..71b79b2a244e 100644 --- a/tests/libtest/lib505.c +++ b/tests/libtest/lib505.c @@ -61,6 +61,7 @@ static CURLcode test_lib505(const char *URL) /* get the file size of the local file */ #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ hd = stat(libtest_arg2, &file_info); #else hd = fstat(fileno(hd_src), &file_info); diff --git a/tests/libtest/lib518.c b/tests/libtest/lib518.c index 9cf3a42554ad..007d26187012 100644 --- a/tests/libtest/lib518.c +++ b/tests/libtest/lib518.c @@ -287,7 +287,7 @@ static int t518_test_rlimit(int keep_open) /* open a dummy descriptor */ - t518_testfd[0] = open(DEV_NULL, O_RDONLY); + t518_testfd[0] = curlx_open(DEV_NULL, O_RDONLY); if(t518_testfd[0] < 0) { curl_msnprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL); t518_store_errmsg(strbuff, errno); diff --git a/tests/libtest/lib525.c b/tests/libtest/lib525.c index 007889fdc722..b34cd261af26 100644 --- a/tests/libtest/lib525.c +++ b/tests/libtest/lib525.c @@ -52,6 +52,7 @@ static CURLcode test_lib525(const char *URL) /* get the file size of the local file */ #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ hd = stat(libtest_arg2, &file_info); #else hd = fstat(fileno(hd_src), &file_info); diff --git a/tests/libtest/lib537.c b/tests/libtest/lib537.c index 90de8a2d0c75..b8bbfb7536c3 100644 --- a/tests/libtest/lib537.c +++ b/tests/libtest/lib537.c @@ -289,7 +289,7 @@ static int t537_test_rlimit(int keep_open) /* open a dummy descriptor */ - t537_testfd[0] = open(DEV_NULL, O_RDONLY); + t537_testfd[0] = curlx_open(DEV_NULL, O_RDONLY); if(t537_testfd[0] < 0) { curl_msnprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL); t537_store_errmsg(strbuff, errno); diff --git a/tests/libtest/lib541.c b/tests/libtest/lib541.c index 3bb64f8ac4a4..5e6e3c2f333b 100644 --- a/tests/libtest/lib541.c +++ b/tests/libtest/lib541.c @@ -52,6 +52,7 @@ static CURLcode test_lib541(const char *URL) /* get the file size of the local file */ #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ hd = stat(libtest_arg2, &file_info); #else hd = fstat(fileno(hd_src), &file_info); diff --git a/tests/libtest/lib568.c b/tests/libtest/lib568.c index 83c6fd23941c..6e53b7998956 100644 --- a/tests/libtest/lib568.c +++ b/tests/libtest/lib568.c @@ -66,7 +66,7 @@ static CURLcode test_lib568(const char *URL) curl_free(stream_uri); stream_uri = NULL; - sdp = open(libtest_arg2, O_RDONLY); + sdp = curlx_open(libtest_arg2, O_RDONLY); if(sdp == -1) { curl_mfprintf(stderr, "can't open %s\n", libtest_arg2); res = TEST_ERR_MAJOR_BAD; diff --git a/tests/libtest/lib572.c b/tests/libtest/lib572.c index ef5e06602357..c3951f8d1df6 100644 --- a/tests/libtest/lib572.c +++ b/tests/libtest/lib572.c @@ -84,7 +84,7 @@ static CURLcode test_lib572(const char *URL) stream_uri = NULL; /* PUT style GET_PARAMETERS */ - params = open(libtest_arg2, O_RDONLY); + params = curlx_open(libtest_arg2, O_RDONLY); if(params == -1) { curl_mfprintf(stderr, "can't open %s\n", libtest_arg2); res = TEST_ERR_MAJOR_BAD; diff --git a/tests/libtest/lib582.c b/tests/libtest/lib582.c index b1970632210d..9671c4b52f66 100644 --- a/tests/libtest/lib582.c +++ b/tests/libtest/lib582.c @@ -253,6 +253,7 @@ static CURLcode test_lib582(const char *URL) /* get the file size of the local file */ #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ hd = stat(libtest_arg2, &file_info); #else hd = fstat(fileno(hd_src), &file_info); diff --git a/tests/server/.checksrc b/tests/server/.checksrc index 670d4b800912..29331433c2cb 100644 --- a/tests/server/.checksrc +++ b/tests/server/.checksrc @@ -3,6 +3,7 @@ allowfunc fclose allowfunc fopen allowfunc freeaddrinfo allowfunc getaddrinfo +allowfunc open allowfunc recv allowfunc send allowfunc socket diff --git a/tests/server/util.c b/tests/server/util.c index 41f42ca42e09..749e33003c29 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -373,12 +373,12 @@ static void exit_signal_handler(int signum) (void)!write(STDERR_FILENO, msg, sizeof(msg) - 1); } else { - int fd; #ifdef _WIN32 - fd = _open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, S_IREAD | S_IWRITE); +#define OPENMODE S_IREAD | S_IWRITE #else - fd = open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR | S_IWUSR); +#define OPENMODE S_IRUSR | S_IWUSR #endif + int fd = open(serverlogfile, O_WRONLY | O_CREAT | O_APPEND, OPENMODE); if(fd != -1) { static const char msg[] = "exit_signal_handler: called\n"; (void)!write(fd, msg, sizeof(msg) - 1); From 583b1ad881daef798cd717c431de7f582a2a622c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 14:31:06 +0000 Subject: [PATCH 214/465] GHA: update dependency openssl/openssl to v3.5.4 Closes #18781 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 05d71b6f107a..ffcab39f1219 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -40,7 +40,7 @@ env: MAKEFLAGS: -j 5 CURL_CI: github # handled in renovate.json - OPENSSL_VERSION: 3.5.3 + OPENSSL_VERSION: 3.5.4 # handled in renovate.json QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 1d38c50db64d..606c83db84d8 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -48,7 +48,7 @@ env: # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # handled in renovate.json - OPENSSL_VERSION: 3.5.3 + OPENSSL_VERSION: 3.5.4 # handled in renovate.json QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=rustls/rustls-ffi versioning=semver registryUrl=https://github.com From f97aa8d7ed029ee99e097d9b0c9bd01570574478 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 30 Sep 2025 18:17:52 +0200 Subject: [PATCH 215/465] tidy-up: `fcntl.h` includes - drop from source files without obvious users. - include in `curlx/fopen.h` also for Windows. Follow-up to 9678ff5b1bfea1c847aee4f9edf023e8f01c9293 #18776 Closes #18782 --- lib/cf-ip-happy.c | 3 --- lib/cf-socket.c | 3 --- lib/connect.c | 3 --- lib/curlx/fopen.h | 7 ++++--- lib/rand.c | 3 --- lib/vtls/vtls.c | 3 --- lib/vtls/vtls_scache.c | 3 --- 7 files changed, 4 insertions(+), 21 deletions(-) diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index 0a1364e4b3f5..897b968114e6 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -41,9 +41,6 @@ #ifdef HAVE_NETDB_H #include #endif -#ifdef HAVE_FCNTL_H -#include -#endif #ifdef HAVE_ARPA_INET_H #include #endif diff --git a/lib/cf-socket.c b/lib/cf-socket.c index d5add9723f0d..cdd496a5e1dd 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -44,9 +44,6 @@ #ifdef HAVE_NETDB_H #include #endif -#ifdef HAVE_FCNTL_H -#include -#endif #ifdef HAVE_ARPA_INET_H #include #endif diff --git a/lib/connect.c b/lib/connect.c index 1182a42d31fa..4f42fef0e833 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -41,9 +41,6 @@ #ifdef HAVE_NETDB_H #include #endif -#ifdef HAVE_FCNTL_H -#include -#endif #ifdef HAVE_ARPA_INET_H #include #endif diff --git a/lib/curlx/fopen.h b/lib/curlx/fopen.h index d1e3d127c53d..b44cbbdfced2 100644 --- a/lib/curlx/fopen.h +++ b/lib/curlx/fopen.h @@ -28,6 +28,10 @@ #include "multibyte.h" +#ifdef HAVE_FCNTL_H +#include /* for open() and attributes */ +#endif + #if defined(_WIN32) && !defined(UNDER_CE) FILE *curlx_win32_fopen(const char *filename, const char *mode); int curlx_win32_stat(const char *path, struct_stat *buffer); @@ -36,9 +40,6 @@ int curlx_win32_open(const char *filename, int oflag, ...); #define curlx_stat(fname, stp) curlx_win32_stat(fname, stp) #define curlx_open curlx_win32_open #else -#ifdef HAVE_FCNTL_H -#include /* for open() */ -#endif #define CURLX_FOPEN_LOW fopen #define curlx_stat(fname, stp) stat(fname, stp) #define curlx_open open diff --git a/lib/rand.c b/lib/rand.c index f30f3de7c34d..8b7f07ae4055 100644 --- a/lib/rand.c +++ b/lib/rand.c @@ -26,9 +26,6 @@ #include -#ifdef HAVE_FCNTL_H -#include -#endif #ifdef HAVE_ARPA_INET_H #include #endif diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 9e3870e47005..1b1f66cc6eba 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -43,9 +43,6 @@ #ifdef HAVE_SYS_TYPES_H #include #endif -#ifdef HAVE_FCNTL_H -#include -#endif #include "../urldata.h" #include "../cfilters.h" diff --git a/lib/vtls/vtls_scache.c b/lib/vtls/vtls_scache.c index 662539cd8960..e934fa3b5eac 100644 --- a/lib/vtls/vtls_scache.c +++ b/lib/vtls/vtls_scache.c @@ -29,9 +29,6 @@ #ifdef HAVE_SYS_TYPES_H #include #endif -#ifdef HAVE_FCNTL_H -#include -#endif #include "../urldata.h" #include "../cfilters.h" From d8823e855c2698e840f6a1faf9aad3adbe4b9fdc Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 29 Sep 2025 16:44:35 +0200 Subject: [PATCH 216/465] asyn-thrdd resolver: clear timeout when done When the async threaded resolver thread returned, clear the started EXPIRE_ASYNC_NAME timeout. Closes #18769 --- lib/asyn-thrdd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index 2edef32f7b38..2aa16de7287c 100644 --- a/lib/asyn-thrdd.c +++ b/lib/asyn-thrdd.c @@ -611,6 +611,7 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, data->state.async.done = TRUE; Curl_resolv_unlink(data, &data->state.async.dns); + Curl_expire_done(data, EXPIRE_ASYNC_NAME); if(thrdd->addr->res) { data->state.async.dns = From b02238975768d0bcbf8c7ef00eaaee3ec379f4ff Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 29 Sep 2025 16:38:55 +0200 Subject: [PATCH 217/465] ip-happy: do not set unnecessary timeout When attempts on all addresses have been started, do no longer set any EXPIRE_HAPPY_EYEBALLS timeouts. Fixes #18767 Reported-by: Johannes Schindelin Closes #18768 --- docs/libcurl/curl_global_trace.md | 4 ++ lib/cf-ip-happy.c | 58 ++++++++++++++++--------- lib/cf-socket.c | 5 ++- lib/curl_trc.c | 39 ++++++++++++----- lib/curl_trc.h | 21 ++++++---- lib/multi.c | 70 ++++++++++++++++--------------- tests/http/test_06_eyeballs.py | 32 ++++++++++++++ tests/http/testenv/curl.py | 3 ++ 8 files changed, 159 insertions(+), 73 deletions(-) diff --git a/docs/libcurl/curl_global_trace.md b/docs/libcurl/curl_global_trace.md index 4a21bdc45569..0459eab6747d 100644 --- a/docs/libcurl/curl_global_trace.md +++ b/docs/libcurl/curl_global_trace.md @@ -138,6 +138,10 @@ Tracing of SSL Session handling, e.g. caching/import/export. Tracing of SMTP operations when this protocol is enabled in your build. +## `timer` + +Tracing of timers set for transfers. + ## `write` Traces writing of download data, received from the server, to the application. diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index 897b968114e6..47560889d446 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -153,12 +153,17 @@ static const struct Curl_addrinfo *cf_ai_iter_next(struct cf_ai_iter *iter) return iter->last; } -#ifdef USE_IPV6 -static bool cf_ai_iter_done(struct cf_ai_iter *iter) +static bool cf_ai_iter_has_more(struct cf_ai_iter *iter) { - return (iter->n >= 0) && !iter->last; + const struct Curl_addrinfo *addr = iter->last ? iter->last->ai_next : + ((iter->n < 0) ? iter->head : NULL); + while(addr) { + if(addr->ai_family == iter->ai_family) + return TRUE; + addr = addr->ai_next; + } + return FALSE; } -#endif struct cf_ip_attempt { struct cf_ip_attempt *next; @@ -353,7 +358,7 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, { CURLcode result = CURLE_OK; struct cf_ip_attempt *a = NULL, **panchor; - bool do_more, more_possible; + bool do_more; struct curltime now; timediff_t next_expire_ms; int i, inconclusive, ongoing; @@ -364,7 +369,6 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, evaluate: now = curlx_now(); ongoing = inconclusive = 0; - more_possible = TRUE; /* check if a running baller connects now */ i = -1; @@ -404,7 +408,13 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, do_more = TRUE; } else { - do_more = (curlx_timediff(now, bs->last_attempt_started) >= + bool more_possible = cf_ai_iter_has_more(&bs->addr_iter); +#ifdef USE_IPV6 + if(!more_possible) + more_possible = cf_ai_iter_has_more(&bs->ipv6_iter); +#endif + do_more = more_possible && + (curlx_timediff(now, bs->last_attempt_started) >= bs->attempt_delay_ms); if(do_more) CURL_TRC_CF(data, cf, "happy eyeballs timeout expired, " @@ -418,7 +428,7 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, int ai_family = 0; #ifdef USE_IPV6 if((bs->last_attempt_ai_family == AF_INET) || - cf_ai_iter_done(&bs->addr_iter)) { + !cf_ai_iter_has_more(&bs->addr_iter)) { addr = cf_ai_iter_next(&bs->ipv6_iter); ai_family = bs->ipv6_iter.ai_family; } @@ -472,11 +482,8 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, /* attempt timeout for restart has not expired yet */ goto out; } - else if(ongoing) { + else if(!ongoing) { /* no more addresses, no inconclusive attempts */ - more_possible = FALSE; - } - else { CURL_TRC_CF(data, cf, "no more attempts to try"); result = CURLE_COULDNT_CONNECT; i = 0; @@ -490,21 +497,34 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, out: if(!result) { + bool more_possible; + /* when do we need to be called again? */ next_expire_ms = Curl_timeleft(data, &now, TRUE); + if(next_expire_ms <= 0) { + failf(data, "Connection timeout after %" FMT_OFF_T " ms", + curlx_timediff(now, data->progress.t_startsingle)); + return CURLE_OPERATION_TIMEDOUT; + } + + more_possible = cf_ai_iter_has_more(&bs->addr_iter); +#ifdef USE_IPV6 + if(!more_possible) + more_possible = cf_ai_iter_has_more(&bs->ipv6_iter); +#endif if(more_possible) { timediff_t expire_ms, elapsed_ms; elapsed_ms = curlx_timediff(now, bs->last_attempt_started); expire_ms = CURLMAX(bs->attempt_delay_ms - elapsed_ms, 0); next_expire_ms = CURLMIN(next_expire_ms, expire_ms); + if(next_expire_ms <= 0) { + CURL_TRC_CF(data, cf, "HAPPY_EYBALLS timeout due, re-evaluate"); + goto evaluate; + } + CURL_TRC_CF(data, cf, "next HAPPY_EYBALLS timeout in %" FMT_TIMEDIFF_T + "ms", next_expire_ms); + Curl_expire(data, next_expire_ms, EXPIRE_HAPPY_EYEBALLS); } - - if(next_expire_ms <= 0) { - failf(data, "Connection timeout after %" FMT_OFF_T " ms", - curlx_timediff(now, data->progress.t_startsingle)); - return CURLE_OPERATION_TIMEDOUT; - } - Curl_expire(data, next_expire_ms, EXPIRE_HAPPY_EYEBALLS); } return result; } diff --git a/lib/cf-socket.c b/lib/cf-socket.c index cdd496a5e1dd..3d1f5e752950 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1329,7 +1329,8 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf, rc = SOCKET_WRITABLE(ctx->sock, 0); if(rc == 0) { /* no connection yet */ - CURL_TRC_CF(data, cf, "not connected yet"); + CURL_TRC_CF(data, cf, "not connected yet on fd=%" FMT_SOCKET_T, + ctx->sock); return CURLE_OK; } else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) { @@ -1339,7 +1340,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf, set_local_ip(cf, data); *done = TRUE; cf->connected = TRUE; - CURL_TRC_CF(data, cf, "connected"); + CURL_TRC_CF(data, cf, "connected on fd=%" FMT_SOCKET_T, ctx->sock); return CURLE_OK; } } diff --git a/lib/curl_trc.c b/lib/curl_trc.c index 9426adcede4f..27dc2b3b44cd 100644 --- a/lib/curl_trc.c +++ b/lib/curl_trc.c @@ -272,6 +272,10 @@ struct curl_trc_feat Curl_trc_feat_dns = { "DNS", CURL_LOG_LVL_NONE, }; +struct curl_trc_feat Curl_trc_feat_timer = { + "TIMER", + CURL_LOG_LVL_NONE, +}; static const char * const Curl_trc_timer_names[]={ "100_TIMEOUT", @@ -291,24 +295,36 @@ static const char * const Curl_trc_timer_names[]={ "SHUTDOWN", }; -const char *Curl_trc_timer_name(int tid) +static const char *trc_timer_name(int tid) { if((tid >= 0) && ((size_t)tid < CURL_ARRAYSIZE(Curl_trc_timer_names))) return Curl_trc_timer_names[(size_t)tid]; return "UNKNOWN?"; } -void Curl_trc_multi_timeouts(struct Curl_easy *data) +void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...) { - struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist); - if(e) { - struct curltime now = curlx_now(); - while(e) { - struct time_node *n = Curl_node_elem(e); - e = Curl_node_next(e); - CURL_TRC_M(data, "[TIMEOUT] %s expires in %" FMT_TIMEDIFF_T "ns", - CURL_TIMER_NAME(n->eid), - curlx_timediff_us(n->time, now)); + DEBUGASSERT(!strchr(fmt, '\n')); + if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_timer)) { + const char *tname = trc_timer_name(tid); + va_list ap; + va_start(ap, fmt); + trc_infof(data, &Curl_trc_feat_timer, tname, 0, fmt, ap); + va_end(ap); + } +} +void Curl_trc_easy_timers(struct Curl_easy *data) +{ + if(CURL_TRC_TIMER_is_verbose(data)) { + struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist); + if(e) { + struct curltime now = curlx_now(); + while(e) { + struct time_node *n = Curl_node_elem(e); + e = Curl_node_next(e); + CURL_TRC_TIMER(data, n->eid, "expires in %" FMT_TIMEDIFF_T "ns", + curlx_timediff_us(n->time, now)); + } } } } @@ -476,6 +492,7 @@ static struct trc_feat_def trc_feats[] = { { &Curl_trc_feat_read, TRC_CT_NONE }, { &Curl_trc_feat_write, TRC_CT_NONE }, { &Curl_trc_feat_dns, TRC_CT_NETWORK }, + { &Curl_trc_feat_timer, TRC_CT_NETWORK }, #ifndef CURL_DISABLE_FTP { &Curl_trc_feat_ftp, TRC_CT_PROTOCOL }, #endif diff --git a/lib/curl_trc.h b/lib/curl_trc.h index 37a373e4a6a6..1a3f8f374e2d 100644 --- a/lib/curl_trc.h +++ b/lib/curl_trc.h @@ -86,7 +86,7 @@ void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...) CURL_PRINTF(2, 3); const char *Curl_trc_mstate_name(int state); const char *Curl_trc_timer_name(int tid); -void Curl_trc_multi_timeouts(struct Curl_easy *data); +void Curl_trc_easy_timers(struct Curl_easy *data); void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...) CURL_PRINTF(2, 3); @@ -94,6 +94,8 @@ void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...) CURL_PRINTF(2, 3); void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...) CURL_PRINTF(2, 3); +void Curl_trc_timer(struct Curl_easy *data, int tid, + const char *fmt, ...) CURL_PRINTF(3, 4); struct curl_trc_feat { const char *name; @@ -125,6 +127,8 @@ void Curl_trc_ws(struct Curl_easy *data, Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi) #define CURL_TRC_DNS_is_verbose(data) \ Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns) +#define CURL_TRC_TIMER_is_verbose(data) \ + Curl_trc_ft_is_verbose(data, &Curl_trc_feat_timer) #if defined(CURL_HAVE_C99) && !defined(CURL_DISABLE_VERBOSE_STRINGS) #define infof(data, ...) \ @@ -145,6 +149,9 @@ void Curl_trc_ws(struct Curl_easy *data, #define CURL_TRC_DNS(data, ...) \ do { if(CURL_TRC_DNS_is_verbose(data)) \ Curl_trc_dns(data, __VA_ARGS__); } while(0) +#define CURL_TRC_TIMER(data, tid, ...) \ + do { if(CURL_TRC_TIMER_is_verbose(data)) \ + Curl_trc_timer(data, tid, __VA_ARGS__); } while(0) #ifndef CURL_DISABLE_FTP #define CURL_TRC_FTP(data, ...) \ @@ -175,6 +182,7 @@ void Curl_trc_ws(struct Curl_easy *data, #define CURL_TRC_WRITE Curl_trc_write #define CURL_TRC_READ Curl_trc_read #define CURL_TRC_DNS Curl_trc_dns +#define CURL_TRC_TIMER Curl_trc_timer #ifndef CURL_DISABLE_FTP #define CURL_TRC_FTP Curl_trc_ftp @@ -198,6 +206,7 @@ extern struct curl_trc_feat Curl_trc_feat_multi; extern struct curl_trc_feat Curl_trc_feat_read; extern struct curl_trc_feat Curl_trc_feat_write; extern struct curl_trc_feat Curl_trc_feat_dns; +extern struct curl_trc_feat Curl_trc_feat_timer; #define Curl_trc_is_verbose(data) \ ((data) && (data)->set.verbose && \ @@ -210,10 +219,9 @@ extern struct curl_trc_feat Curl_trc_feat_dns; (Curl_trc_is_verbose(data) && \ (ft)->log_level >= CURL_LOG_LVL_INFO) #define CURL_MSTATE_NAME(s) Curl_trc_mstate_name((int)(s)) -#define CURL_TIMER_NAME(t) Curl_trc_timer_name((int)(t)) -#define CURL_TRC_M_TIMEOUTS(data) \ - do { if(CURL_TRC_M_is_verbose(data)) \ - Curl_trc_multi_timeouts(data); } while(0) +#define CURL_TRC_EASY_TIMERS(data) \ + do { if(CURL_TRC_TIMER_is_verbose(data)) \ + Curl_trc_easy_timers(data); } while(0) #else /* CURL_DISABLE_VERBOSE_STRINGS */ /* All informational messages are not compiled in for size savings */ @@ -222,8 +230,7 @@ extern struct curl_trc_feat Curl_trc_feat_dns; #define Curl_trc_cf_is_verbose(x,y) (FALSE) #define Curl_trc_ft_is_verbose(x,y) (FALSE) #define CURL_MSTATE_NAME(x) ((void)(x), "-") -#define CURL_TIMER_NAME(x) ((void)(x), "-") -#define CURL_TRC_M_TIMEOUTS(x) Curl_nop_stmt +#define CURL_TRC_EASY_TIMERS(x) Curl_nop_stmt #endif /* !CURL_DISABLE_VERBOSE_STRINGS */ diff --git a/lib/multi.c b/lib/multi.c index 442956f84416..ae38f5f4439b 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1135,7 +1135,7 @@ CURLMcode Curl_multi_pollset(struct Curl_easy *data, caller, ps->n, timeout_count); break; } - CURL_TRC_M_TIMEOUTS(data); + CURL_TRC_EASY_TIMERS(data); } if(expect_sockets && !ps->n && data->multi && @@ -3050,7 +3050,13 @@ static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc) data = Curl_splayget(t); /* assign this for next loop */ if(!data) continue; - + if(CURL_TRC_TIMER_is_verbose(data)) { + struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist); + if(e) { + struct time_node *n = Curl_node_elem(e); + CURL_TRC_TIMER(data, n->eid, "has expired"); + } + } (void)add_next_timeout(mrc->now, multi, data); Curl_multi_mark_dirty(data); } @@ -3323,6 +3329,7 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms) { static const struct curltime tv_zero = {0, 0}; + struct Curl_easy *data = NULL; if(multi->dead) { *timeout_ms = 0; @@ -3350,14 +3357,14 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, curlx_timediff_us(multi->timetree->key, now) > 0) { /* some time left before expiration */ timediff_t diff = curlx_timediff_ceil(multi->timetree->key, now); + data = Curl_splayget(multi->timetree); /* this should be safe even on 32-bit archs, as we do not use that overly long timeouts */ *timeout_ms = (long)diff; } else { if(multi->timetree) { - struct Curl_easy *data = Curl_splayget(multi->timetree); - CURL_TRC_M(data, "multi_timeout() says this has expired"); + data = Curl_splayget(multi->timetree); } /* 0 means immediately */ *timeout_ms = 0; @@ -3368,6 +3375,16 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, *timeout_ms = -1; } + if(data && CURL_TRC_TIMER_is_verbose(data)) { + struct Curl_llist_node *e = + Curl_llist_head(&data->state.timeoutlist); + if(e) { + struct time_node *n = Curl_node_elem(e); + CURL_TRC_TIMER(data, n->eid, "gives multi timeout in %ldms", + *timeout_ms); + } + } + return CURLM_OK; } @@ -3387,8 +3404,6 @@ CURLMcode curl_multi_timeout(CURLM *m, return multi_timeout(multi, &expire_time, timeout_ms); } -#define DEBUG_UPDATE_TIMER 0 - /* * Tell the application it should update its timers, if it subscribes to the * update timer callback. @@ -3407,47 +3422,34 @@ CURLMcode Curl_update_timer(struct Curl_multi *multi) } if(timeout_ms < 0 && multi->last_timeout_ms < 0) { -#if DEBUG_UPDATE_TIMER - fprintf(stderr, "Curl_update_timer(), still no timeout, no change\n"); -#endif + /* nothing to do */ } else if(timeout_ms < 0) { /* there is no timeout now but there was one previously */ -#if DEBUG_UPDATE_TIMER - fprintf(stderr, "Curl_update_timer(), remove timeout, " - " last_timeout=%ldms\n", multi->last_timeout_ms); -#endif + CURL_TRC_M(multi->admin, "[TIMER] clear"); timeout_ms = -1; /* normalize */ set_value = TRUE; } else if(multi->last_timeout_ms < 0) { -#if DEBUG_UPDATE_TIMER - fprintf(stderr, "Curl_update_timer(), had no timeout, set now\n"); -#endif + CURL_TRC_M(multi->admin, "[TIMER] set %ldms, none before", + timeout_ms); set_value = TRUE; } else if(curlx_timediff_us(multi->last_expire_ts, expire_ts)) { /* We had a timeout before and have one now, the absolute timestamp * differs. The relative timeout_ms may be the same, but the starting * point differs. Let the application restart its timer. */ -#if DEBUG_UPDATE_TIMER - fprintf(stderr, "Curl_update_timer(), expire timestamp changed\n"); -#endif + CURL_TRC_M(multi->admin, "[TIMER] set %ldms, replace previous", + timeout_ms); set_value = TRUE; } else { /* We have same expire time as previously. Our relative 'timeout_ms' * may be different now, but the application has the timer running * and we do not to tell it to start this again. */ -#if DEBUG_UPDATE_TIMER - fprintf(stderr, "Curl_update_timer(), same expire timestamp, no change\n"); -#endif } if(set_value) { -#if DEBUG_UPDATE_TIMER - fprintf(stderr, "Curl_update_timer(), set timeout %ldms\n", timeout_ms); -#endif multi->last_expire_ts = expire_ts; multi->last_timeout_ms = timeout_ms; set_in_callback(multi, TRUE); @@ -3491,7 +3493,8 @@ multi_deltimeout(struct Curl_easy *data, expire_id eid) static CURLMcode multi_addtimeout(struct Curl_easy *data, struct curltime *stamp, - expire_id eid) + expire_id eid, + const struct curltime *nowp) { struct Curl_llist_node *e; struct time_node *node; @@ -3499,6 +3502,7 @@ multi_addtimeout(struct Curl_easy *data, size_t n; struct Curl_llist *timeoutlist = &data->state.timeoutlist; + (void)nowp; node = &data->state.expires[eid]; /* copy the timestamp and id */ @@ -3521,6 +3525,8 @@ multi_addtimeout(struct Curl_easy *data, this is the first timeout on the list */ Curl_llist_insert_next(timeoutlist, prev, node, &node->list); + CURL_TRC_TIMER(data, eid, "set for %" FMT_TIMEDIFF_T "ns", + curlx_timediff_us(node->time, *nowp)); return CURLM_OK; } @@ -3553,7 +3559,7 @@ void Curl_expire_ex(struct Curl_easy *data, /* Add it to the timer list. It must stay in the list until it has expired in case we need to recompute the minimum timer later. */ - multi_addtimeout(data, &set, id); + multi_addtimeout(data, &set, id, nowp); if(curr_expire->tv_sec || curr_expire->tv_usec) { /* This means that the struct is added as a node in the splay tree. @@ -3582,9 +3588,6 @@ void Curl_expire_ex(struct Curl_easy *data, Curl_splayset(&data->state.timenode, data); multi->timetree = Curl_splayinsert(*curr_expire, multi->timetree, &data->state.timenode); - if(data->id >= 0) - CURL_TRC_M(data, "[TIMEOUT] set %s to expire in %" FMT_TIMEDIFF_T "ns", - CURL_TIMER_NAME(id), curlx_timediff_us(set, *nowp)); } /* @@ -3610,12 +3613,11 @@ void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id) * Removes the expire timer. Marks it as done. * */ -void Curl_expire_done(struct Curl_easy *data, expire_id id) +void Curl_expire_done(struct Curl_easy *data, expire_id eid) { /* remove the timer, if there */ - multi_deltimeout(data, id); - if(data->id >= 0) - CURL_TRC_M(data, "[TIMEOUT] cleared %s", CURL_TIMER_NAME(id)); + multi_deltimeout(data, eid); + CURL_TRC_TIMER(data, eid, "cleared"); } /* diff --git a/tests/http/test_06_eyeballs.py b/tests/http/test_06_eyeballs.py index 038721fbf9b4..d05eb3c7da58 100644 --- a/tests/http/test_06_eyeballs.py +++ b/tests/http/test_06_eyeballs.py @@ -25,6 +25,7 @@ ########################################################################### # import logging +import re import pytest from testenv import Env, CurlClient @@ -100,3 +101,34 @@ def test_06_12_stats_fail_tcp(self, env: Env, httpd, nghttpx): r.check_response(count=1, http_status=None, exitcode=False) assert r.stats[0]['time_connect'] == 0 # no one should have listened assert r.stats[0]['time_appconnect'] == 0 # did not happen either + + # check timers when trying 3 unresponsive addresses + @pytest.mark.skipif(condition=not Env.curl_has_feature('IPv6'), + reason='curl lacks ipv6 support') + def test_06_13_timers(self, env: Env): + curl = CurlClient(env=env) + # ipv6 0100::/64 is supposed to go into the void (rfc6666) + r = curl.http_download(urls=['https://xxx.invalid/'], extra_args=[ + '--resolve', 'xxx.invalid:443:0100::1,0100::2,0100::3', + '--connect-timeout', '1', + '--happy-eyeballs-timeout-ms', '123', + '--trace-config', 'timer,happy-eyeballs,tcp' + ]) + r.check_response(count=1, http_status=None, exitcode=False) + assert r.stats[0]['time_connect'] == 0 # no one connected + # check that we indeed started attempts on all 3 addresses + tcp_attempts = [line for line in r.trace_lines + if re.match(r'.*Trying \[100::[123]]:443', line)] + assert len(tcp_attempts) == 3, f'fond: {"".join(tcp_attempts)}\n{r.dump_logs()}' + # if the 0100::/64 really goes into the void, we should see 2 HAPPY_EYEBALLS + # timeouts being set here + failed_attempts = [line for line in r.trace_lines + if re.match(r'.*checked connect attempts: 0 ongoing', line)] + if len(failed_attempts): + # github CI fails right away with "Network is unreachable", slackers... + assert len(failed_attempts) == 3, f'found: {"".join(failed_attempts)}\n{r.dump_logs()}' + else: + # no immediately failed attempts, as should be + he_timers_set = [line for line in r.trace_lines + if re.match(r'.*\[TIMER] \[HAPPY_EYEBALLS] set for', line)] + assert len(he_timers_set) == 2, f'found: {"".join(he_timers_set)}\n{r.dump_logs()}' diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py index 7c3f6e72d97c..f8e7b12a2641 100644 --- a/tests/http/testenv/curl.py +++ b/tests/http/testenv/curl.py @@ -895,6 +895,9 @@ def _complete_args(self, urls, timeout=None, options=None, if not isinstance(urls, list): urls = [urls] + if options is not None and '--resolve' in options: + force_resolve = False + args = [self._curl, "-s", "--path-as-is"] if 'CURL_TEST_EVENT' in os.environ: args.append('--test-event') From f284222ffc852c2d908bf5e8397cf4ac7fc91a42 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 1 Oct 2025 08:16:45 +0200 Subject: [PATCH 218/465] TODO: fix a typo Closes #18788 --- docs/TODO | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/TODO b/docs/TODO index d7416f9c8e1b..4db3f5f4ed21 100644 --- a/docs/TODO +++ b/docs/TODO @@ -531,7 +531,7 @@ 5.2 Obey Retry-After in redirects - The Retry-After is said to dicate "the minimum time that the user agent is + The Retry-After is said to dictate "the minimum time that the user agent is asked to wait before issuing the redirected request" and libcurl does not obey this. From a2b7a4157c2b83b523ed6e6886e28d48208e33fb Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 1 Oct 2025 08:19:35 +0200 Subject: [PATCH 219/465] typos.toml: exclude more from typo checks - exclude visual studio project templates - exclude test cases - allow 'proxys' which is used for "secure proxy" in test code - allow Tru64 and secur32 Closes #18789 --- .github/scripts/typos.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/scripts/typos.toml b/.github/scripts/typos.toml index 73ecac136aca..97c682b5b6ee 100644 --- a/.github/scripts/typos.toml +++ b/.github/scripts/typos.toml @@ -12,6 +12,10 @@ extend-ignore-identifiers-re = [ "^[0-9a-zA-Z+]{64,}$", # possibly base64 "^(Januar|eyeballers|HELO_smtp|kno22|MkTypLibCompatible|optin|passin|perfec|__SecURE|SMTP_HELO|v_alue)$", "^(clen|req_clen|smtp_perform_helo|smtp_state_helo_resp|_stati64)$", + "^Tru64$", + "secur32", + # this should be limited to tests/http/*. Short for secure proxy. + "proxys", ] extend-ignore-re = [ @@ -25,4 +29,7 @@ extend-exclude = [ "docs/THANKS", "packages/*", "scripts/wcurl", + "projects/Windows/tmpl/curl.vcxproj", + "projects/Windows/tmpl/libcurl.vcxproj", + "tests/data/test*", ] From 205758d7eaad31b256812ce4da64c2ca01951cc1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 1 Oct 2025 09:12:10 +0200 Subject: [PATCH 220/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 511be250eb03..3977134b8379 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,7 +4,7 @@ curl and libcurl 8.17.0 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3509 + Contributors: 3510 This release includes the following changes: @@ -17,6 +17,7 @@ This release includes the following changes: This release includes the following bugfixes: o ares: fix leak in tracing [91] + o asyn-thrdd resolver: clear timeout when done [97] o asyn-thrdd: drop pthread_cancel [30] o autotools: add support for libgsasl auto-detection via pkg-config [112] o autotools: capitalize 'Rustls' in the log output [106] @@ -26,15 +27,21 @@ This release includes the following bugfixes: o aws-lc: re-enable large read-ahead with v1.61.0 again [16] o base64: accept zero length argument to base64_encode [82] o build: address some `-Weverything` warnings, update picky warnings [74] + o build: avoid overriding system `open` and `stat` symbols [141] + o build: avoid overriding system symbols for fopen functions [150] o build: avoid overriding system symbols for socket functions [68] o build: show llvm/clang in platform flags and `buildinfo.txt` [126] o cf-h2-proxy: break loop on edge case [140] + o cf-ip-happy: mention unix domain path, not port number [161] o cf-socket: use the right byte order for ports in bindlocal [61] o cfilter: unlink and discard [46] + o checksrc: catch banned functions when preceded by `(` [146] + o checksrc: fix possible endless loop when detecting `BANNEDFUNC` [149] o cmake: add `CURL_CODE_COVERAGE` option [78] o cmake: clang detection tidy-ups [116] o cmake: fix building docs when the base directory contains `.3` [18] o cmake: use modern alternatives for `get_filename_component()` [102] + o cmake: use more `COMPILER_OPTIONS`, `LINK_OPTIONS` / `LINK_FLAGS` [152] o cmdline-docs: extended, clarified, refreshed [28] o configure: add "-mt" for pthread support on HP-UX [52] o cookie: avoid saving a cookie file if no transfer was done [11] @@ -54,11 +61,14 @@ This release includes the following bugfixes: o docs: fix/tidy code fences [87] o easy_getinfo: check magic, Curl_close safety [3] o examples: fix two issues found by CodeQL [35] + o examples: fix two more cases of `stat()` TOCTOU [147] o ftp: fix ftp_do_more returning with *completep unset [122] o ftp: fix port number range loop for PORT commands [66] o gtls: avoid potential use of uninitialized variable in trace output [83] o hostip: remove leftover INT_MAX check in Curl_dnscache_prune [88] + o http: handle user-defined connection headers [165] o httpsrr: free old pointers when storing new [57] + o ip-happy: do not set unnecessary timeout [95] o krb5: return appropriate error on send failures [22] o ldap: do not base64 encode zero length string [42] o lib: upgrade/multiplex handling [136] @@ -84,6 +94,7 @@ This release includes the following bugfixes: o ngtcp2: check error code on connect failure [13] o ngtcp2: fix early return [131] o openldap: avoid indexing the result at -1 for blank responses [44] + o openldap: check ber_sockbuf_add_io() return code [163] o openldap: check ldap_get_option() return codes [119] o openssl-quic: check results better [132] o openssl-quic: handle error in SSL_get_stream_read_error_code [129] @@ -122,15 +133,18 @@ This release includes the following bugfixes: o telnet: make printsub require another byte input [21] o telnet: refuse IAC codes in content [111] o telnet: return error on crazy TTYPE or XDISPLOC lengths [123] + o tests/server: drop unsafe `open()` override in signal handler (Windows) [151] o tftp: check and act on tftp_set_timeouts() returning error [38] o tftp: handle tftp_multi_statemach() return code [65] o tftp: pin the first used address [110] o tftp: propagate expired timer from tftp_state_timeout() [39] o tftp: return error when sendto() fails [59] + o tidy-up: `fcntl.h` includes [98] o tidy-up: assortment of small fixes [115] o tidy-up: avoid using the reserved macro namespace [76] o tidy-up: update MS links, allow long URLs via `checksrc` [73] o tidy-up: URLs [101] + o TODO: fix a typo [93] o TODO: remove already implemented or bad items [36] o tool: fix exponential retry delay [47] o tool_cb_hdr: fix fwrite check in header callback [49] @@ -139,6 +153,7 @@ This release includes the following bugfixes: o tool_getparam/set_rate: skip the multiplication on overflow [84] o tool_operate: improve wording in retry message [37] o tool_operate: keep the progress meter for --out-null [33] + o tool_progress: handle possible integer overflows [164] o transfer: avoid busy loop with tiny speed limit [100] o urldata: FILE is not a list-only protocol [9] o vtls: alpn setting, check proto parameter [134] @@ -174,12 +189,13 @@ advice from friends like these: Adam Light, Andrew Kirillov, Andrew Olsen, BobodevMm on github, Christian Schmitz, Dan Fandrich, Daniel Stenberg, dependabot[bot], divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, - fds242 on github, Javier Blazquez, Jicea, jmaggard10 on github, - Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, Marcel Raad, - Michael Osipov, Michał Petryka, Nir Azkiel, Patrick Monnerat, Ray Satiro, - renovate[bot], rinsuki on github, Samuel Dionne-Riel, Stanislav Fort, - Stefan Eissing, Viktor Szakats - (30 contributors) + Evgeny Grin (Karlson2k), fds242 on github, Howard Chu, Javier Blazquez, + Jicea, jmaggard10 on github, Johannes Schindelin, Joseph Birr-Pixton, + Joshua Rogers, kapsiR on github, kuchara on github, Marcel Raad, + Michael Osipov, Michał Petryka, Mohamed Daahir, Nir Azkiel, Patrick Monnerat, + Ray Satiro, renovate[bot], rinsuki on github, Samuel Dionne-Riel, + Stanislav Fort, Stefan Eissing, Viktor Szakats + (35 contributors) References to bug reports and discussions on issues: @@ -274,8 +290,12 @@ References to bug reports and discussions on issues: [90] = https://curl.se/bug/?i=18681 [91] = https://curl.se/bug/?i=18251 [92] = https://curl.se/bug/?i=18739 + [93] = https://curl.se/bug/?i=18788 [94] = https://curl.se/bug/?i=18722 + [95] = https://curl.se/bug/?i=18767 [96] = https://curl.se/bug/?i=18737 + [97] = https://curl.se/bug/?i=18769 + [98] = https://curl.se/bug/?i=18782 [99] = https://curl.se/bug/?i=18733 [100] = https://curl.se/bug/?i=18732 [101] = https://curl.se/bug/?i=18689 @@ -317,7 +337,18 @@ References to bug reports and discussions on issues: [137] = https://curl.se/bug/?i=18719 [139] = https://curl.se/bug/?i=18714 [140] = https://curl.se/bug/?i=18715 + [141] = https://curl.se/bug/?i=18776 [142] = https://curl.se/bug/?i=18713 [143] = https://curl.se/bug/?i=18712 [144] = https://curl.se/bug/?i=18711 [145] = https://curl.se/bug/?i=18682 + [146] = https://curl.se/bug/?i=18779 + [147] = https://curl.se/bug/?i=18778 + [149] = https://curl.se/bug/?i=18775 + [150] = https://curl.se/bug/?i=18510 + [151] = https://curl.se/bug/?i=18774 + [152] = https://curl.se/bug/?i=18762 + [161] = https://curl.se/bug/?i=18749 + [163] = https://curl.se/bug/?i=18747 + [164] = https://curl.se/bug/?i=18744 + [165] = https://curl.se/bug/?i=18662 From a5a17b8ddb69195595b145d3b985a080a87acdc9 Mon Sep 17 00:00:00 2001 From: Samuel Henrique Date: Sat, 27 Sep 2025 09:42:08 +0100 Subject: [PATCH 221/465] wcurl: import v2025.09.27 Closes #18754 --- docs/wcurl.md | 12 +++++++++--- scripts/wcurl | 51 +++++++++++++++++++++++++++------------------------ 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/docs/wcurl.md b/docs/wcurl.md index 4111af52260a..ab5f956fc029 100644 --- a/docs/wcurl.md +++ b/docs/wcurl.md @@ -45,6 +45,9 @@ By default, **wcurl** does: ## * Download multiple URLs in parallel if the installed curl's version is \>= 7.66.0 (--parallel); +## * Use a total number of 5 parallel connections to the same protocol + hostname + port number target + if the installed curl's version is \>= 8.16.0 (--parallel-max-host); + ## * Follow redirects; ## * Automatically choose a filename as output; @@ -124,10 +127,13 @@ Download a file passing the **--progress-bar** and **--http2** flags to curl: **wcurl --curl-options="--progress-bar --http2" example.com/filename.txt** -Resume from an interrupted download (if more options are used, this needs to -be the last one in the list): +* Resume from an interrupted download. The options necessary to resume the download (`--clobber --continue-at -`) must be the **last** options specified in `--curl-options`. Note that the only way to resume interrupted downloads is to allow wcurl to overwrite the destination file: + +**wcurl --curl-options="--clobber --continue-at -" example.com/filename.txt** + +Download multiple files without a limit of concurrent connections per host (the default limit is 5): -**wcurl --curl-options="--continue-at -" example.com/filename.txt** +**wcurl --curl-options="--parallel-max-host 0" example.com/filename1.txt example.com/filename2.txt** # AUTHORS diff --git a/scripts/wcurl b/scripts/wcurl index af66ae7fcac7..1014779e131b 100755 --- a/scripts/wcurl +++ b/scripts/wcurl @@ -29,7 +29,7 @@ # Stop on errors and on usage of unset variables. set -eu -VERSION="2025.05.26" +VERSION="2025.09.27" PROGRAM_NAME="$(basename "$0")" readonly PROGRAM_NAME @@ -91,7 +91,7 @@ error() # Extra curl options provided by the user. # This is set per-URL for every URL provided. -# Some options are global, but we are erroring on the side of needlesly setting +# Some options are global, but we are erroring on the side of needlessly setting # them multiple times instead of causing issues with parameters that needs to # be set per-URL. CURL_OPTIONS="" @@ -133,7 +133,7 @@ sanitize() is_subset_of() { case "${1}" in - *[!${2}]*|'') return 1;; + *[!${2}]* | '') return 1 ;; esac } @@ -151,9 +151,9 @@ percent_decode() decode_out="${decode_out}${decode_hex2}" # Skip decoding if this is a control character (00-1F). # Skip decoding if DECODE_FILENAME is not "true". - if is_subset_of "${decode_hex1}" "23456789abcdefABCDEF" && \ - is_subset_of "${decode_hex2}" "0123456789abcdefABCDEF" && \ - [ "${DECODE_FILENAME}" = "true" ]; then + if is_subset_of "${decode_hex1}" "23456789abcdefABCDEF" \ + && is_subset_of "${decode_hex2}" "0123456789abcdefABCDEF" \ + && [ "${DECODE_FILENAME}" = "true" ]; then # Use printf to decode it into octal and then decode it to the final format. decode_out="$(printf "%b" "\\$(printf %o "0x${decode_hex1}${decode_hex2}")")" fi @@ -171,7 +171,7 @@ get_url_filename() # If what remains contains a slash, there's a path; return it percent-decoded. case "${hostname_and_path}" in # sed to remove everything preceding the last '/', e.g.: "example/something" becomes "something" - */*) percent_decode "$(printf %s "${hostname_and_path}" | sed -e 's,^.*/,,')";; + */*) percent_decode "$(printf %s "${hostname_and_path}" | sed -e 's,^.*/,,')" ;; esac # No slash means there was just a hostname and no path; return empty string. } @@ -181,35 +181,38 @@ exec_curl() { CMD="curl " - # Store version to check if it supports --no-clobber and --parallel. + # Store version to check if it supports --no-clobber, --parallel and --parallel-max-host. curl_version=$($CMD --version | cut -f2 -d' ' | head -n1) curl_version_major=$(echo "$curl_version" | cut -f1 -d.) curl_version_minor=$(echo "$curl_version" | cut -f2 -d.) - CURL_HAS_NO_CLOBBER="" - CURL_HAS_PARALLEL="" + CURL_NO_CLOBBER="" + CURL_PARALLEL="" # --no-clobber is only supported since 7.83.0. # --parallel is only supported since 7.66.0. + # --parallel-max-host is only supported since 8.16.0. if [ "${curl_version_major}" -ge 8 ]; then - CURL_HAS_NO_CLOBBER="--no-clobber" - CURL_HAS_PARALLEL="--parallel" - elif [ "${curl_version_major}" -eq 7 ];then + CURL_NO_CLOBBER="--no-clobber" + CURL_PARALLEL="--parallel" + if [ "${curl_version_minor}" -ge 16 ]; then + CURL_PARALLEL="--parallel --parallel-max-host 5" + fi + elif [ "${curl_version_major}" -eq 7 ]; then if [ "${curl_version_minor}" -ge 83 ]; then - CURL_HAS_NO_CLOBBER="--no-clobber" + CURL_NO_CLOBBER="--no-clobber" fi if [ "${curl_version_minor}" -ge 66 ]; then - CURL_HAS_PARALLEL="--parallel" + CURL_PARALLEL="--parallel" fi fi - # Detecting whether we need --parallel. It's easier to rely on + # Detecting whether we need --parallel. It's easier to rely on # the shell's argument parsing. # shellcheck disable=SC2086 set -- $URLS - if [ "$#" -gt 1 ]; then - CURL_PARALLEL="$CURL_HAS_PARALLEL" - else + # If there are less than two URLs, don't set the parallel flag. + if [ "$#" -lt 2 ]; then CURL_PARALLEL="" fi @@ -231,7 +234,7 @@ exec_curl() [ -z "${OUTPUT_PATH}" ] && OUTPUT_PATH=index.html fi # shellcheck disable=SC2086 - set -- "$@" ${NEXT_PARAMETER} ${PER_URL_PARAMETERS} ${CURL_HAS_NO_CLOBBER} ${CURL_OPTIONS} --output "${OUTPUT_PATH}" "${url}" + set -- "$@" ${NEXT_PARAMETER} ${PER_URL_PARAMETERS} ${CURL_NO_CLOBBER} --output "${OUTPUT_PATH}" ${CURL_OPTIONS} "${url}" NEXT_PARAMETER="--next" done @@ -268,13 +271,13 @@ while [ -n "${1-}" ]; do OUTPUT_PATH="${opt}" ;; - -o|-O|--output) + -o | -O | --output) shift HAS_USER_SET_OUTPUT="true" OUTPUT_PATH="${1}" ;; - -o*|-O*) + -o* | -O*) opt=$(printf "%s\n" "${1}" | sed 's/^-[oO]//') HAS_USER_SET_OUTPUT="true" OUTPUT_PATH="${opt}" @@ -284,12 +287,12 @@ while [ -n "${1-}" ]; do DECODE_FILENAME="false" ;; - -h|--help) + -h | --help) usage exit 0 ;; - -V|--version) + -V | --version) print_version exit 0 ;; From 0e67d97b831e94bd17128a172860e1b9111ea239 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 01:37:23 +0000 Subject: [PATCH 222/465] GHA: update dependency libressl/portable to v4.1.1 Closes #18785 Closes #18786 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- .github/workflows/macos.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index ffcab39f1219..a5430dc5a1f9 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -44,7 +44,7 @@ env: # handled in renovate.json QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com - LIBRESSL_VERSION: 4.1.0 + LIBRESSL_VERSION: 4.1.1 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com AWSLC_VERSION: 1.61.4 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 606c83db84d8..8de911d7e96a 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -38,7 +38,7 @@ env: CURL_CI: github CURL_CLANG_TIDYFLAGS: '-checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.ArrayBound,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,-clang-analyzer-valist.Uninitialized' # renovate: datasource=github-tags depName=libressl-portable/portable versioning=semver registryUrl=https://github.com - LIBRESSL_VERSION: 4.1.0 + LIBRESSL_VERSION: 4.1.1 # renovate: datasource=github-tags depName=wolfSSL/wolfssl versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com WOLFSSL_VERSION: 5.8.2 # renovate: datasource=github-tags depName=Mbed-TLS/mbedtls versioning=semver registryUrl=https://github.com diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 6777f3aa924f..d766cf1c22d5 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -59,7 +59,7 @@ jobs: MATRIX_BUILD: ${{ matrix.build.generate && 'cmake' || 'autotools' }} MATRIX_OPTIONS: ${{ matrix.build.options }} # renovate: datasource=github-tags depName=libressl-portable/portable versioning=semver registryUrl=https://github.com - LIBRESSL_VERSION: 4.1.0 + LIBRESSL_VERSION: 4.1.1 strategy: fail-fast: false matrix: From 150567b0d25b519873800ac883ae43833e8f6aca Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 1 Oct 2025 12:12:30 +0200 Subject: [PATCH 223/465] tidy-up: LibreSSL Git repository URLs and local CI builds Also: - point the source tarball to a working URL. The GitHub release page misses the official source tarball for 4.1.1. - GHA/linux: switch LibreSSL build to cmake (syncing with http3-linux.) - GHA/macos: drop no longer needed LibreSSL build workaround. Closes #18792 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 9 +++++---- .github/workflows/macos.yml | 4 +--- plan9/README | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index a5430dc5a1f9..ce6ee41a8a35 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -213,7 +213,7 @@ jobs: run: | cd ~ curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ - --location "https://github.com/libressl/portable/releases/download/v${LIBRESSL_VERSION}/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz + "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz cd "libressl-${LIBRESSL_VERSION}" cmake -B . -G Ninja -DLIBRESSL_APPS=OFF -DLIBRESSL_TESTS=OFF -DCMAKE_INSTALL_PREFIX=/home/runner/libressl/build cmake --build . diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 8de911d7e96a..068fc0842c78 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -37,7 +37,7 @@ env: MAKEFLAGS: -j 5 CURL_CI: github CURL_CLANG_TIDYFLAGS: '-checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.ArrayBound,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,-clang-analyzer-valist.Uninitialized' - # renovate: datasource=github-tags depName=libressl-portable/portable versioning=semver registryUrl=https://github.com + # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com LIBRESSL_VERSION: 4.1.1 # renovate: datasource=github-tags depName=wolfSSL/wolfssl versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com WOLFSSL_VERSION: 5.8.2 @@ -360,10 +360,11 @@ jobs: if: ${{ contains(matrix.build.install_steps, 'libressl') && steps.cache-libressl.outputs.cache-hit != 'true' }} run: | curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ - --location "https://github.com/libressl/portable/releases/download/v${LIBRESSL_VERSION}/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz + "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz cd "libressl-${LIBRESSL_VERSION}" - ./configure --disable-dependency-tracking --prefix=/home/runner/libressl - make install + cmake -B . -G Ninja -DLIBRESSL_APPS=OFF -DLIBRESSL_TESTS=OFF -DCMAKE_INSTALL_PREFIX=/home/runner/libressl + cmake --build . + cmake --install . - name: 'cache wolfssl (all)' if: ${{ contains(matrix.build.install_steps, 'wolfssl-all') }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index d766cf1c22d5..1e2e61c8af53 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -58,7 +58,7 @@ jobs: LDFLAGS: '' MATRIX_BUILD: ${{ matrix.build.generate && 'cmake' || 'autotools' }} MATRIX_OPTIONS: ${{ matrix.build.options }} - # renovate: datasource=github-tags depName=libressl-portable/portable versioning=semver registryUrl=https://github.com + # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com LIBRESSL_VERSION: 4.1.1 strategy: fail-fast: false @@ -124,9 +124,7 @@ jobs: curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 60 --retry 3 --retry-connrefused \ --location "https://github.com/libressl/portable/releases/download/v${LIBRESSL_VERSION}/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -x cd "libressl-${LIBRESSL_VERSION}" - # FIXME: on the 4.0.1 release, delete '-DHAVE_ENDIAN_H=0' cmake -B . -G Ninja \ - -DHAVE_ENDIAN_H=0 \ -DCMAKE_INSTALL_PREFIX=/Users/runner/libressl \ -DCMAKE_SYSTEM_NAME=iOS \ -DCMAKE_SYSTEM_PROCESSOR=aarch64 \ diff --git a/plan9/README b/plan9/README index 6df23d31a7b1..3372e64f7be0 100644 --- a/plan9/README +++ b/plan9/README @@ -11,7 +11,7 @@ The zlib that is available on Plan 9 can be downloaded from: LibreSSL Portable can be downloaded from: - https://github.com/libressl-portable/portable/pull/510 + https://github.com/libressl/portable/pull/510 Instruction =========== From b2ae19eed4073349ec8bee84007556ab8ded2ad0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 1 Oct 2025 13:33:22 +0200 Subject: [PATCH 224/465] tool_getparam: warn if provided header looks malformed URL: https://fosstodon.org/@galdor/115298664084113519 Closes #18793 --- src/tool_getparam.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tool_getparam.c b/src/tool_getparam.c index eed87bb807d7..60b3b30ad48a 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -1267,6 +1267,10 @@ static ParameterError parse_header(struct OperationConfig *config, } } else { + if(!strchr(nextarg, ':') && !strchr(nextarg, ';')) { + warnf("The provided %s header '%s' does not look like a header?", + (cmd == C_PROXY_HEADER) ? "proxy": "HTTP", nextarg); + } if(cmd == C_PROXY_HEADER) /* --proxy-header */ err = add2list(&config->proxyheaders, nextarg); else From bc37765466e659f1d0bafe131735f2379f3b20ae Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 1 Oct 2025 11:26:16 +0200 Subject: [PATCH 225/465] form.md: drop reference to MANUAL Since it isn't linked and users might not understand what it refers to. Ref: #18755 Closes #18790 --- docs/cmdline-opts/form.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/cmdline-opts/form.md b/docs/cmdline-opts/form.md index 9633b25119f3..100e29e5716e 100644 --- a/docs/cmdline-opts/form.md +++ b/docs/cmdline-opts/form.md @@ -141,5 +141,3 @@ base64 attached file: curl -F '=text message;encoder=quoted-printable' \ -F '=@localfile;encoder=base64' ... smtp://example.com - -See further examples and details in the MANUAL. From e891b4195fdc133e975d86bda865720cafd6add0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 26 Sep 2025 14:10:30 +0200 Subject: [PATCH 226/465] cf-socket: tweak a memcpy() to read better By checking the size of the actual buffer and using that as memcpy target instead of another union member, this helps readers and static code analyzers to determine that this is not a buffer overflow. Ref: #18677 Closes #18787 --- lib/cf-socket.c | 7 +++---- lib/cf-socket.h | 9 +++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 3d1f5e752950..1fabf0ea0b4a 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -333,12 +333,11 @@ static CURLcode sock_assign_addr(struct Curl_sockaddr_ex *dest, } dest->addrlen = (unsigned int)ai->ai_addrlen; - if(dest->addrlen > sizeof(struct Curl_sockaddr_storage)) { - DEBUGASSERT(0); + DEBUGASSERT(dest->addrlen <= sizeof(dest->curl_sa_addrbuf)); + if(dest->addrlen > sizeof(dest->curl_sa_addrbuf)) return CURLE_TOO_LARGE; - } - memcpy(&dest->curl_sa_addr, ai->ai_addr, dest->addrlen); + memcpy(&dest->curl_sa_addrbuf, ai->ai_addr, dest->addrlen); return CURLE_OK; } diff --git a/lib/cf-socket.h b/lib/cf-socket.h index 083202fad900..85b7e5631b56 100644 --- a/lib/cf-socket.h +++ b/lib/cf-socket.h @@ -48,11 +48,12 @@ struct Curl_sockaddr_ex { int protocol; unsigned int addrlen; union { - struct sockaddr addr; - struct Curl_sockaddr_storage buff; - } _sa_ex_u; + struct sockaddr sa; + struct Curl_sockaddr_storage buf; + } addr; }; -#define curl_sa_addr _sa_ex_u.addr +#define curl_sa_addr addr.sa +#define curl_sa_addrbuf addr.buf /* * Parse interface option, and return the interface name and the host part. From d71ec36d1b6ec2feeb3811f143e7e98fceb95be1 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 1 Oct 2025 11:23:27 +0200 Subject: [PATCH 227/465] openssl-quic: ignore unexpected streams opened by server HTTP/3 defines "reserved stream types" that are intended to be ignored by a receiver. This is part of the "greasing" effort that flexes parts of the protocol that are needed for future extensions. curl's OpenSSL-QUIC implementation treated all unexpected streams as an error. Which seems the right thing to do *but* for these reserved types. However OpenSSL does not expose this type and thus, curl needs to silently discard all unexpected streams opened by the server to allow interop with servers that flex the GREASE parts. Fixes #18780 Reported-by: Pocs Norbert Closes #18791 --- lib/vquic/curl_osslq.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index e6278ad961a9..aea03c038fb6 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -453,32 +453,36 @@ static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3, { struct cf_osslq_ctx *ctx = cf->ctx; curl_int64_t stream_id = (curl_int64_t)SSL_get_stream_id(stream_ssl); - - if(h3->remote_ctrl_n >= CURL_ARRAYSIZE(h3->remote_ctrl)) { - /* rejected, we are full */ - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] rejecting remote stream", - stream_id); - SSL_free(stream_ssl); - return CURLE_FAILED_INIT; - } - switch(SSL_get_stream_type(stream_ssl)) { + int stype = SSL_get_stream_type(stream_ssl); + /* This could be a GREASE stream, e.g. HTTP/3 rfc9114 ch 6.2.3 + * reserved stream type that is supposed to be discarded silently. + * BUT OpenSSL does not offer this information to us. So, we silently + * ignore all such streams we do not expect. */ + switch(stype) { case SSL_STREAM_TYPE_READ: { - struct cf_osslq_stream *nstream = &h3->remote_ctrl[h3->remote_ctrl_n++]; + struct cf_osslq_stream *nstream; + if(h3->remote_ctrl_n >= CURL_ARRAYSIZE(h3->remote_ctrl)) { + /* rejected, we are full */ + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reject remote uni stream", + stream_id); + SSL_free(stream_ssl); + return CURLE_OK; + } + nstream = &h3->remote_ctrl[h3->remote_ctrl_n++]; nstream->id = stream_id; nstream->ssl = stream_ssl; Curl_bufq_initp(&nstream->recvbuf, &ctx->stream_bufcp, 1, BUFQ_OPT_NONE); CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] accepted remote uni stream", stream_id); - break; + return CURLE_OK; } default: - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reject remote non-uni-read" - " stream", stream_id); + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reject remote %s" + " stream, type=%x", stream_id, + (stype == SSL_STREAM_TYPE_BIDI) ? "bidi" : "write", stype); SSL_free(stream_ssl); - return CURLE_FAILED_INIT; + return CURLE_OK; } - return CURLE_OK; - } static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf, From 285f64d3a033e33ad0f0805fa6f5d72150b59333 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 1 Oct 2025 21:53:04 +0200 Subject: [PATCH 228/465] GHA/macos: also update LibreSSL source tarball URL Follow-up to 150567b0d25b519873800ac883ae43833e8f6aca #18792 --- .github/workflows/macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 1e2e61c8af53..b0f958d70c98 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -122,7 +122,7 @@ jobs: if: ${{ contains(matrix.build.install_steps, 'libressl') && steps.cache-libressl.outputs.cache-hit != 'true' }} run: | curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 60 --retry 3 --retry-connrefused \ - --location "https://github.com/libressl/portable/releases/download/v${LIBRESSL_VERSION}/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -x + "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz cd "libressl-${LIBRESSL_VERSION}" cmake -B . -G Ninja \ -DCMAKE_INSTALL_PREFIX=/Users/runner/libressl \ From e234c0942648297dd15c265d359f91e7425b24fc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:54:31 +0000 Subject: [PATCH 229/465] GHA: update dependency openssl/openssl to v3.6.0 Closes #18796 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index ce6ee41a8a35..5b1bd5fde680 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -40,7 +40,7 @@ env: MAKEFLAGS: -j 5 CURL_CI: github # handled in renovate.json - OPENSSL_VERSION: 3.5.4 + OPENSSL_VERSION: 3.6.0 # handled in renovate.json QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 068fc0842c78..36d37dfaeaaf 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -48,7 +48,7 @@ env: # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com BORINGSSL_VERSION: 0.20250818.0 # handled in renovate.json - OPENSSL_VERSION: 3.5.4 + OPENSSL_VERSION: 3.6.0 # handled in renovate.json QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=rustls/rustls-ffi versioning=semver registryUrl=https://github.com From 9ebf778e824007f1aad83ba79f5af802ee77c884 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 23 Sep 2025 10:17:29 +0200 Subject: [PATCH 230/465] GHA/linux: add HTTP/3 c-ares scan-build and asan jobs They use Linuxbrew instead of locally built components. Linuxbrew limitations compared to the locally built components in GHA/http3-linux: - libngtcp2 currently supports OpenSSL only. - wolfssl can't coexist with openssl. - somewhat tricky configuration with autotools. Upside is easy of use, always the latest versions (may be downside), and availability of almost all packages. Closes #18693 --- .github/workflows/linux.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 36d37dfaeaaf..3c827ae34b1c 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -239,6 +239,20 @@ jobs: --enable-ech --with-gssapi --enable-ssls-export --disable-debug --disable-unity + - name: 'scan-build H3 c-ares' + install_packages: clang-tools clang libidn2-dev libnghttp2-dev + install_steps: skipall + install_steps_brew: openssl libngtcp2 libnghttp3 c-ares + CC: clang + configure-prefix: scan-build + make-prefix: scan-build --status-bugs + LDFLAGS: -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/openssl/lib -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/libngtcp2/lib -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/libnghttp3/lib -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/c-ares/lib + PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/opt/libngtcp2/lib/pkgconfig:/home/linuxbrew/.linuxbrew/opt/libnghttp3/lib/pkgconfig:/home/linuxbrew/.linuxbrew/opt/c-ares/lib/pkgconfig + configure: >- + --with-openssl=/home/linuxbrew/.linuxbrew/opt/openssl --with-ngtcp2 --with-nghttp3= + --with-libidn2 --enable-httpsrr --enable-ares + --disable-debug --disable-unity + - name: 'address-sanitizer' install_packages: clang libssl-dev libssh-dev libidn2-dev libnghttp2-dev libubsan1 libasan8 libtsan2 install_steps: pytest randcurl @@ -247,6 +261,16 @@ jobs: CC: clang generate: -DENABLE_DEBUG=ON -DCURL_USE_LIBSSH=ON + - name: 'address-sanitizer H3 c-ares' + install_packages: clang libubsan1 libasan8 libtsan2 + install_steps: pytest + install_steps_brew: openssl libngtcp2 libnghttp3 c-ares + CFLAGS: -fsanitize=address,undefined,signed-integer-overflow -fno-sanitize-recover=undefined,integer -Wformat -Werror=format-security -Werror=array-bounds -g + LDFLAGS: -fsanitize=address,undefined -fno-sanitize-recover=undefined,integer -ldl -lubsan -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/c-ares/lib + PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/opt/libngtcp2/lib/pkgconfig:/home/linuxbrew/.linuxbrew/opt/libnghttp3/lib/pkgconfig:/home/linuxbrew/.linuxbrew/opt/c-ares/lib/pkgconfig + CC: clang + generate: -DENABLE_DEBUG=ON -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/home/linuxbrew/.linuxbrew/opt/openssl -DUSE_NGTCP2=ON -DUSE_SSLS_EXPORT=ON -DENABLE_ARES=ON + - name: 'thread-sanitizer' install_packages: clang libtsan2 install_steps: pytest openssl-tsan From e43aea3049ae50e9297d45cf5d96f3ac78999b69 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 1 Oct 2025 22:19:01 +0200 Subject: [PATCH 231/465] lib: fix build error and compiler warnings with verbose strings disabled - asyn-ares: fix compiler warning: ``` lib/asyn-ares.c:751:17: error: code will never be executed [clang-diagnostic-unreachable-code,-warnings-as-errors] 751 | char *csv = ares_get_servers_csv(ares->channel); | ^~~~~~~~~~~~~~~~~~~~ ``` - curl_trc: fix missing symbol: ``` /usr/bin/ld: ../lib/.libs/libcurl.so: undefined reference to `Curl_trc_timer' collect2: error: ld returned 1 exit status ``` Ref: https://app.circleci.com/pipelines/github/curl/curl/15446/workflows/67afa113-9c49-4249-9180-f6f01fc7dfdd/jobs/149177 Ref: https://github.com/curl/curl/actions/runs/18174250400/job/51736249444#step:33:623 Follow-up to b02238975768d0bcbf8c7ef00eaaee3ec379f4ff #18768 - multi: fix `-Wunreachable-code`: ``` lib/multi.c:1107:28: error: code will never be executed [-Werror,-Wunreachable-code] 1107 | size_t timeout_count = Curl_llist_count(&data->state.timeoutlist); | ^~~~~~~~~~~~~~~~ lib/multi.c:3054:35: error: code will never be executed [-Werror,-Wunreachable-code] 3054 | struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist); | ^~~~~~~~~~~~~~~ lib/multi.c:3380:7: error: code will never be executed [-Werror,-Wunreachable-code] 3380 | Curl_llist_head(&data->state.timeoutlist); | ^~~~~~~~~~~~~~~ ``` Cherry-picked from #18797 Closes #18799 --- lib/asyn-ares.c | 3 ++- lib/curl_trc.c | 5 +++++ lib/multi.c | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 0a04f4cc367f..a9988806ac20 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -746,7 +746,8 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data, ares->ares_status = ARES_ENOTFOUND; ares->result = CURLE_OK; -#if ARES_VERSION >= 0x011800 /* >= v1.24.0 */ +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) && \ + ARES_VERSION >= 0x011800 /* >= v1.24.0 */ if(CURL_TRC_DNS_is_verbose(data)) { char *csv = ares_get_servers_csv(ares->channel); CURL_TRC_DNS(data, "asyn-ares: servers=%s", csv); diff --git a/lib/curl_trc.c b/lib/curl_trc.c index 27dc2b3b44cd..e04c425b3249 100644 --- a/lib/curl_trc.c +++ b/lib/curl_trc.c @@ -672,6 +672,11 @@ void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...) (void)data; (void)fmt; } +void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...) +{ + (void)data; (void)tid; (void)fmt; +} + void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...) { (void)data; (void)fmt; diff --git a/lib/multi.c b/lib/multi.c index ae38f5f4439b..91d2f56d4732 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1103,6 +1103,7 @@ CURLMcode Curl_multi_pollset(struct Curl_easy *data, Curl_multi_mark_dirty(data); } +#ifndef CURL_DISABLE_VERBOSE_STRINGS if(CURL_TRC_M_is_verbose(data)) { size_t timeout_count = Curl_llist_count(&data->state.timeoutlist); switch(ps->n) { @@ -1137,6 +1138,7 @@ CURLMcode Curl_multi_pollset(struct Curl_easy *data, } CURL_TRC_EASY_TIMERS(data); } +#endif if(expect_sockets && !ps->n && data->multi && !Curl_uint_bset_contains(&data->multi->dirty, data->mid) && @@ -3050,6 +3052,7 @@ static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc) data = Curl_splayget(t); /* assign this for next loop */ if(!data) continue; +#ifndef CURL_DISABLE_VERBOSE_STRINGS if(CURL_TRC_TIMER_is_verbose(data)) { struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist); if(e) { @@ -3057,6 +3060,7 @@ static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc) CURL_TRC_TIMER(data, n->eid, "has expired"); } } +#endif (void)add_next_timeout(mrc->now, multi, data); Curl_multi_mark_dirty(data); } @@ -3329,7 +3333,9 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms) { static const struct curltime tv_zero = {0, 0}; +#ifndef CURL_DISABLE_VERBOSE_STRINGS struct Curl_easy *data = NULL; +#endif if(multi->dead) { *timeout_ms = 0; @@ -3357,15 +3363,19 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, curlx_timediff_us(multi->timetree->key, now) > 0) { /* some time left before expiration */ timediff_t diff = curlx_timediff_ceil(multi->timetree->key, now); +#ifndef CURL_DISABLE_VERBOSE_STRINGS data = Curl_splayget(multi->timetree); +#endif /* this should be safe even on 32-bit archs, as we do not use that overly long timeouts */ *timeout_ms = (long)diff; } else { +#ifndef CURL_DISABLE_VERBOSE_STRINGS if(multi->timetree) { data = Curl_splayget(multi->timetree); } +#endif /* 0 means immediately */ *timeout_ms = 0; } @@ -3375,6 +3385,7 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, *timeout_ms = -1; } +#ifndef CURL_DISABLE_VERBOSE_STRINGS if(data && CURL_TRC_TIMER_is_verbose(data)) { struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist); @@ -3384,6 +3395,7 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, *timeout_ms); } } +#endif return CURLM_OK; } From 632c5ee8971e3ff1293367d9d034975f068aa4fa Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 1 Oct 2025 22:36:08 +0200 Subject: [PATCH 232/465] runtests: tag tests that require curl verbose strings To skip them when curl has verbose strings disabled, instead of failing. Cherry-picked from #18797 Closes #18800 --- tests/data/test1007 | 3 +++ tests/data/test1287 | 1 + tests/data/test1506 | 3 +++ tests/data/test1538 | 3 +++ tests/data/test1542 | 3 +++ tests/data/test1559 | 1 + tests/data/test1652 | 1 + tests/data/test2402 | 1 + tests/data/test2404 | 1 + tests/data/test2502 | 1 + 10 files changed, 18 insertions(+) diff --git a/tests/data/test1007 b/tests/data/test1007 index 603d4c6390c6..ca128086267e 100644 --- a/tests/data/test1007 +++ b/tests/data/test1007 @@ -13,6 +13,9 @@ FAILURE tftp + +verbose-strings + TFTP send with invalid permission on server diff --git a/tests/data/test1287 b/tests/data/test1287 index 48d71038ad91..c9d2a6cb2db1 100644 --- a/tests/data/test1287 +++ b/tests/data/test1287 @@ -62,6 +62,7 @@ HTTP over proxy-tunnel ignore TE and CL in CONNECT 2xx responses
proxy +verbose-strings diff --git a/tests/data/test1506 b/tests/data/test1506 index ed95e3be6f29..af581ae6bf55 100644 --- a/tests/data/test1506 +++ b/tests/data/test1506 @@ -48,6 +48,9 @@ file contents should appear once for each file http + +verbose-strings + lib%TESTNUMBER diff --git a/tests/data/test1538 b/tests/data/test1538 index bbae00f0e997..df8aca936f63 100644 --- a/tests/data/test1538 +++ b/tests/data/test1538 @@ -13,6 +13,9 @@ verbose logs # Client-side + +verbose-strings + lib%TESTNUMBER diff --git a/tests/data/test1542 b/tests/data/test1542 index 656af421dfd3..e9061a8f2bea 100644 --- a/tests/data/test1542 +++ b/tests/data/test1542 @@ -23,6 +23,9 @@ Content-Length: 0 http + +verbose-strings + lib%TESTNUMBER diff --git a/tests/data/test1559 b/tests/data/test1559 index cf4b13d4a2bc..981e46f9f1a8 100644 --- a/tests/data/test1559 +++ b/tests/data/test1559 @@ -14,6 +14,7 @@ verbose logs # require HTTP so that CURLOPT_POSTFIELDS works as assumed http +verbose-strings lib%TESTNUMBER diff --git a/tests/data/test1652 b/tests/data/test1652 index face77c98120..848d5ca5b522 100644 --- a/tests/data/test1652 +++ b/tests/data/test1652 @@ -9,6 +9,7 @@ infof unittest +verbose-strings infof diff --git a/tests/data/test2402 b/tests/data/test2402 index 4e08e45ac486..5133a0944a83 100644 --- a/tests/data/test2402 +++ b/tests/data/test2402 @@ -49,6 +49,7 @@ file contents should appear once for each file http/2 SSL +verbose-strings http/2 diff --git a/tests/data/test2404 b/tests/data/test2404 index 13e48c8be5cd..881a32120fe5 100644 --- a/tests/data/test2404 +++ b/tests/data/test2404 @@ -49,6 +49,7 @@ file contents should appear once for each file http/2 SSL +verbose-strings http/2 diff --git a/tests/data/test2502 b/tests/data/test2502 index f7822e8c26ce..8625ee7b74b2 100644 --- a/tests/data/test2502 +++ b/tests/data/test2502 @@ -48,6 +48,7 @@ file contents should appear once for each file http/3 +verbose-strings http/3 From 34dc762ceff13250a2338242dfea6f9ce7f061fd Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 1 Oct 2025 23:27:45 +0200 Subject: [PATCH 233/465] pytest: skip specific tests for no-verbose builds Detect via curlinfo if curl has verbose strings disabled, and skip tests that require it. Also: - cmake: make pytests depend on curlinfo. Cherry-picked from #18797 Closes #18801 --- tests/CMakeLists.txt | 6 +++--- tests/http/test_02_download.py | 5 +++++ tests/http/test_06_eyeballs.py | 1 + tests/http/test_10_proxy.py | 8 ++++++++ tests/http/test_13_proxy_auth.py | 2 ++ tests/http/test_15_tracing.py | 2 ++ tests/http/test_17_ssl_use.py | 1 + tests/http/test_19_shutdown.py | 8 ++++++++ tests/http/test_30_vsftpd.py | 2 ++ tests/http/test_31_vsftpds.py | 2 ++ tests/http/test_32_ftps_vsftpd.py | 2 ++ tests/http/testenv/env.py | 12 ++++++++++++ 12 files changed, 48 insertions(+), 3 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8bfca21ca60d..2b12cef83b21 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -31,7 +31,7 @@ configure_file("config.in" "${CMAKE_CURRENT_BINARY_DIR}/config" @ONLY) add_custom_target(testdeps) if(BUILD_CURL_EXE) - add_dependencies(testdeps curlinfo) + add_dependencies(testdeps "curlinfo") endif() if(CURL_CLANG_TIDY) @@ -57,7 +57,7 @@ function(curl_add_runtests _targetname _test_flags) # skipping them, MSBuild doing a re-evaluation, and actually rebuilding them. if(NOT _targetname STREQUAL "test-ci") if(BUILD_CURL_EXE) - list(APPEND _depends ${EXE_NAME}) + list(APPEND _depends "${EXE_NAME}") endif() list(APPEND _depends "testdeps") endif() @@ -86,7 +86,7 @@ function(curl_add_pytests _targetname _test_flags) set(_depends "") if(NOT _targetname STREQUAL "pytest-ci") if(BUILD_CURL_EXE) - list(APPEND _depends ${EXE_NAME}) + list(APPEND _depends "${EXE_NAME}" "curlinfo") endif() list(APPEND _depends "libtests") endif() diff --git a/tests/http/test_02_download.py b/tests/http/test_02_download.py index 4ec781148c94..89bf7e1ab1ec 100644 --- a/tests/http/test_02_download.py +++ b/tests/http/test_02_download.py @@ -600,6 +600,7 @@ def test_02_31_parallel_upgrade(self, env: Env, httpd, nghttpx): # nghttpx is the only server we have that supports TLS early data @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) def test_02_32_earlydata(self, env: Env, httpd, nghttpx, proto): if not env.curl_can_early_data(): @@ -654,6 +655,8 @@ def test_02_32_earlydata(self, env: Env, httpd, nghttpx, proto): def test_02_33_max_host_conns(self, env: Env, httpd, nghttpx, proto, max_host_conns): if not env.curl_is_debug(): pytest.skip('only works for curl debug builds') + if not env.curl_is_verbose(): + pytest.skip('only works for curl with verbose strings') if proto == 'h3' and not env.have_h3(): pytest.skip("h3 not supported") count = 50 @@ -692,6 +695,8 @@ def test_02_33_max_host_conns(self, env: Env, httpd, nghttpx, proto, max_host_co def test_02_34_max_total_conns(self, env: Env, httpd, nghttpx, proto, max_total_conns): if not env.curl_is_debug(): pytest.skip('only works for curl debug builds') + if not env.curl_is_verbose(): + pytest.skip('only works for curl with verbose strings') if proto == 'h3' and not env.have_h3(): pytest.skip("h3 not supported") count = 50 diff --git a/tests/http/test_06_eyeballs.py b/tests/http/test_06_eyeballs.py index d05eb3c7da58..7d2677447671 100644 --- a/tests/http/test_06_eyeballs.py +++ b/tests/http/test_06_eyeballs.py @@ -105,6 +105,7 @@ def test_06_12_stats_fail_tcp(self, env: Env, httpd, nghttpx): # check timers when trying 3 unresponsive addresses @pytest.mark.skipif(condition=not Env.curl_has_feature('IPv6'), reason='curl lacks ipv6 support') + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_06_13_timers(self, env: Env): curl = CurlClient(env=env) # ipv6 0100::/64 is supposed to go into the void (rfc6666) diff --git a/tests/http/test_10_proxy.py b/tests/http/test_10_proxy.py index e61284a4cadf..592acbd60c9b 100644 --- a/tests/http/test_10_proxy.py +++ b/tests/http/test_10_proxy.py @@ -151,6 +151,7 @@ def test_10_05_proxytunnel_http(self, env: Env, httpd, nghttpx_fwd, proto): @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_10_06_proxytunnel_https(self, env: Env, httpd, nghttpx_fwd, proto, tunnel): if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'): pytest.skip('only supported with nghttp2') @@ -169,6 +170,7 @@ def test_10_06_proxytunnel_https(self, env: Env, httpd, nghttpx_fwd, proto, tunn # download many https: with proto via https: proxytunnel @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") @pytest.mark.parametrize("proto", ['http/1.1', 'h2']) @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) @pytest.mark.parametrize("fname, fcount", [ @@ -209,6 +211,7 @@ def test_10_07_pts_down_small(self, env: Env, httpd, nghttpx_fwd, proto, ['data-1m', 5] ]) @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") def test_10_08_upload_seq_large(self, env: Env, httpd, nghttpx, proto, tunnel, fname, fcount): @@ -236,6 +239,7 @@ def test_10_08_upload_seq_large(self, env: Env, httpd, nghttpx, proto, @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_10_09_reuse_server(self, env: Env, httpd, nghttpx_fwd, tunnel): if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'): pytest.skip('only supported with nghttp2') @@ -259,6 +263,7 @@ def test_10_09_reuse_server(self, env: Env, httpd, nghttpx_fwd, tunnel): @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_10_10_reuse_proxy(self, env: Env, httpd, nghttpx_fwd, tunnel): # url twice via https: proxy separated with '--next', will reuse if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'): @@ -287,6 +292,7 @@ def test_10_10_reuse_proxy(self, env: Env, httpd, nghttpx_fwd, tunnel): @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") @pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_10_11_noreuse_proxy_https(self, env: Env, httpd, nghttpx_fwd, tunnel): # different --proxy-tls13-ciphers, no reuse of connection for https: curl = CurlClient(env=env) @@ -313,6 +319,7 @@ def test_10_11_noreuse_proxy_https(self, env: Env, httpd, nghttpx_fwd, tunnel): @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") @pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_10_12_noreuse_proxy_http(self, env: Env, httpd, nghttpx_fwd, tunnel): # different --proxy-tls13-ciphers, no reuse of connection for http: if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'): @@ -339,6 +346,7 @@ def test_10_12_noreuse_proxy_http(self, env: Env, httpd, nghttpx_fwd, tunnel): @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") @pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_10_13_noreuse_https(self, env: Env, httpd, nghttpx_fwd, tunnel): # different --tls13-ciphers on https: same proxy config if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'): diff --git a/tests/http/test_13_proxy_auth.py b/tests/http/test_13_proxy_auth.py index fe45ae40ec0d..1f7c41e2dd5c 100644 --- a/tests/http/test_13_proxy_auth.py +++ b/tests/http/test_13_proxy_auth.py @@ -120,6 +120,7 @@ def test_13_06_tunnel_http_auth(self, env: Env, httpd, configures_httpd): @pytest.mark.skipif(condition=not Env.curl_has_feature('HTTPS-proxy'), reason='curl lacks HTTPS-proxy support') @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") @pytest.mark.parametrize("proto", ['http/1.1', 'h2']) @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) def test_13_07_tunnels_no_auth(self, env: Env, httpd, configures_httpd, nghttpx_fwd, proto, tunnel): @@ -139,6 +140,7 @@ def test_13_07_tunnels_no_auth(self, env: Env, httpd, configures_httpd, nghttpx_ @pytest.mark.skipif(condition=not Env.curl_has_feature('HTTPS-proxy'), reason='curl lacks HTTPS-proxy support') @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") @pytest.mark.parametrize("proto", ['http/1.1', 'h2']) @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) def test_13_08_tunnels_auth(self, env: Env, httpd, configures_httpd, nghttpx_fwd, proto, tunnel): diff --git a/tests/http/test_15_tracing.py b/tests/http/test_15_tracing.py index 7e7d55de71c7..c94827aa4f89 100644 --- a/tests/http/test_15_tracing.py +++ b/tests/http/test_15_tracing.py @@ -77,6 +77,8 @@ def test_15_03_trace_ids_time(self, env: Env, httpd): # trace all def test_15_04_trace_all(self, env: Env, httpd): + if not env.curl_is_verbose(): + pytest.skip('only works for curl with verbose strings') curl = CurlClient(env=env) url = f'http://{env.domain1}:{env.http_port}/data.json' r = curl.http_get(url=url, def_tracing=False, extra_args=[ diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py index 33dd50e939b9..b346281dfc28 100644 --- a/tests/http/test_17_ssl_use.py +++ b/tests/http/test_17_ssl_use.py @@ -367,6 +367,7 @@ def test_17_09_ssl_min_max(self, env: Env, httpd, configures_httpd, server_tls, assert r.exit_code != 0, f'should fail, server={server_ver:04x}, curl=[{curl_min_ver:04x}, {curl_max_ver:04x}]\n{r.dump_logs()}' @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_17_10_h3_session_reuse(self, env: Env, httpd, nghttpx): if not env.have_h3(): pytest.skip("h3 not supported") diff --git a/tests/http/test_19_shutdown.py b/tests/http/test_19_shutdown.py index 9b3a6c90e962..a0167549fd43 100644 --- a/tests/http/test_19_shutdown.py +++ b/tests/http/test_19_shutdown.py @@ -90,6 +90,8 @@ def test_19_02_check_shutdown(self, env: Env, httpd, proto): def test_19_03_shutdown_by_server(self, env: Env, httpd, proto): if not env.curl_is_debug(): pytest.skip('only works for curl debug builds') + if not env.curl_is_verbose(): + pytest.skip('only works for curl with verbose strings') count = 10 curl = CurlClient(env=env, run_env={ 'CURL_GRACEFUL_SHUTDOWN': '2000', @@ -109,6 +111,8 @@ def test_19_03_shutdown_by_server(self, env: Env, httpd, proto): def test_19_04_shutdown_by_curl(self, env: Env, httpd, proto): if not env.curl_is_debug(): pytest.skip('only works for curl debug builds') + if not env.curl_is_verbose(): + pytest.skip('only works for curl with verbose strings') count = 10 docname = 'data.json' url = f'https://localhost:{env.https_port}/{docname}' @@ -132,6 +136,8 @@ def test_19_04_shutdown_by_curl(self, env: Env, httpd, proto): def test_19_05_event_shutdown_by_server(self, env: Env, httpd, proto): if not env.curl_is_debug(): pytest.skip('only works for curl debug builds') + if not env.curl_is_verbose(): + pytest.skip('only works for curl with verbose strings') count = 10 run_env = os.environ.copy() # forbid connection reuse to trigger shutdowns after transfer @@ -162,6 +168,8 @@ def test_19_06_check_shutdown(self, env: Env, httpd, nghttpx, proto): pytest.skip("h3 not supported") if not env.curl_is_debug(): pytest.skip('only works for curl debug builds') + if not env.curl_is_verbose(): + pytest.skip('only works for curl with verbose strings') curl = CurlClient(env=env, run_env={ 'CURL_GRACEFUL_SHUTDOWN': '2000', 'CURL_DEBUG': 'all' diff --git a/tests/http/test_30_vsftpd.py b/tests/http/test_30_vsftpd.py index 5f294fdfc882..bffeae35cf7b 100644 --- a/tests/http/test_30_vsftpd.py +++ b/tests/http/test_30_vsftpd.py @@ -141,6 +141,7 @@ def _rmf(self, path): # check with `tcpdump` if curl causes any TCP RST packets @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_30_06_shutdownh_download(self, env: Env, vsftpd: VsFTPD): docname = 'data-1k' curl = CurlClient(env=env) @@ -158,6 +159,7 @@ def test_30_06_shutdownh_download(self, env: Env, vsftpd: VsFTPD): # check with `tcpdump` if curl causes any TCP RST packets @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_30_07_shutdownh_upload(self, env: Env, vsftpd: VsFTPD): docname = 'upload-1k' curl = CurlClient(env=env) diff --git a/tests/http/test_31_vsftpds.py b/tests/http/test_31_vsftpds.py index a3a9e66ca516..f7e32cb77b77 100644 --- a/tests/http/test_31_vsftpds.py +++ b/tests/http/test_31_vsftpds.py @@ -148,6 +148,7 @@ def _rmf(self, path): # check with `tcpdump` if curl causes any TCP RST packets @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_31_06_shutdownh_download(self, env: Env, vsftpds: VsFTPD): docname = 'data-1k' curl = CurlClient(env=env) @@ -164,6 +165,7 @@ def test_31_06_shutdownh_download(self, env: Env, vsftpds: VsFTPD): # check with `tcpdump` if curl causes any TCP RST packets @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_31_07_shutdownh_upload(self, env: Env, vsftpds: VsFTPD): docname = 'upload-1k' curl = CurlClient(env=env) diff --git a/tests/http/test_32_ftps_vsftpd.py b/tests/http/test_32_ftps_vsftpd.py index 4a2861224274..46690a84355e 100644 --- a/tests/http/test_32_ftps_vsftpd.py +++ b/tests/http/test_32_ftps_vsftpd.py @@ -160,6 +160,7 @@ def _rmf(self, path): # check with `tcpdump` if curl causes any TCP RST packets @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_32_06_shutdownh_download(self, env: Env, vsftpds: VsFTPD): docname = 'data-1k' curl = CurlClient(env=env) @@ -176,6 +177,7 @@ def test_32_06_shutdownh_download(self, env: Env, vsftpds: VsFTPD): # check with `tcpdump` if curl causes any TCP RST packets @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") @pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug") + @pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings") def test_32_07_shutdownh_upload(self, env: Env, vsftpds: VsFTPD): docname = 'upload-1k' curl = CurlClient(env=env) diff --git a/tests/http/testenv/env.py b/tests/http/testenv/env.py index ad1173a9845e..0cd9101342d1 100644 --- a/tests/http/testenv/env.py +++ b/tests/http/testenv/env.py @@ -64,6 +64,7 @@ def init_config_from(conf_path): CONFIG_PATH = ALT_CONFIG_PATH DEF_CONFIG = init_config_from(CONFIG_PATH) CURL = os.path.join(TOP_PATH, 'src', 'curl') +CURLINFO = os.path.join(TOP_PATH, 'src', 'curlinfo') class NghttpxUtil: @@ -110,6 +111,7 @@ def __init__(self, pytestconfig: Optional[pytest.Config] = None, self.config = DEF_CONFIG # check cur and its features self.curl = CURL + self.curlinfo = CURLINFO if 'CURL' in os.environ: self.curl = os.environ['CURL'] self.curl_props = { @@ -157,6 +159,12 @@ def __init__(self, pytestconfig: Optional[pytest.Config] = None, prot.lower() for prot in line[11:].split(' ') } + p = subprocess.run(args=[self.curlinfo], + capture_output=True, text=True) + if p.returncode != 0: + raise RuntimeError(f'{self.curlinfo} failed with exit code: {p.returncode}') + self.curl_is_verbose = 'verbose-strings: ON' in p.stdout + self.ports = {} self.httpd = self.config['httpd']['httpd'] @@ -462,6 +470,10 @@ def curl_version() -> str: def curl_is_debug() -> bool: return Env.CONFIG.curl_is_debug + @staticmethod + def curl_is_verbose() -> bool: + return Env.CONFIG.curl_is_verbose + @staticmethod def curl_can_early_data() -> bool: if Env.curl_uses_lib('gnutls'): From e49698925c7f90e8f1e70c2a71fb5d2b67918409 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 2 Oct 2025 11:31:52 +0200 Subject: [PATCH 234/465] tool_progress: make max5data() use an algorithm Instead of a list of conditions. Makes a unified decimal output when the value is less than 100. Prepares for > 64 bit data type. Closes #18807 --- src/tool_progress.c | 60 ++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/src/tool_progress.c b/src/tool_progress.c index aae2ff68b184..b03fbf16a18a 100644 --- a/src/tool_progress.c +++ b/src/tool_progress.c @@ -31,48 +31,30 @@ Add suffix k, M, G when suitable... */ static char *max5data(curl_off_t bytes, char *max5) { -#define ONE_KILOBYTE (curl_off_t)1024 -#define ONE_MEGABYTE (1024 * ONE_KILOBYTE) -#define ONE_GIGABYTE (1024 * ONE_MEGABYTE) -#define ONE_TERABYTE (1024 * ONE_GIGABYTE) -#define ONE_PETABYTE (1024 * ONE_TERABYTE) - + /* a signed 64-bit value is 8192 petabytes maximum */ + const char unit[] = { 'k', 'M', 'G', 'T', 'P', 0 }; + int k = 0; if(bytes < 100000) msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); - else if(bytes < 10000 * ONE_KILOBYTE) - msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE); - - else if(bytes < 100 * ONE_MEGABYTE) - /* 'XX.XM' is good as long as we are less than 100 megs */ - msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" - CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, - (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/10) ); - - else if(bytes < 10000 * ONE_MEGABYTE) - /* 'XXXXM' is good until we are at 10000MB or above */ - msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); - - else if(bytes < 100 * ONE_GIGABYTE) - /* 10000 MB - 100 GB, we show it as XX.XG */ - msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" - CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE, - (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/10) ); - - else if(bytes < 10000 * ONE_GIGABYTE) - /* up to 10000GB, display without decimal: XXXXG */ - msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE); - - else if(bytes < 10000 * ONE_TERABYTE) - /* up to 10000TB, display without decimal: XXXXT */ - msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE); - - else - /* up to 10000PB, display without decimal: XXXXP */ - msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); - - /* 16384 petabytes (16 exabytes) is the maximum a 64-bit unsigned number can - hold, but our data type is signed so 8192PB will be the maximum. */ + do { + curl_off_t nbytes = bytes / 1024; + if(nbytes < 100) { + /* display with a decimal */ + msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + CURL_FORMAT_CURL_OFF_T "%c", bytes/1024, + (bytes%1024) / (1024/10), unit[k]); + break; + } + else if(nbytes < 10000) { + /* no decimals */ + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "%c", nbytes, unit[k]); + break; + } + bytes = nbytes; + k++; + DEBUGASSERT(unit[k]); + } while(unit[k]); return max5; } From 7f0fd14d9f6b1c28b3b3e2276e4937a24ec3997e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 2 Oct 2025 10:20:59 +0200 Subject: [PATCH 235/465] tool_getparam: always disable "lib-ids" for tracing Since the tool code itself adds the ids (controlled with "ids"), getting them (also) added by the library adds nothing good. Always disable the lib-ids even when "--trace-config all" is selected. Also: change "== Info:" into just "* " to reduce output redundancy. Ref: #18755 Reported-by: Alice Lee Poetics Closes #18805 --- src/tool_cb_dbg.c | 2 +- src/tool_getparam.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tool_cb_dbg.c b/src/tool_cb_dbg.c index b454f5ca9bad..d9aa1ff07a1f 100644 --- a/src/tool_cb_dbg.c +++ b/src/tool_cb_dbg.c @@ -201,7 +201,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type, switch(type) { case CURLINFO_TEXT: - fprintf(output, "%s%s== Info: %.*s", timebuf, idsbuf, (int)size, data); + fprintf(output, "%s%s* %.*s", timebuf, idsbuf, (int)size, data); FALLTHROUGH(); default: /* in case a new one is introduced to shock us */ return 0; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 60b3b30ad48a..0fdd6373e566 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -736,7 +736,10 @@ static CURLcode set_trace_config(const char *token) if((len == 3) && curl_strnequal(name, "all", 3)) { global->traceids = toggle; global->tracetime = toggle; - result = curl_global_trace(token); + if(toggle) + result = curl_global_trace("all,-lib-ids"); + else + result = curl_global_trace(token); if(result) goto out; } @@ -747,8 +750,8 @@ static CURLcode set_trace_config(const char *token) global->tracetime = toggle; } else { - char buffer[32]; - msnprintf(buffer, sizeof(buffer), "%c%.*s", toggle ? '+' : '-', + char buffer[64]; + msnprintf(buffer, sizeof(buffer), "%c%.*s,-lib-ids", toggle ? '+' : '-', (int)len, name); result = curl_global_trace(buffer); if(result) From ea4ba6d9ef21a271bfbccedb0456d09a1ed57173 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 2 Oct 2025 08:30:52 +0200 Subject: [PATCH 236/465] lib: remove personal names from comments - it's just too random who got mentioned - we can't mention all, so better consistently mention none - make sure they all are mentioned in THANKS - also remove some unnecessary comment ramblings Closes #18803 --- docs/THANKS | 2 ++ lib/cf-socket.c | 4 ++-- lib/curlx/inet_ntop.c | 3 --- lib/if2ip.h | 3 +-- lib/md4.c | 12 ------------ lib/md5.c | 12 ------------ lib/sha256.c | 4 ++-- lib/vtls/openssl.c | 19 +++++++------------ 8 files changed, 14 insertions(+), 45 deletions(-) diff --git a/docs/THANKS b/docs/THANKS index b5a838f57d0f..97f9999b080a 100644 --- a/docs/THANKS +++ b/docs/THANKS @@ -3245,6 +3245,7 @@ Tommy Tam Tom Regner Tom Seddon Tom Sparrow +Tom St Denis Tom van der Woerdt Tom Wright tomy2105 on github @@ -3317,6 +3318,7 @@ VictorVG on github Victor Vieux Vijay Panghal Vikram Saxena +Viktor Dukhovni Viktor Petersson Viktor Szakats Vilhelm Prytz diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 1fabf0ea0b4a..8ed1116c07b3 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -821,8 +821,8 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) * In October 2003 we effectively nullified this function on Windows due to * problems with it using all CPU in multi-threaded cases. * - * In May 2004, we bring it back to offer more info back on connect failures. - * Gisle Vanem could reproduce the former problems with this function, but + * In May 2004, we brought it back to offer more info back on connect + * failures. We could reproduce the former problems with this function, but * could avoid them by adding this SleepEx() call below: * * "I do not have Rational Quantify, but the hint from his post was diff --git a/lib/curlx/inet_ntop.c b/lib/curlx/inet_ntop.c index 3f8bcbf36683..884cfb79c2d8 100644 --- a/lib/curlx/inet_ntop.c +++ b/lib/curlx/inet_ntop.c @@ -16,9 +16,6 @@ * * SPDX-License-Identifier: ISC */ -/* - * Original code by Paul Vixie. "curlified" by Gisle Vanem. - */ #include "../curl_setup.h" diff --git a/lib/if2ip.h b/lib/if2ip.h index f4b2f4c15d97..b33e41aebd0b 100644 --- a/lib/if2ip.h +++ b/lib/if2ip.h @@ -73,8 +73,7 @@ struct ifreq { } ifr_ifru; }; -/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the - C code. */ +/* This define exists to avoid an extra #ifdef INTERIX in the C code. */ #define ifr_name ifr_ifrn.ifrn_name /* interface name */ #define ifr_addr ifr_ifru.ifru_addr /* address */ diff --git a/lib/md4.c b/lib/md4.c index b30881213e95..241aadf14e7a 100644 --- a/lib/md4.c +++ b/lib/md4.c @@ -247,18 +247,6 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) * There is ABSOLUTELY NO WARRANTY, express or implied. * * (This is a heavily cut-down "BSD license".) - * - * This differs from Colin Plumb's older public domain implementation in that - * no exactly 32-bit integer data type is required (any 32-bit or wider - * unsigned integer data type will do), there is no compile-time endianness - * configuration, and the function prototypes match OpenSSL's. No code from - * Colin Plumb's implementation has been reused; this comment merely compares - * the properties of the two independent implementations. - * - * The primary goals of this implementation are portability and ease of use. - * It is meant to be fast, but not as fast as possible. Some known - * optimizations are not included to reduce source code size and avoid - * compile-time configuration. */ /* Any 32-bit or wider unsigned integer data type will do */ diff --git a/lib/md5.c b/lib/md5.c index e5cc4088dac6..e7d42ec1c0f1 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -282,18 +282,6 @@ static void my_md5_final(unsigned char *digest, void *in) * There is ABSOLUTELY NO WARRANTY, express or implied. * * (This is a heavily cut-down "BSD license".) - * - * This differs from Colin Plumb's older public domain implementation in that - * no exactly 32-bit integer data type is required (any 32-bit or wider - * unsigned integer data type will do), there is no compile-time endianness - * configuration, and the function prototypes match OpenSSL's. No code from - * Colin Plumb's implementation has been reused; this comment merely compares - * the properties of the two independent implementations. - * - * The primary goals of this implementation are portability and ease of use. - * It is meant to be fast, but not as fast as possible. Some known - * optimizations are not included to reduce source code size and avoid - * compile-time configuration. */ /* Any 32-bit or wider unsigned integer data type will do */ diff --git a/lib/sha256.c b/lib/sha256.c index 6f519add58a9..c5ed8b9c8f69 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -231,8 +231,8 @@ static void my_sha256_final(unsigned char *digest, void *in) /* When no other crypto library is available we use this code segment */ -/* This is based on SHA256 implementation in LibTomCrypt that was released into - * public domain by Tom St Denis. */ +/* This is based on the SHA256 implementation in LibTomCrypt that was released + * into public domain. */ #define WPA_GET_BE32(a) ((((unsigned long)(a)[0]) << 24) | \ (((unsigned long)(a)[1]) << 16) | \ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 36818daa9e17..01c0b5513c24 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -1773,8 +1773,6 @@ static CURLcode client_cert(struct Curl_easy *data, x509 = SSL_get_certificate(ssl); - /* This version was provided by Evan Jordan and is supposed to not - leak memory as the previous version: */ if(x509) { EVP_PKEY *pktmp = X509_get_pubkey(x509); EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl)); @@ -2931,10 +2929,9 @@ ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx, case CURL_SSLVERSION_MAX_NONE: /* none selected */ case CURL_SSLVERSION_MAX_DEFAULT: /* max selected */ default: - /* SSL_CTX_set_max_proto_version states that: - setting the maximum to 0 will enable - protocol versions up to the highest version - supported by the library */ + /* SSL_CTX_set_max_proto_version states that: setting the maximum to 0 + will enable protocol versions up to the highest version supported by + the library */ ossl_ssl_version_max = 0; break; } @@ -3291,9 +3288,9 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data, if(!x509) continue; - /* Try to import the certificate. This may fail for legitimate - reasons such as duplicate certificate, which is allowed by MS but - not OpenSSL. */ + /* Try to import the certificate. This may fail for legitimate reasons + such as duplicate certificate, which is allowed by MS but not + OpenSSL. */ if(X509_STORE_add_cert(store, x509) == 1) { #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) infof(data, "SSL: Imported cert"); @@ -4721,9 +4718,7 @@ static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, return result; do { - /* Begin Gyrations to get the subjectPublicKeyInfo */ - /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */ - + /* Get the subjectPublicKeyInfo */ /* https://groups.google.com/group/mailing.openssl.users/browse_thread/thread/d61858dae102c6c7 */ len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); if(len1 < 1) From dba87aea7d0a54a6a8318363a397dcf9c0fd071a Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 2 Oct 2025 10:23:42 +0200 Subject: [PATCH 237/465] multi_ev: remove unnecessary data check that confuses analysers Closes #18804 --- lib/multi_ev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/multi_ev.c b/lib/multi_ev.c index 49e6e673a040..f43423510ff9 100644 --- a/lib/multi_ev.c +++ b/lib/multi_ev.c @@ -507,7 +507,7 @@ static CURLMcode mev_assess(struct Curl_multi *multi, goto out; } } - else if(data) + else Curl_multi_pollset(data, &ps, "ev assess"); last_ps = mev_get_last_pollset(data, conn); From af7900fb283dcfe20e628305d53070cd7c1f58ff Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 1 Oct 2025 22:07:37 +0200 Subject: [PATCH 238/465] CI: move no-verbose build from Circle CI to existing GHA jobs, with tests To test it in GHA and catch issues at PR time. Before this patch, Circle CI caught them after pushing to master (or non-fork PR branches.) GHA also run runtests, pytests and static analysis on these builds, after this patch. - GHA/linux: enable no-verbose in an existing job. - GHA/linux: enable no-verbose in the H3 scan-build job too. - GHA/macos: enable no-verbose in one build (= 3 jobs with different compilers). - GHA/codeql: enable no-verbose in the MultiSSL Linux build. - circleci: delete openssl no-verbose job in favor of the above. Closes #18797 --- .circleci/config.yml | 21 --------------------- .github/workflows/codeql.yml | 3 ++- .github/workflows/linux.yml | 3 ++- .github/workflows/macos.yml | 2 +- 4 files changed, 5 insertions(+), 24 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 39201708e81b..63eae308c49f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,15 +70,6 @@ commands: --with-openssl \ || { tail -1000 config.log; false; } - configure-openssl-no-verbose: - steps: - - run: - command: | - autoreconf -fi - ./configure --disable-dependency-tracking --enable-option-checking=fatal --enable-unity --enable-werror \ - --with-openssl --disable-verbose \ - || { tail -1000 config.log; false; } - configure-no-proxy: steps: - run: @@ -139,14 +130,6 @@ jobs: - build - test - no-verbose: - executor: ubuntu - steps: - - checkout - - install-deps - - configure-openssl-no-verbose - - build - no-proxy: executor: ubuntu steps: @@ -216,10 +199,6 @@ workflows: jobs: - no-proxy - openssl-no-verbose: - jobs: - - no-verbose - arm-openssl: jobs: - arm diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 53505673a473..fe33518d8b16 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -107,7 +107,8 @@ jobs: export PKG_CONFIG_PATH; PKG_CONFIG_PATH="$(brew --prefix c-ares)/lib/pkgconfig:$(brew --prefix mbedtls)/lib/pkgconfig:$(brew --prefix rustls-ffi)/lib/pkgconfig:$(brew --prefix gsasl)/lib/pkgconfig" cmake -B _bld1 -G Ninja -DENABLE_DEBUG=ON \ -DCURL_USE_GNUTLS=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_RUSTLS=ON -DCURL_USE_WOLFSSL=ON \ - -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON -DUSE_ECH=ON -DENABLE_ARES=ON + -DUSE_LIBRTMP=ON -DCURL_USE_GSASL=ON -DCURL_USE_GSSAPI=ON -DUSE_SSLS_EXPORT=ON -DUSE_ECH=ON -DENABLE_ARES=ON \ + -DCURL_DISABLE_VERBOSE_STRINGS=ON cmake --build _bld1 cmake --build _bld1 --target curlinfo cmake --build _bld1 --target servers diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 3c827ae34b1c..3cdb9a47cd60 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -156,7 +156,7 @@ jobs: - name: 'openssl arm' install_steps: pytest - configure: CFLAGS=-std=gnu89 --with-openssl --enable-debug + configure: CFLAGS=-std=gnu89 --with-openssl --enable-debug --disable-verbose image: 'ubuntu-24.04-arm' - name: 'openssl -O3 libssh valgrind' @@ -252,6 +252,7 @@ jobs: --with-openssl=/home/linuxbrew/.linuxbrew/opt/openssl --with-ngtcp2 --with-nghttp3= --with-libidn2 --enable-httpsrr --enable-ares --disable-debug --disable-unity + --disable-verbose - name: 'address-sanitizer' install_packages: clang libssl-dev libssh-dev libidn2-dev libnghttp2-dev libubsan1 libasan8 libtsan2 diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index b0f958d70c98..a321d28b3358 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -277,7 +277,7 @@ jobs: # cmake - name: 'OpenSSL gsasl rtmp AppleIDN' install: libnghttp3 libngtcp2 gsasl rtmpdump - generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON -DUSE_APPLE_IDN=ON -DUSE_NGTCP2=ON + generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON -DUSE_APPLE_IDN=ON -DUSE_NGTCP2=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON - name: 'MultiSSL AppleIDN clang-tidy +examples' compiler: clang install: llvm brotli zstd gnutls nettle libressl krb5 mbedtls gsasl rustls-ffi rtmpdump libssh fish From 9ac3a9a670acc55674c420c11a222c1714bb9d55 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 2 Oct 2025 13:03:49 +0200 Subject: [PATCH 239/465] INTERNALS: drop Winsock 2.2 from the dependency list It's implied by the minimum requirement of Windows XP. Also Windows CE is soon to be deleted via #17927. Closes #18808 --- docs/INTERNALS.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index 93546ebe4bbe..f3c34c114339 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -38,7 +38,6 @@ versions of libs and build tools. - MIT Kerberos 1.2.4 - Heimdal ? - nghttp2 1.15.0 - - Winsock 2.2 (on Windows 95+ and Windows CE .NET 4.1+) ## Build tools From 7682bd80e7d51c6d02e3279ea6b99c7d9e4296d0 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 2 Oct 2025 14:37:14 +0200 Subject: [PATCH 240/465] cmake: drop exclamation in comment looking like a name Ref: https://github.com/curl/curl/pull/3316#issuecomment-442343555 Follow-up to ea4ba6d9ef21a271bfbccedb0456d09a1ed57173 #18803 Follow-up to 558814e16d84aa202c5ccc0c8108a9d728e77a58 Closes #18810 --- CMake/FindGSS.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index 172259e28253..78a9194cd604 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -181,7 +181,7 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr "inc" ) - if(_gss_INCLUDE_DIRS) # jay, we have found something + if(_gss_INCLUDE_DIRS) # We have found something cmake_push_check_state() list(APPEND CMAKE_REQUIRED_INCLUDES "${_gss_INCLUDE_DIRS}") check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers) From b04137c1c6ed164594279c7d04b5e051634453ea Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 27 Sep 2025 16:32:22 +0200 Subject: [PATCH 241/465] renovate: adjust commit message prefixes, try making CodeQL and AWS-LC updates monthly Also: - enable pip bumps in Dependabot. - reduce dependabot to check monthly (was: weekly) Dependabot acts as a backup for mend/renovate. Closes #18761 --- .github/dependabot.yml | 7 ++++++- renovate.json | 26 +++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 701a5d01cfc4..a21592ee3e48 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,4 +7,9 @@ updates: - package-ecosystem: 'github-actions' directory: '/' schedule: - interval: 'weekly' + interval: 'monthly' + + - package-ecosystem: 'pip' + directory: '/' + schedule: + interval: 'monthly' diff --git a/renovate.json b/renovate.json index efb9064dabf2..1bc0309f3a6c 100644 --- a/renovate.json +++ b/renovate.json @@ -10,7 +10,7 @@ "matchManagers": [ "github-actions" ], - "commitMessagePrefix": "gha: ", + "commitMessagePrefix": "GHA: ", "labels": [ "CI" ] @@ -21,7 +21,7 @@ "pinDigest", "digest" ], - "commitMessagePrefix": "ci: ", + "commitMessagePrefix": "CI: ", "labels": [ "CI" ] @@ -30,7 +30,7 @@ "matchManagers": [ "custom.regex" ], - "commitMessagePrefix": "ci: ", + "commitMessagePrefix": "CI: ", "labels": [ "CI" ] @@ -43,6 +43,26 @@ ".github/workflows/linux-old.yml" ], "enabled": false + }, + { + "description": "Schedule CodeQL updates on the 10th of each month", + "matchPackageNames": [ + "/codeql/i" + ], + "groupName": "CodeQL", + "schedule": [ + "* * 10 * *" + ] + }, + { + "description": "Schedule package updates on the 10th of each month", + "matchSourceUrls": [ + "**/awslabs/**" + ], + "groupName": "monthly updates", + "schedule": [ + "* * 10 * *" + ] } ], "customManagers": [ From 03fe4467894848fc58a82a30e25f0d70f793baa7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 2 Oct 2025 13:39:35 +0200 Subject: [PATCH 242/465] INTERNALS: specify minimum version for Heimdal: 7.1.0 Released on 2016-Dec-19, it's the first "revamped" stable version, and the earliest available as a source tarball at the official repository: https://github.com/heimdal/heimdal/releases/tag/heimdal-7.1.0 It's also the first version hosted by Homebrew. It builds fine locally with curl, and also builds in CI with old linux: 7.1.0+dfsg-13+deb9u4. Closes #18809 --- docs/INTERNALS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index f3c34c114339..84b939f4dcb4 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -36,7 +36,7 @@ versions of libs and build tools. - wolfSSL 3.4.6 - OpenLDAP 2.0 - MIT Kerberos 1.2.4 - - Heimdal ? + - Heimdal 7.1.0 - nghttp2 1.15.0 ## Build tools From 2a25ebe9580e52b375533a7d12a86dff29a36c44 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Thu, 2 Oct 2025 09:46:36 -0400 Subject: [PATCH 243/465] vtls_scache: fix race condition - Lock before counting the cache sessions. Prior to this change when taking a session a trace command counted the sessions but not under lock, which caused a race condition. Reported by: Viktor Szakats Fixes https://github.com/curl/curl/issues/18806 Closes https://github.com/curl/curl/pull/18813 --- lib/vtls/vtls_scache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vtls/vtls_scache.c b/lib/vtls/vtls_scache.c index e934fa3b5eac..74b2b20cf674 100644 --- a/lib/vtls/vtls_scache.c +++ b/lib/vtls/vtls_scache.c @@ -902,7 +902,6 @@ CURLcode Curl_ssl_scache_take(struct Curl_cfilter *cf, peer->age = scache->age; /* set this as used in this age */ } } - Curl_ssl_scache_unlock(data); if(s) { *ps = s; CURL_TRC_SSLS(data, "took session for %s [proto=0x%x, " @@ -914,6 +913,7 @@ CURLcode Curl_ssl_scache_take(struct Curl_cfilter *cf, else { CURL_TRC_SSLS(data, "no cached session for %s", ssl_peer_key); } + Curl_ssl_scache_unlock(data); return result; } From e5316069f13ec9189d9fe0499dc09afaa9fb5cee Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 2 Oct 2025 19:10:35 +0200 Subject: [PATCH 244/465] GHA/macos: drop macos-13 runner image from combo jobs - replace with macos-14. - refresh tables, exceptions. - apply a pending TODO. Closes #18818 --- .github/workflows/macos.yml | 48 ++++++++++--------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index a321d28b3358..f731406bfbb9 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -554,62 +554,42 @@ jobs: fail-fast: false matrix: # Sources: - # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-arm64-Readme.md # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md # https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md compiler: [gcc-12, gcc-13, gcc-15, llvm@15, llvm@18, llvm@20, clang] - # Xcode support matrix as of 2024-07, with default macOS SDK versions and OS names, years: + # Xcode support matrix as of 2025-10, with default macOS SDK versions and OS names, years: # * = default Xcode on the runner. - # macos-13: 14.1, 14.2, 14.3.1, 15.0.1, 15.1,*15.2 - # macos-14: 15.0.1, 15.1, 15.2, 15.3,*15.4 - # macos-15: 16.0, 16.1, 16.2, 16.3,*16.4, 26.0 - # macos-26: 16.4 *26.0 - # macOSSDK: 13.0, 13.1, 13.3, 14.0, 14.2, 14.2, 14.4, 14.5, 15.0, 15.1, 15.2, 15.4, 15.5, 26.0 - # Ventura (2022) Sonoma (2023) Sequoia (2024) Tahoe (2025) + # macos-14: 15.0.1, 15.1, 15.2, 15.3,*15.4 + # macos-15: 16.0, 16.1, 16.2, 16.3,*16.4, 26.0 + # macos-26: 16.4 *26.0 + # macOSSDK: 14.0, 14.2, 14.2, 14.4, 14.5, 15.0, 15.1, 15.2, 15.4, 15.5, 26.0 + # Sonoma (2023) Sequoia (2024) Tahoe (2025) # https://github.com/actions/runner-images/tree/main/images/macos # https://en.wikipedia.org/wiki/MacOS_version_history - # TODO when dropping macos-13: replace '$(brew --prefix ...' with /opt/homebrew - image: [macos-13, macos-15, macos-26] + image: [macos-14, macos-15, macos-26] # Can skip these to reduce jobs: # 15.1 has the same default macOS SDK as 15.2 and identical test results. - # 14.1, 15.4 not revealing new fallouts. - #xcode: ['14.1', '14.2', '14.3.1', '15.0.1', '15.1', '15.2', '15.3', '15.4', '16.0', '16.1'] # all Xcode - #xcode: ['14.1', '14.2', '14.3.1', '15.0.1' , '15.2', '15.3', '15.4', '16.0', '16.1'] # all SDK - #xcode: [ '14.2', '14.3.1', '15.0.1' , '15.2', '15.3' , '16.0' ] # coverage + # 15.4 not revealing new fallouts. + #xcode: ['15.0.1', '15.1', '15.2', '15.3', '15.4', '16.0', '16.1'] # all Xcode + #xcode: ['15.0.1' , '15.2', '15.3', '15.4', '16.0', '16.1'] # all SDK + #xcode: ['15.0.1' , '15.2', '15.3' , '16.0' ] # coverage xcode: [''] # default Xcodes macos-version-min: [''] build: [autotools, cmake] exclude: # Combinations not covered by runner images: - - { image: macos-13, xcode: '15.3' } - - { image: macos-13, xcode: '15.4' } - - { image: macos-13, xcode: '16.0' } - - { image: macos-13, xcode: '16.1' } - - { image: macos-13, xcode: '16.2' } - - { image: macos-13, xcode: '16.3' } - - { image: macos-13, xcode: '16.4' } - - { image: macos-13, xcode: '26.0' } - - { image: macos-14, xcode: '14.1' } - - { image: macos-14, xcode: '14.2' } - - { image: macos-14, xcode: '14.3.1' } - { image: macos-14, xcode: '16.0' } - { image: macos-14, xcode: '16.1' } - { image: macos-14, xcode: '16.2' } - { image: macos-14, xcode: '16.3' } - { image: macos-14, xcode: '16.4' } - { image: macos-14, xcode: '26.0' } - - { image: macos-15, xcode: '14.1' } - - { image: macos-15, xcode: '14.2' } - - { image: macos-15, xcode: '14.3.1' } - { image: macos-15, xcode: '15.0.1' } - { image: macos-15, xcode: '15.1' } - { image: macos-15, xcode: '15.2' } - { image: macos-15, xcode: '15.3' } - { image: macos-15, xcode: '15.4' } - - { image: macos-26, xcode: '14.1' } - - { image: macos-26, xcode: '14.2' } - - { image: macos-26, xcode: '14.3.1' } - { image: macos-26, xcode: '15.0.1' } - { image: macos-26, xcode: '15.1' } - { image: macos-26, xcode: '15.2' } @@ -619,8 +599,6 @@ jobs: - { image: macos-26, xcode: '16.1' } - { image: macos-26, xcode: '16.2' } - { image: macos-26, xcode: '16.3' } - - { image: macos-13, compiler: 'llvm@18' } - - { image: macos-13, compiler: 'llvm@20' } - { image: macos-14, compiler: 'llvm@18' } - { image: macos-14, compiler: 'llvm@20' } - { image: macos-15, compiler: 'llvm@15' } @@ -650,7 +628,7 @@ jobs: ls -l /Library/Developer/CommandLineTools/SDKs || true echo '::group::compiler defaults'; echo 'int main(void) {}' | "${CC}" -v -x c -; echo '::endgroup::' echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::' - echo '::group::brew packages preinstalled'; ls -l "$(brew --prefix)/opt"; echo '::endgroup::' + echo '::group::brew packages preinstalled'; ls -l /opt/homebrew/opt; echo '::endgroup::' - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: @@ -686,7 +664,7 @@ jobs: -DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON \ -DCMAKE_OSX_SYSROOT="${sysroot}" \ -DCMAKE_C_COMPILER_TARGET="$(uname -m | sed 's/arm64/aarch64e/')-apple-darwin$(uname -r)" \ - -DCMAKE_IGNORE_PREFIX_PATH="$(brew --prefix)" \ + -DCMAKE_IGNORE_PREFIX_PATH=/opt/homebrew \ -DBUILD_LIBCURL_DOCS=OFF -DBUILD_MISC_DOCS=OFF -DENABLE_CURL_MANUAL=OFF \ -DCURL_USE_OPENSSL=ON \ -DUSE_NGHTTP2=OFF -DUSE_LIBIDN2=OFF \ From 95ac33fc4f8356b1c0685e70d1d8ab7842aecf3a Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 2 Oct 2025 16:39:37 +0200 Subject: [PATCH 245/465] ip-happy: prevent event-based stall on retry When delaying an IP happy eyeball restart, set an actual timer or the connection will stall when running event based. Closes #18815 --- lib/cf-ip-happy.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index 47560889d446..c0150dd08747 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -461,10 +461,10 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, else if(inconclusive) { /* tried all addresses, no success but some where inconclusive. * Let's restart the inconclusive ones. */ - if(curlx_timediff(now, bs->last_attempt_started) >= - bs->attempt_delay_ms) { - CURL_TRC_CF(data, cf, "tried all addresses with inconclusive results" - ", restarting one"); + timediff_t since_ms = curlx_timediff(now, bs->last_attempt_started); + timediff_t delay_ms = bs->attempt_delay_ms - since_ms; + if(delay_ms <= 0) { + CURL_TRC_CF(data, cf, "all attempts inconclusive, restarting one"); i = -1; for(a = bs->running; a; a = a->next) { ++i; @@ -479,6 +479,12 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, } DEBUGASSERT(0); /* should not come here */ } + else { + /* let's wait some more before restarting */ + infof(data, "connect attempts inconclusive, retrying " + "in %" FMT_TIMEDIFF_T "ms", delay_ms); + Curl_expire(data, delay_ms, EXPIRE_HAPPY_EYEBALLS); + } /* attempt timeout for restart has not expired yet */ goto out; } From 06625975af40ddf6067f2105250555ba76b0a6ae Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 2 Oct 2025 17:17:22 +0200 Subject: [PATCH 246/465] cmdline-opts/_PROGRESS.md: explain the suffixes Closes #18817 --- .github/scripts/spellcheck.words | 5 ++++- docs/cmdline-opts/_PROGRESS.md | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/scripts/spellcheck.words b/.github/scripts/spellcheck.words index aafaeff6d927..fb4d9532e6fa 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/spellcheck.words @@ -231,9 +231,9 @@ else's encodings enctype endianness -enums Engler enum +enums epoll EPRT EPSV @@ -294,6 +294,7 @@ GETing getpwuid ggcov Ghedini +giga Gisle Glesys globbed @@ -617,6 +618,7 @@ PEM pem perl permafailing +peta PINGs pipelining PKCS @@ -846,6 +848,7 @@ Tatsuhiro TBD TCP tcpdump +tera testability testcurl TFTP diff --git a/docs/cmdline-opts/_PROGRESS.md b/docs/cmdline-opts/_PROGRESS.md index 4cbbd8eb7800..9ab1ce8c9bf7 100644 --- a/docs/cmdline-opts/_PROGRESS.md +++ b/docs/cmdline-opts/_PROGRESS.md @@ -5,8 +5,8 @@ curl normally displays a progress meter during operations, indicating the amount of transferred data, transfer speeds and estimated time left, etc. The progress meter displays the transfer rate in bytes per second. The suffixes -(k, M, G, T, P) are 1024 based. For example 1k is 1024 bytes. 1M is 1048576 -bytes. +(`k` for kilo, `M` for mega, `G` for giga, `T` for tera, and `P` for peta) are +1024 based. For example 1k is 1024 bytes. 1M is 1048576 bytes. curl displays this data to the terminal by default, so if you invoke curl to do an operation and it is about to write data to the terminal, it *disables* From 18e4fbad4c08b85dcc5b37997d156b954820bbc5 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 2 Oct 2025 14:41:41 +0200 Subject: [PATCH 247/465] tcp-nodelay.md: expand the documentation Instead of referring to another document. Closes #18811 --- docs/cmdline-opts/tcp-nodelay.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/cmdline-opts/tcp-nodelay.md b/docs/cmdline-opts/tcp-nodelay.md index 6944d70142b2..8ef7f9416d1b 100644 --- a/docs/cmdline-opts/tcp-nodelay.md +++ b/docs/cmdline-opts/tcp-nodelay.md @@ -14,8 +14,18 @@ Example: # `--tcp-nodelay` -Turn on the TCP_NODELAY option. See the *curl_easy_setopt(3)* man page for -details about this option. +Turn on the TCP_NODELAY option. + +This option disables the Nagle algorithm on TCP connections. The purpose of +this algorithm is to minimize the number of small packets on the network +(where "small packets" means TCP segments less than the Maximum Segment Size +for the network). + +Maximizing the amount of data sent per TCP segment is good because it +amortizes the overhead of the send. However, in some cases small segments may +need to be sent without delay. This is less efficient than sending larger +amounts of data at a time, and can contribute to congestion on the network if +overdone. curl sets this option by default and you need to explicitly switch it off if you do not want it on (added in 7.50.2). From 84c4b485f38f339b71665f946216a2612a103e84 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 2 Oct 2025 17:07:05 +0200 Subject: [PATCH 248/465] time-cond.md: refer to the singular curl_getdate man page Closes #18816 --- docs/cmdline-opts/time-cond.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cmdline-opts/time-cond.md b/docs/cmdline-opts/time-cond.md index 44cb166349a8..d902dd49d1f8 100644 --- a/docs/cmdline-opts/time-cond.md +++ b/docs/cmdline-opts/time-cond.md @@ -24,7 +24,7 @@ Request a file that has been modified later than the given time and date, or one that has been modified before that time. The date expression can be all sorts of date strings or if it does not match any internal ones, it is treated as a filename and curl tries to get the modification date (mtime) from that -file instead. See the *curl_getdate(3)* man pages for date expression details. +file instead. See the *curl_getdate(3)* man page for date expression details. Start the date expression with a dash (-) to make it request for a document that is older than the given date/time, default is a document that is newer From 06c0f8c5cd5da1b2cfe616f03ae0a187cdee18e6 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 2 Oct 2025 22:50:25 +0200 Subject: [PATCH 249/465] DEPRECATE.md: We remove the OpenSSL-QUIC backend in March 2026 URL: https://curl.se/mail/lib-2025-10/0000.html Closes #18820 --- docs/DEPRECATE.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/DEPRECATE.md b/docs/DEPRECATE.md index 786b6a92c7e0..e74ccc56e859 100644 --- a/docs/DEPRECATE.md +++ b/docs/DEPRECATE.md @@ -55,6 +55,21 @@ free version risk being vulnerable. We remove support for this OpenSSL version from curl in June 2026. +## OpenSSL-QUIC + +OpenSSL-QUIC is what we call the curl QUIC backend that uses the OpenSSL QUIC +stack. + + - It is slower and uses more memory than the alternatives and is only + experimental in curl. + - It gets little attention from OpenSSL and we have no expectation of the + major flaws getting corrected anytime soon. + - No one has spoken up for keeping it + - curl users building with vanilla OpenSSL can still use QUIC through the + means of ngtcp2 + +We remove the OpenSSL-QUIC backend in March 2026. + ## Past removals - axTLS (removed in 7.63.0) From 0a3459ca51754ae54101c5aa0dab9a87a27a6aec Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 2 Oct 2025 23:00:24 +0200 Subject: [PATCH 250/465] DEPRECATE.md: remove OpenSSL 1.1.1 support already in December 2025 No sponsors == remove it Closes #18822 --- docs/DEPRECATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DEPRECATE.md b/docs/DEPRECATE.md index e74ccc56e859..43c94875b175 100644 --- a/docs/DEPRECATE.md +++ b/docs/DEPRECATE.md @@ -53,7 +53,7 @@ We remove support for this OpenSSL version from curl in December 2025. OpenSSL and others only ship fixes to paying customers, meaning users of the free version risk being vulnerable. -We remove support for this OpenSSL version from curl in June 2026. +We remove support for this OpenSSL version from curl in December 2025. ## OpenSSL-QUIC From 2b1fda1fe6e91fee40dd70562fcb91d9ab1ba19b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 3 Oct 2025 08:26:56 +0200 Subject: [PATCH 251/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 55 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 3977134b8379..232cb7a5f853 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,7 +4,7 @@ curl and libcurl 8.17.0 Command line options: 272 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3510 + Contributors: 3513 This release includes the following changes: @@ -12,6 +12,7 @@ This release includes the following changes: o krb5: drop support for Kerberos FTP [43] o libssh2: up the minimum requirement to 1.9.0 [85] o vssh: drop support for wolfSSH [58] + o wcurl: import v2025.09.27 [182] o write-out: make %header{} able to output *all* occurrences of a header [25] This release includes the following bugfixes: @@ -33,16 +34,19 @@ This release includes the following bugfixes: o build: show llvm/clang in platform flags and `buildinfo.txt` [126] o cf-h2-proxy: break loop on edge case [140] o cf-ip-happy: mention unix domain path, not port number [161] + o cf-socket: tweak a memcpy() to read better [177] o cf-socket: use the right byte order for ports in bindlocal [61] o cfilter: unlink and discard [46] o checksrc: catch banned functions when preceded by `(` [146] o checksrc: fix possible endless loop when detecting `BANNEDFUNC` [149] o cmake: add `CURL_CODE_COVERAGE` option [78] o cmake: clang detection tidy-ups [116] + o cmake: drop exclamation in comment looking like a name [160] o cmake: fix building docs when the base directory contains `.3` [18] o cmake: use modern alternatives for `get_filename_component()` [102] o cmake: use more `COMPILER_OPTIONS`, `LINK_OPTIONS` / `LINK_FLAGS` [152] o cmdline-docs: extended, clarified, refreshed [28] + o cmdline-opts/_PROGRESS.md: explain the suffixes [154] o configure: add "-mt" for pthread support on HP-UX [52] o cookie: avoid saving a cookie file if no transfer was done [11] o curl_easy_getinfo: error code on NULL arg [2] @@ -62,15 +66,21 @@ This release includes the following bugfixes: o easy_getinfo: check magic, Curl_close safety [3] o examples: fix two issues found by CodeQL [35] o examples: fix two more cases of `stat()` TOCTOU [147] + o form.md: drop reference to MANUAL [178] o ftp: fix ftp_do_more returning with *completep unset [122] o ftp: fix port number range loop for PORT commands [66] o gtls: avoid potential use of uninitialized variable in trace output [83] o hostip: remove leftover INT_MAX check in Curl_dnscache_prune [88] o http: handle user-defined connection headers [165] o httpsrr: free old pointers when storing new [57] + o INTERNALS: drop Winsock 2.2 from the dependency list [162] + o INTERNALS: specify minimum version for Heimdal: 7.1.0 [158] o ip-happy: do not set unnecessary timeout [95] + o ip-happy: prevent event-based stall on retry [155] o krb5: return appropriate error on send failures [22] o ldap: do not base64 encode zero length string [42] + o lib: fix build error and compiler warnings with verbose strings disabled [173] + o lib: remove personal names from comments [168] o lib: upgrade/multiplex handling [136] o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] @@ -91,6 +101,7 @@ This release includes the following bugfixes: o mbedtls: check result of setting ALPN [127] o mbedtls: handle WANT_WRITE from mbedtls_ssl_read() [145] o multi.h: add CURLMINFO_LASTENTRY [51] + o multi_ev: remove unnecessary data check that confuses analysers [167] o ngtcp2: check error code on connect failure [13] o ngtcp2: fix early return [131] o openldap: avoid indexing the result at -1 for blank responses [44] @@ -98,15 +109,18 @@ This release includes the following bugfixes: o openldap: check ldap_get_option() return codes [119] o openssl-quic: check results better [132] o openssl-quic: handle error in SSL_get_stream_read_error_code [129] + o openssl-quic: ignore unexpected streams opened by server [176] o openssl: clear retry flag on x509 error [130] o openssl: fail the transfer if ossl_certchain() fails [23] o openssl: make the asn1_object_dump name null terminated [56] o openssl: set io_need always [99] o OS400: fix a use-after-free/double-free case [142] + o pytest: skip specific tests for no-verbose builds [171] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] o quiche: fix verbose message when ip quadruple cannot be obtained. [128] o quiche: when ingress processing fails, return that error code [103] + o runtests: tag tests that require curl verbose strings [172] o rustls: fix clang-tidy warning [107] o rustls: fix comment describing cr_recv() [117] o rustls: typecast variable for safer trace output [69] @@ -130,6 +144,7 @@ This release includes the following bugfixes: o socks_sspi: restore non-blocking socket on error paths [48] o ssl-sessions.md: mark option experimental [12] o sws: fix checking `sscanf()` return value [17] + o tcp-nodelay.md: expand the documentation [153] o telnet: make printsub require another byte input [21] o telnet: refuse IAC codes in content [111] o telnet: return error on crazy TTYPE or XDISPLOC lengths [123] @@ -144,6 +159,7 @@ This release includes the following bugfixes: o tidy-up: avoid using the reserved macro namespace [76] o tidy-up: update MS links, allow long URLs via `checksrc` [73] o tidy-up: URLs [101] + o time-cond.md: refer to the singular curl_getdate man page [148] o TODO: fix a typo [93] o TODO: remove already implemented or bad items [36] o tool: fix exponential retry delay [47] @@ -151,13 +167,17 @@ This release includes the following bugfixes: o tool_cb_hdr: size is always 1 [70] o tool_doswin: fix to use curl socket functions [108] o tool_getparam/set_rate: skip the multiplication on overflow [84] + o tool_getparam: always disable "lib-ids" for tracing [169] + o tool_getparam: warn if provided header looks malformed [179] o tool_operate: improve wording in retry message [37] o tool_operate: keep the progress meter for --out-null [33] o tool_progress: handle possible integer overflows [164] + o tool_progress: make max5data() use an algorithm [170] o transfer: avoid busy loop with tiny speed limit [100] o urldata: FILE is not a list-only protocol [9] o vtls: alpn setting, check proto parameter [134] o vtls_int.h: clarify data_pending [124] + o vtls_scache: fix race condition [157] o windows: replace `_beginthreadex()` with `CreateThread()` [80] o windows: stop passing unused, optional argument for Win9x compatibility [75] o wolfssl: check BIO read parameters [133] @@ -186,16 +206,17 @@ Planned upcoming removals include: This release would not have looked like this without help, code, reports and advice from friends like these: - Adam Light, Andrew Kirillov, Andrew Olsen, BobodevMm on github, - Christian Schmitz, Dan Fandrich, Daniel Stenberg, dependabot[bot], - divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, + Adam Light, Alice Lee Poetics, Andrew Kirillov, Andrew Olsen, + BobodevMm on github, Christian Schmitz, Dan Fandrich, Daniel Stenberg, + dependabot[bot], divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, Evgeny Grin (Karlson2k), fds242 on github, Howard Chu, Javier Blazquez, Jicea, jmaggard10 on github, Johannes Schindelin, Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, kuchara on github, Marcel Raad, Michael Osipov, MichaÅ‚ Petryka, Mohamed Daahir, Nir Azkiel, Patrick Monnerat, - Ray Satiro, renovate[bot], rinsuki on github, Samuel Dionne-Riel, - Stanislav Fort, Stefan Eissing, Viktor Szakats - (35 contributors) + Pocs Norbert, Ray Satiro, renovate[bot], rinsuki on github, + Samuel Dionne-Riel, Samuel Henrique, Stanislav Fort, Stefan Eissing, + Viktor Szakats + (38 contributors) References to bug reports and discussions on issues: @@ -344,11 +365,31 @@ References to bug reports and discussions on issues: [145] = https://curl.se/bug/?i=18682 [146] = https://curl.se/bug/?i=18779 [147] = https://curl.se/bug/?i=18778 + [148] = https://curl.se/bug/?i=18816 [149] = https://curl.se/bug/?i=18775 [150] = https://curl.se/bug/?i=18510 [151] = https://curl.se/bug/?i=18774 [152] = https://curl.se/bug/?i=18762 + [153] = https://curl.se/bug/?i=18811 + [154] = https://curl.se/bug/?i=18817 + [155] = https://curl.se/bug/?i=18815 + [157] = https://curl.se/bug/?i=18806 + [158] = https://curl.se/bug/?i=18809 + [160] = https://curl.se/bug/?i=18810 [161] = https://curl.se/bug/?i=18749 + [162] = https://curl.se/bug/?i=18808 [163] = https://curl.se/bug/?i=18747 [164] = https://curl.se/bug/?i=18744 [165] = https://curl.se/bug/?i=18662 + [167] = https://curl.se/bug/?i=18804 + [168] = https://curl.se/bug/?i=18803 + [169] = https://curl.se/bug/?i=18805 + [170] = https://curl.se/bug/?i=18807 + [171] = https://curl.se/bug/?i=18801 + [172] = https://curl.se/bug/?i=18800 + [173] = https://curl.se/bug/?i=18799 + [176] = https://curl.se/bug/?i=18780 + [177] = https://curl.se/bug/?i=18787 + [178] = https://curl.se/bug/?i=18790 + [179] = https://curl.se/bug/?i=18793 + [182] = https://curl.se/bug/?i=18754 From 9cc1ee55a4a363e6a13408bfac58f4f7a17e625f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 3 Oct 2025 08:30:55 +0200 Subject: [PATCH 252/465] RELEASE-NOTES: synced Add OpenSSL-QUIC as an item to get removed --- RELEASE-NOTES | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 232cb7a5f853..b638b559c4cd 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -197,6 +197,7 @@ Planned upcoming removals include: o Builds using VS2008 o OpenSSL 1.x support + o OpenSSL-QUIC o Support for c-ares versions before 1.16.0 o Support for Windows XP/2003 o Windows CE support From eefd03c572996e5de4dec4fe295ad6f103e0eefc Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 24 Sep 2025 10:19:46 +0200 Subject: [PATCH 253/465] ssl: support Apple SecTrust configurations - configure/cmake support for enabling the option - supported in OpenSSL and GnuTLS backends - when configured, Apple SecTrust is the default trust store for peer verification. When one of the CURLOPT_* for adding certificates is used, that default does not apply. - add documentation of build options and SSL use Closes #18703 --- .github/scripts/spellcheck.words | 1 + .github/workflows/configure-vs-cmake.yml | 4 +- .github/workflows/macos.yml | 9 +- CMakeLists.txt | 19 +- acinclude.m4 | 10 + configure.ac | 8 + docs/INSTALL-CMAKE.md | 1 + docs/INSTALL.md | 19 + docs/SSLCERTS.md | 54 +- docs/cmdline-opts/ca-native.md | 6 +- lib/Makefile.inc | 2 + lib/curl_config.h.cmake | 3 + lib/setopt.c | 14 +- lib/url.c | 30 - lib/urldata.h | 3 + lib/vquic/vquic-tls.c | 4 +- lib/vtls/apple.c | 297 +++++++++ lib/vtls/apple.h | 55 ++ lib/vtls/gtls.c | 370 ++++++----- lib/vtls/gtls.h | 3 +- lib/vtls/openssl.c | 784 ++++++++++++++--------- lib/vtls/openssl.h | 4 +- lib/vtls/vtls.c | 141 ++-- lib/vtls/vtls_scache.c | 2 +- m4/curl-apple-sectrust.m4 | 58 ++ tests/data/test305 | 2 +- tests/http/test_02_download.py | 2 + tests/http/test_07_upload.py | 2 + tests/http/test_17_ssl_use.py | 4 +- 29 files changed, 1342 insertions(+), 569 deletions(-) create mode 100644 lib/vtls/apple.c create mode 100644 lib/vtls/apple.h create mode 100644 m4/curl-apple-sectrust.m4 diff --git a/.github/scripts/spellcheck.words b/.github/scripts/spellcheck.words index fb4d9532e6fa..73e68f48840e 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/spellcheck.words @@ -743,6 +743,7 @@ scp SDK se SEB +SecTrust SEK selectable Serv diff --git a/.github/workflows/configure-vs-cmake.yml b/.github/workflows/configure-vs-cmake.yml index 984fccd59221..b259daee514a 100644 --- a/.github/workflows/configure-vs-cmake.yml +++ b/.github/workflows/configure-vs-cmake.yml @@ -92,13 +92,13 @@ jobs: run: | autoreconf -fi export PKG_CONFIG_DEBUG_SPEW=1 - mkdir bld-am && cd bld-am && ../configure --enable-static=no --with-openssl --without-libpsl --disable-ldap --with-brotli --with-zstd + mkdir bld-am && cd bld-am && ../configure --enable-static=no --with-openssl --without-libpsl --disable-ldap --with-brotli --with-zstd --with-apple-sectrust - name: 'run cmake' run: | cmake -B bld-cm -DCURL_WERROR=ON -DCURL_USE_LIBPSL=OFF -DCURL_DISABLE_LDAP=ON \ -DCMAKE_C_COMPILER_TARGET="$(uname -m | sed 's/arm64/aarch64/')-apple-darwin$(uname -r)" \ - -DCURL_USE_LIBSSH2=OFF + -DCURL_USE_LIBSSH2=OFF -DUSE_APPLE_SECTRUST=ON - name: 'configure log' run: cat bld-am/config.log 2>/dev/null || true diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index f731406bfbb9..931abc8693c9 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -265,6 +265,11 @@ jobs: install: libnghttp3 libngtcp2 install_steps: pytest configure: --enable-debug --with-openssl=/opt/homebrew/opt/openssl --with-ngtcp2 + - name: 'OpenSSL SecTrust' + compiler: clang + install: libnghttp3 libngtcp2 + install_steps: pytest + configure: --enable-debug --with-openssl=/opt/homebrew/opt/openssl --with-ngtcp2 --with-apple-sectrust - name: 'OpenSSL event-based' compiler: clang configure: --enable-debug --with-openssl=/opt/homebrew/opt/openssl @@ -275,9 +280,9 @@ jobs: configure: --enable-debug --disable-ldap --with-openssl=/opt/homebrew/opt/quictls LDFLAGS=-L/opt/homebrew/opt/quictls/lib macos-version-min: '10.15' # cmake - - name: 'OpenSSL gsasl rtmp AppleIDN' + - name: 'OpenSSL gsasl rtmp AppleIDN SecTrust' install: libnghttp3 libngtcp2 gsasl rtmpdump - generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON -DUSE_APPLE_IDN=ON -DUSE_NGTCP2=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON + generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON -DUSE_APPLE_IDN=ON -DUSE_NGTCP2=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DUSE_APPLE_SECTRUST=ON - name: 'MultiSSL AppleIDN clang-tidy +examples' compiler: clang install: llvm brotli zstd gnutls nettle libressl krb5 mbedtls gsasl rustls-ffi rtmpdump libssh fish diff --git a/CMakeLists.txt b/CMakeLists.txt index 115eaa5f3419..3b5ed10f8061 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -764,6 +764,23 @@ if(CURL_WINDOWS_SSPI AND NOT WINDOWS_STORE) set(USE_WINDOWS_SSPI ON) endif() +if(APPLE) + option(USE_APPLE_SECTRUST "Use Apple OS-native certificate verification" OFF) + if(USE_APPLE_SECTRUST) + find_library(COREFOUNDATION_FRAMEWORK NAMES "Security") + mark_as_advanced(COREFOUNDATION_FRAMEWORK) + if(NOT COREFOUNDATION_FRAMEWORK) + message(FATAL_ERROR "Security framework not found") + endif() + list(APPEND CURL_LIBS "-framework Security") + + set(_use_core_foundation_and_core_services ON) + message(STATUS "Apple OS-native certificate verification enabled") + endif() +else() + set(USE_APPLE_SECTRUST OFF) +endif() + if(_use_core_foundation_and_core_services) find_library(COREFOUNDATION_FRAMEWORK NAMES "CoreFoundation") mark_as_advanced(COREFOUNDATION_FRAMEWORK) @@ -1531,7 +1548,7 @@ if(_curl_ca_bundle_supported) unset(CURL_CA_BUNDLE CACHE) elseif(CURL_CA_BUNDLE STREQUAL "auto") unset(CURL_CA_BUNDLE CACHE) - if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32) + if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32 AND NOT USE_APPLE_SECTRUST) set(_curl_ca_bundle_autodetect TRUE) endif() else() diff --git a/acinclude.m4 b/acinclude.m4 index 7b26dfd466a3..517de0c4a63e 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1149,6 +1149,12 @@ AS_HELP_STRING([--without-ca-path], [Don't use a default CA path]), capath_warning=" (warning: certs not found)" check_capath="" + if test "x$APPLE_SECTRUST_ENABLED" = "x1"; then + ca_native="Apple SecTrust" + else + ca_native="no" + fi + if test "x$want_ca" != "xno" -a "x$want_ca" != "xunset" -a \ "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then dnl both given @@ -1162,6 +1168,10 @@ AS_HELP_STRING([--without-ca-path], [Don't use a default CA path]), dnl --with-ca-path given capath="$want_capath" ca="no" + elif test "x$ca_native" != "xno"; then + # native ca configured, do not look further + ca="no" + capath="no" else dnl First try auto-detecting a CA bundle, then a CA path. dnl Both auto-detections can be skipped by --without-ca-* diff --git a/configure.ac b/configure.ac index fddae6a630d1..5dde9f6c96f2 100644 --- a/configure.ac +++ b/configure.ac @@ -277,6 +277,12 @@ AS_HELP_STRING([--with-rustls=PATH],[where to look for Rustls, PATH points to th fi ]) +OPT_APPLE_SECTRUST=$curl_cv_apple +AC_ARG_WITH(apple-sectrust,dnl +AS_HELP_STRING([--with-apple-sectrust],[enable Apple OS native certificate verification]),[ + OPT_APPLE_SECTRUST=$withval + ]) + AC_PATH_PROG(PERL, perl,, $PATH:/usr/local/bin/perl:/usr/bin/:/usr/local/bin) AC_SUBST(PERL) AM_CONDITIONAL(PERL, test -n "$PERL") @@ -2016,6 +2022,7 @@ CURL_WITH_GNUTLS CURL_WITH_MBEDTLS CURL_WITH_WOLFSSL CURL_WITH_RUSTLS +CURL_WITH_APPLE_SECTRUST dnl link required libraries for USE_WIN32_CRYPTO or SCHANNEL_ENABLED if test "x$USE_WIN32_CRYPTO" = "x1" -o "x$SCHANNEL_ENABLED" = "x1"; then @@ -5588,6 +5595,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl: Verbose errors: ${curl_verbose_msg} Code coverage: ${curl_coverage_msg} SSPI: ${curl_sspi_msg} + ca native: ${ca_native} ca cert bundle: ${ca}${ca_warning} ca cert path: ${capath}${capath_warning} ca cert embed: ${CURL_CA_EMBED_msg} diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index 566fee742314..4c7875252198 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -368,6 +368,7 @@ Details via CMake - `CURL_ZSTD`: Use zstd (`ON`, `OFF` or `AUTO`). Default: `AUTO` - `ENABLE_ARES`: Enable c-ares support. Default: `OFF` - `USE_APPLE_IDN`: Use Apple built-in IDN support. Default: `OFF` +- `USE_APPLE_SECTRUST`: Use Apple OS-native certificate verification. Default: `OFF` - `USE_LIBIDN2`: Use libidn2 for IDN support. Default: `ON` - `USE_LIBRTMP`: Enable librtmp from rtmpdump. Default: `OFF` - `USE_NGHTTP2`: Use nghttp2 library. Default: `ON` diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 80fcb9321613..453071afd57b 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -153,6 +153,25 @@ conflicting identical symbol names. When you build with multiple TLS backends, you can select the active one at runtime when curl starts up. +### Selecting TLS Trust Anchors Defaults + +Verifying a server certificate established a chain of trust that needs to +start somewhere. Those "root" certificates make the set of Trust Anchors. + +While the build system tries to find good defaults on the platform you +use, you may specify these explicitly. The following options are provided: + + - `--with-ca-bundle=FILE`: the file that libcurl loads default root + certificates from. + - `--with-ca-path=DIRECTORY`: a directory in which root certificates files + are found. + - `--with-ca-embed=FILE`: a file read *at build time* and added to `libcurl`. + - `--with-ca-fallback`: an OpenSSL specific option for delegating default + trust anchor selection to what OpenSSL thinks is best, *if* there are +no other certificates configured by the application. + - `--with-apple-sectrust`: use the system "SecTrust" service on Apple + operating systems for verification. (Added in 8.17.0) + ## MultiSSL and HTTP/3 HTTP/3 needs QUIC and QUIC needs TLS. Building libcurl with HTTP/3 and QUIC diff --git a/docs/SSLCERTS.md b/docs/SSLCERTS.md index 4efb9cf00ba7..de3954553421 100644 --- a/docs/SSLCERTS.md +++ b/docs/SSLCERTS.md @@ -8,8 +8,10 @@ SPDX-License-Identifier: curl ## Native vs file based -If curl was built with Schannel support, then curl uses the system native CA -store for verification. All other TLS libraries use a file based CA store by +If curl was built with Schannel support, then curl uses the Windows native CA +store for verification. On Apple operating systems, it is possible to use Apple's +"SecTrust" services for certain TLS backends, details below. +All other TLS libraries use a file based CA store by default. ## Verification @@ -71,8 +73,10 @@ another option to restrict search to the application's directory. ### Use the native store -In several environments, in particular on Windows, you can ask curl to use the -system's native CA store when verifying the certificate. +In several environments, in particular on Microsoft and Apple operating +systems, you can ask curl to use the system's native CA store when verifying +the certificate. Depending on how curl was built, this may already be the +default. With the curl command line tool: `--ca-native`. @@ -102,14 +106,46 @@ latest Firefox bundle. ## Native CA store -If curl was built with Schannel or was instructed to use the native CA Store, -then curl uses the certificates that are built into the OS. These are the same -certificates that appear in the Internet Options control panel (under Windows) -or Keychain Access application (under macOS). Any custom security rules for -certificates are honored. +### Windows + Schannel + +If curl was built with Schannel, then curl uses the certificates that are +built into the OS. These are the same certificates that appear in the +Internet Options control panel (under Windows). +Any custom security rules for certificates are honored. Schannel runs CRL checks on certificates unless peer verification is disabled. +### Apple + OpenSSL/GnuTLS + +When curl is built with Apple SecTrust enabled and uses an OpenSSL compatible +TLS backend or GnuTLS, the default verification is handled by that Apple +service. As in: + + curl https://example.com + +You may still provide your own certificates on the command line, such as: + + curl --cacert mycerts.pem https://example.com + +In this situation, Apple SecTrust is **not** used and verification is done +**only** with the trust anchors found in `mycerts.pem`. If you want **both** +Apple SecTrust and your own file to be considered, use: + + curl --ca-native --cacert mycerts.pem https://example.com + + +#### Other Combinations + +How well the use of native CA stores work in all other combinations depends +on the TLS backend and the OS. Many TLS backends offer functionality to access +the native CA on a range of operating systems. Some provide this only on specific +configurations. + +Specific support in curl exists for Windows and OpenSSL compatible TLS backends. +It tries to load the certificates from the Windows "CA" and "ROOT" stores for +transfers requesting the native CA. Due to Window's delayed population of those +stores, this might not always find all certificates. + ## HTTPS proxy curl can do HTTPS to the proxy separately from the connection to the server. diff --git a/docs/cmdline-opts/ca-native.md b/docs/cmdline-opts/ca-native.md index 7e833c9d1572..a8e8c5e9a8ae 100644 --- a/docs/cmdline-opts/ca-native.md +++ b/docs/cmdline-opts/ca-native.md @@ -25,12 +25,14 @@ This option is independent of other CA certificate locations set at run time or build time. Those locations are searched in addition to the native CA store. This option works with OpenSSL and its forks (LibreSSL, BoringSSL, etc) on -Windows. (Added in 7.71.0) +Windows (Added in 7.71.0) and on Apple OS when libcurl is built with +Apple SecTrust enabled. (Added in 8.17.0) This option works with wolfSSL on Windows, Linux (Debian, Ubuntu, Gentoo, Fedora, RHEL), macOS, Android and iOS. (Added in 8.3.0) -This option works with GnuTLS. (Added in 8.5.0) +This option works with GnuTLS (Added in 8.5.0) and also uses Apple +SecTrust when libcurl is built with it. (Added in 8.17.0) This option works with rustls on Windows, macOS, Android and iOS. On Linux it is equivalent to using the Mozilla CA certificate bundle. When used with rustls diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 1447e53a1e5b..ff8144fb5ac0 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -77,6 +77,7 @@ LIB_VAUTH_HFILES = \ vauth/vauth.h LIB_VTLS_CFILES = \ + vtls/apple.c \ vtls/cipher_suite.c \ vtls/gtls.c \ vtls/hostcheck.c \ @@ -94,6 +95,7 @@ LIB_VTLS_CFILES = \ vtls/x509asn1.c LIB_VTLS_HFILES = \ + vtls/apple.h \ vtls/cipher_suite.h \ vtls/gtls.h \ vtls/hostcheck.h \ diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index bc8c1cd487cc..521a439eef3e 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -788,6 +788,9 @@ ${SIZEOF_TIME_T_CODE} /* to enable Apple IDN */ #cmakedefine USE_APPLE_IDN 1 +/* to enable Apple OS-native certificate verification */ +#cmakedefine USE_APPLE_SECTRUST 1 + /* Define to 1 if OpenSSL has the SSL_CTX_set_srp_username function. */ #cmakedefine HAVE_OPENSSL_SRP 1 diff --git a/lib/setopt.c b/lib/setopt.c index 3f628c443ca4..1c9ee42d41b9 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -2206,6 +2206,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, /* * Set CA info for SSL connection. Specify filename of the CA certificate */ + s->ssl.custom_cafile = TRUE; return Curl_setstropt(&s->str[STRING_SSL_CAFILE], ptr); #ifndef CURL_DISABLE_PROXY @@ -2214,6 +2215,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Set CA info SSL connection for proxy. Specify filename of the * CA certificate */ + s->proxy_ssl.custom_cafile = TRUE; return Curl_setstropt(&s->str[STRING_SSL_CAFILE_PROXY], ptr); #endif @@ -2223,9 +2225,11 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * certificates which have been prepared using openssl c_rehash utility. */ #ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) + if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) { /* This does not work on Windows. */ + s->ssl.custom_capath = TRUE; return Curl_setstropt(&s->str[STRING_SSL_CAPATH], ptr); + } #endif return CURLE_NOT_BUILT_IN; #ifndef CURL_DISABLE_PROXY @@ -2235,9 +2239,11 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * CA certificates which have been prepared using openssl c_rehash utility. */ #ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) + if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) { /* This does not work on Windows. */ + s->proxy_ssl.custom_capath = TRUE; return Curl_setstropt(&s->str[STRING_SSL_CAPATH_PROXY], ptr); + } #endif return CURLE_NOT_BUILT_IN; #endif @@ -2900,8 +2906,10 @@ static CURLcode setopt_blob(struct Curl_easy *data, CURLoption option, * Specify entire PEM of the CA certificate */ #ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) + if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) { + s->ssl.custom_cablob = TRUE; return Curl_setblobopt(&s->blobs[BLOB_CAINFO], blob); + } #endif return CURLE_NOT_BUILT_IN; case CURLOPT_ISSUERCERT_BLOB: diff --git a/lib/url.c b/lib/url.c index 41a63890e6ef..0dface920d92 100644 --- a/lib/url.c +++ b/lib/url.c @@ -435,36 +435,6 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->socks5_gssapi_nec = FALSE; #endif - /* Set the default CA cert bundle/path detected/specified at build time. - * - * If Schannel is the selected SSL backend then these locations are ignored. - * We allow setting CA location for Schannel when explicitly specified by - * the user via CURLOPT_CAINFO / --cacert. - */ - if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) { -#ifdef CURL_CA_BUNDLE - result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); - if(result) - return result; -#ifndef CURL_DISABLE_PROXY - result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], - CURL_CA_BUNDLE); - if(result) - return result; -#endif -#endif -#ifdef CURL_CA_PATH - result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH); - if(result) - return result; -#ifndef CURL_DISABLE_PROXY - result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH); - if(result) - return result; -#endif -#endif - } - /* set default minimum TLS version */ #ifdef USE_SSL Curl_setopt_SSLVERSION(data, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT); diff --git a/lib/urldata.h b/lib/urldata.h index 3c7e634b0008..d924b911941d 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -285,6 +285,9 @@ struct ssl_config_data { BIT(native_ca_store); /* use the native ca store of operating system */ BIT(auto_client_cert); /* automatically locate and use a client certificate for authentication (Schannel) */ + BIT(custom_cafile); /* application has set custom CA file */ + BIT(custom_capath); /* application has set custom CA path */ + BIT(custom_cablob); /* application has set custom CA blob */ }; struct ssl_general_config { diff --git a/lib/vquic/vquic-tls.c b/lib/vquic/vquic-tls.c index 4bdd23c981cd..6576c5cd454a 100644 --- a/lib/vquic/vquic-tls.c +++ b/lib/vquic/vquic-tls.c @@ -130,7 +130,7 @@ CURLcode Curl_vquic_tls_before_recv(struct curl_tls_ctx *ctx, { #ifdef USE_OPENSSL if(!ctx->ossl.x509_store_setup) { - CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ossl.ssl_ctx); + CURLcode result = Curl_ssl_setup_x509_store(cf, data, &ctx->ossl); if(result) return result; ctx->ossl.x509_store_setup = TRUE; @@ -170,7 +170,7 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx, result = Curl_ossl_check_peer_cert(cf, data, &ctx->ossl, peer); #elif defined(USE_GNUTLS) if(conn_config->verifyhost) { - result = Curl_gtls_verifyserver(data, ctx->gtls.session, + result = Curl_gtls_verifyserver(cf, data, ctx->gtls.session, conn_config, &data->set.ssl, peer, data->set.str[STRING_SSL_PINNEDPUBLICKEY]); if(result) diff --git a/lib/vtls/apple.c b/lib/vtls/apple.c new file mode 100644 index 000000000000..b565c8f031e1 --- /dev/null +++ b/lib/vtls/apple.c @@ -0,0 +1,297 @@ +/*************************************************************************** + * _ _ ____ _ + * 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 + * + ***************************************************************************/ + +/* This file is for implementing all "generic" SSL functions that all libcurl + internals should use. It is then responsible for calling the proper + "backend" function. + + SSL-functions in libcurl should call functions in this source file, and not + to any specific SSL-layer. + + Curl_ssl_ - prefix for generic ones + + Note that this source code uses the functions of the configured SSL + backend via the global Curl_ssl instance. + + "SSL/TLS Strong Encryption: An Introduction" + https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html +*/ + +#include "../curl_setup.h" + +#include "../urldata.h" +#include "../cfilters.h" +#include "../curl_trc.h" +#include "vtls.h" +#include "apple.h" + +#if defined(USE_SSL) && defined(USE_APPLE_SECTRUST) +#include +#endif /* USE_SSL && USE_APPLE_SECTRUST */ + +/* The last #include files should be: */ +#include "../curl_memory.h" +#include "../memdebug.h" + + +#if defined(USE_SSL) && defined(USE_APPLE_SECTRUST) +#define SSL_SYSTEM_VERIFIER + +#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) \ + && MAC_OS_X_VERSION_MAX_ALLOWED >= 101400) \ + || (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) \ + && __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000) +#define SUPPORTS_SecTrustEvaluateWithError 1 +#endif + +#if defined(SUPPORTS_SecTrustEvaluateWithError) \ + && ((defined(MAC_OS_X_VERSION_MIN_REQUIRED) \ + && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) \ + || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) \ + && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)) +#define REQUIRES_SecTrustEvaluateWithError 1 +#endif + +#if defined(SUPPORTS_SecTrustEvaluateWithError) \ + && !defined(HAVE_BUILTIN_AVAILABLE) \ + && !defined(REQUIRES_SecTrustEvaluateWithError) +#undef SUPPORTS_SecTrustEvaluateWithError +#endif + +#if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) \ + && MAC_OS_X_VERSION_MAX_ALLOWED >= 100900) \ + || (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) \ + && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) +#define SUPPORTS_SecOCSP 1 +#endif + +CURLcode Curl_vtls_apple_verify(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ssl_peer *peer, + size_t num_certs, + Curl_vtls_get_cert_der *der_cb, + void *cb_user_data, + const unsigned char *ocsp_buf, + size_t ocsp_len) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + CURLcode result = CURLE_OK; + SecTrustRef trust = NULL; + SecPolicyRef policy = NULL; + CFMutableArrayRef policies = NULL; + CFMutableArrayRef cert_array = NULL; + CFStringRef host_str = NULL; + CFErrorRef error = NULL; + OSStatus status = noErr; + CFStringRef error_ref = NULL; + char *err_desc = NULL; + size_t i; + + if(conn_config->verifyhost) { + host_str = CFStringCreateWithCString(NULL, + peer->sni ? peer->sni : peer->hostname, kCFStringEncodingUTF8); + if(!host_str) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + + policies = CFArrayCreateMutable(NULL, 2, &kCFTypeArrayCallBacks); + if(!policies) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + policy = SecPolicyCreateSSL(true, host_str); + if(!policy) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + CFArrayAppendValue(policies, policy); + CFRelease(policy); + policy = NULL; + +#if defined(HAVE_BUILTIN_AVAILABLE) && defined(SUPPORTS_SecOCSP) + { + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + if(!ssl_config->no_revoke) { + if(__builtin_available(macOS 10.9, iOS 7, tvOS 9, watchOS 2, *)) { + /* Even without this set, validation will seemingly-unavoidably fail + * for certificates that trustd already knows to be revoked. + * This policy further allows trustd to consult CRLs and OCSP data + * to determine revocation status (which it may then cache). */ + CFOptionFlags revocation_flags = kSecRevocationUseAnyAvailableMethod; +#if 0 + /* `revoke_best_effort` is off by default in libcurl. When we + * add `kSecRevocationRequirePositiveResponse` to the Apple + * Trust policies, it interprets this as it NEEDs a confirmation + * of a cert being NOT REVOKED. Which not in general available for + * certificates on the internet. + * It seems that applications using this policy are expected to PIN + * their certificate public keys or verification will fail. + * This does not seem to be what we want here. */ + if(!ssl_config->revoke_best_effort) { + revocation_flags |= kSecRevocationRequirePositiveResponse; + } +#endif + policy = SecPolicyCreateRevocation(revocation_flags); + if(!policy) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + CFArrayAppendValue(policies, policy); + } + } + } +#endif + + cert_array = CFArrayCreateMutable(NULL, num_certs, &kCFTypeArrayCallBacks); + if(!cert_array) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + for(i = 0; i < num_certs; i++) { + SecCertificateRef cert; + CFDataRef certdata; + unsigned char *der; + size_t der_len; + + result = der_cb(cf, data, cb_user_data, i, &der, &der_len); + if(result) + goto out; + + certdata = CFDataCreate(NULL, der, (CFIndex)der_len); + if(!certdata) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + cert = SecCertificateCreateWithData(NULL, certdata); + CFRelease(certdata); + if(!cert) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + CFArrayAppendValue(cert_array, cert); + CFRelease(cert); + } + + status = SecTrustCreateWithCertificates(cert_array, policies, &trust); + if(status != noErr || !trust) { + failf(data, "Apple SecTrust: failed to create validation trust"); + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; + } + +#if defined(HAVE_BUILTIN_AVAILABLE) && defined(SUPPORTS_SecOCSP) + if(ocsp_len > 0) { + if(__builtin_available(macOS 10.9, iOS 7, tvOS 9, watchOS 2, *)) { + CFDataRef ocspdata = + CFDataCreate(NULL, ocsp_buf, (CFIndex)ocsp_len); + + status = SecTrustSetOCSPResponse(trust, ocspdata); + CFRelease(ocspdata); + if(status != noErr) { + failf(data, "Apple SecTrust: failed to set OCSP response: %i", + (int)status); + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; + } + } + } +#else + (void)ocsp_buf; + (void)ocsp_len; +#endif + +#ifdef SUPPORTS_SecTrustEvaluateWithError +#if defined(HAVE_BUILTIN_AVAILABLE) + if(__builtin_available(macOS 10.14, iOS 12, tvOS 12, watchOS 5, *)) { +#else + if(1) { +#endif + result = SecTrustEvaluateWithError(trust, &error) ? + CURLE_OK : CURLE_PEER_FAILED_VERIFICATION; + if(error) { + CFIndex code = CFErrorGetCode(error); + error_ref = CFErrorCopyDescription(error); + + if(error_ref) { + CFIndex size = CFStringGetMaximumSizeForEncoding( + CFStringGetLength(error_ref), kCFStringEncodingUTF8); + err_desc = malloc(size + 1); + if(err_desc) { + if(!CFStringGetCString(error_ref, err_desc, size, + kCFStringEncodingUTF8)) { + free(err_desc); + err_desc = NULL; + } + } + } + infof(data, "Apple SecTrust failure %ld%s%s", code, + err_desc ? ": " : "", err_desc ? err_desc : ""); + } + } + else +#endif /* SUPPORTS_SecTrustEvaluateWithError */ + { +#ifndef REQUIRES_SecTrustEvaluateWithError + SecTrustResultType sec_result; + status = SecTrustEvaluate(trust, &sec_result); + + if(status != noErr) { + failf(data, "Apple SecTrust verification failed: error %i", (int)status); + } + else if((status == kSecTrustResultUnspecified) || + (status == kSecTrustResultProceed)) { + /* "unspecified" means system-trusted with no explicit user setting */ + result = CURLE_OK; + } +#endif /* REQUIRES_SecTrustEvaluateWithError */ + } + +out: + free(err_desc); + if(error_ref) + CFRelease(error_ref); + if(error) + CFRelease(error); + if(host_str) + CFRelease(host_str); + if(policies) + CFRelease(policies); + if(policy) + CFRelease(policy); + if(cert_array) + CFRelease(cert_array); + if(trust) + CFRelease(trust); + return result; +} + +#endif /* USE_SSL && USE_APPLE_SECTRUST */ diff --git a/lib/vtls/apple.h b/lib/vtls/apple.h new file mode 100644 index 000000000000..c965a449f14f --- /dev/null +++ b/lib/vtls/apple.h @@ -0,0 +1,55 @@ +#ifndef HEADER_CURL_VTLS_APPLE_H +#define HEADER_CURL_VTLS_APPLE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Jan Venekamp, + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "../curl_setup.h" + +#if defined(USE_SSL) && defined(USE_APPLE_SECTRUST) +struct Curl_cfilter; +struct Curl_easy; +struct ssl_peer; + +/* Get the DER encoded i-th certificate in the server handshake */ +typedef CURLcode Curl_vtls_get_cert_der(struct Curl_cfilter *cf, + struct Curl_easy *data, + void *user_data, + size_t i, + unsigned char **pder, + size_t *pder_len); + +/* Ask Apple's Security framework to verify the certificate chain + * send by the peer. On CURLE_OK it has been verified. + */ +CURLcode Curl_vtls_apple_verify(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ssl_peer *peer, + size_t num_certs, + Curl_vtls_get_cert_der *der_cb, + void *cb_user_data, + const unsigned char *ocsp_buf, + size_t ocsp_len); +#endif /* USE_SSL && USE_APPLE_SECTRUST */ + +#endif /* HEADER_CURL_VTLS_APPLE_H */ diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 2db73ca2d5d1..3d69ab1d1cab 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -48,6 +48,7 @@ #include "vtls.h" #include "vtls_int.h" #include "vtls_scache.h" +#include "apple.h" #include "../vauth/vauth.h" #include "../parsedate.h" #include "../connect.h" /* for the connect timeout */ @@ -454,62 +455,75 @@ static CURLcode gtls_populate_creds(struct Curl_cfilter *cf, { struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + bool creds_are_empty = TRUE; int rc; - if(config->verifypeer) { - bool imported_native_ca = FALSE; + if(!config->verifypeer) { + infof(data, "SSL Trust: peer verification disabled"); + return CURLE_OK; + } - if(ssl_config->native_ca_store) { - rc = gnutls_certificate_set_x509_system_trust(creds); - if(rc < 0) - infof(data, "error reading native ca store (%s), continuing anyway", - gnutls_strerror(rc)); - else { - infof(data, "found %d certificates in native ca store", rc); - if(rc > 0) - imported_native_ca = TRUE; - } + infof(data, "SSL Trust Anchors:"); + if(ssl_config->native_ca_store) { +#ifdef USE_APPLE_SECTRUST + infof(data, " Native: Apple SecTrust"); + creds_are_empty = FALSE; +#else + rc = gnutls_certificate_set_x509_system_trust(creds); + if(rc < 0) + infof(data, "error reading native ca store (%s), continuing anyway", + gnutls_strerror(rc)); + else { + infof(data, " Native: %d certificates from system trust", rc); + if(rc > 0) + creds_are_empty = FALSE; } +#endif + } - if(config->CAfile) { - /* set the trusted CA cert bundle file */ - gnutls_certificate_set_verify_flags(creds, - GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); - - rc = gnutls_certificate_set_x509_trust_file(creds, - config->CAfile, - GNUTLS_X509_FMT_PEM); - if(rc < 0) { - infof(data, "error reading ca cert file %s (%s)%s", - config->CAfile, gnutls_strerror(rc), - (imported_native_ca ? ", continuing anyway" : "")); - if(!imported_native_ca) { - ssl_config->certverifyresult = rc; - return CURLE_SSL_CACERT_BADFILE; - } + if(config->CAfile) { + /* set the trusted CA cert bundle file */ + gnutls_certificate_set_verify_flags(creds, + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); + + rc = gnutls_certificate_set_x509_trust_file(creds, + config->CAfile, + GNUTLS_X509_FMT_PEM); + creds_are_empty = creds_are_empty && (rc <= 0); + if(rc < 0) { + infof(data, "error reading ca cert file %s (%s)%s", + config->CAfile, gnutls_strerror(rc), + (creds_are_empty ? "" : ", continuing anyway")); + if(creds_are_empty) { + ssl_config->certverifyresult = rc; + return CURLE_SSL_CACERT_BADFILE; } - else - infof(data, "found %d certificates in %s", rc, config->CAfile); } + else + infof(data, " CAfile: %d certificates in %s", rc, config->CAfile); + } - if(config->CApath) { - /* set the trusted CA cert directory */ - rc = gnutls_certificate_set_x509_trust_dir(creds, config->CApath, - GNUTLS_X509_FMT_PEM); - if(rc < 0) { - infof(data, "error reading ca cert file %s (%s)%s", - config->CApath, gnutls_strerror(rc), - (imported_native_ca ? ", continuing anyway" : "")); - if(!imported_native_ca) { - ssl_config->certverifyresult = rc; - return CURLE_SSL_CACERT_BADFILE; - } + if(config->CApath) { + /* set the trusted CA cert directory */ + rc = gnutls_certificate_set_x509_trust_dir(creds, config->CApath, + GNUTLS_X509_FMT_PEM); + creds_are_empty = creds_are_empty && (rc <= 0); + if(rc < 0) { + infof(data, "error reading ca cert file %s (%s)%s", + config->CApath, gnutls_strerror(rc), + (creds_are_empty ? "" : ", continuing anyway")); + if(creds_are_empty) { + ssl_config->certverifyresult = rc; + return CURLE_SSL_CACERT_BADFILE; } - else - infof(data, "found %d certificates in %s", rc, config->CApath); } + else + infof(data, " CApath: %d certificates in %s", rc, config->CApath); } + if(creds_are_empty) + infof(data, " no trust anchors configured"); + if(config->CRLfile) { /* set the CRL list file */ rc = gnutls_certificate_set_x509_crl_file(creds, config->CRLfile, @@ -520,7 +534,7 @@ static CURLcode gtls_populate_creds(struct Curl_cfilter *cf, return CURLE_SSL_CRL_BADFILE; } else - infof(data, "found %d CRL in %s", rc, config->CRLfile); + infof(data, " CRLfile: %d CRL in %s", rc, config->CRLfile); } return CURLE_OK; @@ -1520,31 +1534,76 @@ static CURLcode gtls_verify_ocsp_status(struct Curl_easy *data, return result; } +struct gtls_cert_chain { + const gnutls_datum_t *certs; + unsigned int num_certs; +}; + +#ifdef USE_APPLE_SECTRUST +static CURLcode gtls_chain_get_der(struct Curl_cfilter *cf, + struct Curl_easy *data, + void *user_data, + size_t i, + unsigned char **pder, + size_t *pder_len) +{ + struct gtls_cert_chain *chain = user_data; + + (void)cf; + (void)data; + *pder_len = 0; + *pder = NULL; + + if(i >= chain->num_certs) + return CURLE_TOO_LARGE; + *pder = chain->certs[i].data; + *pder_len = (size_t)chain->certs[i].size; + return CURLE_OK; +} + +static CURLcode glts_apple_verify(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ssl_peer *peer, + struct gtls_cert_chain *chain, + bool *pverified) +{ + CURLcode result; + + result = Curl_vtls_apple_verify(cf, data, peer, chain->num_certs, + gtls_chain_get_der, chain, + NULL, 0); + *pverified = !result; + if(*pverified) + infof(data, " SSL certificate verified by Apple SecTrust."); + return result; +} +#endif /* USE_APPLE_SECTRUST */ + CURLcode -Curl_gtls_verifyserver(struct Curl_easy *data, +Curl_gtls_verifyserver(struct Curl_cfilter *cf, + struct Curl_easy *data, gnutls_session_t session, struct ssl_primary_config *config, struct ssl_config_data *ssl_config, struct ssl_peer *peer, const char *pinned_key) { - unsigned int cert_list_size; - const gnutls_datum_t *chainp; - unsigned int verify_status = 0; + struct gtls_cert_chain chain; gnutls_x509_crt_t x509_cert = NULL, x509_issuer = NULL; time_t certclock; int rc; CURLcode result = CURLE_OK; long * const certverifyresult = &ssl_config->certverifyresult; + (void)cf; /* This function will return the peer's raw certificate (chain) as sent by the peer. These certificates are in raw format (DER encoded for X.509). In case of a X.509 then a certificate list may be present. The first certificate in the list is the peer's certificate, following the issuer's certificate, then the issuer's issuer etc. */ - chainp = gnutls_certificate_get_peers(session, &cert_list_size); - if(!chainp) { + chain.certs = gnutls_certificate_get_peers(session, &chain.num_certs); + if(!chain.certs) { if(config->verifypeer || config->verifyhost || config->issuercert) { @@ -1567,16 +1626,16 @@ Curl_gtls_verifyserver(struct Curl_easy *data, infof(data, " common name: WARNING could not obtain"); } - if(data->set.ssl.certinfo && chainp) { + if(data->set.ssl.certinfo && chain.certs) { unsigned int i; - result = Curl_ssl_init_certinfo(data, (int)cert_list_size); + result = Curl_ssl_init_certinfo(data, (int)chain.num_certs); if(result) goto out; - for(i = 0; i < cert_list_size; i++) { - const char *beg = (const char *) chainp[i].data; - const char *end = beg + chainp[i].size; + for(i = 0; i < chain.num_certs; i++) { + const char *beg = (const char *) chain.certs[i].data; + const char *end = beg + chain.certs[i].size; result = Curl_extract_certinfo(data, (int)i, beg, end); if(result) @@ -1585,13 +1644,15 @@ Curl_gtls_verifyserver(struct Curl_easy *data, } if(config->verifypeer) { - /* This function will try to verify the peer's certificate and return its - status (trusted, invalid etc.). The value of status should be one or - more of the gnutls_certificate_status_t enumerated elements bitwise - or'd. To avoid denial of service attacks some default upper limits - regarding the certificate key size and chain size are set. To override - them use gnutls_certificate_set_verify_limits(). */ - + bool verified = FALSE; + unsigned int verify_status = 0; + /* This function will try to verify the peer's certificate and return + its status (trusted, invalid etc.). The value of status should be + one or more of the gnutls_certificate_status_t enumerated elements + bitwise or'd. To avoid denial of service attacks some default + upper limits regarding the certificate key size and chain size + are set. To override them use + gnutls_certificate_set_verify_limits(). */ rc = gnutls_certificate_verify_peers2(session, &verify_status); if(rc < 0) { failf(data, "server cert verify failed: %d", rc); @@ -1599,37 +1660,109 @@ Curl_gtls_verifyserver(struct Curl_easy *data, result = CURLE_SSL_CONNECT_ERROR; goto out; } - *certverifyresult = verify_status; + verified = !(verify_status & GNUTLS_CERT_INVALID); + if(verified) + infof(data, " SSL certificate verified by GnuTLS"); + +#ifdef USE_APPLE_SECTRUST + if(!verified && ssl_config->native_ca_store && + (verify_status & GNUTLS_CERT_SIGNER_NOT_FOUND)) { + result = glts_apple_verify(cf, data, peer, &chain, &verified); + if(result && (result != CURLE_PEER_FAILED_VERIFICATION)) + goto out; /* unexpected error */ + if(verified) { + infof(data, "SSL certificate verified via Apple SecTrust."); + *certverifyresult = 0; + } + } +#endif + + if(!verified) { + /* verify_status is a bitmask of gnutls_certificate_status bits */ + const char *cause = "certificate error, no details available"; + if(verify_status & GNUTLS_CERT_EXPIRED) + cause = "certificate has expired"; + else if(verify_status & GNUTLS_CERT_SIGNER_NOT_FOUND) + cause = "certificate signer not trusted"; + else if(verify_status & GNUTLS_CERT_INSECURE_ALGORITHM) + cause = "certificate uses insecure algorithm"; + else if(verify_status & GNUTLS_CERT_INVALID_OCSP_STATUS) + cause = "attached OCSP status response is invalid"; + failf(data, "SSL certificate verification failed: %s. (CAfile: %s " + "CRLfile: %s)", cause, + config->CAfile ? config->CAfile : "none", + ssl_config->primary.CRLfile ? + ssl_config->primary.CRLfile : "none"); + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; + } + } + else + infof(data, " SSL certificate verification SKIPPED"); + + /* initialize an X.509 certificate structure. */ + gnutls_x509_crt_init(&x509_cert); + + if(chain.certs) + /* convert the given DER or PEM encoded Certificate to the native + gnutls_x509_crt_t format */ + gnutls_x509_crt_import(x509_cert, chain.certs, GNUTLS_X509_FMT_DER); + + /* Check for time-based validity */ + certclock = gnutls_x509_crt_get_expiration_time(x509_cert); - /* verify_status is a bitmask of gnutls_certificate_status bits */ - if(verify_status & GNUTLS_CERT_INVALID) { + if(certclock == (time_t)-1) { + if(config->verifypeer) { + failf(data, "server cert expiration date verify failed"); + *certverifyresult = GNUTLS_CERT_EXPIRED; + result = CURLE_SSL_CONNECT_ERROR; + goto out; + } + else + infof(data, " SSL certificate expiration date verify FAILED"); + } + else { + if(certclock < time(NULL)) { if(config->verifypeer) { - const char *cause = "certificate error, no details available"; - if(verify_status & GNUTLS_CERT_EXPIRED) - cause = "certificate has expired"; - else if(verify_status & GNUTLS_CERT_SIGNER_NOT_FOUND) - cause = "certificate signer not trusted"; - else if(verify_status & GNUTLS_CERT_INSECURE_ALGORITHM) - cause = "certificate uses insecure algorithm"; - else if(verify_status & GNUTLS_CERT_INVALID_OCSP_STATUS) - cause = "attached OCSP status response is invalid"; - failf(data, "server verification failed: %s. (CAfile: %s " - "CRLfile: %s)", cause, - config->CAfile ? config->CAfile : "none", - ssl_config->primary.CRLfile ? - ssl_config->primary.CRLfile : "none"); + failf(data, "server certificate expiration date has passed."); + *certverifyresult = GNUTLS_CERT_EXPIRED; result = CURLE_PEER_FAILED_VERIFICATION; goto out; } else - infof(data, " server certificate verification FAILED"); + infof(data, " SSL certificate expiration date FAILED"); } else - infof(data, " server certificate verification OK"); + infof(data, " SSL certificate expiration date OK"); + } + + certclock = gnutls_x509_crt_get_activation_time(x509_cert); + + if(certclock == (time_t)-1) { + if(config->verifypeer) { + failf(data, "server cert activation date verify failed"); + *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; + result = CURLE_SSL_CONNECT_ERROR; + goto out; + } + else + infof(data, " SSL certificate activation date verify FAILED"); + } + else { + if(certclock > time(NULL)) { + if(config->verifypeer) { + failf(data, "server certificate not activated yet."); + *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; + } + else + infof(data, " SSL certificate activation date FAILED"); + } + else + infof(data, " SSL certificate activation date OK"); } - else - infof(data, " server certificate verification SKIPPED"); if(config->verifystatus) { result = gtls_verify_ocsp_status(data, session); @@ -1637,15 +1770,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data, goto out; } else - infof(data, " server certificate status verification SKIPPED"); - - /* initialize an X.509 certificate structure. */ - gnutls_x509_crt_init(&x509_cert); - - if(chainp) - /* convert the given DER or PEM encoded Certificate to the native - gnutls_x509_crt_t format */ - gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); + infof(data, " SSL certificate status verification SKIPPED"); if(config->issuercert) { gnutls_datum_t issuerp; @@ -1660,7 +1785,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data, result = CURLE_SSL_ISSUER_ERROR; goto out; } - infof(data, " server certificate issuer check OK (Issuer Cert: %s)", + infof(data, " SSL certificate issuer check OK (Issuer Cert: %s)", config->issuercert ? config->issuercert : "none"); } @@ -1725,61 +1850,6 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(result) goto out; - /* Check for time-based validity */ - certclock = gnutls_x509_crt_get_expiration_time(x509_cert); - - if(certclock == (time_t)-1) { - if(config->verifypeer) { - failf(data, "server cert expiration date verify failed"); - *certverifyresult = GNUTLS_CERT_EXPIRED; - result = CURLE_SSL_CONNECT_ERROR; - goto out; - } - else - infof(data, " server certificate expiration date verify FAILED"); - } - else { - if(certclock < time(NULL)) { - if(config->verifypeer) { - failf(data, "server certificate expiration date has passed."); - *certverifyresult = GNUTLS_CERT_EXPIRED; - result = CURLE_PEER_FAILED_VERIFICATION; - goto out; - } - else - infof(data, " server certificate expiration date FAILED"); - } - else - infof(data, " server certificate expiration date OK"); - } - - certclock = gnutls_x509_crt_get_activation_time(x509_cert); - - if(certclock == (time_t)-1) { - if(config->verifypeer) { - failf(data, "server cert activation date verify failed"); - *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; - result = CURLE_SSL_CONNECT_ERROR; - goto out; - } - else - infof(data, " server certificate activation date verify FAILED"); - } - else { - if(certclock > time(NULL)) { - if(config->verifypeer) { - failf(data, "server certificate not activated yet."); - *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; - result = CURLE_PEER_FAILED_VERIFICATION; - goto out; - } - else - infof(data, " server certificate activation date FAILED"); - } - else - infof(data, " server certificate activation date OK"); - } - if(pinned_key) { result = pkp_pin_peer_pubkey(data, x509_cert, pinned_key); if(result != CURLE_OK) { @@ -1814,7 +1884,7 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf, #endif CURLcode result; - result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config, + result = Curl_gtls_verifyserver(cf, data, session, conn_config, ssl_config, &connssl->peer, pinned_key); if(result) goto out; diff --git a/lib/vtls/gtls.h b/lib/vtls/gtls.h index 01f8b43ac8fc..afbe51eb9cb8 100644 --- a/lib/vtls/gtls.h +++ b/lib/vtls/gtls.h @@ -100,7 +100,8 @@ CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf, struct Curl_easy *data, struct gtls_ctx *gtls); -CURLcode Curl_gtls_verifyserver(struct Curl_easy *data, +CURLcode Curl_gtls_verifyserver(struct Curl_cfilter *cf, + struct Curl_easy *data, gnutls_session_t session, struct ssl_primary_config *config, struct ssl_config_data *ssl_config, diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 01c0b5513c24..193723b64904 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -67,6 +67,7 @@ #include "../strdup.h" #include "../strerror.h" #include "../curl_printf.h" +#include "apple.h" #include #include @@ -738,7 +739,7 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen) /* Before returning server replies to the SSL instance, we need * to have setup the x509 store or verification will fail. */ if(!octx->x509_store_setup) { - r2 = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx); + r2 = Curl_ssl_setup_x509_store(cf, data, octx); if(r2) { BIO_clear_retry_flags(bio); octx->io_result = r2; @@ -1816,6 +1817,7 @@ static CURLcode client_cert(struct Curl_easy *data, return CURLE_OK; } +#ifndef CURL_DISABLE_VERBOSE_STRINGS /* returns non-zero on failure */ static CURLcode x509_name_oneline(X509_NAME *a, struct dynbuf *d) { @@ -1837,6 +1839,7 @@ static CURLcode x509_name_oneline(X509_NAME *a, struct dynbuf *d) } return result; } +#endif /** * Global SSL init @@ -2392,7 +2395,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, string and we cannot match it. */ Curl_cert_hostcheck(altptr, altlen, peer->hostname, hostlen)) { matched = TRUE; - infof(data, " subjectAltName: host \"%s\" matched cert's \"%.*s\"", + infof(data, " subjectAltName: \"%s\" matches cert's \"%.*s\"", peer->dispname, (int)altlen, altptr); } break; @@ -2403,7 +2406,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { matched = TRUE; infof(data, - " subjectAltName: host \"%s\" matched cert's IP address!", + " subjectAltName: \"%s\" matches cert's IP address!", peer->dispname); } break; @@ -3169,17 +3172,17 @@ static CURLcode load_cacert_from_memory(X509_STORE *store, } #ifdef USE_WIN32_CRYPTO -static CURLcode import_windows_cert_store(struct Curl_easy *data, - const char *name, - X509_STORE *store, - bool *imported) +static CURLcode ossl_win_load_store(struct Curl_easy *data, + const char *win_store, + X509_STORE *store, + bool *padded) { CURLcode result = CURLE_OK; HCERTSTORE hStore; - *imported = FALSE; + *padded = FALSE; - hStore = CertOpenSystemStoreA(0, name); + hStore = CertOpenSystemStoreA(0, win_store); if(hStore) { PCCERT_CONTEXT pContext = NULL; /* The array of enhanced key usage OIDs will vary per certificate and @@ -3295,7 +3298,7 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data, #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) infof(data, "SSL: Imported cert"); #endif - *imported = TRUE; + *padded = TRUE; } X509_free(x509); } @@ -3310,125 +3313,181 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data, return result; } -#endif -static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf, +static CURLcode ossl_windows_load_anchors(struct Curl_cfilter *cf, + struct Curl_easy *data, + X509_STORE *store, + bool *padded) +{ + /* Import certificates from the Windows root certificate store if + requested. + https://stackoverflow.com/questions/9507184/ + https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037 + https://datatracker.ietf.org/doc/html/rfc5280 */ + const char *win_stores[] = { + "ROOT", /* Trusted Root Certification Authorities */ + "CA" /* Intermediate Certification Authorities */ + }; + size_t i; + CURLcode result = CURLE_OK; + + *padded = FALSE; + for(i = 0; i < CURL_ARRAYSIZE(win_stores); ++i) { + bool store_added = FALSE; + result = ossl_win_load_store(data, win_stores[i], store, &store_added); + if(result) + return result; + if(store_added) { + CURL_TRC_CF(data, cf, "added trust anchors from Windows %s store", + win_stores[i]); + *padded = TRUE; + } + else + infof(data, "error importing Windows %s store, continuing anyway", + win_stores[i]); + } + return result; +} + +#endif /* USE_WIN32_CRYPTO */ + +static CURLcode ossl_load_trust_anchors(struct Curl_cfilter *cf, struct Curl_easy *data, + struct ossl_ctx *octx, X509_STORE *store) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); CURLcode result = CURLE_OK; - X509_LOOKUP *lookup = NULL; - const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; const char * const ssl_cafile = /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ - (ca_info_blob ? NULL : conn_config->CAfile); + (conn_config->ca_info_blob ? NULL : conn_config->CAfile); const char * const ssl_capath = conn_config->CApath; - const char * const ssl_crlfile = ssl_config->primary.CRLfile; - const bool verifypeer = conn_config->verifypeer; - bool imported_native_ca = FALSE; - bool imported_ca_info_blob = FALSE; + bool have_native_check = FALSE; - CURL_TRC_CF(data, cf, "ossl_populate_x509_store, path=%s, blob=%d", - ssl_cafile ? ssl_cafile : "none", !!ca_info_blob); - if(!store) - return CURLE_OUT_OF_MEMORY; - - if(verifypeer) { + octx->store_is_empty = TRUE; + if(ssl_config->native_ca_store) { #ifdef USE_WIN32_CRYPTO - /* Import certificates from the Windows root certificate store if - requested. - https://stackoverflow.com/questions/9507184/ - https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037 - https://datatracker.ietf.org/doc/html/rfc5280 */ - if(ssl_config->native_ca_store) { - const char *storeNames[] = { - "ROOT", /* Trusted Root Certification Authorities */ - "CA" /* Intermediate Certification Authorities */ - }; - size_t i; - for(i = 0; i < CURL_ARRAYSIZE(storeNames); ++i) { - bool imported = FALSE; - result = import_windows_cert_store(data, storeNames[i], store, - &imported); - if(result) - return result; - if(imported) { - infof(data, "successfully imported Windows %s store", storeNames[i]); - imported_native_ca = TRUE; - } - else - infof(data, "error importing Windows %s store, continuing anyway", - storeNames[i]); - } + bool added = FALSE; + result = ossl_windows_load_anchors(cf, data, store, &added); + if(result) + return result; + if(added) { + infof(data, " Native: Windows System Stores ROOT+CA"); + octx->store_is_empty = FALSE; } +#elif defined(USE_APPLE_SECTRUST) + infof(data, " Native: Apple SecTrust"); + have_native_check = TRUE; #endif - if(ca_info_blob) { - result = load_cacert_from_memory(store, ca_info_blob); - if(result) { - failf(data, "error importing CA certificate blob"); - return result; - } - else { - imported_ca_info_blob = TRUE; - infof(data, "successfully imported CA certificate blob"); - } + } + + if(conn_config->ca_info_blob) { + result = load_cacert_from_memory(store, conn_config->ca_info_blob); + if(result) { + failf(data, "error adding trust anchors from certificate blob: %d", + result); + return result; } + infof(data, " CA Blob from configuration"); + octx->store_is_empty = FALSE; + } - if(ssl_cafile || ssl_capath) { + if(ssl_cafile || ssl_capath) { #ifdef HAVE_OPENSSL3 - /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ - if(ssl_cafile && !X509_STORE_load_file(store, ssl_cafile)) { - if(!imported_native_ca && !imported_ca_info_blob) { + /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ + if(ssl_cafile) { + if(!X509_STORE_load_file(store, ssl_cafile)) { + if(octx->store_is_empty && !have_native_check) { /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate file: %s", ssl_cafile); + failf(data, "error adding trust anchors from file: %s", ssl_cafile); return CURLE_SSL_CACERT_BADFILE; } else infof(data, "error setting certificate file, continuing anyway"); } - if(ssl_capath && !X509_STORE_load_path(store, ssl_capath)) { - if(!imported_native_ca && !imported_ca_info_blob) { + infof(data, " CAfile: %s", ssl_cafile); + octx->store_is_empty = FALSE; + } + if(ssl_capath) { + if(!X509_STORE_load_path(store, ssl_capath)) { + if(octx->store_is_empty && !have_native_check) { /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate path: %s", ssl_capath); + failf(data, "error adding trust anchors from path: %s", ssl_capath); return CURLE_SSL_CACERT_BADFILE; } else infof(data, "error setting certificate path, continuing anyway"); } + infof(data, " CApath: %s", ssl_capath); + octx->store_is_empty = FALSE; + } #else - /* tell OpenSSL where to find CA certificates that are used to verify the - server's certificate. */ - if(!X509_STORE_load_locations(store, ssl_cafile, ssl_capath)) { - if(!imported_native_ca && !imported_ca_info_blob) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate verify locations:" - " CAfile: %s CApath: %s", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - return CURLE_SSL_CACERT_BADFILE; - } - else { - infof(data, "error setting certificate verify locations," - " continuing anyway"); - } + /* tell OpenSSL where to find CA certificates that are used to verify the + server's certificate. */ + if(!X509_STORE_load_locations(store, ssl_cafile, ssl_capath)) { + if(octx->store_is_empty && !have_native_check) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error adding trust anchors from locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return CURLE_SSL_CACERT_BADFILE; + } + else { + infof(data, "error setting certificate verify locations," + " continuing anyway"); } -#endif - infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); - infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); } + if(ssl_cafile) + infof(data, " CAfile: %s", ssl_cafile); + if(ssl_capath) + infof(data, " CApath: %s", ssl_capath); + octx->store_is_empty = FALSE; +#endif + } #ifdef CURL_CA_FALLBACK - if(!ssl_cafile && !ssl_capath && - !imported_native_ca && !imported_ca_info_blob) { - /* verifying the peer without any CA certificates will not - work so use OpenSSL's built-in default as fallback */ - X509_STORE_set_default_paths(store); - } + if(octx->store_is_empty) { + /* verifying the peer without any CA certificates will not + work so use OpenSSL's built-in default as fallback */ + X509_STORE_set_default_paths(store); + infof(data, " OpenSSL default paths (fallback)"); + octx->store_is_empty = FALSE; + } #endif + if(octx->store_is_empty && !have_native_check) + infof(data, " no trust anchors configured"); + + return result; +} + +static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ossl_ctx *octx, + X509_STORE *store) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + CURLcode result = CURLE_OK; + X509_LOOKUP *lookup = NULL; + const char * const ssl_crlfile = ssl_config->primary.CRLfile; + + CURL_TRC_CF(data, cf, "configuring OpenSSL's x509 trust store"); + if(!store) + return CURLE_OUT_OF_MEMORY; + + if(!conn_config->verifypeer) { + infof(data, "SSL Trust: peer verification disabled"); + return CURLE_OK; } + infof(data, "SSL Trust Anchors:"); + result = ossl_load_trust_anchors(cf, data, octx, store); + if(result) + return result; + + /* Does not make sense to load a CRL file without peer verification */ if(ssl_crlfile) { /* tell OpenSSL where to find CRL file that is used to check certificate * revocation */ @@ -3438,33 +3497,28 @@ static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf, failf(data, "error loading CRL file: %s", ssl_crlfile); return CURLE_SSL_CRL_BADFILE; } - /* Everything is fine. */ - infof(data, "successfully loaded CRL file:"); X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); - - infof(data, " CRLfile: %s", ssl_crlfile); + infof(data, " CRLfile: %s", ssl_crlfile); } - if(verifypeer) { - /* Try building a chain using issuers in the trusted store first to avoid - problems with server-sent legacy intermediates. Newer versions of - OpenSSL do alternate chain checking by default but we do not know how to - determine that in a reliable manner. - https://web.archive.org/web/20190422050538/rt.openssl.org/Ticket/Display.html?id=3621 + /* Try building a chain using issuers in the trusted store first to avoid + problems with server-sent legacy intermediates. Newer versions of + OpenSSL do alternate chain checking by default but we do not know how to + determine that in a reliable manner. + https://web.archive.org/web/20190422050538/rt.openssl.org/Ticket/Display.html?id=3621 + */ + X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST); + if(!ssl_config->no_partialchain && !ssl_crlfile) { + /* Have intermediate certificates in the trust store be treated as + trust-anchors, in the same way as self-signed root CA certificates + are. This allows users to verify servers using the intermediate cert + only, instead of needing the whole chain. + + Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we + cannot do partial chains with a CRL check. */ - X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST); - if(!ssl_config->no_partialchain && !ssl_crlfile) { - /* Have intermediate certificates in the trust store be treated as - trust-anchors, in the same way as self-signed root CA certificates - are. This allows users to verify servers using the intermediate cert - only, instead of needing the whole chain. - - Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we - cannot do partial chains with a CRL check. - */ - X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN); - } + X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN); } return result; @@ -3479,6 +3533,7 @@ struct ossl_x509_share { char *CAfile; /* CAfile path used to generate X509 store */ X509_STORE *store; /* cached X509 store or NULL if none */ struct curltime time; /* when the cached store was created */ + BIT(store_is_empty); /* no certs/paths/blobs are in the store */ }; static void oss_x509_share_free(void *key, size_t key_len, void *p) @@ -3523,13 +3578,15 @@ ossl_cached_x509_store_different(struct Curl_cfilter *cf, } static X509_STORE *ossl_get_cached_x509_store(struct Curl_cfilter *cf, - const struct Curl_easy *data) + const struct Curl_easy *data, + bool *pempty) { struct Curl_multi *multi = data->multi; struct ossl_x509_share *share; X509_STORE *store = NULL; DEBUGASSERT(multi); + *pempty = TRUE; share = multi ? Curl_hash_pick(&multi->proto_hash, CURL_UNCONST(MPROTO_OSSL_X509_KEY), sizeof(MPROTO_OSSL_X509_KEY)-1) : NULL; @@ -3537,6 +3594,7 @@ static X509_STORE *ossl_get_cached_x509_store(struct Curl_cfilter *cf, !ossl_cached_x509_store_expired(data, share) && !ossl_cached_x509_store_different(cf, share)) { store = share->store; + *pempty = share->store_is_empty; } return store; @@ -3544,7 +3602,8 @@ static X509_STORE *ossl_get_cached_x509_store(struct Curl_cfilter *cf, static void ossl_set_cached_x509_store(struct Curl_cfilter *cf, const struct Curl_easy *data, - X509_STORE *store) + X509_STORE *store, + bool is_empty) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct Curl_multi *multi = data->multi; @@ -3588,19 +3647,20 @@ static void ossl_set_cached_x509_store(struct Curl_cfilter *cf, share->time = curlx_now(); share->store = store; + share->store_is_empty = is_empty; share->CAfile = CAfile; } } CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, struct Curl_easy *data, - SSL_CTX *ssl_ctx) + struct ossl_ctx *octx) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); CURLcode result = CURLE_OK; X509_STORE *cached_store; - bool cache_criteria_met; + bool cache_criteria_met, is_empty; /* Consider the X509 store cacheable if it comes exclusively from a CAfile, or no source is provided and we are falling back to OpenSSL's built-in @@ -3614,16 +3674,17 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, ERR_set_mark(); - cached_store = ossl_get_cached_x509_store(cf, data); + cached_store = ossl_get_cached_x509_store(cf, data, &is_empty); if(cached_store && cache_criteria_met && X509_STORE_up_ref(cached_store)) { - SSL_CTX_set_cert_store(ssl_ctx, cached_store); + SSL_CTX_set_cert_store(octx->ssl_ctx, cached_store); + octx->store_is_empty = is_empty; } else { - X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx); + X509_STORE *store = SSL_CTX_get_cert_store(octx->ssl_ctx); - result = ossl_populate_x509_store(cf, data, store); + result = ossl_populate_x509_store(cf, data, octx, store); if(result == CURLE_OK && cache_criteria_met) { - ossl_set_cached_x509_store(cf, data, store); + ossl_set_cached_x509_store(cf, data, store, octx->store_is_empty); } } @@ -3634,15 +3695,15 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, #else /* HAVE_SSL_X509_STORE_SHARE */ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, struct Curl_easy *data, - SSL_CTX *ssl_ctx) + struct ossl_ctx *octx) { CURLcode result; X509_STORE *store; ERR_set_mark(); - store = SSL_CTX_get_cert_store(ssl_ctx); - result = ossl_populate_x509_store(cf, data, store); + store = SSL_CTX_get_cert_store(octx->ssl_ctx); + result = ossl_populate_x509_store(cf, data, octx, store); ERR_pop_to_mark(); @@ -3900,7 +3961,6 @@ static CURLcode ossl_init_ssl(struct ossl_ctx *octx, SSL_set_connect_state(octx->ssl); - octx->server_cert = NULL; if(peer->sni) { if(!SSL_set_tlsext_host_name(octx->ssl, peer->sni)) { failf(data, "Failed set SNI"); @@ -4004,7 +4064,6 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, char * const ssl_cert = ssl_config->primary.clientcert; const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob; const char * const ssl_cert_type = ssl_config->cert_type; - const bool verifypeer = conn_config->verifypeer; unsigned int ssl_version_min; char error_buffer[256]; @@ -4238,12 +4297,11 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, } #endif /* HAVE_OPENSSL_SRP && USE_TLS_SRP */ - /* OpenSSL always tries to verify the peer, this only says whether it should - * fail to connect if the verification fails, or if it should continue - * anyway. In the latter case the result of the verification is checked with - * SSL_get_verify_result() below. */ - SSL_CTX_set_verify(octx->ssl_ctx, - verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); + /* OpenSSL always tries to verify the peer. By setting the failure mode + * to NONE, we allow the connect to complete, regardless of the outcome. + * We then explicitly check the result and may try alternatives like + * Apple's SecTrust for verification. */ + SSL_CTX_set_verify(octx->ssl_ctx, SSL_VERIFY_NONE, NULL); /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ #ifdef HAVE_KEYLOG_CALLBACK @@ -4269,7 +4327,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, * we need to do the full initialization before calling it. * See: #11800 */ if(!octx->x509_store_setup) { - result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx); + result = Curl_ssl_setup_x509_store(cf, data, octx); if(result) return result; octx->x509_store_setup = TRUE; @@ -4481,7 +4539,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, if(!octx->x509_store_setup) { /* After having send off the ClientHello, we prepare the x509 * store to verify the coming certificate from the server */ - CURLcode result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx); + CURLcode result = Curl_ssl_setup_x509_store(cf, data, octx); if(result) return result; octx->x509_store_setup = TRUE; @@ -4762,6 +4820,9 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl) int num_cert_levels; int cert_level; + if(!Curl_trc_is_verbose(data)) + return; + verify_result = SSL_get_verify_result(ssl); if(verify_result != X509_V_OK) certstack = SSL_get_peer_cert_chain(ssl); @@ -4818,7 +4879,229 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl) #define infof_certstack(data, ssl) #endif +static CURLcode ossl_check_issuer(struct Curl_cfilter *cf, + struct Curl_easy *data, + X509 *server_cert) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + X509 *issuer = NULL; + BIO *fp = NULL; + char err_buf[256]=""; + bool strict = (conn_config->verifypeer || conn_config->verifyhost); + CURLcode result = CURLE_OK; + + /* e.g. match issuer name with provided issuer certificate */ + if(conn_config->issuercert_blob) { + fp = BIO_new_mem_buf(conn_config->issuercert_blob->data, + (int)conn_config->issuercert_blob->len); + if(!fp) { + failf(data, "BIO_new_mem_buf NULL, " OSSL_PACKAGE " error %s", + ossl_strerror(ERR_get_error(), err_buf, sizeof(err_buf))); + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + else if(conn_config->issuercert) { + fp = BIO_new(BIO_s_file()); + if(!fp) { + failf(data, "BIO_new return NULL, " OSSL_PACKAGE " error %s", + ossl_strerror(ERR_get_error(), err_buf, sizeof(err_buf))); + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + if(BIO_read_filename(fp, conn_config->issuercert) <= 0) { + if(strict) + failf(data, "SSL: Unable to open issuer cert (%s)", + conn_config->issuercert); + result = CURLE_SSL_ISSUER_ERROR; + goto out; + } + } + + if(fp) { + issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL); + if(!issuer) { + if(strict) + failf(data, "SSL: Unable to read issuer cert (%s)", + conn_config->issuercert); + result = CURLE_SSL_ISSUER_ERROR; + goto out; + } + + if(X509_check_issued(issuer, server_cert) != X509_V_OK) { + if(strict) + failf(data, "SSL: Certificate issuer check failed (%s)", + conn_config->issuercert); + result = CURLE_SSL_ISSUER_ERROR; + goto out; + } + + infof(data, " SSL certificate issuer check ok (%s)", + conn_config->issuercert); + } + +out: + if(fp) + BIO_free(fp); + if(issuer) + X509_free(issuer); + return result; +} + +static CURLcode ossl_check_pinned_key(struct Curl_cfilter *cf, + struct Curl_easy *data, + X509 *server_cert) +{ + const char *ptr; + CURLcode result = CURLE_OK; + + (void)cf; +#ifndef CURL_DISABLE_PROXY + ptr = Curl_ssl_cf_is_proxy(cf) ? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY]; +#else + ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; +#endif + if(ptr) { + result = ossl_pkp_pin_peer_pubkey(data, server_cert, ptr); + if(result) + failf(data, "SSL: public key does not match pinned public key"); + } + return result; +} + +#ifndef CURL_DISABLE_VERBOSE_STRINGS #define MAX_CERT_NAME_LENGTH 2048 +static CURLcode ossl_infof_cert(struct Curl_cfilter *cf, + struct Curl_easy *data, + X509 *server_cert) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + bool strict = (conn_config->verifypeer || conn_config->verifyhost); + BIO *mem = NULL; + struct dynbuf dname; + char err_buf[256] = ""; + char *buf; + long len; + CURLcode result = CURLE_OK; + + if(!Curl_trc_is_verbose(data)) + return CURLE_OK; + + curlx_dyn_init(&dname, MAX_CERT_NAME_LENGTH); + mem = BIO_new(BIO_s_mem()); + if(!mem) { + failf(data, "BIO_new return NULL, " OSSL_PACKAGE " error %s", + ossl_strerror(ERR_get_error(), err_buf, sizeof(err_buf))); + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + infof(data, "%s certificate:", Curl_ssl_cf_is_proxy(cf) ? + "Proxy" : "Server"); + + result = x509_name_oneline(X509_get_subject_name(server_cert), &dname); + infof(data, " subject: %s", result ? "[NONE]" : curlx_dyn_ptr(&dname)); + + ASN1_TIME_print(mem, X509_get0_notBefore(server_cert)); + len = BIO_get_mem_data(mem, (char **) &buf); + infof(data, " start date: %.*s", (int)len, buf); + (void)BIO_reset(mem); + + ASN1_TIME_print(mem, X509_get0_notAfter(server_cert)); + len = BIO_get_mem_data(mem, (char **) &buf); + infof(data, " expire date: %.*s", (int)len, buf); + (void)BIO_reset(mem); + + result = x509_name_oneline(X509_get_issuer_name(server_cert), &dname); + if(result) { + if(strict) + failf(data, "SSL: could not get X509-issuer name"); + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; + } + infof(data, " issuer: %s", curlx_dyn_ptr(&dname)); + +out: + BIO_free(mem); + curlx_dyn_free(&dname); + return result; +} +#endif /* ! CURL_DISABLE_VERBOSE_STRINGS */ + + +#ifdef USE_APPLE_SECTRUST +struct ossl_certs_ctx { + STACK_OF(X509) *sk; + size_t num_certs; +}; + +static CURLcode ossl_chain_get_der(struct Curl_cfilter *cf, + struct Curl_easy *data, + void *user_data, + size_t i, + unsigned char **pder, + size_t *pder_len) +{ + struct ossl_certs_ctx *chain = user_data; + X509 *cert; + int der_len; + + (void)cf; + (void)data; + *pder_len = 0; + *pder = NULL; + + if(i >= chain->num_certs) + return CURLE_TOO_LARGE; + cert = sk_X509_value(chain->sk, (int)i); + if(!cert) + return CURLE_FAILED_INIT; + der_len = i2d_X509(cert, pder); + if(der_len < 0) + return CURLE_FAILED_INIT; + *pder_len = (size_t)der_len; + return CURLE_OK; +} + +static CURLcode ossl_apple_verify(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ossl_ctx *octx, + struct ssl_peer *peer, + bool *pverified) +{ + struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); + struct ossl_certs_ctx chain; + long ocsp_len = 0; +#ifdef HAVE_BORINGSSL_LIKE + const uint8_t *ocsp_data = NULL; +#else + unsigned char *ocsp_data = NULL; +#endif + CURLcode result; + + memset(&chain, 0, sizeof(chain)); + chain.sk = SSL_get_peer_cert_chain(octx->ssl); + chain.num_certs = chain.sk ? sk_X509_num(chain.sk) : 0; + + if(!chain.num_certs && + (conn_config->verifypeer || conn_config->verifyhost)) { + failf(data, "SSL: could not get peer certificate"); + result = CURLE_PEER_FAILED_VERIFICATION; + } + + if(conn_config->verifystatus && !octx->reused_session) + ocsp_len = (long)SSL_get_tlsext_status_ocsp_resp(octx->ssl, &ocsp_data); + + result = Curl_vtls_apple_verify(cf, data, peer, chain.num_certs, + ossl_chain_get_der, &chain, + ocsp_data, ocsp_len); + *pverified = !result; + return result; +} +#endif /* USE_APPLE_SECTRUST */ CURLcode Curl_ossl_check_peer_cert(struct Curl_cfilter *cf, struct Curl_easy *data, @@ -4829,216 +5112,93 @@ CURLcode Curl_ossl_check_peer_cert(struct Curl_cfilter *cf, struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); CURLcode result = CURLE_OK; - long lerr; - X509 *issuer; - BIO *fp = NULL; - char error_buffer[256]=""; - const char *ptr; - BIO *mem = BIO_new(BIO_s_mem()); + long ossl_verify; bool strict = (conn_config->verifypeer || conn_config->verifyhost); - struct dynbuf dname; - - DEBUGASSERT(octx); - - curlx_dyn_init(&dname, MAX_CERT_NAME_LENGTH); - - if(!mem) { - failf(data, - "BIO_new return NULL, " OSSL_PACKAGE " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - return CURLE_OUT_OF_MEMORY; - } + X509 *server_cert; + bool verified = FALSE; if(data->set.ssl.certinfo && !octx->reused_session) { /* asked to gather certificate info. Reused sessions don't have cert chains */ result = ossl_certchain(data, octx->ssl); - if(result) { - BIO_free(mem); + if(result) return result; - } } - octx->server_cert = SSL_get1_peer_certificate(octx->ssl); - if(!octx->server_cert) { - BIO_free(mem); + server_cert = SSL_get1_peer_certificate(octx->ssl); + if(!server_cert) { if(!strict) - return CURLE_OK; + goto out; failf(data, "SSL: could not get peer certificate"); - return CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; } - infof(data, "%s certificate:", - Curl_ssl_cf_is_proxy(cf) ? "Proxy" : "Server"); - - result = x509_name_oneline(X509_get_subject_name(octx->server_cert), - &dname); - infof(data, " subject: %s", result ? "[NONE]" : curlx_dyn_ptr(&dname)); - #ifndef CURL_DISABLE_VERBOSE_STRINGS - { - char *buf; - long len; - ASN1_TIME_print(mem, X509_get0_notBefore(octx->server_cert)); - len = BIO_get_mem_data(mem, (char **) &buf); - infof(data, " start date: %.*s", (int)len, buf); - (void)BIO_reset(mem); - - ASN1_TIME_print(mem, X509_get0_notAfter(octx->server_cert)); - len = BIO_get_mem_data(mem, (char **) &buf); - infof(data, " expire date: %.*s", (int)len, buf); - (void)BIO_reset(mem); - } + result = ossl_infof_cert(cf, data, server_cert); + if(result) + goto out; + infof_certstack(data, octx->ssl); #endif - BIO_free(mem); - if(conn_config->verifyhost) { - result = ossl_verifyhost(data, conn, peer, octx->server_cert); - if(result) { - X509_free(octx->server_cert); - octx->server_cert = NULL; - curlx_dyn_free(&dname); - return result; - } - } - - result = x509_name_oneline(X509_get_issuer_name(octx->server_cert), - &dname); - if(result) { - if(strict) - failf(data, "SSL: could not get X509-issuer name"); - result = CURLE_PEER_FAILED_VERIFICATION; + result = ossl_verifyhost(data, conn, peer, server_cert); + if(result) + goto out; } - else { - infof(data, " issuer: %s", curlx_dyn_ptr(&dname)); - curlx_dyn_free(&dname); - - /* We could do all sorts of certificate verification stuff here before - deallocating the certificate. */ - - /* e.g. match issuer name with provided issuer certificate */ - if(conn_config->issuercert || conn_config->issuercert_blob) { - if(conn_config->issuercert_blob) { - fp = BIO_new_mem_buf(conn_config->issuercert_blob->data, - (int)conn_config->issuercert_blob->len); - if(!fp) { - failf(data, - "BIO_new_mem_buf NULL, " OSSL_PACKAGE " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - X509_free(octx->server_cert); - octx->server_cert = NULL; - return CURLE_OUT_OF_MEMORY; - } - } - else { - fp = BIO_new(BIO_s_file()); - if(!fp) { - failf(data, - "BIO_new return NULL, " OSSL_PACKAGE " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - X509_free(octx->server_cert); - octx->server_cert = NULL; - return CURLE_OUT_OF_MEMORY; - } - if(BIO_read_filename(fp, conn_config->issuercert) <= 0) { - if(strict) - failf(data, "SSL: Unable to open issuer cert (%s)", - conn_config->issuercert); - BIO_free(fp); - X509_free(octx->server_cert); - octx->server_cert = NULL; - return CURLE_SSL_ISSUER_ERROR; - } - } + ossl_verify = SSL_get_verify_result(octx->ssl); + ssl_config->certverifyresult = ossl_verify; - issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL); - if(!issuer) { - if(strict) - failf(data, "SSL: Unable to read issuer cert (%s)", - conn_config->issuercert); - BIO_free(fp); - X509_free(issuer); - X509_free(octx->server_cert); - octx->server_cert = NULL; - return CURLE_SSL_ISSUER_ERROR; - } - - if(X509_check_issued(issuer, octx->server_cert) != X509_V_OK) { - if(strict) - failf(data, "SSL: Certificate issuer check failed (%s)", - conn_config->issuercert); - BIO_free(fp); - X509_free(issuer); - X509_free(octx->server_cert); - octx->server_cert = NULL; - return CURLE_SSL_ISSUER_ERROR; - } + verified = (ossl_verify == X509_V_OK); + if(verified) + infof(data, "SSL certificate verified via OpenSSL."); - infof(data, " SSL certificate issuer check ok (%s)", - conn_config->issuercert); - BIO_free(fp); - X509_free(issuer); - } - - lerr = SSL_get_verify_result(octx->ssl); - ssl_config->certverifyresult = lerr; - if(lerr != X509_V_OK) { - if(conn_config->verifypeer) { - /* We probably never reach this, because SSL_connect() will fail - and we return earlier if verifypeer is set? */ - if(strict) - failf(data, "SSL certificate verify result: %s (%ld)", - X509_verify_cert_error_string(lerr), lerr); - result = CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, " SSL certificate verify result: %s (%ld)," - " continuing anyway.", - X509_verify_cert_error_string(lerr), lerr); +#ifdef USE_APPLE_SECTRUST + if(!verified && + conn_config->verifypeer && ssl_config->native_ca_store && + (ossl_verify == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) { + /* we verify using Apple SecTrust *unless* OpenSSL already verified. + * This may happen if the application intercepted the OpenSSL callback + * and installed its own. */ + result = ossl_apple_verify(cf, data, octx, peer, &verified); + if(result && (result != CURLE_PEER_FAILED_VERIFICATION)) + goto out; /* unexpected error */ + if(verified) { + infof(data, "SSL certificate verified via Apple SecTrust."); + ssl_config->certverifyresult = X509_V_OK; } - else - infof(data, " SSL certificate verify ok."); } - infof_certstack(data, octx->ssl); +#endif + + if(!verified) { + /* no trust established, report the OpenSSL status */ + failf(data, "SSL certificate OpenSSL verify result: %s (%ld)", + X509_verify_cert_error_string(ossl_verify), ossl_verify); + result = CURLE_PEER_FAILED_VERIFICATION; + if(conn_config->verifypeer) + goto out; + infof(data, " SSL certificate verification failed, continuing anyway!"); + } #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_OCSP) if(conn_config->verifystatus && !octx->reused_session) { /* do not do this after Session ID reuse */ result = verifystatus(cf, data, octx); - if(result) { - X509_free(octx->server_cert); - octx->server_cert = NULL; - return result; - } + if(result) + goto out; } #endif - if(!strict) - /* when not strict, we do not bother about the verify cert problems */ - result = CURLE_OK; - -#ifndef CURL_DISABLE_PROXY - ptr = Curl_ssl_cf_is_proxy(cf) ? - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : - data->set.str[STRING_SSL_PINNEDPUBLICKEY]; -#else - ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; -#endif - if(!result && ptr) { - result = ossl_pkp_pin_peer_pubkey(data, octx->server_cert, ptr); - if(result) - failf(data, "SSL: public key does not match pinned public key"); - } + result = ossl_check_issuer(cf, data, server_cert); + if(result) + goto out; - X509_free(octx->server_cert); - octx->server_cert = NULL; + result = ossl_check_pinned_key(cf, data, server_cert); +out: + X509_free(server_cert); return result; } diff --git a/lib/vtls/openssl.h b/lib/vtls/openssl.h index e263ee2eb266..021d754a62b4 100644 --- a/lib/vtls/openssl.h +++ b/lib/vtls/openssl.h @@ -71,7 +71,6 @@ struct ossl_ctx { /* these ones requires specific SSL-types */ SSL_CTX* ssl_ctx; SSL* ssl; - X509* server_cert; BIO_METHOD *bio_method; CURLcode io_result; /* result of last BIO cfilter operation */ /* blocked writes need to retry with same length, remember it */ @@ -82,6 +81,7 @@ struct ossl_ctx { bool keylog_done; #endif BIT(x509_store_setup); /* x509 store has been set up */ + BIT(store_is_empty); /* no certs/paths/blobs in x509 store */ BIT(reused_session); /* session-ID was reused for this */ }; @@ -122,7 +122,7 @@ extern const struct Curl_ssl Curl_ssl_openssl; */ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, struct Curl_easy *data, - SSL_CTX *ssl_ctx); + struct ossl_ctx *octx); CURLcode Curl_ossl_ctx_configure(struct Curl_cfilter *cf, struct Curl_easy *data, diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 1b1f66cc6eba..ccd567cd864c 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -75,9 +75,14 @@ #include "../curlx/inet_pton.h" #include "../connect.h" #include "../select.h" +#include "../setopt.h" #include "../strdup.h" #include "../rand.h" +#ifdef USE_APPLE_SECTRUST +#include +#endif /* USE_APPLE_SECTRUST */ + /* The last #include files should be: */ #include "../curl_memory.h" #include "../memdebug.h" @@ -290,62 +295,100 @@ static void free_primary_ssl_config(struct ssl_primary_config *sslc) CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data) { - data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH]; - data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE]; - data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE]; - data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT]; - data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT]; - data->set.ssl.primary.cipher_list = - data->set.str[STRING_SSL_CIPHER_LIST]; - data->set.ssl.primary.cipher_list13 = - data->set.str[STRING_SSL_CIPHER13_LIST]; - data->set.ssl.primary.signature_algorithms = + struct ssl_config_data *sslc = &data->set.ssl; +#if defined(CURL_CA_PATH) || defined(CURL_CA_BUNDLE) + struct UserDefined *set = &data->set; + CURLcode result; +#endif + + if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) { +#ifdef USE_APPLE_SECTRUST + if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob) + sslc->native_ca_store = TRUE; +#endif +#ifdef CURL_CA_PATH + if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH]) { + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH); + if(result) + return result; + } + sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH]; +#endif +#ifdef CURL_CA_BUNDLE + if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE]) { + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); + if(result) + return result; + } +#endif + } + sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE]; + sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE]; + sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT]; + sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT]; + sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST]; + sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST]; + sslc->primary.signature_algorithms = data->set.str[STRING_SSL_SIGNATURE_ALGORITHMS]; - data->set.ssl.primary.pinned_key = + sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; - data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT]; - data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO]; - data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES]; + sslc->primary.cert_blob = data->set.blobs[BLOB_CERT]; + sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO]; + sslc->primary.curves = data->set.str[STRING_SSL_EC_CURVES]; #ifdef USE_TLS_SRP - data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME]; - data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD]; + sslc->primary.username = data->set.str[STRING_TLSAUTH_USERNAME]; + sslc->primary.password = data->set.str[STRING_TLSAUTH_PASSWORD]; #endif - data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE]; - data->set.ssl.key = data->set.str[STRING_KEY]; - data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE]; - data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD]; - data->set.ssl.primary.clientcert = data->set.str[STRING_CERT]; - data->set.ssl.key_blob = data->set.blobs[BLOB_KEY]; + sslc->cert_type = data->set.str[STRING_CERT_TYPE]; + sslc->key = data->set.str[STRING_KEY]; + sslc->key_type = data->set.str[STRING_KEY_TYPE]; + sslc->key_passwd = data->set.str[STRING_KEY_PASSWD]; + sslc->primary.clientcert = data->set.str[STRING_CERT]; + sslc->key_blob = data->set.blobs[BLOB_KEY]; #ifndef CURL_DISABLE_PROXY - data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; - data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; - data->set.proxy_ssl.primary.cipher_list = - data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; - data->set.proxy_ssl.primary.cipher_list13 = - data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; - data->set.proxy_ssl.primary.pinned_key = - data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; - data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY]; - data->set.proxy_ssl.primary.ca_info_blob = - data->set.blobs[BLOB_CAINFO_PROXY]; - data->set.proxy_ssl.primary.issuercert = - data->set.str[STRING_SSL_ISSUERCERT_PROXY]; - data->set.proxy_ssl.primary.issuercert_blob = - data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY]; - data->set.proxy_ssl.primary.CRLfile = - data->set.str[STRING_SSL_CRLFILE_PROXY]; - data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; - data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; - data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; - data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; - data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; - data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY]; + sslc = &data->set.proxy_ssl; + if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) { +#ifdef USE_APPLE_SECTRUST + if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob) + sslc->native_ca_store = TRUE; +#endif +#ifdef CURL_CA_PATH + if(!sslc->custom_capath && !set->str[STRING_SSL_CAPATH_PROXY]) { + result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], + CURL_CA_PATH); + if(result) + return result; + } + sslc->primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; +#endif +#ifdef CURL_CA_BUNDLE + if(!sslc->custom_cafile && !set->str[STRING_SSL_CAFILE_PROXY]) { + result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], + CURL_CA_BUNDLE); + if(result) + return result; + } +#endif + } + sslc->primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; + sslc->primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; + sslc->primary.cipher_list13 = data->set.str[STRING_SSL_CIPHER13_LIST_PROXY]; + sslc->primary.pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]; + sslc->primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY]; + sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO_PROXY]; + sslc->primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY]; + sslc->primary.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; + sslc->cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; + sslc->key = data->set.str[STRING_KEY_PROXY]; + sslc->key_type = data->set.str[STRING_KEY_TYPE_PROXY]; + sslc->key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; + sslc->primary.clientcert = data->set.str[STRING_CERT_PROXY]; + sslc->key_blob = data->set.blobs[BLOB_KEY_PROXY]; #ifdef USE_TLS_SRP - data->set.proxy_ssl.primary.username = - data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; - data->set.proxy_ssl.primary.password = - data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; + sslc->primary.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; + sslc->primary.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; #endif #endif /* CURL_DISABLE_PROXY */ diff --git a/lib/vtls/vtls_scache.c b/lib/vtls/vtls_scache.c index 74b2b20cf674..16e3f0314f64 100644 --- a/lib/vtls/vtls_scache.c +++ b/lib/vtls/vtls_scache.c @@ -371,7 +371,7 @@ void Curl_ssl_scache_unlock(struct Curl_easy *data) static CURLcode cf_ssl_peer_key_add_path(struct dynbuf *buf, const char *name, - char *path, + const char *path, bool *is_local) { if(path && path[0]) { diff --git a/m4/curl-apple-sectrust.m4 b/m4/curl-apple-sectrust.m4 new file mode 100644 index 000000000000..792f719d38af --- /dev/null +++ b/m4/curl-apple-sectrust.m4 @@ -0,0 +1,58 @@ +#*************************************************************************** +# _ _ ____ _ +# 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 +# +#*************************************************************************** + +AC_DEFUN([CURL_WITH_APPLE_SECTRUST], [ +AC_MSG_CHECKING([whether to enable Apple OS native certificate validation]) +if test "x$OPT_APPLE_SECTRUST" = xyes; then + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + #include + #include + ]],[[ + #if TARGET_OS_MAC + return 0; + #else + #error Not macOS + #endif + ]]) + ],[ + build_for_apple="yes" + ],[ + build_for_apple="no" + ]) + if test "x$build_for_apple" != "xno"; then + AC_MSG_RESULT(yes) + AC_DEFINE(USE_APPLE_SECTRUST, 1, [enable Apple OS certificate validation]) + APPLE_SECTRUST_ENABLED=1 + APPLE_SECTRUST_LDFLAGS='-framework CoreFoundation -framework CoreServices -framework Security' + LDFLAGS="$LDFLAGS $APPLE_SECTRUST_LDFLAGS" + LDFLAGSPC="$LDFLAGSPC $APPLE_SECTRUST_LDFLAGS" + else + AC_MSG_RESULT(no) + fi +else + AC_MSG_RESULT(no) +fi + +]) diff --git a/tests/data/test305 b/tests/data/test305 index 9e7dc8dcb0f9..2d4ffd1aab93 100644 --- a/tests/data/test305 +++ b/tests/data/test305 @@ -19,7 +19,7 @@ https insecure HTTPS without permission -https://%HOSTIP:%HTTPSPORT/want/%TESTNUMBER --cacert moooo +https://%HOSTIP:%HTTPSPORT/want/%TESTNUMBER --cacert moooo --no-ca-native diff --git a/tests/http/test_02_download.py b/tests/http/test_02_download.py index 89bf7e1ab1ec..26da1d2feee9 100644 --- a/tests/http/test_02_download.py +++ b/tests/http/test_02_download.py @@ -610,6 +610,8 @@ def test_02_32_earlydata(self, env: Env, httpd, nghttpx, proto): pytest.skip("h3 not supported") if proto != 'h3' and sys.platform.startswith('darwin') and env.ci_run: pytest.skip('failing on macOS CI runners') + if proto == 'h3' and sys.platform.startswith('darwin') and env.curl_uses_lib('gnutls'): + pytest.skip('h3 gnutls early data failing on macOS') count = 2 docname = 'data-10k' # we want this test to always connect to nghttpx, since it is diff --git a/tests/http/test_07_upload.py b/tests/http/test_07_upload.py index 0868a406ab31..d17d3a44ad04 100644 --- a/tests/http/test_07_upload.py +++ b/tests/http/test_07_upload.py @@ -693,6 +693,8 @@ def test_07_70_put_earlydata(self, env: Env, httpd, nghttpx, proto, upload_size, pytest.skip("h3 not supported") if proto != 'h3' and sys.platform.startswith('darwin') and env.ci_run: pytest.skip('failing on macOS CI runners') + if proto == 'h3' and sys.platform.startswith('darwin') and env.curl_uses_lib('gnutls'): + pytest.skip('h3 gnutls early data failing on macOS') count = 2 # we want this test to always connect to nghttpx, since it is # the only server we have that supports TLS earlydata diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py index b346281dfc28..619ecd25e6f1 100644 --- a/tests/http/test_17_ssl_use.py +++ b/tests/http/test_17_ssl_use.py @@ -433,9 +433,9 @@ def test_17_14_expired_cert(self, env: Env, proto, httpd): exp_trace = None match_trace = None if env.curl_uses_lib('openssl') or env.curl_uses_lib('quictls'): - exp_trace = r'.*SSL certificate problem: certificate has expired$' + exp_trace = r'.*SSL certificate OpenSSL verify result: certificate has expired.*$' elif env.curl_uses_lib('gnutls'): - exp_trace = r'.*server verification failed: certificate has expired\..*' + exp_trace = r'.*SSL certificate verification failed: certificate has expired\..*' elif env.curl_uses_lib('wolfssl'): exp_trace = r'.*server verification failed: certificate has expired\.$' if exp_trace is not None: From 9aa8e9a783c43ed3fad244a98455ac2d7288909f Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 2 Oct 2025 14:20:05 +0200 Subject: [PATCH 254/465] vquic: handling of io improvements - better tracing of what system call is used and how often - ngtcp2: combine vquic_send into larger chunks - ngtcp2: define own PMTU values and enable MTU probing - ngtcp2: trace interesting remote transport parameters Closes #18812 --- lib/vquic/curl_ngtcp2.c | 147 ++++++++++++++++++++++++---------------- lib/vquic/vquic.c | 95 +++++++++++++++----------- 2 files changed, 146 insertions(+), 96 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 4998400d96aa..4a45c1f6dbff 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -410,13 +410,23 @@ static void qlog_callback(void *user_data, uint32_t flags, ctx->qlogfd = -1; } } - } static void quic_settings(struct cf_ngtcp2_ctx *ctx, struct Curl_easy *data, struct pkt_io_ctx *pktx) { +#ifdef NGTCP2_SETTINGS_V2x +static uint16_t mtu_probes[] = { + 1472, /* what h2o offers */ + 1452, /* what Caddy offers */ + 1454 - 48, /* The well known MTU used by a domestic optic fiber + service in Japan. */ + 1390 - 48, /* Typical Tunneled MTU */ + 1280 - 48, /* IPv6 minimum MTU */ + 1492 - 48, /* PPPoE */ +}; +#endif ngtcp2_settings *s = &ctx->settings; ngtcp2_transport_params *t = &ctx->transport_params; @@ -433,6 +443,12 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx, data->set.connecttimeout * NGTCP2_MILLISECONDS : QUIC_HANDSHAKE_TIMEOUT; s->max_window = 100 * ctx->max_stream_window; s->max_stream_window = 10 * ctx->max_stream_window; + s->no_pmtud = FALSE; +#ifdef NGTCP2_SETTINGS_V2x + s->pmtud_probes = mtu_probes; + s->pmtud_probeslen = CURL_ARRAYSIZE(mtu_probes); + s->max_tx_udp_payload_size = 64 * 1024; /* mtu_probes[0]; */ +#endif t->initial_max_data = 10 * ctx->max_stream_window; t->initial_max_stream_data_bidi_local = ctx->max_stream_window; @@ -468,8 +484,18 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) ctx->tls_vrfy_result = Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); - CURL_TRC_CF(data, cf, "handshake complete after %dms", - (int)curlx_timediff(ctx->handshake_at, ctx->started_at)); + if(Curl_trc_is_verbose(data)) { + const ngtcp2_transport_params *rp; + rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); + CURL_TRC_CF(data, cf, "handshake complete after %dms, remote transport[" + "max_udp_payload=%" FMT_PRIu64 + ", initial_max_data=%" FMT_PRIu64 + "]", + (int)curlx_timediff(ctx->handshake_at, ctx->started_at), + (curl_uint64_t)rp->max_udp_payload_size, + (curl_uint64_t)rp->initial_max_data); + } + /* In case of earlydata, where we simulate being connected, update * the handshake time when we really did connect */ if(ctx->use_earlydata) @@ -1678,6 +1704,9 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, ngtcp2_path path; int rv; + if(ecn) + CURL_TRC_CF(pktx->data, pktx->cf, "vquic_recv(len=%zu, ecn=%x)", + pktlen, ecn); ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr, (socklen_t)ctx->q.local_addrlen); ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr, @@ -1696,7 +1725,6 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, return CURLE_PEER_FAILED_VERIFICATION; return CURLE_RECV_ERROR; } - return CURLE_OK; } @@ -1712,6 +1740,10 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, pktx_init(&local_pktx, cf, data); pktx = &local_pktx; } + else { + pktx_update_time(pktx, cf); + ngtcp2_path_storage_zero(&pktx->ps); + } result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); if(result) @@ -1831,9 +1863,10 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, { struct cf_ngtcp2_ctx *ctx = cf->ctx; size_t nread; - size_t max_payload_size, path_max_payload_size, max_pktcnt; + size_t max_payload_size, path_max_payload_size; size_t pktcnt = 0; size_t gsolen = 0; /* this disables gso until we have a clue */ + size_t send_quantum; CURLcode curlcode; struct pkt_io_ctx local_pktx; @@ -1869,71 +1902,69 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, max_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(ctx->qconn); path_max_payload_size = ngtcp2_conn_get_path_max_tx_udp_payload_size(ctx->qconn); - /* maximum number of packets buffered before we flush to the socket */ - max_pktcnt = CURLMIN(MAX_PKT_BURST, - ctx->q.sendbuf.chunk_size / max_payload_size); - + send_quantum = ngtcp2_conn_get_send_quantum(ctx->qconn); + CURL_TRC_CF(data, cf, "egress, collect and send packets, quantum=%zu", + send_quantum); for(;;) { /* add the next packet to send, if any, to our buffer */ curlcode = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size, read_pkt_to_send, pktx, &nread); - if(curlcode) { - if(curlcode != CURLE_AGAIN) - return curlcode; - /* Nothing more to add, flush and leave */ - curlcode = vquic_send(cf, data, &ctx->q, gsolen); - if(curlcode) { - if(curlcode == CURLE_AGAIN) { - Curl_expire(data, 1, EXPIRE_QUIC); - return CURLE_OK; - } - return curlcode; + if(curlcode == CURLE_AGAIN) + break; + else if(curlcode) + return curlcode; + else { + size_t buflen = Curl_bufq_len(&ctx->q.sendbuf); + if((buflen >= send_quantum) || + ((buflen + gsolen) >= ctx->q.sendbuf.chunk_size)) + break; + DEBUGASSERT(nread > 0); + ++pktcnt; + if(pktcnt == 1) { + /* first packet in buffer. This is either of a known, "good" + * payload size or it is a PMTUD. We will see. */ + gsolen = nread; } - goto out; - } - - DEBUGASSERT(nread > 0); - if(pktcnt == 0) { - /* first packet in buffer. This is either of a known, "good" - * payload size or it is a PMTUD. We will see. */ - gsolen = nread; - } - else if(nread > gsolen || - (gsolen > path_max_payload_size && nread != gsolen)) { - /* The just added packet is a PMTUD *or* the one(s) before the - * just added were PMTUD and the last one is smaller. - * Flush the buffer before the last add. */ - curlcode = vquic_send_tail_split(cf, data, &ctx->q, - gsolen, nread, nread); - if(curlcode) { - if(curlcode == CURLE_AGAIN) { - Curl_expire(data, 1, EXPIRE_QUIC); - return CURLE_OK; + else if(nread > gsolen || + (gsolen > path_max_payload_size && nread != gsolen)) { + /* The just added packet is a PMTUD *or* the one(s) before the + * just added were PMTUD and the last one is smaller. + * Flush the buffer before the last add. */ + curlcode = vquic_send_tail_split(cf, data, &ctx->q, + gsolen, nread, nread); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; } - return curlcode; + pktcnt = 0; + } + else if(nread < gsolen) { + /* Reached MAX_PKT_BURST *or* + * the capacity of our buffer *or* + * last add was shorter than the previous ones, flush */ + break; } - pktcnt = 0; - continue; } + } - if(++pktcnt >= max_pktcnt || nread < gsolen) { - /* Reached MAX_PKT_BURST *or* - * the capacity of our buffer *or* - * last add was shorter than the previous ones, flush */ - curlcode = vquic_send(cf, data, &ctx->q, gsolen); - if(curlcode) { - if(curlcode == CURLE_AGAIN) { - Curl_expire(data, 1, EXPIRE_QUIC); - return CURLE_OK; - } - return curlcode; + if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) { + /* time to send */ + CURL_TRC_CF(data, cf, "egress, send collected %zu packets in %zu bytes", + pktcnt, Curl_bufq_len(&ctx->q.sendbuf)); + curlcode = vquic_send(cf, data, &ctx->q, gsolen); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; } - /* pktbuf has been completely sent */ - pktcnt = 0; + return curlcode; } + pktx_update_time(pktx, cf); + ngtcp2_conn_update_pkt_tx_time(ctx->qconn, pktx->ts); } - -out: return CURLE_OK; } diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index c50981975211..275ea8bcccdf 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -55,7 +55,7 @@ #if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) #define NW_CHUNK_SIZE (64 * 1024) -#define NW_SEND_CHUNKS 2 +#define NW_SEND_CHUNKS 1 int Curl_vquic_init(void) @@ -125,6 +125,7 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf, const uint8_t *pkt, size_t pktlen, size_t gsolen, size_t *psent) { + CURLcode result = CURLE_OK; #ifdef HAVE_SENDMSG struct iovec msg_iov; struct msghdr msg = {0}; @@ -181,12 +182,14 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf, FALLTHROUGH(); default: failf(data, "sendmsg() returned %zd (errno %d)", sent, SOCKERRNO); - return CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; + goto out; } } else if(pktlen != (size_t)sent) { failf(data, "sendmsg() sent only %zd/%zu bytes", sent, pktlen); - return CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; + goto out; } #else ssize_t sent; @@ -201,12 +204,14 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf, if(sent == -1) { if(SOCKERRNO == EAGAIN || SOCKERRNO == SOCKEWOULDBLOCK) { - return CURLE_AGAIN; + result = CURLE_AGAIN; + goto out; } else { failf(data, "send() returned %zd (errno %d)", sent, SOCKERRNO); if(SOCKERRNO != SOCKEMSGSIZE) { - return CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; + goto out; } /* UDP datagram is too large; caused by PMTUD. Just let it be lost. */ @@ -216,9 +221,16 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf, (void)cf; *psent = pktlen; - return CURLE_OK; +out: + return result; } +#ifdef HAVE_SENDMSG +#define VQUIC_SEND_METHOD "sendmsg" +#else +#define VQUIC_SEND_METHOD "send" +#endif + static CURLcode send_packet_no_gso(struct Curl_cfilter *cf, struct Curl_easy *data, struct cf_quic_ctx *qctx, @@ -226,19 +238,23 @@ static CURLcode send_packet_no_gso(struct Curl_cfilter *cf, size_t gsolen, size_t *psent) { const uint8_t *p, *end = pkt + pktlen; - size_t sent; + size_t sent, len, calls = 0; + CURLcode result = CURLE_OK; *psent = 0; for(p = pkt; p < end; p += gsolen) { - size_t len = CURLMIN(gsolen, (size_t)(end - p)); - CURLcode curlcode = do_sendmsg(cf, data, qctx, p, len, len, &sent); - if(curlcode != CURLE_OK) { - return curlcode; - } + len = CURLMIN(gsolen, (size_t)(end - p)); + result = do_sendmsg(cf, data, qctx, p, len, len, &sent); + if(result) + goto out; *psent += sent; + ++calls; } - +out: + CURL_TRC_CF(data, cf, "vquic_%s(len=%zu, gso=%zu, calls=%zu)" + " -> %d, sent=%zu", + VQUIC_SEND_METHOD, pktlen, gsolen, calls, result, *psent); return CURLE_OK; } @@ -266,6 +282,9 @@ static CURLcode vquic_send_packets(struct Curl_cfilter *cf, } else { result = do_sendmsg(cf, data, qctx, pkt, pktlen, gsolen, psent); + CURL_TRC_CF(data, cf, "vquic_%s(len=%zu, gso=%zu, calls=1)" + " -> %d, sent=%zu", + VQUIC_SEND_METHOD, pktlen, gsolen, result, *psent); } if(!result) qctx->last_io = qctx->last_op; @@ -289,8 +308,6 @@ CURLcode vquic_flush(struct Curl_cfilter *cf, struct Curl_easy *data, } result = vquic_send_packets(cf, data, qctx, buf, blen, gsolen, &sent); - CURL_TRC_CF(data, cf, "vquic_send(len=%zu, gso=%zu) -> %d, sent=%zu", - blen, gsolen, result, sent); if(result) { if(result == CURLE_AGAIN) { Curl_bufq_skip(&qctx->sendbuf, sent); @@ -369,7 +386,7 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf, struct mmsghdr mmsg[MMSG_NUM]; uint8_t msg_ctrl[MMSG_NUM * CMSG_SPACE(sizeof(int))]; struct sockaddr_storage remote_addr[MMSG_NUM]; - size_t total_nread = 0, pkts = 0; + size_t total_nread = 0, pkts = 0, calls = 0; int mcount, i, n; char errstr[STRERROR_LEN]; CURLcode result = CURLE_OK; @@ -424,7 +441,7 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf, goto out; } - CURL_TRC_CF(data, cf, "recvmmsg() -> %d packets", mcount); + ++calls; for(i = 0; i < mcount; ++i) { total_nread += mmsg[i].msg_len; @@ -454,8 +471,8 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf, out: if(total_nread || result) - CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d", - pkts, total_nread, result); + CURL_TRC_CF(data, cf, "vquic_recvmmsg(len=%zu, packets=%zu, calls=%zu)" + " -> %d", total_nread, pkts, calls, result); Curl_multi_xfer_sockbuf_release(data, sockbuf); return result; } @@ -471,8 +488,9 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf, struct msghdr msg; uint8_t buf[64*1024]; struct sockaddr_storage remote_addr; - size_t total_nread, pkts; - ssize_t nread; + size_t total_nread, pkts, calls; + ssize_t rc; + size_t nread; char errstr[STRERROR_LEN]; CURLcode result = CURLE_OK; uint8_t msg_ctrl[CMSG_SPACE(sizeof(int))]; @@ -481,7 +499,7 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf, size_t offset, to; DEBUGASSERT(max_pkts > 0); - for(pkts = 0, total_nread = 0; pkts < max_pkts;) { + for(pkts = 0, total_nread = 0, calls = 0; pkts < max_pkts;) { /* fully initialise this on each call to `recvmsg()`. There seem to * operating systems out there that mess with `msg_iov.iov_len`. */ memset(&msg, 0, sizeof(msg)); @@ -494,10 +512,10 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf, msg.msg_namelen = sizeof(remote_addr); msg.msg_controllen = sizeof(msg_ctrl); - while((nread = recvmsg(qctx->sockfd, &msg, 0)) == -1 && + while((rc = recvmsg(qctx->sockfd, &msg, 0)) == -1 && (SOCKERRNO == SOCKEINTR || SOCKERRNO == SOCKEMSGSIZE)) ; - if(nread == -1) { + if(rc == -1) { if(SOCKERRNO == EAGAIN || SOCKERRNO == SOCKEWOULDBLOCK) { goto out; } @@ -511,28 +529,28 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf, } Curl_strerror(SOCKERRNO, errstr, sizeof(errstr)); failf(data, "QUIC: recvmsg() unexpectedly returned %zd (errno=%d; %s)", - nread, SOCKERRNO, errstr); + rc, SOCKERRNO, errstr); result = CURLE_RECV_ERROR; goto out; } - total_nread += (size_t)nread; + nread = (size_t)rc; + total_nread += nread; + ++calls; gso_size = vquic_msghdr_get_udp_gro(&msg); if(gso_size == 0) { - gso_size = (size_t)nread; + gso_size = nread; } - for(offset = 0; offset < (size_t)nread; offset = to) { + for(offset = 0; offset < nread; offset = to) { ++pkts; to = offset + gso_size; - if(to > (size_t)nread) { - pktlen = (size_t)nread - offset; - } - else { + if(to > nread) + pktlen = nread - offset; + else pktlen = gso_size; - } result = recv_cb(buf + offset, pktlen, msg.msg_name, msg.msg_namelen, 0, userp); @@ -543,8 +561,8 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf, out: if(total_nread || result) - CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d", - pkts, total_nread, result); + CURL_TRC_CF(data, cf, "vquic_recvmsg(len=%zu, packets=%zu, calls=%zu)" + " -> %d", total_nread, pkts, calls, result); return result; } @@ -559,7 +577,7 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf, int bufsize = (int)sizeof(buf); struct sockaddr_storage remote_addr; socklen_t remote_addrlen = sizeof(remote_addr); - size_t total_nread, pkts; + size_t total_nread, pkts, calls = 0; ssize_t nread; char errstr[STRERROR_LEN]; CURLcode result = CURLE_OK; @@ -592,6 +610,7 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf, } ++pkts; + ++calls; total_nread += (size_t)nread; result = recv_cb(buf, (size_t)nread, &remote_addr, remote_addrlen, 0, userp); @@ -601,8 +620,8 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf, out: if(total_nread || result) - CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d", - pkts, total_nread, result); + CURL_TRC_CF(data, cf, "vquic_recvfrom(len=%zu, packets=%zu, calls=%zu)" + " -> %d", total_nread, pkts, calls, result); return result; } #endif /* !HAVE_SENDMMSG && !HAVE_SENDMSG */ From 3b583ab7d72105e3bd80f602544e8c6795b13de3 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 3 Oct 2025 12:38:40 +0200 Subject: [PATCH 255/465] docs/cmdline-opts: drop double quotes from GLOBBING and URL examples It looks easier on the eye without them Closes #18829 --- docs/cmdline-opts/_GLOBBING.md | 14 +++++++------- docs/cmdline-opts/_URL.md | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/cmdline-opts/_GLOBBING.md b/docs/cmdline-opts/_GLOBBING.md index 282356c3efba..c3c7951acb27 100644 --- a/docs/cmdline-opts/_GLOBBING.md +++ b/docs/cmdline-opts/_GLOBBING.md @@ -6,31 +6,31 @@ or ranges within brackets. We call this "globbing". Provide a list with three different names like this: - "http://site.{one,two,three}.com" + http://site.{one,two,three}.com Do sequences of alphanumeric series by using [] as in: - "ftp://ftp.example.com/file[1-100].txt" + ftp://ftp.example.com/file[1-100].txt With leading zeroes: - "ftp://ftp.example.com/file[001-100].txt" + ftp://ftp.example.com/file[001-100].txt With letters through the alphabet: - "ftp://ftp.example.com/file[a-z].txt" + ftp://ftp.example.com/file[a-z].txt Nested sequences are not supported, but you can use several ones next to each other: - "http://example.com/archive[1996-1999]/vol[1-4]/part{a,b,c}.html" + http://example.com/archive[1996-1999]/vol[1-4]/part{a,b,c}.html You can specify a step counter for the ranges to get every Nth number or letter: - "http://example.com/file[1-100:10].txt" + http://example.com/file[1-100:10].txt - "http://example.com/file[a-z:2].txt" + http://example.com/file[a-z:2].txt When using [] or {} sequences when invoked from a command line prompt, you probably have to put the full URL within double quotes to avoid the shell from diff --git a/docs/cmdline-opts/_URL.md b/docs/cmdline-opts/_URL.md index 48ae02a556ff..580974f06252 100644 --- a/docs/cmdline-opts/_URL.md +++ b/docs/cmdline-opts/_URL.md @@ -22,7 +22,7 @@ separate curl runs. Provide an IPv6 zone id in the URL with an escaped percentage sign. Like in - "http://[fe80::3%25eth0]/" + http://[fe80::3%25eth0]/ Everything provided on the command line that is not a command line option or its argument, curl assumes is a URL and treats it as such. From 4e2edde102a46305edc498879c1188b58bcc8403 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 3 Oct 2025 10:18:27 +0200 Subject: [PATCH 256/465] tool_progress: fix < 10000 output Follow-up to e49698925c7f90e Closes #18826 --- src/tool_progress.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tool_progress.c b/src/tool_progress.c index b03fbf16a18a..d29bfdc4dad5 100644 --- a/src/tool_progress.c +++ b/src/tool_progress.c @@ -34,8 +34,10 @@ static char *max5data(curl_off_t bytes, char *max5) /* a signed 64-bit value is 8192 petabytes maximum */ const char unit[] = { 'k', 'M', 'G', 'T', 'P', 0 }; int k = 0; - if(bytes < 100000) + if(bytes < 100000) { msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); + return max5; + } do { curl_off_t nbytes = bytes / 1024; From 2e5993ab0812fd1a983738f6d6efbc7bb0806144 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 3 Oct 2025 11:43:10 +0200 Subject: [PATCH 257/465] GHA/checksrc: pass zizmor a GH token, fix warnings found For a complete, online, check. After this patch the check takes 30s, up from a fraction of a second. Also bump CodeQL actions to their latest version. Closes #18827 --- .github/workflows/checksrc.yml | 2 ++ .github/workflows/codeql.yml | 8 ++++---- .github/workflows/distcheck.yml | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 71ee031d68a8..71d096cac51d 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -129,6 +129,8 @@ jobs: persist-credentials: false - name: 'zizmor GHA' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" zizmor --pedantic .github/workflows/*.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index fe33518d8b16..b1e20b4d2dda 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -48,13 +48,13 @@ jobs: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 + uses: github/codeql-action/init@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 with: languages: actions, python queries: security-extended - name: 'perform analysis' - uses: github/codeql-action/analyze@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 + uses: github/codeql-action/analyze@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 c: name: 'C' @@ -84,7 +84,7 @@ jobs: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 + uses: github/codeql-action/init@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 with: languages: cpp build-mode: manual @@ -130,4 +130,4 @@ jobs: fi - name: 'perform analysis' - uses: github/codeql-action/analyze@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3 + uses: github/codeql-action/analyze@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index 7a1a4dad844f..5a5c117ce1ab 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -49,7 +49,7 @@ jobs: - name: 'maketgz' run: SOURCE_DATE_EPOCH=1711526400 ./scripts/maketgz 99.98.97 - - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 + - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: name: 'release-tgz' path: 'curl-99.98.97.tar.gz' From 2313696e96c6c436f4b0c97361c45c5c0c8ae2b1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 11:55:38 +0000 Subject: [PATCH 258/465] GHA: update actions/upload-artifact action to v4.6.2 Closes #18830 --- .github/workflows/distcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index 5a5c117ce1ab..9bc556562385 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -49,7 +49,7 @@ jobs: - name: 'maketgz' run: SOURCE_DATE_EPOCH=1711526400 ./scripts/maketgz 99.98.97 - - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: 'release-tgz' path: 'curl-99.98.97.tar.gz' From 4b8278fb3d0a43fecf66caa23ad1cd28f759de71 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 3 Oct 2025 10:51:46 +0200 Subject: [PATCH 259/465] progress: expand to use 6 characters per size Previously the progress meter used a maximum of five digits+letter in the progress meter output: up to 99999 bytes and then 9999k, 9999M etc. The output then used two spaces after the size between the next field in the display. This new approach uses one letter more with only one space in between the fields. It makes it possible to show up to 999999 bytes and then 99999k, 99999M etc. The function uses a single decimal when outputting a value less than 1000 in any unit. Like 999.9M. Closes #18828 --- lib/progress.c | 93 +++++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 55 deletions(-) diff --git a/lib/progress.c b/lib/progress.c index fdae3194c55d..2fa0fa122886 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -63,54 +63,37 @@ static void time2str(char *r, curl_off_t seconds) } /* The point of this function would be to return a string of the input data, - but never longer than 5 columns (+ one zero byte). + but never longer than 6 columns (+ one zero byte). Add suffix k, M, G when suitable... */ -static char *max5data(curl_off_t bytes, char *max5) +static char *max6data(curl_off_t bytes, char *max6) { -#define ONE_KILOBYTE (curl_off_t)1024 -#define ONE_MEGABYTE (1024 * ONE_KILOBYTE) -#define ONE_GIGABYTE (1024 * ONE_MEGABYTE) -#define ONE_TERABYTE (1024 * ONE_GIGABYTE) -#define ONE_PETABYTE (1024 * ONE_TERABYTE) - - if(bytes < 100000) - msnprintf(max5, 6, "%5" FMT_OFF_T, bytes); - - else if(bytes < 10000 * ONE_KILOBYTE) - msnprintf(max5, 6, "%4" FMT_OFF_T "k", bytes/ONE_KILOBYTE); - - else if(bytes < 100 * ONE_MEGABYTE) - /* 'XX.XM' is good as long as we are less than 100 megs */ - msnprintf(max5, 6, "%2" FMT_OFF_T ".%0" - FMT_OFF_T "M", bytes/ONE_MEGABYTE, - (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/10) ); - - else if(bytes < 10000 * ONE_MEGABYTE) - /* 'XXXXM' is good until we are at 10000MB or above */ - msnprintf(max5, 6, "%4" FMT_OFF_T "M", bytes/ONE_MEGABYTE); - - else if(bytes < 100 * ONE_GIGABYTE) - /* 10000 MB - 100 GB, we show it as XX.XG */ - msnprintf(max5, 6, "%2" FMT_OFF_T ".%0" - FMT_OFF_T "G", bytes/ONE_GIGABYTE, - (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/10) ); - - else if(bytes < 10000 * ONE_GIGABYTE) - /* up to 10000GB, display without decimal: XXXXG */ - msnprintf(max5, 6, "%4" FMT_OFF_T "G", bytes/ONE_GIGABYTE); - - else if(bytes < 10000 * ONE_TERABYTE) - /* up to 10000TB, display without decimal: XXXXT */ - msnprintf(max5, 6, "%4" FMT_OFF_T "T", bytes/ONE_TERABYTE); - - else - /* up to 10000PB, display without decimal: XXXXP */ - msnprintf(max5, 6, "%4" FMT_OFF_T "P", bytes/ONE_PETABYTE); - - /* 16384 petabytes (16 exabytes) is the maximum a 64-bit unsigned number can - hold, but our data type is signed so 8192PB will be the maximum. */ + /* a signed 64-bit value is 8192 petabytes maximum */ + const char unit[] = { 'k', 'M', 'G', 'T', 'P', 0 }; + int k = 0; + if(bytes < 1000000) { + msnprintf(max6, 7, "%5" CURL_FORMAT_CURL_OFF_T, bytes); + return max6; + } - return max5; + do { + curl_off_t nbytes = bytes / 1024; + if(nbytes < 1000) { + /* xxx.yU */ + msnprintf(max6, 7, "%3" CURL_FORMAT_CURL_OFF_T + ".%" CURL_FORMAT_CURL_OFF_T "%c", nbytes, + (bytes%1024) / (1024/10), unit[k]); + break; + } + else if(nbytes < 100000) { + /* xxxxxU */ + msnprintf(max6, 7, "%5" CURL_FORMAT_CURL_OFF_T "%c", nbytes, unit[k]); + break; + } + bytes = nbytes; + k++; + DEBUGASSERT(unit[k]); + } while(unit[k]); + return max6; } #endif @@ -503,7 +486,7 @@ static void pgrs_estimates(struct pgrs_dir *d, static void progress_meter(struct Curl_easy *data) { struct Progress *p = &data->progress; - char max5[6][10]; + char max6[6][7]; struct pgrs_estimate dl_estm; struct pgrs_estimate ul_estm; struct pgrs_estimate total_estm; @@ -561,21 +544,21 @@ static void progress_meter(struct Curl_easy *data) fprintf(data->set.err, "\r" - "%3" FMT_OFF_T " %s " - "%3" FMT_OFF_T " %s " - "%3" FMT_OFF_T " %s %s %s %s %s %s %s", + "%3" FMT_OFF_T " %s " + "%3" FMT_OFF_T " %s " + "%3" FMT_OFF_T " %s %s %s %s %s %s %s", total_estm.percent, /* 3 letters */ /* total % */ - max5data(total_expected_size, max5[2]), /* total size */ + max6data(total_expected_size, max6[2]), /* total size */ dl_estm.percent, /* 3 letters */ /* rcvd % */ - max5data(p->dl.cur_size, max5[0]), /* rcvd size */ + max6data(p->dl.cur_size, max6[0]), /* rcvd size */ ul_estm.percent, /* 3 letters */ /* xfer % */ - max5data(p->ul.cur_size, max5[1]), /* xfer size */ - max5data(p->dl.speed, max5[3]), /* avrg dl speed */ - max5data(p->ul.speed, max5[4]), /* avrg ul speed */ + max6data(p->ul.cur_size, max6[1]), /* xfer size */ + max6data(p->dl.speed, max6[3]), /* avrg dl speed */ + max6data(p->ul.speed, max6[4]), /* avrg ul speed */ time_total, /* 8 letters */ /* total time */ time_spent, /* 8 letters */ /* time spent */ time_left, /* 8 letters */ /* time left */ - max5data(p->current_speed, max5[5]) + max6data(p->current_speed, max6[5]) ); /* we flush the output stream to make it appear as soon as possible */ From e73759f1a9cc32c70a0eaa7c2db2beef1fb2f124 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 3 Oct 2025 14:27:28 +0200 Subject: [PATCH 260/465] GHA: show full versions next to pinned actions Also quotes to a configuration entry. Follow-up to 2e5993ab0812fd1a983738f6d6efbc7bb0806144 #18827 Closes #18832 --- .github/workflows/checkdocs.yml | 12 ++--- .github/workflows/checksrc.yml | 10 ++-- .github/workflows/codeql.yml | 4 +- .github/workflows/configure-vs-cmake.yml | 6 +-- .github/workflows/curl-for-win.yml | 10 ++-- .github/workflows/distcheck.yml | 24 +++++----- .github/workflows/hacktoberfest-accepted.yml | 2 +- .github/workflows/http3-linux.yml | 48 ++++++++++---------- .github/workflows/label.yml | 2 +- .github/workflows/linux-old.yml | 2 +- .github/workflows/linux.yml | 22 ++++----- .github/workflows/macos.yml | 8 ++-- .github/workflows/non-native.yml | 8 ++-- .github/workflows/windows.yml | 30 ++++++------ 14 files changed, 94 insertions(+), 94 deletions(-) diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index 3f802b5c4edc..ad0c41e37aac 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -39,7 +39,7 @@ jobs: # name: 'proselint' # runs-on: ubuntu-latest # steps: - # - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + # - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 # with: # persist-credentials: false # @@ -93,7 +93,7 @@ jobs: name: 'linkcheck' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -104,7 +104,7 @@ jobs: name: 'pyspelling' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -135,7 +135,7 @@ jobs: name: 'badwords, synopsis' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -151,7 +151,7 @@ jobs: name: 'man-examples' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -163,7 +163,7 @@ jobs: runs-on: ubuntu-24.04-arm timeout-minutes: 5 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 71d096cac51d..4ea1961412d0 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -36,7 +36,7 @@ jobs: name: 'checksrc' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -47,7 +47,7 @@ jobs: name: 'spellcheck, linters, REUSE' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -101,7 +101,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 3 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -124,13 +124,13 @@ jobs: - name: 'install prereqs' run: HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install shellcheck zizmor - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: 'zizmor GHA' env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}' run: | eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" zizmor --pedantic .github/workflows/*.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b1e20b4d2dda..da12e575abc9 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -43,7 +43,7 @@ jobs: permissions: security-events: write # To create/update security events steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -79,7 +79,7 @@ jobs: libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install c-ares gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/configure-vs-cmake.yml b/.github/workflows/configure-vs-cmake.yml index b259daee514a..35f5290d1898 100644 --- a/.github/workflows/configure-vs-cmake.yml +++ b/.github/workflows/configure-vs-cmake.yml @@ -37,7 +37,7 @@ jobs: name: 'Linux' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -84,7 +84,7 @@ jobs: - name: 'toolchain versions' run: echo '::group::brew packages installed'; ls -l /opt/homebrew/opt; echo '::endgroup::' - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -133,7 +133,7 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install mingw-w64 - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/curl-for-win.yml b/.github/workflows/curl-for-win.yml index e29a2a66e85d..91b0382a7562 100644 --- a/.github/workflows/curl-for-win.yml +++ b/.github/workflows/curl-for-win.yml @@ -47,7 +47,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false path: 'curl' @@ -76,7 +76,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false path: 'curl' @@ -105,7 +105,7 @@ jobs: env: CW_JOBS: '4' steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false path: 'curl' @@ -123,7 +123,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false path: 'curl' @@ -150,7 +150,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false path: 'curl' diff --git a/.github/workflows/distcheck.yml b/.github/workflows/distcheck.yml index 9bc556562385..c6b4e775ebe2 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -75,7 +75,7 @@ jobs: timeout-minutes: 10 needs: maketgz-and-verify-in-tree steps: - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: 'release-tgz' @@ -99,7 +99,7 @@ jobs: timeout-minutes: 10 needs: maketgz-and-verify-in-tree steps: - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: 'release-tgz' @@ -125,7 +125,7 @@ jobs: timeout-minutes: 10 needs: maketgz-and-verify-in-tree steps: - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: 'release-tgz' @@ -149,7 +149,7 @@ jobs: timeout-minutes: 10 needs: maketgz-and-verify-in-tree steps: - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: 'release-tgz' @@ -170,7 +170,7 @@ jobs: timeout-minutes: 5 needs: maketgz-and-verify-in-tree steps: - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: 'release-tgz' @@ -192,7 +192,7 @@ jobs: timeout-minutes: 5 needs: maketgz-and-verify-in-tree steps: - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: 'release-tgz' @@ -214,11 +214,11 @@ jobs: timeout-minutes: 5 needs: maketgz-and-verify-in-tree steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: 'release-tgz' @@ -230,7 +230,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -267,7 +267,7 @@ jobs: matrix: image: [ubuntu-latest, macos-latest, windows-2022] steps: - - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2 + - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0 if: ${{ contains(matrix.image, 'windows') }} with: msystem: mingw64 @@ -302,7 +302,7 @@ jobs: printf '%s' ~/cmake-"${OLD_CMAKE_VERSION}"-Darwin-x86_64/CMake.app/Contents/bin/cmake > ~/old-cmake-path.txt fi - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/hacktoberfest-accepted.yml b/.github/workflows/hacktoberfest-accepted.yml index 3aacbd6d0c5c..f934193a6e28 100644 --- a/.github/workflows/hacktoberfest-accepted.yml +++ b/.github/workflows/hacktoberfest-accepted.yml @@ -26,7 +26,7 @@ jobs: issues: write # To edit labels on PRs pull-requests: write # To edit labels on PRs steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false fetch-depth: 100 diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 5b1bd5fde680..09b03ef1e187 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -69,7 +69,7 @@ jobs: steps: - name: 'cache openssl' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-openssl-http3 env: cache-name: cache-openssl-http3 @@ -78,7 +78,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }} - name: 'cache libressl' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-libressl env: cache-name: cache-libressl @@ -87,7 +87,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.LIBRESSL_VERSION }} - name: 'cache awslc' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-awslc env: cache-name: cache-awslc @@ -96,7 +96,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.AWSLC_VERSION }} - name: 'cache boringssl' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-boringssl env: cache-name: cache-boringssl @@ -105,7 +105,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.BORINGSSL_VERSION }} - name: 'cache quictls' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-quictls-no-deprecated env: cache-name: cache-quictls-no-deprecated @@ -114,7 +114,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.QUICTLS_VERSION }}-quic1 - name: 'cache gnutls' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-gnutls env: cache-name: cache-gnutls @@ -123,7 +123,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.GNUTLS_VERSION }} - name: 'cache wolfssl' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-wolfssl env: cache-name: cache-wolfssl @@ -132,7 +132,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.WOLFSSL_VERSION }} - name: 'cache nghttp3' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-nghttp3 env: cache-name: cache-nghttp3 @@ -141,7 +141,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGHTTP3_VERSION }} - name: 'cache ngtcp2' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-ngtcp2 env: cache-name: cache-ngtcp2 @@ -150,7 +150,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGTCP2_VERSION }}-${{ env.OPENSSL_VERSION }}-${{ env.LIBRESSL_VERSION }}-${{ env.AWSLC_VERSION }}-${{ env.QUICTLS_VERSION }}-${{ env.GNUTLS_VERSION }}-${{ env.WOLFSSL_VERSION }} - name: 'cache ngtcp2 boringssl' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-ngtcp2-boringssl env: cache-name: cache-ngtcp2-boringssl @@ -159,7 +159,7 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGTCP2_VERSION }}-${{ env.BORINGSSL_VERSION }} - name: 'cache nghttp2' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-nghttp2 env: cache-name: cache-nghttp2 @@ -517,7 +517,7 @@ jobs: - name: 'cache openssl' if: ${{ matrix.build.name == 'openssl' || matrix.build.name == 'openssl-quic' }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-openssl-http3 env: cache-name: cache-openssl-http3 @@ -527,7 +527,7 @@ jobs: fail-on-cache-miss: true - name: 'cache libressl' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-libressl env: cache-name: cache-libressl @@ -537,7 +537,7 @@ jobs: fail-on-cache-miss: true - name: 'cache awslc' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-awslc env: cache-name: cache-awslc @@ -547,7 +547,7 @@ jobs: fail-on-cache-miss: true - name: 'cache boringssl' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-boringssl env: cache-name: cache-boringssl @@ -557,7 +557,7 @@ jobs: fail-on-cache-miss: true - name: 'cache quictls' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-quictls-no-deprecated env: cache-name: cache-quictls-no-deprecated @@ -568,7 +568,7 @@ jobs: - name: 'cache gnutls' if: ${{ matrix.build.name == 'gnutls' }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-gnutls env: cache-name: cache-gnutls @@ -579,7 +579,7 @@ jobs: - name: 'cache wolfssl' if: ${{ matrix.build.name == 'wolfssl' }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-wolfssl env: cache-name: cache-wolfssl @@ -589,7 +589,7 @@ jobs: fail-on-cache-miss: true - name: 'cache nghttp3' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-nghttp3 env: cache-name: cache-nghttp3 @@ -599,7 +599,7 @@ jobs: fail-on-cache-miss: true - name: 'cache ngtcp2' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-ngtcp2 env: cache-name: cache-ngtcp2 @@ -609,7 +609,7 @@ jobs: fail-on-cache-miss: true - name: 'cache ngtcp2 boringssl' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-ngtcp2-boringssl env: cache-name: cache-ngtcp2-boringssl @@ -619,7 +619,7 @@ jobs: fail-on-cache-miss: true - name: 'cache nghttp2' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-nghttp2 env: cache-name: cache-nghttp2 @@ -630,7 +630,7 @@ jobs: - name: 'cache quiche' if: ${{ matrix.build.name == 'quiche' }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-quiche env: cache-name: cache-quiche @@ -659,7 +659,7 @@ jobs: # lib dir # /home/runner/quiche/quiche/deps/boringssl/src/lib - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index cfafde14f7fe..f2050bd2cedb 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -23,6 +23,6 @@ jobs: pull-requests: write # To edit labels on PRs steps: - - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6 + - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 with: repo-token: '${{ secrets.GITHUB_TOKEN }}' diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index e7aad3c3e73a..5cb292cafcd5 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -76,7 +76,7 @@ jobs: httrack --get https://deb.freexian.com/extended-lts/pool/main/g/gcc-8/libstdc++6_8.3.0-6_amd64.deb dpkg -i --force-depends libc6_*_amd64.deb libstdc++6_*_amd64.deb - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 3cdb9a47cd60..ee9da7e9a3aa 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -373,7 +373,7 @@ jobs: - name: 'cache libressl' if: ${{ contains(matrix.build.install_steps, 'libressl') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-libressl env: cache-name: cache-libressl @@ -393,7 +393,7 @@ jobs: - name: 'cache wolfssl (all)' if: ${{ contains(matrix.build.install_steps, 'wolfssl-all') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-wolfssl-all env: cache-name: cache-wolfssl-all @@ -414,7 +414,7 @@ jobs: - name: 'cache wolfssl (opensslextra)' # does support `OPENSSL_COEXIST` if: ${{ contains(matrix.build.install_steps, 'wolfssl-opensslextra') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-wolfssl-opensslextra env: cache-name: cache-wolfssl-opensslextra @@ -435,7 +435,7 @@ jobs: - name: 'cache mbedtls' if: ${{ contains(matrix.build.install_steps, 'mbedtls') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-mbedtls env: cache-name: cache-mbedtls-threadsafe @@ -458,7 +458,7 @@ jobs: - name: 'cache openldap-static' if: ${{ contains(matrix.build.install_steps, 'openldap-static') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-openldap-static env: cache-name: cache-openldap-static @@ -478,7 +478,7 @@ jobs: - name: 'cache openssl (thread sanitizer)' if: ${{ contains(matrix.build.install_steps, 'openssl-tsan') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-openssl-tsan env: cache-name: cache-openssl-tsan @@ -497,7 +497,7 @@ jobs: - name: 'cache quictls' if: ${{ contains(matrix.build.install_steps, 'quictls') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-quictls env: cache-name: cache-quictls @@ -516,7 +516,7 @@ jobs: - name: 'cache awslc' if: ${{ contains(matrix.build.install_steps, 'awslc') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-awslc env: cache-name: cache-awslc @@ -536,7 +536,7 @@ jobs: - name: 'cache boringssl' if: ${{ contains(matrix.build.install_steps, 'boringssl') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-boringssl env: cache-name: cache-boringssl @@ -557,7 +557,7 @@ jobs: - name: 'cache rustls' if: ${{ contains(matrix.build.install_steps, 'rustls') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-rustls env: cache-name: cache-rustls @@ -590,7 +590,7 @@ jobs: source /opt/intel/oneapi/setvars.sh printenv >> "$GITHUB_ENV" - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 931abc8693c9..87fc53d33490 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -110,7 +110,7 @@ jobs: - name: 'cache libressl' if: ${{ contains(matrix.build.install_steps, 'libressl') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-libressl env: cache-name: cache-libressl @@ -134,7 +134,7 @@ jobs: cmake --build . cmake --install . --verbose - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -388,7 +388,7 @@ jobs: echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::' echo '::group::brew packages installed'; ls -l /opt/homebrew/opt; echo '::endgroup::' - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -635,7 +635,7 @@ jobs: echo '::group::macros predefined'; "${CC}" -dM -E - < /dev/null | sort || true; echo '::endgroup::' echo '::group::brew packages preinstalled'; ls -l /opt/homebrew/opt; echo '::endgroup::' - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/non-native.yml b/.github/workflows/non-native.yml index 03abced26eb4..f0368a9240d1 100644 --- a/.github/workflows/non-native.yml +++ b/.github/workflows/non-native.yml @@ -47,7 +47,7 @@ jobs: matrix: arch: ['x86_64'] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: 'cmake' @@ -92,7 +92,7 @@ jobs: matrix: arch: ['x86_64'] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: 'cmake' @@ -142,7 +142,7 @@ jobs: - { build: 'cmake' , arch: 'arm64', compiler: 'clang' } fail-fast: false steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: '${{ matrix.build }}' @@ -261,7 +261,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e1219dfadc48..b5e31ee9c183 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -53,7 +53,7 @@ jobs: steps: - name: 'install build prereqs' if: ${{ steps.cache-perl-win32-pkgs.outputs.cache-hit != 'true' }} - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2 + uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0 with: msystem: msys install: gcc make @@ -62,7 +62,7 @@ jobs: run: perl --version | tee "$GITHUB_WORKSPACE"/perlversion - name: 'cache perl packages' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs @@ -133,7 +133,7 @@ jobs: libnghttp2-devel ${{ matrix.install }} - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -282,7 +282,7 @@ jobs: - run: git config --global core.autocrlf input shell: pwsh - - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2 + - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0 if: ${{ matrix.sys == 'msys' }} with: msystem: ${{ matrix.sys }} @@ -298,7 +298,7 @@ jobs: libpsl-devel ${{ matrix.install }} - - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2 + - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0 if: ${{ matrix.sys != 'msys' }} with: msystem: ${{ matrix.sys }} @@ -311,7 +311,7 @@ jobs: mingw-w64-${{ matrix.env }}-c-ares ${{ matrix.install }} - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -433,7 +433,7 @@ jobs: - name: 'cache perl packages' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' && matrix.sys != 'msys' }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs @@ -558,7 +558,7 @@ jobs: tflags: 'skipall' fail-fast: false steps: - - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2 + - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0 with: msystem: ${{ matrix.dir }} release: false @@ -570,7 +570,7 @@ jobs: ${{ matrix.install }} - name: 'cache compiler (gcc ${{ matrix.ver }}-${{ matrix.env }})' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-compiler with: path: D:\my-cache @@ -594,7 +594,7 @@ jobs: - run: git config --global core.autocrlf input - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -663,7 +663,7 @@ jobs: - name: 'cache perl packages' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs @@ -723,7 +723,7 @@ jobs: sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install gcc-mingw-w64-x86-64-win32 - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -892,7 +892,7 @@ jobs: fail-fast: false steps: - - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2 + - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0 with: msystem: ${{ matrix.arch == 'arm64' && 'clangarm64' || 'ucrt64' }} release: ${{ contains(matrix.image, 'arm') }} @@ -914,7 +914,7 @@ jobs: timeout-minutes: 45 run: vcpkg x-set-installed ${MATRIX_INSTALL_VCPKG} --triplet="${MATRIX_ARCH}-${MATRIX_PLAT}" - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -1057,7 +1057,7 @@ jobs: - name: 'cache perl packages' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-perl-win32-pkgs env: cache-name: cache-perl-win32-pkgs From 733c994b1e575d855a6bb59eb85e76a9f3884579 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 3 Oct 2025 14:15:04 +0200 Subject: [PATCH 261/465] doh: inherit new custom ssl flags The new custom_* flags in the SSL config need to be inherited when setting up the doh easy handle, so that defaults apply the same way as for the original easy handle. Closes #18831 --- lib/doh.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/doh.c b/lib/doh.c index a76f42207d60..15e01357b82c 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -377,6 +377,9 @@ static CURLcode doh_probe_run(struct Curl_easy *data, options should be added to check doh proxy insecure separately, CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER. */ + doh->set.ssl.custom_cafile = data->set.ssl.custom_cafile; + doh->set.ssl.custom_capath = data->set.ssl.custom_capath; + doh->set.ssl.custom_cablob = data->set.ssl.custom_cablob; if(data->set.str[STRING_SSL_CAFILE]) { ERROR_CHECK_SETOPT(CURLOPT_CAINFO, data->set.str[STRING_SSL_CAFILE]); From 7468faffc14e24a14e5f7badc6cc11e4459dc5aa Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 3 Oct 2025 21:15:33 +0200 Subject: [PATCH 262/465] Makefile.example: fix option order [ci skip] The `ld` linker is sensitive to this, and did not find libcurl symbol with the order before this patch. Seen with mingw-w64 gcc. Follow-up to f6ddc1fc1e25ff8ea866f90942719af898d0ef0c #18554 Closes #18835 --- docs/examples/Makefile.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/Makefile.example b/docs/examples/Makefile.example index f2994e73e1e4..fbbca8a9a9c0 100644 --- a/docs/examples/Makefile.example +++ b/docs/examples/Makefile.example @@ -47,4 +47,4 @@ LIBS := -lcurl $(LIBS) # Link the target with all objects and libraries $(TARGET) : $(SRC) - $(CC) -o $(TARGET) $(CFLAGS) $(LDFLAGS) $(LIBS) $< + $(CC) $< $(CFLAGS) $(LDFLAGS) $(LIBS) -o $(TARGET) From 99433d06e696a869879213cc1c741b77d5f34b21 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 15:54:06 +0000 Subject: [PATCH 263/465] GHA: update dependency google/boringssl to v0.20251002.0 Closes #18834 --- .github/workflows/http3-linux.yml | 2 +- .github/workflows/linux.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 09b03ef1e187..c14a64009771 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -48,7 +48,7 @@ env: # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com AWSLC_VERSION: 1.61.4 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com - BORINGSSL_VERSION: 0.20250818.0 + BORINGSSL_VERSION: 0.20251002.0 # renovate: datasource=github-tags depName=gnutls/gnutls versioning=semver registryUrl=https://github.com GNUTLS_VERSION: 3.8.10 # renovate: datasource=github-tags depName=wolfSSL/wolfssl versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index ee9da7e9a3aa..5b2b5e711c3b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -46,7 +46,7 @@ env: # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com AWSLC_VERSION: 1.61.4 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com - BORINGSSL_VERSION: 0.20250818.0 + BORINGSSL_VERSION: 0.20251002.0 # handled in renovate.json OPENSSL_VERSION: 3.6.0 # handled in renovate.json From fff36a360ed781ff1073bfc918747828d57face2 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 3 Oct 2025 03:12:39 +0200 Subject: [PATCH 264/465] checksrc: fix to handle `)` predecing a banned function Fixing: ``` Unmatched ) in regex; marked by <-- HERE in m/ \*buffer_len = \(ssize_t) <-- HERE strtol\(/ at /home/runner/work/curl/curl/scripts/checksrc.pl line 916, <$R> line 380. ``` Ref: https://github.com/curl/curl/actions/runs/18209824275/job/51848079550#step:3:5 Also add a test case. Follow-up to 684f4cdd3ef0cc41c547fce0e45d8a059a3058b3 #18779 Cherry-picked from #18823 Closes #18836 --- scripts/checksrc.pl | 1 + tests/data/test1185 | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 0907c3f9ad4c..af705d10c4db 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -908,6 +908,7 @@ sub scanfile { $prefix =~ s/\[/\\[/; $prefix =~ s/\]/\\]/; $prefix =~ s/\(/\\(/; + $prefix =~ s/\)/\\)/; $suff =~ s/\(/\\(/; $l =~ s/$prefix$bad$suff/$prefix$replace/; goto again; diff --git a/tests/data/test1185 b/tests/data/test1185 index 14a23dc01ac9..7323c59a0dce 100644 --- a/tests/data/test1185 +++ b/tests/data/test1185 @@ -75,6 +75,7 @@ void startfunc(int a, int b) { if(a) b++; if(sprintf(buffer, "%s", moo)) {} + *buffer_len = (ssize_t)alsobad((char *)buffer, NULL, 16); // CPP comment ? @@ -197,7 +198,10 @@ void startfunc(int a, int b) { ./%LOGDIR/code1185.c:59:5: warning: use of sprintf is banned (BANNEDFUNC) if(sprintf(buffer, "%s", moo)) {} ^ -./%LOGDIR/code1185.c:61:2: warning: // comment (CPPCOMMENTS) +./%LOGDIR/code1185.c:60:25: warning: use of alsobad is banned (BANNEDFUNC) + *buffer_len = (ssize_t)alsobad((char *)buffer, NULL, 16); + ^ +./%LOGDIR/code1185.c:62:2: warning: // comment (CPPCOMMENTS) // CPP comment ? ^ ./%LOGDIR/code1185.c:1:1: error: Missing copyright statement (COPYRIGHT) @@ -206,7 +210,7 @@ void startfunc(int a, int b) { ./%LOGDIR/code1185.c:1:1: error: Missing closing comment (OPENCOMMENT) ^ -checksrc: 0 errors and 40 warnings +checksrc: 0 errors and 41 warnings 5 From 45438c8d6f8e70385d66c029568524e9e803c539 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 2 Oct 2025 21:33:48 +0200 Subject: [PATCH 265/465] checksrc: reduce directory-specific exceptions By making them defaults, then fixing and/or reshuffling remaining exceptions as necessary. - checksrc: ban by default: `snprintf`, `vsnprintf`, `sscanf`, `strtol`. - examples: replace `strtol` with `atoi` to avoid a checksrc exception. - tests/libtest: replace `strtol` with `atol`. - tests/server: replace most `strtol` with `atol`. - tests/server: replace most `strtoul` with `atol`/`atoi`. - tests/server: drop no longer used `util_ultous`. - fix typo in checksrc rules: `vsnprint` -> `vsnprintf`. - update local exceptions. Also: - examples: ban curl printf functions. They're discouraged in user code. - examples: replace curl printf with system printf. Add `snprintf` workaround for #include +#elif (_MSC_VER < 1900) +#define snprintf _snprintf #endif #ifdef _WIN32 @@ -162,8 +164,8 @@ int my_trace(CURL *handle, curl_infotype type, } secs = epoch_offset + tv.tv_sec; now = localtime(&secs); /* not thread safe but we do not care */ - curl_msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld", - now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec); + snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld", + now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec); switch(type) { case CURLINFO_TEXT: @@ -215,7 +217,7 @@ static int setup(struct input *i, int num, const char *upload) hnd = i->hnd = NULL; i->num = num; - curl_msnprintf(filename, 128, "dl-%d", num); + snprintf(filename, sizeof(filename), "dl-%d", num); out = fopen(filename, "wb"); if(!out) { fprintf(stderr, "error: could not open file %s for writing: %s\n", upload, @@ -223,7 +225,7 @@ static int setup(struct input *i, int num, const char *upload) return 1; } - curl_msnprintf(url, 256, "https://localhost:8443/upload-%d", num); + snprintf(url, sizeof(url), "https://localhost:8443/upload-%d", num); i->in = fopen(upload, "rb"); if(!i->in) { diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c index 8d7af7c8c4c3..dd21082446a7 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -72,15 +72,32 @@ */ #include -#include -#include -#ifdef _WIN32 -#include +#ifndef _WIN32 +int main(void) { printf("Platform not supported.\n"); return 1; } #else -#error "This example requires Windows." + +#if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \ + defined(WINAPI_FAMILY) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ + !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define CURL_WINDOWS_UWP +# endif #endif +#ifdef CURL_WINDOWS_UWP +int main(void) { printf("Platform not supported.\n"); return 1; } +#else + +#include +#include + +#include + +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif #define MAX_STRING 256 #define MAX_STRING1 MAX_STRING + 1 @@ -139,7 +156,7 @@ static size_t SyncTime_CURL_WriteHeader(void *ptr, size_t size, size_t nmemb, *TmpStr1 = 0; *TmpStr2 = 0; if(strlen((char *)(ptr)) > 50) /* Can prevent buffer overflow to - TmpStr1 & 2? */ + TmpStr1 & 2? */ AutoSyncTime = 0; else { int RetVal = sscanf((char *)(ptr), "Date: %25s %hu %s %hu %hu:%hu:%hu", @@ -305,7 +322,7 @@ int main(int argc, char *argv[]) tzonediffFloat = difftime(tt_local, tt_gmt); tzonediffWord = (int)(tzonediffFloat/3600.0); - if((double)(tzonediffWord * 3600) == tzonediffFloat) + if(tzonediffWord == (int)(tzonediffFloat/3600.0)) snprintf(tzoneBuf, sizeof(tzoneBuf), "%+03d'00'", tzonediffWord); else snprintf(tzoneBuf, sizeof(tzoneBuf), "%+03d'30'", tzonediffWord); @@ -358,3 +375,5 @@ int main(int argc, char *argv[]) } return RetValue; } +#endif /* CURL_WINDOWS_UWP */ +#endif /* _WIN32 */ diff --git a/docs/internals/CODE_STYLE.md b/docs/internals/CODE_STYLE.md index aef5103fed6f..0d072c04c306 100644 --- a/docs/internals/CODE_STYLE.md +++ b/docs/internals/CODE_STYLE.md @@ -362,6 +362,6 @@ This is the full list of functions generally banned. strtok_r strtol strtoul - vsnprint + vsnprintf vsprintf wcsdup diff --git a/lib/.checksrc b/lib/.checksrc index 22ca8e0b5370..9b8d799ea285 100644 --- a/lib/.checksrc +++ b/lib/.checksrc @@ -1,5 +1 @@ -banfunc snprintf -banfunc sscanf banfunc strerror -banfunc strtol -banfunc vsnprint diff --git a/lib/curlx/.checksrc b/lib/curlx/.checksrc index 22ca8e0b5370..9b8d799ea285 100644 --- a/lib/curlx/.checksrc +++ b/lib/curlx/.checksrc @@ -1,5 +1 @@ -banfunc snprintf -banfunc sscanf banfunc strerror -banfunc strtol -banfunc vsnprint diff --git a/lib/vauth/.checksrc b/lib/vauth/.checksrc index 22ca8e0b5370..9b8d799ea285 100644 --- a/lib/vauth/.checksrc +++ b/lib/vauth/.checksrc @@ -1,5 +1 @@ -banfunc snprintf -banfunc sscanf banfunc strerror -banfunc strtol -banfunc vsnprint diff --git a/lib/vquic/.checksrc b/lib/vquic/.checksrc index 22ca8e0b5370..9b8d799ea285 100644 --- a/lib/vquic/.checksrc +++ b/lib/vquic/.checksrc @@ -1,5 +1 @@ -banfunc snprintf -banfunc sscanf banfunc strerror -banfunc strtol -banfunc vsnprint diff --git a/lib/vssh/.checksrc b/lib/vssh/.checksrc index 22ca8e0b5370..9b8d799ea285 100644 --- a/lib/vssh/.checksrc +++ b/lib/vssh/.checksrc @@ -1,5 +1 @@ -banfunc snprintf -banfunc sscanf banfunc strerror -banfunc strtol -banfunc vsnprint diff --git a/lib/vtls/.checksrc b/lib/vtls/.checksrc index 22ca8e0b5370..9b8d799ea285 100644 --- a/lib/vtls/.checksrc +++ b/lib/vtls/.checksrc @@ -1,5 +1 @@ -banfunc snprintf -banfunc sscanf banfunc strerror -banfunc strtol -banfunc vsnprint diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index af705d10c4db..637c0b7c8b5d 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -53,11 +53,15 @@ "gets" => 1, "strtok" => 1, "sprintf" => 1, + "snprintf" => 1, "vsprintf" => 1, + "vsnprintf" => 1, + "sscanf" => 1, "strcat" => 1, "strncat" => 1, "strncpy" => 1, "strtok_r" => 1, + "strtol" => 1, "strtoul" => 1, "_mbscat" => 1, "_mbsncat" => 1, diff --git a/src/.checksrc b/src/.checksrc index 7b71afb23689..946367c4999f 100644 --- a/src/.checksrc +++ b/src/.checksrc @@ -1,5 +1 @@ enable STDERR -banfunc snprintf -banfunc sscanf -banfunc strtol -banfunc vsnprint diff --git a/tests/libtest/cli_hx_download.c b/tests/libtest/cli_hx_download.c index 7a6a48c171b5..5ab4db024c58 100644 --- a/tests/libtest/cli_hx_download.c +++ b/tests/libtest/cli_hx_download.c @@ -317,32 +317,32 @@ static CURLcode test_cli_hx_download(const char *URL) forbid_reuse_d = 1; break; case 'm': - max_parallel = (size_t)strtol(coptarg, NULL, 10); + max_parallel = (size_t)atol(coptarg); break; case 'n': - transfer_count_d = (size_t)strtol(coptarg, NULL, 10); + transfer_count_d = (size_t)atol(coptarg); break; case 'x': fresh_connect = 1; break; case 'A': - abort_offset = (size_t)strtol(coptarg, NULL, 10); + abort_offset = (size_t)atol(coptarg); break; case 'F': - fail_offset = (size_t)strtol(coptarg, NULL, 10); + fail_offset = (size_t)atol(coptarg); break; case 'M': - max_host_conns = (size_t)strtol(coptarg, NULL, 10); + max_host_conns = (size_t)atol(coptarg); break; case 'P': - pause_offset = (size_t)strtol(coptarg, NULL, 10); + pause_offset = (size_t)atol(coptarg); break; case 'r': free(resolve); resolve = strdup(coptarg); break; case 'T': - max_total_conns = (size_t)strtol(coptarg, NULL, 10); + max_total_conns = (size_t)atol(coptarg); break; case 'V': { if(!strcmp("http/1.1", coptarg)) diff --git a/tests/libtest/cli_hx_upload.c b/tests/libtest/cli_hx_upload.c index 40e486c41a1a..a0a6b95db847 100644 --- a/tests/libtest/cli_hx_upload.c +++ b/tests/libtest/cli_hx_upload.c @@ -257,22 +257,22 @@ static CURLcode test_cli_hx_upload(const char *URL) announce_length = 1; break; case 'm': - max_parallel = (size_t)strtol(coptarg, NULL, 10); + max_parallel = (size_t)atol(coptarg); break; case 'n': - transfer_count_u = (size_t)strtol(coptarg, NULL, 10); + transfer_count_u = (size_t)atol(coptarg); break; case 'A': - abort_offset = (size_t)strtol(coptarg, NULL, 10); + abort_offset = (size_t)atol(coptarg); break; case 'F': - fail_offset = (size_t)strtol(coptarg, NULL, 10); + fail_offset = (size_t)atol(coptarg); break; case 'M': method = coptarg; break; case 'P': - pause_offset = (size_t)strtol(coptarg, NULL, 10); + pause_offset = (size_t)atol(coptarg); break; case 'r': resolve = coptarg; @@ -281,7 +281,7 @@ static CURLcode test_cli_hx_upload(const char *URL) reuse_easy = 1; break; case 'S': - send_total = (size_t)strtol(coptarg, NULL, 10); + send_total = (size_t)atol(coptarg); break; case 'V': { if(!strcmp("http/1.1", coptarg)) diff --git a/tests/libtest/cli_ws_data.c b/tests/libtest/cli_ws_data.c index 32356552a807..26cecc19fea3 100644 --- a/tests/libtest/cli_ws_data.c +++ b/tests/libtest/cli_ws_data.c @@ -431,13 +431,13 @@ static CURLcode test_cli_ws_data(const char *URL) res = CURLE_BAD_FUNCTION_ARGUMENT; goto cleanup; case 'c': - count = (size_t)strtol(coptarg, NULL, 10); + count = (size_t)atol(coptarg); break; case 'm': - plen_min = (size_t)strtol(coptarg, NULL, 10); + plen_min = (size_t)atol(coptarg); break; case 'M': - plen_max = (size_t)strtol(coptarg, NULL, 10); + plen_max = (size_t)atol(coptarg); break; default: test_ws_data_usage("invalid option"); diff --git a/tests/libtest/first.c b/tests/libtest/first.c index 49ec8a5f91b4..79baca331ea9 100644 --- a/tests/libtest/first.c +++ b/tests/libtest/first.c @@ -137,9 +137,8 @@ static void memory_tracking_init(void) /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */ env = getenv("CURL_MEMLIMIT"); if(env) { - char *endptr; - long num = strtol(env, &endptr, 10); - if((endptr != env) && (endptr == env + strlen(env)) && (num > 0)) + long num = atol(env); + if(num > 0) curl_dbg_memlimit(num); } } diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c index 1973d8a916e9..0071bb0f8b8f 100644 --- a/tests/libtest/lib1560.c +++ b/tests/libtest/lib1560.c @@ -1198,6 +1198,7 @@ static CURLUcode updateurl(CURLU *u, const char *cmd, unsigned int setflags) memset(value, 0, sizeof(value)); /* Avoid valgrind false positive. */ memcpy(buf, p, n); buf[n] = 0; + /* !checksrc! disable BANNEDFUNC 1 */ if(sscanf(buf, "%79[^=]=%79[^,]", part, value) == 2) { CURLUPart what = part2id(part); #if 0 diff --git a/tests/libtest/lib1568.c b/tests/libtest/lib1568.c index a2451486fd41..695badc85ce2 100644 --- a/tests/libtest/lib1568.c +++ b/tests/libtest/lib1568.c @@ -39,7 +39,7 @@ static CURLcode test_lib1568(const char *URL) curl_easy_setopt(hnd, CURLOPT_USERAGENT, "lib1568"); curl_easy_setopt(hnd, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); - curl_easy_setopt(hnd, CURLOPT_PORT, strtol(libtest_arg2, NULL, 10)); + curl_easy_setopt(hnd, CURLOPT_PORT, atol(libtest_arg2)); ret = curl_easy_perform(hnd); diff --git a/tests/libtest/lib521.c b/tests/libtest/lib521.c index 32bf7b3022a2..c02c45a3c103 100644 --- a/tests/libtest/lib521.c +++ b/tests/libtest/lib521.c @@ -43,7 +43,7 @@ static CURLcode test_lib521(const char *URL) } test_setopt(curl, CURLOPT_URL, URL); - test_setopt(curl, CURLOPT_PORT, strtol(libtest_arg2, NULL, 10)); + test_setopt(curl, CURLOPT_PORT, atol(libtest_arg2)); test_setopt(curl, CURLOPT_USERPWD, "xxx:yyy"); test_setopt(curl, CURLOPT_VERBOSE, 1L); diff --git a/tests/libtest/lib562.c b/tests/libtest/lib562.c index 016dffe1bda1..1c3bf8cff837 100644 --- a/tests/libtest/lib562.c +++ b/tests/libtest/lib562.c @@ -55,7 +55,7 @@ static CURLcode test_lib562(const char *URL) test_setopt(curl, CURLOPT_VERBOSE, 1L); /* set port number */ - test_setopt(curl, CURLOPT_PORT, strtol(libtest_arg2, NULL, 10)); + test_setopt(curl, CURLOPT_PORT, atol(libtest_arg2)); /* specify target */ test_setopt(curl, CURLOPT_URL, URL); diff --git a/tests/libtest/lib591.c b/tests/libtest/lib591.c index 77a038c7c320..c85c42b0c228 100644 --- a/tests/libtest/lib591.c +++ b/tests/libtest/lib591.c @@ -71,8 +71,7 @@ static CURLcode test_lib591(const char *URL) easy_setopt(easy, CURLOPT_FTPPORT, "-"); /* server connection timeout */ - easy_setopt(easy, CURLOPT_ACCEPTTIMEOUT_MS, - strtol(libtest_arg2, NULL, 10)*1000); + easy_setopt(easy, CURLOPT_ACCEPTTIMEOUT_MS, atol(libtest_arg2)*1000); multi_init(multi); diff --git a/tests/server/.checksrc b/tests/server/.checksrc index 29331433c2cb..d6506e14020a 100644 --- a/tests/server/.checksrc +++ b/tests/server/.checksrc @@ -6,5 +6,7 @@ allowfunc getaddrinfo allowfunc open allowfunc recv allowfunc send +allowfunc snprintf allowfunc socket -allowfunc strtoul +allowfunc sscanf +allowfunc vsnprintf diff --git a/tests/server/dnsd.c b/tests/server/dnsd.c index dc49723da313..2d0ce35e6f40 100644 --- a/tests/server/dnsd.c +++ b/tests/server/dnsd.c @@ -441,9 +441,7 @@ static int test_dnsd(int argc, char **argv) else if(!strcmp("--port", argv[arg])) { arg++; if(argc > arg) { - char *endptr; - unsigned long ulnum = strtoul(argv[arg], &endptr, 10); - port = util_ultous(ulnum); + port = (unsigned short)atoi(argv[arg]); arg++; } } diff --git a/tests/server/first.h b/tests/server/first.h index 44dd272ce2b3..4d3ae61de7ed 100644 --- a/tests/server/first.h +++ b/tests/server/first.h @@ -148,7 +148,6 @@ extern void restore_signal_handlers(bool keep_sigalrm); extern int bind_unix_socket(curl_socket_t sock, const char *unix_socket, struct sockaddr_un *sau); #endif -extern unsigned short util_ultous(unsigned long ulnum); extern curl_socket_t sockdaemon(curl_socket_t sock, unsigned short *listenport, const char *unix_socket, diff --git a/tests/server/mqttd.c b/tests/server/mqttd.c index 7f5abf1b5d6e..9414eef504f1 100644 --- a/tests/server/mqttd.c +++ b/tests/server/mqttd.c @@ -782,15 +782,13 @@ static int test_mqttd(int argc, char *argv[]) else if(!strcmp("--port", argv[arg])) { arg++; if(argc > arg) { - char *endptr; - unsigned long ulnum = strtoul(argv[arg], &endptr, 10); - if((endptr != argv[arg] + strlen(argv[arg])) || - ((ulnum != 0UL) && ((ulnum < 1025UL) || (ulnum > 65535UL)))) { + int inum = atoi(argv[arg]); + if(inum && ((inum < 1025) || (inum > 65535))) { fprintf(stderr, "mqttd: invalid --port argument (%s)\n", argv[arg]); return 0; } - server_port = util_ultous(ulnum); + server_port = (unsigned short)inum; arg++; } } diff --git a/tests/server/rtspd.c b/tests/server/rtspd.c index 67829922dc92..0a4f9159c054 100644 --- a/tests/server/rtspd.c +++ b/tests/server/rtspd.c @@ -211,7 +211,7 @@ static int rtspd_ProcessRequest(struct rtspd_httprequest *req) while(*ptr && !ISDIGIT(*ptr)) ptr++; - req->testno = strtol(ptr, &ptr, 10); + req->testno = atol(ptr); if(req->testno > 10000) { req->partno = req->testno % 10000; @@ -358,7 +358,7 @@ static int rtspd_ProcessRequest(struct rtspd_httprequest *req) CONNECT line will be used as test number! */ char *portp = strchr(doc, ':'); if(portp && (*(portp + 1) != '\0') && ISDIGIT(*(portp + 1))) - req->testno = strtol(portp + 1, NULL, 10); + req->testno = atol(portp + 1); else req->testno = DOCNUMBER_CONNECT; } @@ -1045,9 +1045,7 @@ static int test_rtspd(int argc, char *argv[]) else if(!strcmp("--port", argv[arg])) { arg++; if(argc > arg) { - char *endptr; - unsigned long ulnum = strtoul(argv[arg], &endptr, 10); - port = util_ultous(ulnum); + port = (unsigned short)atol(argv[arg]); arg++; } } diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index a52efe0a1bf6..c6536fee4a31 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -376,6 +376,7 @@ static bool read_data_block(unsigned char *buffer, ssize_t maxlen, buffer[5] = '\0'; + /* !checksrc! disable BANNEDFUNC 1 */ *buffer_len = (ssize_t)strtol((char *)buffer, NULL, 16); if(*buffer_len > maxlen) { logmsg("Buffer size (%zd bytes) too small for data size error " @@ -1278,9 +1279,7 @@ static int test_sockfilt(int argc, char *argv[]) else if(!strcmp("--port", argv[arg])) { arg++; if(argc > arg) { - char *endptr; - unsigned long ulnum = strtoul(argv[arg], &endptr, 10); - server_port = util_ultous(ulnum); + server_port = (unsigned short)atol(argv[arg]); arg++; } } @@ -1289,15 +1288,13 @@ static int test_sockfilt(int argc, char *argv[]) doing a passive server-style listening. */ arg++; if(argc > arg) { - char *endptr; - unsigned long ulnum = strtoul(argv[arg], &endptr, 10); - if((endptr != argv[arg] + strlen(argv[arg])) || - (ulnum < 1025UL) || (ulnum > 65535UL)) { + int inum = atoi(argv[arg]); + if(inum && ((inum < 1025) || (inum > 65535))) { fprintf(stderr, "sockfilt: invalid --connect argument (%s)\n", argv[arg]); return 0; } - server_connectport = util_ultous(ulnum); + server_connectport = (unsigned short)inum; arg++; } } diff --git a/tests/server/socksd.c b/tests/server/socksd.c index 4d599e16b61a..06283e042403 100644 --- a/tests/server/socksd.c +++ b/tests/server/socksd.c @@ -108,7 +108,7 @@ static void socksd_resetdefaults(void) static unsigned short shortval(char *value) { - unsigned long num = strtoul(value, NULL, 10); + unsigned long num = (unsigned long)atol(value); return num & 0xffff; } @@ -831,9 +831,7 @@ static int test_socksd(int argc, char *argv[]) else if(!strcmp("--port", argv[arg])) { arg++; if(argc > arg) { - char *endptr; - unsigned long ulnum = strtoul(argv[arg], &endptr, 10); - server_port = util_ultous(ulnum); + server_port = (unsigned short)atol(argv[arg]); arg++; } } diff --git a/tests/server/sws.c b/tests/server/sws.c index a512a7a31e26..20d2bf763261 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -389,7 +389,7 @@ static int sws_ProcessRequest(struct sws_httprequest *req) ptr++; /* skip the slash */ - req->testno = strtol(ptr, &ptr, 10); + req->testno = atol(ptr); if(req->testno > 10000) { req->partno = req->testno % 10000; @@ -430,6 +430,7 @@ static int sws_ProcessRequest(struct sws_httprequest *req) in the 'part' variable and use as test case number!! */ while(*p && (ISXDIGIT(*p) || (*p == ':') || (*p == '.'))) { char *endp; + /* !checksrc! disable BANNEDFUNC 1 */ part = strtoul(p, &endp, 16); if(ISXDIGIT(*p)) p = endp; @@ -449,11 +450,11 @@ static int sws_ProcessRequest(struct sws_httprequest *req) portp = strchr(doc, ':'); if(portp && (*(portp + 1) != '\0') && ISDIGIT(*(portp + 1))) { - unsigned long ulnum = strtoul(portp + 1, NULL, 10); - if(!ulnum || (ulnum > 65535UL)) + int inum = atoi(portp + 1); + if((inum <= 0) || (inum > 65535)) logmsg("Invalid CONNECT port received"); else - req->connect_port = util_ultous(ulnum); + req->connect_port = (unsigned short)inum; } logmsg("Port number: %d, test case number: %ld", @@ -490,7 +491,7 @@ static int sws_ProcessRequest(struct sws_httprequest *req) /* check for a Testno: header with the test case number */ char *testno = strstr(line, "\nTestno: "); if(testno) { - req->testno = strtol(&testno[9], NULL, 10); + req->testno = atol(&testno[9]); logmsg("Found test number %ld in Testno: header!", req->testno); } else { @@ -516,7 +517,7 @@ static int sws_ProcessRequest(struct sws_httprequest *req) while(*ptr && !ISDIGIT(*ptr)) ptr++; - req->testno = strtol(ptr, &ptr, 10); + req->testno = atol(ptr); if(req->testno > 10000) { req->partno = req->testno % 10000; @@ -2071,15 +2072,13 @@ static int test_sws(int argc, char *argv[]) else if(!strcmp("--port", argv[arg])) { arg++; if(argc > arg) { - char *endptr; - unsigned long ulnum = strtoul(argv[arg], &endptr, 10); - if((endptr != argv[arg] + strlen(argv[arg])) || - (ulnum && ((ulnum < 1025UL) || (ulnum > 65535UL)))) { + int inum = atoi(argv[arg]); + if(inum && ((inum < 1025) || (inum > 65535))) { fprintf(stderr, "sws: invalid --port argument (%s)\n", argv[arg]); return 0; } - port = util_ultous(ulnum); + port = (unsigned short)inum; arg++; } } @@ -2093,15 +2092,13 @@ static int test_sws(int argc, char *argv[]) else if(!strcmp("--keepalive", argv[arg])) { arg++; if(argc > arg) { - char *endptr; - unsigned long ulnum = strtoul(argv[arg], &endptr, 10); - if((endptr != argv[arg] + strlen(argv[arg])) || - (ulnum && (ulnum > 65535UL))) { + int inum = atoi(argv[arg]); + if(inum && (inum > 65535)) { fprintf(stderr, "sws: invalid --keepalive argument (%s), must " "be number of seconds\n", argv[arg]); return 0; } - keepalive_secs = util_ultous(ulnum); + keepalive_secs = (unsigned short)inum; arg++; } } diff --git a/tests/server/tftpd.c b/tests/server/tftpd.c index 193afac1377e..4c37685ab716 100644 --- a/tests/server/tftpd.c +++ b/tests/server/tftpd.c @@ -607,9 +607,7 @@ static int test_tftpd(int argc, char **argv) else if(!strcmp("--port", argv[arg])) { arg++; if(argc > arg) { - char *endptr; - unsigned long ulnum = strtoul(argv[arg], &endptr, 10); - port = util_ultous(ulnum); + port = (unsigned short)atol(argv[arg]); arg++; } } @@ -1100,7 +1098,7 @@ static int validate_access(struct testcase *test, ptr++; /* get the number */ - testno = strtol(ptr, &ptr, 10); + testno = atol(ptr); if(testno > 10000) { partno = testno % 10000; diff --git a/tests/server/util.c b/tests/server/util.c index 749e33003c29..f4802745c8d6 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -133,7 +133,7 @@ void logmsg(const char *msg, ...) unsigned char byteval(char *value) { - unsigned long num = strtoul(value, NULL, 10); + unsigned int num = (unsigned int)atoi(value); return num & 0xff; } @@ -748,27 +748,6 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket, } #endif -/* -** unsigned long to unsigned short -*/ -#define CURL_MASK_USHORT ((unsigned short)~0) -#define CURL_MASK_SSHORT (CURL_MASK_USHORT >> 1) - -unsigned short util_ultous(unsigned long ulnum) -{ -#ifdef __INTEL_COMPILER -# pragma warning(push) -# pragma warning(disable:810) /* conversion may lose significant bits */ -#endif - - DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT); - return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT); - -#ifdef __INTEL_COMPILER -# pragma warning(pop) -#endif -} - curl_socket_t sockdaemon(curl_socket_t sock, unsigned short *listenport, const char *unix_socket, From 4deea9396bc7dd25c6362fa746a57bf309c74ada Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 2 Oct 2025 16:01:15 +0200 Subject: [PATCH 266/465] tests: stop overriding system printf symbols To make the source code match the functions called at runtime. And to avoid the preprocessor trick that may introduces build issues. Before this patch, libtests, tunits and units were calling a mixture of curl and system printf calls, then transformed them all to curl printf calls by including `curl_printf.h`. Changes made: - tests: stop including `curl_printf.h`. - libtest: switch a couple of outlier system printf calls to curl printf. - unit: use more curl printf to avoid casts and show whole values. - unit: switch remaining calls to curl printf explicitly. - tunit: switch to call curl printf explicitly. - libtest, tunit, unit: ban system printf. - unit1307, unit1607, unit1609, unit1652, unit1655, unit3214: bump types/masks to avoid casts. After this patch: - libtests, tunits, units: use exclusively curl printf. (as before, but explicitly, without relying on redefinitions.) - servers: is unchanged (it can only use system printf). Closes #18814 --- REUSE.toml | 3 ++ tests/libtest/.checksrc | 8 +++++ tests/libtest/Makefile.am | 2 +- tests/libtest/first.h | 2 -- tests/libtest/lib1549.c | 4 +-- tests/tunit/.checksrc | 8 +++++ tests/tunit/Makefile.am | 2 +- tests/tunit/tool1394.c | 24 +++++++------- tests/tunit/tool1604.c | 55 ++++++++++++++++---------------- tests/tunit/tool1621.c | 5 +-- tests/unit/.checksrc | 8 +++++ tests/unit/Makefile.am | 2 +- tests/unit/unit1302.c | 26 +++++++-------- tests/unit/unit1307.c | 18 +++++------ tests/unit/unit1309.c | 14 ++++----- tests/unit/unit1323.c | 14 ++++----- tests/unit/unit1396.c | 4 +-- tests/unit/unit1607.c | 36 ++++++++++----------- tests/unit/unit1609.c | 28 ++++++++--------- tests/unit/unit1652.c | 8 ++--- tests/unit/unit1655.c | 4 +-- tests/unit/unit1658.c | 4 +-- tests/unit/unit1660.c | 4 +-- tests/unit/unit1664.c | 66 +++++++++++++++++++-------------------- tests/unit/unit2604.c | 14 ++++----- tests/unit/unit3214.c | 11 ++++--- 26 files changed, 200 insertions(+), 174 deletions(-) create mode 100644 tests/libtest/.checksrc create mode 100644 tests/tunit/.checksrc create mode 100644 tests/unit/.checksrc diff --git a/REUSE.toml b/REUSE.toml index 6e8a272e795c..0d07c8b3e152 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -48,7 +48,10 @@ path = [ "lib/vssh/.checksrc", "lib/vtls/.checksrc", "src/.checksrc", + "tests/libtest/.checksrc", "tests/server/.checksrc", + "tests/tunit/.checksrc", + "tests/unit/.checksrc", ] SPDX-FileCopyrightText = "Daniel Stenberg, , et al." SPDX-License-Identifier = "curl" diff --git a/tests/libtest/.checksrc b/tests/libtest/.checksrc new file mode 100644 index 000000000000..a3f8f307e792 --- /dev/null +++ b/tests/libtest/.checksrc @@ -0,0 +1,8 @@ +banfunc aprintf +banfunc fprintf +banfunc msnprintf +banfunc mvsnprintf +banfunc printf +banfunc vaprintf +banfunc vfprintf +banfunc vprintf diff --git a/tests/libtest/Makefile.am b/tests/libtest/Makefile.am index b62a359eabef..482e09d098a4 100644 --- a/tests/libtest/Makefile.am +++ b/tests/libtest/Makefile.am @@ -41,7 +41,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ # Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TESTS_C variables include Makefile.inc -EXTRA_DIST = CMakeLists.txt $(FIRST_C) $(FIRST_H) $(UTILS_C) $(UTILS_H) $(TESTS_C) \ +EXTRA_DIST = CMakeLists.txt .checksrc $(FIRST_C) $(FIRST_H) $(UTILS_C) $(UTILS_H) $(TESTS_C) \ test307.pl test610.pl test613.pl test1013.pl test1022.pl mk-lib1521.pl CFLAGS += @CURL_CFLAG_EXTRAS@ diff --git a/tests/libtest/first.h b/tests/libtest/first.h index 1592922e39a8..a902bdb8f0ed 100644 --- a/tests/libtest/first.h +++ b/tests/libtest/first.h @@ -52,8 +52,6 @@ extern int unitfail; /* for unittests */ #include #endif -#include "curl_printf.h" - /* GCC <4.6 does not support '#pragma GCC diagnostic push' and does not support 'pragma GCC diagnostic' inside functions. */ #if (defined(__GNUC__) && \ diff --git a/tests/libtest/lib1549.c b/tests/libtest/lib1549.c index b7bf010612c0..10d318381027 100644 --- a/tests/libtest/lib1549.c +++ b/tests/libtest/lib1549.c @@ -58,14 +58,14 @@ static CURLcode test_lib1549(const char *URL) /* a linked list of cookies in cookie file format */ struct curl_slist *each = cookies; while(each) { - printf("%s\n", each->data); + curl_mprintf("%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); + curl_mfprintf(stderr, "%d cookies\n", num); } test_cleanup: diff --git a/tests/tunit/.checksrc b/tests/tunit/.checksrc new file mode 100644 index 000000000000..a3f8f307e792 --- /dev/null +++ b/tests/tunit/.checksrc @@ -0,0 +1,8 @@ +banfunc aprintf +banfunc fprintf +banfunc msnprintf +banfunc mvsnprintf +banfunc printf +banfunc vaprintf +banfunc vfprintf +banfunc vprintf diff --git a/tests/tunit/Makefile.am b/tests/tunit/Makefile.am index 219b7a10579c..fea9d51152ae 100644 --- a/tests/tunit/Makefile.am +++ b/tests/tunit/Makefile.am @@ -43,7 +43,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ # Get BUNDLE, FIRST_C, TESTS_C variables include Makefile.inc -EXTRA_DIST = CMakeLists.txt README.md $(TESTS_C) +EXTRA_DIST = CMakeLists.txt .checksrc README.md $(TESTS_C) CFLAGS += @CURL_CFLAG_EXTRAS@ diff --git a/tests/tunit/tool1394.c b/tests/tunit/tool1394.c index 77a2021b0a88..3a5256bae1fc 100644 --- a/tests/tunit/tool1394.c +++ b/tests/tunit/tool1394.c @@ -73,42 +73,42 @@ static CURLcode test_tool1394(const char *arg) if(p[1]) { if(certname) { if(strcmp(p[1], certname)) { - printf("expected certname '%s' but got '%s' " - "for -E param '%s'\n", p[1], certname, p[0]); + curl_mprintf("expected certname '%s' but got '%s' " + "for -E param '%s'\n", p[1], certname, p[0]); fail("assertion failure"); } } else { - printf("expected certname '%s' but got NULL " - "for -E param '%s'\n", p[1], p[0]); + curl_mprintf("expected certname '%s' but got NULL " + "for -E param '%s'\n", p[1], p[0]); fail("assertion failure"); } } else { if(certname) { - printf("expected certname NULL but got '%s' " - "for -E param '%s'\n", certname, p[0]); + curl_mprintf("expected certname NULL but got '%s' " + "for -E param '%s'\n", certname, p[0]); fail("assertion failure"); } } if(p[2]) { if(passphrase) { if(strcmp(p[2], passphrase)) { - printf("expected passphrase '%s' but got '%s'" - "for -E param '%s'\n", p[2], passphrase, p[0]); + curl_mprintf("expected passphrase '%s' but got '%s'" + "for -E param '%s'\n", p[2], passphrase, p[0]); fail("assertion failure"); } } else { - printf("expected passphrase '%s' but got NULL " - "for -E param '%s'\n", p[2], p[0]); + curl_mprintf("expected passphrase '%s' but got NULL " + "for -E param '%s'\n", p[2], p[0]); fail("assertion failure"); } } else { if(passphrase) { - printf("expected passphrase NULL but got '%s' " - "for -E param '%s'\n", passphrase, p[0]); + curl_mprintf("expected passphrase NULL but got '%s' " + "for -E param '%s'\n", passphrase, p[0]); fail("assertion failure"); } } diff --git a/tests/tunit/tool1604.c b/tests/tunit/tool1604.c index db7ed1412408..3b6f006e7cfd 100644 --- a/tests/tunit/tool1604.c +++ b/tests/tunit/tool1604.c @@ -33,11 +33,11 @@ static char *getflagstr(int flags) { char *buf = malloc(256); if(buf) { - msnprintf(buf, 256, "%s,%s", - ((flags & SANITIZE_ALLOW_PATH) ? - "SANITIZE_ALLOW_PATH" : ""), - ((flags & SANITIZE_ALLOW_RESERVED) ? - "SANITIZE_ALLOW_RESERVED" : "")); + curl_msnprintf(buf, 256, "%s,%s", + ((flags & SANITIZE_ALLOW_PATH) ? + "SANITIZE_ALLOW_PATH" : ""), + ((flags & SANITIZE_ALLOW_RESERVED) ? + "SANITIZE_ALLOW_RESERVED" : "")); } return buf; } @@ -46,13 +46,12 @@ static char *getcurlcodestr(int cc) { char *buf = malloc(256); if(buf) { - msnprintf(buf, 256, "%s (%d)", - (cc == SANITIZE_ERR_OK ? "SANITIZE_ERR_OK" : - cc == SANITIZE_ERR_BAD_ARGUMENT ? "SANITIZE_ERR_BAD_ARGUMENT" : - cc == SANITIZE_ERR_INVALID_PATH ? "SANITIZE_ERR_INVALID_PATH" : - cc == SANITIZE_ERR_OUT_OF_MEMORY ? "SANITIZE_ERR_OUT_OF_MEMORY": - "unexpected error code - add name"), - cc); + curl_msnprintf(buf, 256, "%s (%d)", + (cc == SANITIZE_ERR_OK ? "SANITIZE_ERR_OK" : + cc == SANITIZE_ERR_BAD_ARGUMENT ? "SANITIZE_ERR_BAD_ARGUMENT" : + cc == SANITIZE_ERR_INVALID_PATH ? "SANITIZE_ERR_INVALID_PATH" : + cc == SANITIZE_ERR_OUT_OF_MEMORY ? "SANITIZE_ERR_OUT_OF_MEMORY" : + "unexpected error code - add name"), cc); } return buf; } @@ -225,21 +224,21 @@ static CURLcode test_tool1604(const char *arg) abort_unless(expected_ccstr, "out of memory"); unitfail++; - fprintf(stderr, "\n" - "%s:%d sanitize_file_name failed.\n" - "input: %s\n" - "flags: %s\n" - "output: %s\n" - "result: %s\n" - "expected output: %s\n" - "expected result: %s\n", - __FILE__, __LINE__, - data[i].input, - flagstr, - (output ? output : "(null)"), - received_ccstr, - (data[i].expected_output ? data[i].expected_output : "(null)"), - expected_ccstr); + curl_mfprintf(stderr, "\n" + "%s:%d sanitize_file_name failed.\n" + "input: %s\n" + "flags: %s\n" + "output: %s\n" + "result: %s\n" + "expected output: %s\n" + "expected result: %s\n", + __FILE__, __LINE__, + data[i].input, + flagstr, + output ? output : "(null)", + received_ccstr, + data[i].expected_output ? data[i].expected_output : "(null)", + expected_ccstr); free(output); free(flagstr); @@ -248,7 +247,7 @@ static CURLcode test_tool1604(const char *arg) } /* END sanitize_file_name */ #else - fprintf(stderr, "Skipped test not for this platform\n"); + curl_mfprintf(stderr, "Skipped test not for this platform\n"); #endif /* _WIN32 || MSDOS */ UNITTEST_END_SIMPLE diff --git a/tests/tunit/tool1621.c b/tests/tunit/tool1621.c index c7dfedddce23..bb709cf39d21 100644 --- a/tests/tunit/tool1621.c +++ b/tests/tunit/tool1621.c @@ -74,8 +74,9 @@ static CURLcode test_tool1621(const char *arg) const char *url = tests[i].input; char *stripped = stripcredentials(url); const char *strippedstr = stripped ? stripped : "(null)"; - printf("Test %u got input \"%s\", output: \"%s\", expected: \"%s\"\n", - i, tests[i].input, strippedstr, tests[i].output); + curl_mprintf("Test %u got input \"%s\", output: \"%s\", " + "expected: \"%s\"\n", + i, tests[i].input, strippedstr, tests[i].output); fail_if(strcmp(tests[i].output, strippedstr), tests[i].output); curl_free(stripped); diff --git a/tests/unit/.checksrc b/tests/unit/.checksrc new file mode 100644 index 000000000000..a3f8f307e792 --- /dev/null +++ b/tests/unit/.checksrc @@ -0,0 +1,8 @@ +banfunc aprintf +banfunc fprintf +banfunc msnprintf +banfunc mvsnprintf +banfunc printf +banfunc vaprintf +banfunc vfprintf +banfunc vprintf diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 32c2f3895594..1e9940f48a0c 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -42,7 +42,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ # Get BUNDLE, FIRST_C, TESTS_C variables include Makefile.inc -EXTRA_DIST = CMakeLists.txt README.md $(TESTS_C) +EXTRA_DIST = CMakeLists.txt .checksrc README.md $(TESTS_C) CFLAGS += @CURL_CFLAG_EXTRAS@ diff --git a/tests/unit/unit1302.c b/tests/unit/unit1302.c index a1676699f27d..2c4404d72702 100644 --- a/tests/unit/unit1302.c +++ b/tests/unit/unit1302.c @@ -137,7 +137,7 @@ static CURLcode test_unit1302(const char *arg) abort_unless(rc == CURLE_OK, "return code should be CURLE_OK"); abort_unless(olen == e->olen, "wrong output size"); if(memcmp(out, e->output, e->olen)) { - fprintf(stderr, "Test %u encoded badly\n", i); + curl_mfprintf(stderr, "Test %u encoded badly\n", i); unitfail++; } Curl_safefree(out); @@ -145,17 +145,17 @@ static CURLcode test_unit1302(const char *arg) /* then verify decode */ rc = curlx_base64_decode(e->output, &decoded, &dlen); if(rc != CURLE_OK) { - fprintf(stderr, "Test %u URL decode returned %d\n", i, (int)rc); + curl_mfprintf(stderr, "Test %u URL decode returned %d\n", i, (int)rc); unitfail++; } if(dlen != e->ilen) { - fprintf(stderr, "Test %u URL decode output length %d instead of %d\n", - i, (int)dlen, (int)e->ilen); + curl_mfprintf(stderr, "Test %u URL decode output length %zu " + "instead of %zu\n", i, dlen, e->ilen); unitfail++; } if(memcmp(decoded, e->input, dlen)) { - fprintf(stderr, "Test %u URL decoded badly. Got '%s', expected '%s'\n", - i, decoded, e->input); + curl_mfprintf(stderr, "Test %u URL decoded badly. Got '%s', " + "expected '%s'\n", i, decoded, e->input); unitfail++; } @@ -169,12 +169,12 @@ static CURLcode test_unit1302(const char *arg) rc = curlx_base64url_encode(e->input, e->ilen, &out, &olen); abort_unless(rc == CURLE_OK, "return code should be CURLE_OK"); if(olen != e->olen) { - fprintf(stderr, "Test %u URL encoded output length %d instead of %d\n", - i, (int)olen, (int)e->olen); + curl_mfprintf(stderr, "Test %u URL encoded output length %zu " + "instead of %zu\n", i, olen, e->olen); } if(out && memcmp(out, e->output, e->olen)) { - fprintf(stderr, "Test %u URL encoded badly. Got '%s', expected '%s'\n", - i, out, e->output); + curl_mfprintf(stderr, "Test %u URL encoded badly. Got '%s', " + "expected '%s'\n", i, out, e->output); unitfail++; } Curl_safefree(out); @@ -188,9 +188,9 @@ static CURLcode test_unit1302(const char *arg) /* then verify decode with illegal inputs */ rc = curlx_base64_decode(e->output, &decoded, &dlen); if(rc != CURLE_BAD_CONTENT_ENCODING) { - fprintf(stderr, "Test %u URL bad decoded badly. " - "Returned '%d', expected '%d'\n", - i, (int)rc, CURLE_BAD_CONTENT_ENCODING); + curl_mfprintf(stderr, "Test %u URL bad decoded badly. " + "Returned '%d', expected '%d'\n", + i, (int)rc, CURLE_BAD_CONTENT_ENCODING); unitfail++; } } diff --git a/tests/unit/unit1307.c b/tests/unit/unit1307.c index 6eb1d4826b70..248adb99c255 100644 --- a/tests/unit/unit1307.c +++ b/tests/unit/unit1307.c @@ -264,7 +264,7 @@ static CURLcode test_unit1307(const char *arg) "a", NOMATCH|LINUX_FAIL} }; - int i; + size_t i; enum system { SYSTEM_CUSTOM, @@ -280,14 +280,14 @@ static CURLcode test_unit1307(const char *arg) #else machine = SYSTEM_LINUX; #endif - printf("Tested with system fnmatch(), %s-style\n", - machine == SYSTEM_LINUX ? "linux" : "mac"); + curl_mprintf("Tested with system fnmatch(), %s-style\n", + machine == SYSTEM_LINUX ? "linux" : "mac"); #else - printf("Tested with custom fnmatch()\n"); + curl_mprintf("Tested with custom fnmatch()\n"); machine = SYSTEM_CUSTOM; #endif - for(i = 0; i < (int)CURL_ARRAYSIZE(tests); i++) { + for(i = 0; i < CURL_ARRAYSIZE(tests); i++) { int result = tests[i].result; int rc = Curl_fnmatch(NULL, tests[i].pattern, tests[i].string); if(result & (LINUX_DIFFER|MAC_DIFFER)) { @@ -298,10 +298,10 @@ static CURLcode test_unit1307(const char *arg) result &= 0x03; /* filter off all high bits */ } if(rc != result) { - printf("Curl_fnmatch(\"%s\", \"%s\") should return %s (returns %s)" - " [%d]\n", - tests[i].pattern, tests[i].string, ret2name(result), - ret2name(rc), i); + curl_mprintf("Curl_fnmatch(\"%s\", \"%s\") should return %s (returns %s)" + " [%zu]\n", + tests[i].pattern, tests[i].string, ret2name(result), + ret2name(rc), i); fail("pattern mismatch"); } } diff --git a/tests/unit/unit1309.c b/tests/unit/unit1309.c index 35b38fd8b625..2e2af21f2c75 100644 --- a/tests/unit/unit1309.c +++ b/tests/unit/unit1309.c @@ -36,10 +36,10 @@ static void splayprint(struct Curl_tree *t, int d, char output) splayprint(t->larger, d + 1, output); for(i = 0; i < d; i++) if(output) - printf(" "); + curl_mprintf(" "); if(output) { - printf("%ld.%ld[%d]", (long)t->key.tv_sec, (long)t->key.tv_usec, i); + curl_mprintf("%ld.%ld[%d]", (long)t->key.tv_sec, (long)t->key.tv_usec, i); } for(count = 0, node = t->samen; node != t; node = node->samen, count++) @@ -47,9 +47,9 @@ static void splayprint(struct Curl_tree *t, int d, char output) if(output) { if(count) - printf(" [%d more]\n", count); + curl_mprintf(" [%d more]\n", count); else - printf("\n"); + curl_mprintf("\n"); } splayprint(t->smaller, d + 1, output); @@ -86,14 +86,14 @@ static CURLcode test_unit1309(const char *arg) for(i = 0; i < NUM_NODES; i++) { int rem = (i + 7)%NUM_NODES; - printf("Tree look:\n"); + curl_mprintf("Tree look:\n"); splayprint(root, 0, 1); curl_mprintf("remove pointer %d, payload %zu\n", rem, *(size_t *)Curl_splayget(&nodes[rem])); rc = Curl_splayremove(root, &nodes[rem], &root); if(rc) { /* failed! */ - printf("remove %d failed!\n", rem); + curl_mprintf("remove %d failed!\n", rem); fail("remove"); } } @@ -117,7 +117,7 @@ static CURLcode test_unit1309(const char *arg) removed = NULL; for(i = 0; i <= 1100; i += 100) { - printf("Removing nodes not larger than %d\n", i); + curl_mprintf("Removing nodes not larger than %d\n", i); tv_now.tv_usec = i; root = Curl_splaygetbest(tv_now, root, &removed); while(removed) { diff --git a/tests/unit/unit1323.c b/tests/unit/unit1323.c index f53df89226d5..41d4fd31d307 100644 --- a/tests/unit/unit1323.c +++ b/tests/unit/unit1323.c @@ -45,13 +45,13 @@ static CURLcode test_unit1323(const char *arg) for(i = 0; i < CURL_ARRAYSIZE(tests); i++) { timediff_t result = curlx_timediff(tests[i].first, tests[i].second); if(result != tests[i].result) { - printf("%ld.%06u to %ld.%06u got %d, but expected %ld\n", - (long)tests[i].first.tv_sec, - tests[i].first.tv_usec, - (long)tests[i].second.tv_sec, - tests[i].second.tv_usec, - (int)result, - (long)tests[i].result); + curl_mprintf("%ld.%06u to %ld.%06u got %d, but expected %ld\n", + (long)tests[i].first.tv_sec, + tests[i].first.tv_usec, + (long)tests[i].second.tv_sec, + tests[i].second.tv_usec, + (int)result, + (long)tests[i].result); fail("unexpected result!"); } } diff --git a/tests/unit/unit1396.c b/tests/unit/unit1396.c index aa7ee9337581..0b74afa84f94 100644 --- a/tests/unit/unit1396.c +++ b/tests/unit/unit1396.c @@ -95,7 +95,7 @@ static CURLcode test_unit1396(const char *arg) fail_unless(!memcmp(out, list1[i].out, list1[i].outlen), "bad output data returned"); - printf("curl_easy_unescape test %d DONE\n", i); + curl_mprintf("curl_easy_unescape test %d DONE\n", i); curl_free(out); } @@ -110,7 +110,7 @@ static CURLcode test_unit1396(const char *arg) fail_unless(!memcmp(out, list2[i].out, list2[i].outlen), "bad output data returned"); - printf("curl_easy_escape test %d DONE (%s)\n", i, out); + curl_mprintf("curl_easy_escape test %d DONE (%s)\n", i, out); curl_free(out); } diff --git a/tests/unit/unit1607.c b/tests/unit/unit1607.c index ad0df33be8d6..dda67697829e 100644 --- a/tests/unit/unit1607.c +++ b/tests/unit/unit1607.c @@ -102,14 +102,14 @@ static CURLcode test_unit1607(const char *arg) }, }; - int i; + size_t i; struct Curl_multi *multi = NULL; struct Curl_easy *easy = NULL; struct curl_slist *list = NULL; - for(i = 0; i < (int)CURL_ARRAYSIZE(tests); ++i) { - int j; - int addressnum = CURL_ARRAYSIZE(tests[i].address); + for(i = 0; i < CURL_ARRAYSIZE(tests); ++i) { + size_t j; + size_t addressnum = CURL_ARRAYSIZE(tests[i].address); struct Curl_addrinfo *addr; struct Curl_dns_entry *dns; void *entry_id; @@ -152,7 +152,7 @@ static CURLcode test_unit1607(const char *arg) if(addr && !Curl_addr2string(addr->ai_addr, addr->ai_addrlen, ipaddress, &port)) { - curl_mfprintf(stderr, "%s:%d tests[%d] failed. " + curl_mfprintf(stderr, "%s:%d tests[%zu] failed. " "getaddressinfo failed.\n", __FILE__, __LINE__, i); problem = true; @@ -160,24 +160,24 @@ static CURLcode test_unit1607(const char *arg) } if(addr && !tests[i].address[j]) { - curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " - "is %s but tests[%d].address[%d] is NULL.\n", + curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the retrieved addr " + "is %s but tests[%zu].address[%zu] is NULL.\n", __FILE__, __LINE__, i, ipaddress, i, j); problem = true; break; } if(!addr && tests[i].address[j]) { - curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " - "is NULL but tests[%d].address[%d] is %s.\n", + curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the retrieved addr " + "is NULL but tests[%zu].address[%zu] is %s.\n", __FILE__, __LINE__, i, i, j, tests[i].address[j]); problem = true; break; } if(!curl_strequal(ipaddress, tests[i].address[j])) { - curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " - "%s is not equal to tests[%d].address[%d] %s.\n", + curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the retrieved addr " + "%s is not equal to tests[%zu].address[%zu] %s.\n", __FILE__, __LINE__, i, ipaddress, i, j, tests[i].address[j]); problem = true; @@ -185,9 +185,9 @@ static CURLcode test_unit1607(const char *arg) } if(port != tests[i].port) { - curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved port " - "for tests[%d].address[%d] is %d " - "but tests[%d].port is %d.\n", + curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the retrieved port " + "for tests[%zu].address[%zu] is %d " + "but tests[%zu].port is %d.\n", __FILE__, __LINE__, i, i, j, port, i, tests[i].port); problem = true; break; @@ -195,16 +195,16 @@ static CURLcode test_unit1607(const char *arg) if(dns->timestamp.tv_sec && tests[i].permanent) { curl_mfprintf(stderr, - "%s:%d tests[%d] failed. the timestamp is not zero " - "but tests[%d].permanent is TRUE\n", + "%s:%d tests[%zu] failed. the timestamp is not zero " + "but tests[%zu].permanent is TRUE\n", __FILE__, __LINE__, i, i); problem = true; break; } if(dns->timestamp.tv_sec == 0 && !tests[i].permanent) { - curl_mfprintf(stderr, "%s:%d tests[%d] failed. the timestamp is zero " - "but tests[%d].permanent is FALSE\n", + curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the timestamp is zero " + "but tests[%zu].permanent is FALSE\n", __FILE__, __LINE__, i, i); problem = true; break; diff --git a/tests/unit/unit1609.c b/tests/unit/unit1609.c index 4485c3f046e2..26934d89bf45 100644 --- a/tests/unit/unit1609.c +++ b/tests/unit/unit1609.c @@ -94,7 +94,7 @@ static CURLcode test_unit1609(const char *arg) }, }; - int i; + size_t i; struct Curl_multi *multi = NULL; struct Curl_easy *easy = NULL; struct curl_slist *list = NULL; @@ -103,9 +103,9 @@ static CURLcode test_unit1609(const char *arg) and also clean cache after the loop. In contrast,for example, test 1607 sets up and cleans cache on each iteration. */ - for(i = 0; i < (int)CURL_ARRAYSIZE(tests); ++i) { - int j; - int addressnum = CURL_ARRAYSIZE(tests[i].address); + for(i = 0; i < CURL_ARRAYSIZE(tests); ++i) { + size_t j; + size_t addressnum = CURL_ARRAYSIZE(tests[i].address); struct Curl_addrinfo *addr; struct Curl_dns_entry *dns; void *entry_id; @@ -152,31 +152,31 @@ static CURLcode test_unit1609(const char *arg) if(addr && !Curl_addr2string(addr->ai_addr, addr->ai_addrlen, ipaddress, &port)) { curl_mfprintf(stderr, - "%s:%d tests[%d] failed. Curl_addr2string failed.\n", + "%s:%d tests[%zu] failed. Curl_addr2string failed.\n", __FILE__, __LINE__, i); problem = true; break; } if(addr && !tests[i].address[j]) { - curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " - "is %s but tests[%d].address[%d] is NULL.\n", + curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the retrieved addr " + "is %s but tests[%zu].address[%zu] is NULL.\n", __FILE__, __LINE__, i, ipaddress, i, j); problem = true; break; } if(!addr && tests[i].address[j]) { - curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " - "is NULL but tests[%d].address[%d] is %s.\n", + curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the retrieved addr " + "is NULL but tests[%zu].address[%zu] is %s.\n", __FILE__, __LINE__, i, i, j, tests[i].address[j]); problem = true; break; } if(!curl_strequal(ipaddress, tests[i].address[j])) { - curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " - "%s is not equal to tests[%d].address[%d] %s.\n", + curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the retrieved addr " + "%s is not equal to tests[%zu].address[%zu] %s.\n", __FILE__, __LINE__, i, ipaddress, i, j, tests[i].address[j]); problem = true; @@ -184,9 +184,9 @@ static CURLcode test_unit1609(const char *arg) } if(port != tests[i].port) { - curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved port " - "for tests[%d].address[%d] is %d " - "but tests[%d].port is %d.\n", + curl_mfprintf(stderr, "%s:%d tests[%zu] failed. the retrieved port " + "for tests[%zu].address[%zu] is %d " + "but tests[%zu].port is %d.\n", __FILE__, __LINE__, i, i, j, port, i, tests[i].port); problem = true; break; diff --git a/tests/unit/unit1652.c b/tests/unit/unit1652.c index ad3014edca47..0b3337f6888f 100644 --- a/tests/unit/unit1652.c +++ b/tests/unit/unit1652.c @@ -124,7 +124,7 @@ static CURLcode test_unit1652(const char *arg) memset(input, '\0', sizeof(input)); memset(input, 'A', 2045); Curl_infof(easy, "%s", input); - fprintf(stderr, "output len %d: %s", (int)strlen(output), output); + curl_mfprintf(stderr, "output len %zu: %s", strlen(output), output); /* output is input + \n */ fail_unless(strlen(output) == 2046, "No truncation of infof input"); fail_unless(verify(output, input) == 0, "No truncation of infof input"); @@ -134,7 +134,7 @@ static CURLcode test_unit1652(const char *arg) /* Just over the limit without newline for truncation via '...' */ memset(input + 2045, 'A', 4); Curl_infof(easy, "%s", input); - fprintf(stderr, "output len %d: %s", (int)strlen(output), output); + curl_mfprintf(stderr, "output len %zu: %s", strlen(output), output); fail_unless(strlen(output) == 2047, "Truncation of infof input 1"); fail_unless(output[sizeof(output) - 1] == '\0', "Truncation of infof input 1"); @@ -143,7 +143,7 @@ static CURLcode test_unit1652(const char *arg) memset(input + 2045, 'A', 4); memset(input + 2045 + 4, '\n', 1); Curl_infof(easy, "%s", input); - fprintf(stderr, "output len %d: %s", (int)strlen(output), output); + curl_mfprintf(stderr, "output len %zu: %s", strlen(output), output); fail_unless(strlen(output) == 2047, "Truncation of infof input 2"); fail_unless(output[sizeof(output) - 1] == '\0', "Truncation of infof input 2"); @@ -152,7 +152,7 @@ static CURLcode test_unit1652(const char *arg) memset(input, '\0', sizeof(input)); memset(input, 'A', sizeof(input) - 1); Curl_infof(easy, "%s", input); - fprintf(stderr, "output len %d: %s", (int)strlen(output), output); + curl_mfprintf(stderr, "output len %zu: %s", strlen(output), output); fail_unless(strlen(output) == 2047, "Truncation of infof input 3"); fail_unless(output[sizeof(output) - 1] == '\0', "Truncation of infof input 3"); diff --git a/tests/unit/unit1655.c b/tests/unit/unit1655.c index a22e08727139..8b49fb32f89e 100644 --- a/tests/unit/unit1655.c +++ b/tests/unit/unit1655.c @@ -67,7 +67,7 @@ static CURLcode test_unit1655(const char *arg) "this.is.an.otherwise-valid.hostname." "with-a-label-of-greater-length-than-the-sixty-three-characters-" "specified.in.the.RFCs."; - int i; + size_t i; struct test { const char *name; @@ -89,7 +89,7 @@ static CURLcode test_unit1655(const char *arg) { max, DOH_OK } /* expect buffer overwrite */ }; - for(i = 0; i < (int)(CURL_ARRAYSIZE(playlist)); i++) { + for(i = 0; i < CURL_ARRAYSIZE(playlist); i++) { const char *name = playlist[i].name; size_t olen = 100000; struct demo victim; diff --git a/tests/unit/unit1658.c b/tests/unit/unit1658.c index 0a6a2e71c15e..6db104309287 100644 --- a/tests/unit/unit1658.c +++ b/tests/unit/unit1658.c @@ -514,7 +514,7 @@ static CURLcode test_unit1658(const char *arg) for(i = 0; i < CURL_ARRAYSIZE(t); i++) { struct Curl_https_rrinfo *hrr; - printf("test %i: %s\n", i, t[i].name); + curl_mprintf("test %u: %s\n", i, t[i].name); result = doh_resp_decode_httpsrr(easy, t[i].dns, t[i].len, &hrr); @@ -523,7 +523,7 @@ static CURLcode test_unit1658(const char *arg) /* is the output the expected? */ if(strcmp(rrbuffer, t[i].expect)) { - curl_mfprintf(stderr, "Test %s (%i) failed\n" + curl_mfprintf(stderr, "Test %s (%u) failed\n" "Expected: %s\n" "Received: %s\n", t[i].name, i, t[i].expect, rrbuffer); unitfail++; diff --git a/tests/unit/unit1660.c b/tests/unit/unit1660.c index 5c66b1831cf5..e74285d74ec4 100644 --- a/tests/unit/unit1660.c +++ b/tests/unit/unit1660.c @@ -38,7 +38,7 @@ static CURLcode test_unit1660(const char *arg) static void showsts(struct stsentry *e, const char *chost) { if(!e) - printf("'%s' is not HSTS\n", chost); + curl_mprintf("'%s' is not HSTS\n", chost); else { curl_mprintf("%s [%s]: %" CURL_FORMAT_CURL_OFF_T "%s\n", chost, e->host, e->expires, @@ -141,7 +141,7 @@ static CURLcode test_unit1660(const char *arg) continue; } else if(result) { - printf("Input %u: error %d\n", i, (int) result); + curl_mprintf("Input %u: error %d\n", i, (int) result); continue; } } diff --git a/tests/unit/unit1664.c b/tests/unit/unit1664.c index 72ae49676bd8..773bd8d386cc 100644 --- a/tests/unit/unit1664.c +++ b/tests/unit/unit1664.c @@ -57,26 +57,26 @@ static CURLcode test_unit1664(const char *arg) }; int i; - printf("curlx_str_word\n"); + curl_mprintf("curlx_str_word\n"); for(i = 0; wordparse[i]; i++) { struct Curl_str out; const char *line = wordparse[i]; const char *orgline = line; int rc = curlx_str_word(&line, &out, 7); - printf("%u: (\"%s\") %d, \"%.*s\" [%d], line %d\n", - i, orgline, rc, (int)out.len, out.str, (int)out.len, - (int)(line - orgline)); + curl_mprintf("%u: (\"%s\") %d, \"%.*s\" [%d], line %d\n", + i, orgline, rc, (int)out.len, out.str, (int)out.len, + (int)(line - orgline)); } - printf("curlx_str_until\n"); + curl_mprintf("curlx_str_until\n"); for(i = 0; wordparse[i]; i++) { struct Curl_str out; const char *line = wordparse[i]; const char *orgline = line; int rc = curlx_str_until(&line, &out, 7, 'd'); - printf("%u: (\"%s\") %d, \"%.*s\" [%d], line %d\n", - i, orgline, rc, (int)out.len, out.str, (int)out.len, - (int)(line - orgline)); + curl_mprintf("%u: (\"%s\") %d, \"%.*s\" [%d], line %d\n", + i, orgline, rc, (int)out.len, out.str, (int)out.len, + (int)(line - orgline)); } { @@ -96,15 +96,15 @@ static CURLcode test_unit1664(const char *arg) NULL }; - printf("curlx_str_quotedword\n"); + curl_mprintf("curlx_str_quotedword\n"); for(i = 0; qwords[i]; i++) { struct Curl_str out; const char *line = qwords[i]; const char *orgline = line; int rc = curlx_str_quotedword(&line, &out, 7); - printf("%u: (\"%s\") %d, \"%.*s\" [%d], line %d\n", - i, orgline, rc, (int)out.len, out.str, (int)out.len, - (int)(line - orgline)); + curl_mprintf("%u: (\"%s\") %d, \"%.*s\" [%d], line %d\n", + i, orgline, rc, (int)out.len, out.str, (int)out.len, + (int)(line - orgline)); } } @@ -119,13 +119,13 @@ static CURLcode test_unit1664(const char *arg) "", NULL }; - printf("curlx_str_single\n"); + curl_mprintf("curlx_str_single\n"); for(i = 0; single[i]; i++) { const char *line = single[i]; const char *orgline = line; int rc = curlx_str_single(&line, 'a'); - printf("%u: (\"%s\") %d, line %d\n", - i, orgline, rc, (int)(line - orgline)); + curl_mprintf("%u: (\"%s\") %d, line %d\n", + i, orgline, rc, (int)(line - orgline)); } } { @@ -141,13 +141,13 @@ static CURLcode test_unit1664(const char *arg) "", NULL }; - printf("curlx_str_singlespace\n"); + curl_mprintf("curlx_str_singlespace\n"); for(i = 0; single[i]; i++) { const char *line = single[i]; const char *orgline = line; int rc = curlx_str_singlespace(&line); - printf("%u: (\"%s\") %d, line %d\n", - i, orgline, rc, (int)(line - orgline)); + curl_mprintf("%u: (\"%s\") %d, line %d\n", + i, orgline, rc, (int)(line - orgline)); } } @@ -162,13 +162,13 @@ static CURLcode test_unit1664(const char *arg) "", NULL }; - printf("curlx_str_single\n"); + curl_mprintf("curlx_str_single\n"); for(i = 0; single[i]; i++) { const char *line = single[i]; const char *orgline = line; int rc = curlx_str_single(&line, 'a'); - printf("%u: (\"%s\") %d, line %d\n", - i, orgline, rc, (int)(line - orgline)); + curl_mprintf("%u: (\"%s\") %d, line %d\n", + i, orgline, rc, (int)(line - orgline)); } } { @@ -187,14 +187,14 @@ static CURLcode test_unit1664(const char *arg) "", NULL }; - printf("curlx_str_number\n"); + curl_mprintf("curlx_str_number\n"); for(i = 0; nums[i]; i++) { curl_off_t num; const char *line = nums[i]; const char *orgline = line; int rc = curlx_str_number(&line, &num, 1235); - printf("%u: (\"%s\") %d, [%u] line %d\n", - i, orgline, rc, (int)num, (int)(line - orgline)); + curl_mprintf("%u: (\"%s\") %d, [%u] line %d\n", + i, orgline, rc, (int)num, (int)(line - orgline)); } } @@ -219,7 +219,7 @@ static CURLcode test_unit1664(const char *arg) { "12", 10}, {NULL, 0} }; - printf("curlx_str_number varying max\n"); + curl_mprintf("curlx_str_number varying max\n"); for(i = 0; nums[i].str; i++) { curl_off_t num; const char *line = nums[i].str; @@ -259,7 +259,7 @@ static CURLcode test_unit1664(const char *arg) { "12", 16}, {NULL, 0} }; - printf("curlx_str_hex varying max\n"); + curl_mprintf("curlx_str_hex varying max\n"); for(i = 0; nums[i].str; i++) { curl_off_t num; const char *line = nums[i].str; @@ -294,7 +294,7 @@ static CURLcode test_unit1664(const char *arg) { "8", 10}, {NULL, 0} }; - printf("curlx_str_octal varying max\n"); + curl_mprintf("curlx_str_octal varying max\n"); for(i = 0; nums[i].str; i++) { curl_off_t num; const char *line = nums[i].str; @@ -330,7 +330,7 @@ static CURLcode test_unit1664(const char *arg) "999999999999999999", NULL }; - printf("curlx_str_number / max\n"); + curl_mprintf("curlx_str_number / max\n"); for(i = 0; nums[i]; i++) { curl_off_t num; const char *line = nums[i]; @@ -356,7 +356,7 @@ static CURLcode test_unit1664(const char *arg) "", NULL }; - printf("curlx_str_newline\n"); + curl_mprintf("curlx_str_newline\n"); for(i = 0; newl[i]; i++) { const char *line = newl[i]; const char *orgline = line; @@ -382,7 +382,7 @@ static CURLcode test_unit1664(const char *arg) "", NULL }; - printf("curlx_str_hex\n"); + curl_mprintf("curlx_str_hex\n"); for(i = 0; nums[i]; i++) { curl_off_t num; const char *line = nums[i]; @@ -409,7 +409,7 @@ static CURLcode test_unit1664(const char *arg) "", NULL }; - printf("curlx_str_octal\n"); + curl_mprintf("curlx_str_octal\n"); for(i = 0; nums[i]; i++) { curl_off_t num; const char *line = nums[i]; @@ -433,7 +433,7 @@ static CURLcode test_unit1664(const char *arg) "666666666666666666666", NULL }; - printf("curlx_str_octal / max\n"); + curl_mprintf("curlx_str_octal / max\n"); for(i = 0; nums[i]; i++) { curl_off_t num; const char *line = nums[i]; @@ -469,7 +469,7 @@ static CURLcode test_unit1664(const char *arg) "ABCDEF", NULL }; - printf("curlx_str_hex / max\n"); + curl_mprintf("curlx_str_hex / max\n"); for(i = 0; nums[i]; i++) { curl_off_t num; const char *line = nums[i]; diff --git a/tests/unit/unit2604.c b/tests/unit/unit2604.c index 9111edafb884..3d57f16c8ff1 100644 --- a/tests/unit/unit2604.c +++ b/tests/unit/unit2604.c @@ -83,21 +83,21 @@ static CURLcode test_unit2604(const char *arg) char *path; const char *cp = i == 0 ? cp0 : list[i].cp; CURLcode result = Curl_get_pathname(&cp, &path, list[i].home); - printf("%u - Curl_get_pathname(\"%s\", ... \"%s\") == %u\n", i, - list[i].cp, list[i].home, list[i].result); + curl_mprintf("%u - Curl_get_pathname(\"%s\", ... \"%s\") == %u\n", i, + list[i].cp, list[i].home, list[i].result); if(result != list[i].result) { - printf("... returned %d\n", result); + curl_mprintf("... returned %d\n", result); unitfail++; } if(!result) { if(cp && strcmp(cp, list[i].next)) { - printf("... cp points to '%s', not '%s' as expected \n", - cp, list[i].next); + curl_mprintf("... cp points to '%s', not '%s' as expected \n", + cp, list[i].next); unitfail++; } if(path && strcmp(path, list[i].expect)) { - printf("... gave '%s', not '%s' as expected \n", - path, list[i].expect); + curl_mprintf("... gave '%s', not '%s' as expected \n", + path, list[i].expect); unitfail++; } curl_free(path); diff --git a/tests/unit/unit3214.c b/tests/unit/unit3214.c index 34549fc2966c..08ce6fff3944 100644 --- a/tests/unit/unit3214.c +++ b/tests/unit/unit3214.c @@ -28,14 +28,15 @@ static void checksize(const char *name, size_t size, size_t allowed) { if(size > allowed) { - fprintf(stderr, "BAD: struct %s is %d bytes, allowed to be %d", - name, (int)size, (int)allowed); - fprintf(stderr, ": %d bytes too big\n", (int)(size - allowed)); + curl_mfprintf(stderr, "BAD: struct %s is %zu bytes, " + "allowed to be %zu: %zu bytes too big\n", + name, size, allowed, size - allowed); unitfail++; } else { - printf("FINE: struct %s is %d bytes, allowed %d (margin: %d bytes)\n", - name, (int)size, (int)allowed, (int)(allowed - size)); + curl_mprintf("FINE: struct %s is %zu bytes, " + "allowed %zu (margin: %zu bytes)\n", + name, size, allowed, allowed - size); } } From c9edc26afedefc9ce338a72910b8bd9616e8ebca Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 4 Oct 2025 03:11:09 +0200 Subject: [PATCH 267/465] lib: drop unused include and duplicate guards Closes #18839 --- lib/curlx/winapi.c | 8 +------- lib/strerror.c | 4 ---- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/curlx/winapi.c b/lib/curlx/winapi.c index 6069424becc5..7e3d1aa9ca9a 100644 --- a/lib/curlx/winapi.c +++ b/lib/curlx/winapi.c @@ -38,14 +38,13 @@ /* adjust for old MSVC */ #if defined(_MSC_VER) && (_MSC_VER < 1900) -# define SNPRINTF _snprintf +#define SNPRINTF _snprintf #else #define SNPRINTF snprintf #endif #endif /* !BUILDING_LIBCURL */ -#ifdef _WIN32 /* This is a helper function for Curl_strerror that converts Windows API error * codes (GetLastError) to error messages. * Returns NULL if no error message was found for error code. @@ -86,13 +85,10 @@ const char *curlx_get_winapi_error(int err, char *buf, size_t buflen) return *buf ? buf : NULL; } -#endif /* _WIN32 */ const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen) { -#ifdef _WIN32 DWORD old_win_err = GetLastError(); -#endif int old_errno = errno; if(!buflen) @@ -125,10 +121,8 @@ const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen) if(errno != old_errno) CURL_SETERRNO(old_errno); -#ifdef _WIN32 if(old_win_err != GetLastError()) SetLastError(old_win_err); -#endif return buf; } diff --git a/lib/strerror.c b/lib/strerror.c index f0f36ed1b716..cf0876564f37 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -34,10 +34,6 @@ #include -#ifdef USE_LIBIDN2 -#include -#endif - #ifdef USE_WINDOWS_SSPI #include "curl_sspi.h" #endif From 56026dae0245841380a5d96093e4451cfd77e0d7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 4 Oct 2025 04:12:17 +0200 Subject: [PATCH 268/465] openssl: fix build for v1.0.2 ``` lib/vtls/openssl.c: In function 'asn1_object_dump': lib/vtls/openssl.c:299:42: error: passing argument 3 of 'i2t_ASN1_OBJECT' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] 299 | int i = i2t_ASN1_OBJECT(buf, (int)len, a); | ^ In file included from /home/runner/djgpp/include/openssl/objects.h:965, from /home/runner/djgpp/include/openssl/evp.h:94, from /home/runner/djgpp/include/openssl/x509.h:73, from /home/runner/djgpp/include/openssl/ssl.h:156, from lib/curl_ntlm_core.c:71, from bld/lib/CMakeFiles/libcurl_static.dir/Unity/unity_0_c.c:88: /home/runner/djgpp/include/openssl/asn1.h:921:58: note: expected 'ASN1_OBJECT *' {aka 'struct asn1_object_st *'} but argument is of type 'const ASN1_OBJECT *' {aka 'const struct asn1_object_st *'} 921 | int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a); | ~~~~~~~~~~~~~^ ``` Ref: https://github.com/curl/curl/actions/runs/18236773678/job/51931937131?pr=18039 Follow-up to bb46d42407cd0503a9c499b4646af594a4db4947 #18647 Closes #18841 --- lib/vtls/openssl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 193723b64904..fd5529f5abd5 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -296,7 +296,12 @@ do { \ static int asn1_object_dump(const ASN1_OBJECT *a, char *buf, size_t len) { - int i = i2t_ASN1_OBJECT(buf, (int)len, a); + int i; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + i = i2t_ASN1_OBJECT(buf, (int)len, a); +#else + i = i2t_ASN1_OBJECT(buf, (int)len, CURL_UNCONST(a)); +#endif return (i >= (int)len); /* buffer too small */ } From ed1e72143a08ede124ae93b43c803609f967fdcb Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 4 Oct 2025 04:51:19 +0200 Subject: [PATCH 269/465] examples: drop unused `curl/mprintf.h` includes Follow-up to 45438c8d6f8e70385d66c029568524e9e803c539 #18823 Closes #18842 --- docs/examples/cookie_interface.c | 1 - docs/examples/http2-download.c | 1 - docs/examples/http2-serverpush.c | 1 - docs/examples/http2-upload.c | 1 - 4 files changed, 4 deletions(-) diff --git a/docs/examples/cookie_interface.c b/docs/examples/cookie_interface.c index 113429bbda03..cb68977121c1 100644 --- a/docs/examples/cookie_interface.c +++ b/docs/examples/cookie_interface.c @@ -32,7 +32,6 @@ #include #include -#include #if defined(_MSC_VER) && (_MSC_VER < 1900) #define snprintf _snprintf diff --git a/docs/examples/http2-download.c b/docs/examples/http2-download.c index 68c4f456295b..a524cac27f32 100644 --- a/docs/examples/http2-download.c +++ b/docs/examples/http2-download.c @@ -36,7 +36,6 @@ /* curl stuff */ #include -#include #if defined(_MSC_VER) && (_MSC_VER < 1900) #define snprintf _snprintf diff --git a/docs/examples/http2-serverpush.c b/docs/examples/http2-serverpush.c index 734d35beb79c..cea54e3af1a5 100644 --- a/docs/examples/http2-serverpush.c +++ b/docs/examples/http2-serverpush.c @@ -31,7 +31,6 @@ /* curl stuff */ #include -#include #if defined(_MSC_VER) && (_MSC_VER < 1900) #define snprintf _snprintf diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index dc474cc54951..9508da694b91 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -54,7 +54,6 @@ /* curl stuff */ #include -#include #ifndef CURLPIPE_MULTIPLEX /* This little trick makes sure that we do not enable pipelining for libcurls From 4535532ed36d2129b107ab357262072f82c2b34a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 4 Oct 2025 04:33:49 +0200 Subject: [PATCH 270/465] examples: fix two build issues surfaced with WinCE Both may apply to rare non-WinCE Windows builds too. - fix gcc 4.4.0 preprocessor error: ``` docs/examples/http2-upload.c:43:8: error: "_MSC_VER" is not defined ``` Ref: https://github.com/curl/curl/actions/runs/18238150607/job/51935502616 - fix wrong header order: Inlcude `windows.h` after `winsock2.h` via `curl/curl.h`. Regressions from 45438c8d6f8e70385d66c029568524e9e803c539 #18823 Closes #18843 --- docs/examples/http2-upload.c | 6 ++++-- docs/examples/synctime.c | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index 9508da694b91..a22161d76dd2 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -40,8 +40,6 @@ #ifndef _MSC_VER #include #include -#elif (_MSC_VER < 1900) -#define snprintf _snprintf #endif #ifdef _WIN32 @@ -52,6 +50,10 @@ #define fileno _fileno #endif +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif + /* curl stuff */ #include diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c index dd21082446a7..d8264d012e15 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -90,11 +90,12 @@ int main(void) { printf("Platform not supported.\n"); return 1; } int main(void) { printf("Platform not supported.\n"); return 1; } #else -#include #include #include +#include + #if defined(_MSC_VER) && (_MSC_VER < 1900) #define snprintf _snprintf #endif From c96bf36557ea2302e4cb838ee1e4bb9827fecee7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 3 Oct 2025 16:40:28 +0200 Subject: [PATCH 271/465] GHA: drop quictls 3.3.0 builds in favor of openssl 3.5+ - http3-linux: move local nghttpx (nghttp2) build to openssl (from quictls). Also tried LibreSSL, but it made some HTTP/2 tests fails. - http3-linux: drop quictls ngtcp2 build. - http3-linux: build local openssl with `no-deprecated`. (previously tested in the quictls local build.) - http3-linux: explicitly disable LDAP in cmake openssl jobs. cmake builds auto-detect OpenLDAP (autotools don't), and when enabled, linking curl fails because system `libsasl.so` requires MD5 openssl functions, which are missing from openssl no-deprecated builds. - macos: move options tested in quictls jobs to other ones. - linux: drop unused quictls local build. (it was used for msh3.) Follow-up to 91138b014d960d2ef6ce9cd0ca237d0220b2458d #17729 - renovate: drop quictls bump detection. Closes #18833 --- .github/workflows/http3-linux.yml | 89 +++++++------------------------ .github/workflows/linux.yml | 21 -------- .github/workflows/macos.yml | 17 ++---- renovate.json | 14 ----- 4 files changed, 25 insertions(+), 116 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index c14a64009771..3d0fec9efb5c 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -41,8 +41,6 @@ env: CURL_CI: github # handled in renovate.json OPENSSL_VERSION: 3.6.0 - # handled in renovate.json - QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com LIBRESSL_VERSION: 4.1.1 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com @@ -70,12 +68,12 @@ jobs: steps: - name: 'cache openssl' uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - id: cache-openssl-http3 + id: cache-openssl-http3-no-deprecated env: - cache-name: cache-openssl-http3 + cache-name: cache-openssl-http3-no-deprecated with: path: ~/openssl/build - key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }} + key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }}-no-deprecated - name: 'cache libressl' uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 @@ -104,15 +102,6 @@ jobs: path: ~/boringssl/build key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.BORINGSSL_VERSION }} - - name: 'cache quictls' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - id: cache-quictls-no-deprecated - env: - cache-name: cache-quictls-no-deprecated - with: - path: ~/quictls/build - key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.QUICTLS_VERSION }}-quic1 - - name: 'cache gnutls' uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-gnutls @@ -147,7 +136,7 @@ jobs: cache-name: cache-ngtcp2 with: path: ~/ngtcp2/build - key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGTCP2_VERSION }}-${{ env.OPENSSL_VERSION }}-${{ env.LIBRESSL_VERSION }}-${{ env.AWSLC_VERSION }}-${{ env.QUICTLS_VERSION }}-${{ env.GNUTLS_VERSION }}-${{ env.WOLFSSL_VERSION }} + key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGTCP2_VERSION }}-${{ env.OPENSSL_VERSION }}-${{ env.LIBRESSL_VERSION }}-${{ env.AWSLC_VERSION }}-${{ env.GNUTLS_VERSION }}-${{ env.WOLFSSL_VERSION }} - name: 'cache ngtcp2 boringssl' uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 @@ -165,15 +154,14 @@ jobs: cache-name: cache-nghttp2 with: path: ~/nghttp2/build - key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGHTTP2_VERSION }}-${{ env.QUICTLS_VERSION }}-${{ env.NGTCP2_VERSION }}-${{ env.NGHTTP3_VERSION }} + key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGHTTP2_VERSION }}-${{ env.OPENSSL_VERSION }}-${{ env.NGTCP2_VERSION }}-${{ env.NGHTTP3_VERSION }} - id: settings if: >- - ${{ steps.cache-openssl-http3.outputs.cache-hit != 'true' || + ${{ steps.cache-openssl-http3-no-deprecated.outputs.cache-hit != 'true' || steps.cache-libressl.outputs.cache-hit != 'true' || steps.cache-awslc.outputs.cache-hit != 'true' || steps.cache-boringssl.outputs.cache-hit != 'true' || - steps.cache-quictls-no-deprecated.outputs.cache-hit != 'true' || steps.cache-gnutls.outputs.cache-hit != 'true' || steps.cache-wolfssl.outputs.cache-hit != 'true' || steps.cache-nghttp3.outputs.cache-hit != 'true' || @@ -199,12 +187,12 @@ jobs: echo 'CXX=g++-12' >> "$GITHUB_ENV" - name: 'build openssl' - if: ${{ steps.cache-openssl-http3.outputs.cache-hit != 'true' }} + if: ${{ steps.cache-openssl-http3-no-deprecated.outputs.cache-hit != 'true' }} run: | cd ~ git clone --quiet --depth=1 -b "openssl-${OPENSSL_VERSION}" https://github.com/openssl/openssl cd openssl - ./config --prefix="$PWD"/build --libdir=lib no-makedepend no-apps no-docs no-tests + ./config --prefix="$PWD"/build --libdir=lib no-makedepend no-apps no-docs no-tests no-deprecated make make -j1 install_sw @@ -241,16 +229,6 @@ jobs: cmake --build . cmake --install . - - name: 'build quictls' - if: ${{ steps.cache-quictls-no-deprecated.outputs.cache-hit != 'true' }} - run: | - cd ~ - git clone --quiet --depth=1 -b "openssl-${QUICTLS_VERSION}-quic1" https://github.com/quictls/openssl quictls - cd quictls - ./config no-deprecated --prefix="$PWD"/build --libdir=lib no-makedepend no-apps no-docs no-tests - make - make -j1 install_sw - - name: 'build gnutls' if: ${{ steps.cache-gnutls.outputs.cache-hit != 'true' }} run: | @@ -292,7 +270,7 @@ jobs: - name: 'build ngtcp2' if: ${{ steps.cache-ngtcp2.outputs.cache-hit != 'true' }} - # building 3 times to get crypto libs for ossl, libressl, quictls and awslc installed + # building twice to get crypto libs for ossl, libressl and awslc installed run: | cd ~ git clone --quiet --depth=1 -b "v${NGTCP2_VERSION}" https://github.com/ngtcp2/ngtcp2 @@ -302,10 +280,6 @@ jobs: PKG_CONFIG_PATH=/home/runner/libressl/build/lib/pkgconfig --enable-lib-only --with-openssl make install make clean - ./configure --disable-dependency-tracking --prefix="$PWD"/build \ - PKG_CONFIG_PATH=/home/runner/quictls/build/lib/pkgconfig --enable-lib-only --with-openssl - make install - make clean ./configure --disable-dependency-tracking --prefix="$PWD"/build \ PKG_CONFIG_PATH=/home/runner/openssl/build/lib/pkgconfig:/home/runner/gnutls/build/lib/pkgconfig:/home/runner/wolfssl/build/lib/pkgconfig \ --enable-lib-only --with-openssl --with-gnutls --with-wolfssl --with-boringssl \ @@ -337,8 +311,8 @@ jobs: # required (for nghttpx application): libc-ares-dev libev-dev zlib1g-dev # optional (for nghttpx application): libbrotli-dev ./configure --disable-dependency-tracking --prefix="$PWD"/build \ - PKG_CONFIG_PATH=/home/runner/quictls/build/lib/pkgconfig:/home/runner/nghttp3/build/lib/pkgconfig:/home/runner/ngtcp2/build/lib/pkgconfig \ - LDFLAGS=-Wl,-rpath,/home/runner/quictls/build/lib \ + PKG_CONFIG_PATH=/home/runner/openssl/build/lib/pkgconfig:/home/runner/nghttp3/build/lib/pkgconfig:/home/runner/ngtcp2/build/lib/pkgconfig \ + LDFLAGS=-Wl,-rpath,/home/runner/openssl/build/lib \ --with-libbrotlienc --with-libbrotlidec \ --enable-app --enable-http3 make install @@ -367,8 +341,9 @@ jobs: install_steps: skipall PKG_CONFIG_PATH: /home/runner/openssl/build/lib/pkgconfig:/home/runner/nghttp3/build/lib/pkgconfig:/home/runner/ngtcp2/build/lib/pkgconfig:/home/runner/nghttp2/build/lib/pkgconfig generate: >- - -DOPENSSL_ROOT_DIR=/home/runner/openssl/build - -DUSE_NGTCP2=ON -DCURL_DISABLE_NTLM=ON + -DOPENSSL_ROOT_DIR=/home/runner/openssl/build -DUSE_NGTCP2=ON + -DCURL_DISABLE_LDAP=ON + -DCURL_DISABLE_NTLM=ON -DCMAKE_UNITY_BUILD=ON - name: 'libressl' @@ -416,21 +391,6 @@ jobs: -DUSE_NGTCP2=ON -DCURL_DISABLE_NTLM=ON -DCMAKE_UNITY_BUILD=ON - - name: 'quictls' - install_steps: skipall - PKG_CONFIG_PATH: /home/runner/quictls/build/lib/pkgconfig:/home/runner/nghttp3/build/lib/pkgconfig:/home/runner/ngtcp2/build/lib/pkgconfig:/home/runner/nghttp2/build/lib/pkgconfig - configure: >- - LDFLAGS=-Wl,-rpath,/home/runner/quictls/build/lib - --with-ngtcp2 --disable-ntlm - --with-openssl=/home/runner/quictls/build --enable-ssls-export - --enable-unity - - - name: 'quictls' - PKG_CONFIG_PATH: /home/runner/quictls/build/lib/pkgconfig:/home/runner/nghttp3/build/lib/pkgconfig:/home/runner/ngtcp2/build/lib/pkgconfig:/home/runner/nghttp2/build/lib/pkgconfig - generate: >- - -DOPENSSL_ROOT_DIR=/home/runner/quictls/build - -DUSE_NGTCP2=ON -DCURL_DISABLE_NTLM=ON - - name: 'gnutls' install_packages: nettle-dev libp11-kit-dev install_steps: skipall @@ -476,6 +436,7 @@ jobs: PKG_CONFIG_PATH: /home/runner/openssl/build/lib/pkgconfig:/home/runner/nghttp3/build/lib/pkgconfig:/home/runner/nghttp2/build/lib/pkgconfig generate: >- -DOPENSSL_ROOT_DIR=/home/runner/openssl/build -DUSE_OPENSSL_QUIC=ON + -DCURL_DISABLE_LDAP=ON -DCURL_DISABLE_NTLM=ON -DCMAKE_UNITY_BUILD=ON @@ -518,12 +479,12 @@ jobs: - name: 'cache openssl' if: ${{ matrix.build.name == 'openssl' || matrix.build.name == 'openssl-quic' }} uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - id: cache-openssl-http3 + id: cache-openssl-http3-no-deprecated env: - cache-name: cache-openssl-http3 + cache-name: cache-openssl-http3-no-deprecated with: path: ~/openssl/build - key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }} + key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }}-no-deprecated fail-on-cache-miss: true - name: 'cache libressl' @@ -556,16 +517,6 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.BORINGSSL_VERSION }} fail-on-cache-miss: true - - name: 'cache quictls' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - id: cache-quictls-no-deprecated - env: - cache-name: cache-quictls-no-deprecated - with: - path: ~/quictls/build - key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.QUICTLS_VERSION }}-quic1 - fail-on-cache-miss: true - - name: 'cache gnutls' if: ${{ matrix.build.name == 'gnutls' }} uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 @@ -605,7 +556,7 @@ jobs: cache-name: cache-ngtcp2 with: path: ~/ngtcp2/build - key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGTCP2_VERSION }}-${{ env.OPENSSL_VERSION }}-${{ env.LIBRESSL_VERSION }}-${{ env.AWSLC_VERSION }}-${{ env.QUICTLS_VERSION }}-${{ env.GNUTLS_VERSION }}-${{ env.WOLFSSL_VERSION }} + key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGTCP2_VERSION }}-${{ env.OPENSSL_VERSION }}-${{ env.LIBRESSL_VERSION }}-${{ env.AWSLC_VERSION }}-${{ env.GNUTLS_VERSION }}-${{ env.WOLFSSL_VERSION }} fail-on-cache-miss: true - name: 'cache ngtcp2 boringssl' @@ -625,7 +576,7 @@ jobs: cache-name: cache-nghttp2 with: path: ~/nghttp2/build - key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGHTTP2_VERSION }}-${{ env.QUICTLS_VERSION }}-${{ env.NGTCP2_VERSION }}-${{ env.NGHTTP3_VERSION }} + key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.NGHTTP2_VERSION }}-${{ env.OPENSSL_VERSION }}-${{ env.NGTCP2_VERSION }}-${{ env.NGHTTP3_VERSION }} fail-on-cache-miss: true - name: 'cache quiche' diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 5b2b5e711c3b..d78789b8a1a5 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -49,8 +49,6 @@ env: BORINGSSL_VERSION: 0.20251002.0 # handled in renovate.json OPENSSL_VERSION: 3.6.0 - # handled in renovate.json - QUICTLS_VERSION: 3.3.0 # renovate: datasource=github-tags depName=rustls/rustls-ffi versioning=semver registryUrl=https://github.com RUSTLS_VERSION: 0.15.0 # handled in renovate.json @@ -495,25 +493,6 @@ jobs: make make -j1 install_sw - - name: 'cache quictls' - if: ${{ contains(matrix.build.install_steps, 'quictls') }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - id: cache-quictls - env: - cache-name: cache-quictls - with: - path: ~/quictls - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.QUICTLS_VERSION }}-quic1 - - - name: 'build quictls' - if: ${{ contains(matrix.build.install_steps, 'quictls') && steps.cache-quictls.outputs.cache-hit != 'true' }} - run: | - git clone --quiet --depth=1 -b "openssl-${QUICTLS_VERSION}-quic1" https://github.com/quictls/openssl - cd openssl - ./config --prefix=/home/runner/quictls --libdir=lib no-makedepend no-apps no-docs no-tests - make - make -j1 install_sw - - name: 'cache awslc' if: ${{ contains(matrix.build.install_steps, 'awslc') }} uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 87fc53d33490..c32b71439c13 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -255,16 +255,17 @@ jobs: --without-nghttp2 --disable-ntlm --without-ssl --without-zlib --without-zstd macos-version-min: '10.15' # Catalina (2019) - - name: 'LibreSSL +examples' + - name: 'LibreSSL !ldap +examples' compiler: clang install: libressl install_steps: pytest - configure: --enable-debug --with-openssl=/opt/homebrew/opt/libressl - - name: 'OpenSSL' + configure: --enable-debug --with-openssl=/opt/homebrew/opt/libressl --disable-ldap + - name: 'OpenSSL 10.15' compiler: clang install: libnghttp3 libngtcp2 install_steps: pytest configure: --enable-debug --with-openssl=/opt/homebrew/opt/openssl --with-ngtcp2 + macos-version-min: '10.15' - name: 'OpenSSL SecTrust' compiler: clang install: libnghttp3 libngtcp2 @@ -274,11 +275,6 @@ jobs: compiler: clang configure: --enable-debug --with-openssl=/opt/homebrew/opt/openssl tflags: --test-event - - name: 'quictls libssh2 !ldap 10.15' - compiler: clang - install: quictls - configure: --enable-debug --disable-ldap --with-openssl=/opt/homebrew/opt/quictls LDFLAGS=-L/opt/homebrew/opt/quictls/lib - macos-version-min: '10.15' # cmake - name: 'OpenSSL gsasl rtmp AppleIDN SecTrust' install: libnghttp3 libngtcp2 gsasl rtmpdump @@ -306,9 +302,6 @@ jobs: -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/heimdal -DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy - - name: 'quictls +static libssh +examples' - install: quictls libssh - generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/quictls -DBUILD_STATIC_LIBS=ON -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON - name: 'LibreSSL openldap heimdal c-ares +examples' install: libressl heimdal openldap generate: -DENABLE_DEBUG=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/libressl -DENABLE_ARES=ON -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/heimdal -DLDAP_INCLUDE_DIR=/opt/homebrew/opt/openldap/include -DLDAP_LIBRARY=/opt/homebrew/opt/openldap/lib/libldap.dylib -DLDAP_LBER_LIBRARY=/opt/homebrew/opt/openldap/lib/liblber.dylib @@ -370,7 +363,7 @@ jobs: while [[ $? == 0 ]]; do for i in 1 2 3; do if brew update && brew bundle install --file /tmp/Brewfile; then break 2; else echo Error: wait to try again; sleep 10; fi; done; false Too many retries; done - name: 'brew unlink openssl' - if: ${{ contains(matrix.build.install, 'aws-lc') || contains(matrix.build.install, 'libressl') || contains(matrix.build.install, 'quictls') }} + if: ${{ contains(matrix.build.install, 'aws-lc') || contains(matrix.build.install, 'libressl') }} run: | if [ -d /opt/homebrew/include/openssl ]; then brew unlink openssl diff --git a/renovate.json b/renovate.json index 1bc0309f3a6c..102bf42521fd 100644 --- a/renovate.json +++ b/renovate.json @@ -102,20 +102,6 @@ "versioningTemplate": "semver", "extractVersionTemplate": "^openssl-(?.*)$" }, - { - "customType": "regex", - "managerFilePatterns": [ - "/^.github/workflows/linux.yml$/", - "/^.github/workflows/http3-linux.yml$/" - ], - "matchStrings": [ - "QUICTLS_VERSION: (?.*)\\s" - ], - "datasourceTemplate": "github-tags", - "depNameTemplate": "quictls/openssl", - "versioningTemplate": "semver", - "extractVersionTemplate": "^openssl-(?.*)-quic1$" - }, { "customType": "regex", "managerFilePatterns": [ From 455d41d4605a3d7aacc97fd580a64648ca203698 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 4 Oct 2025 02:53:02 +0200 Subject: [PATCH 272/465] unit1664: drop casts, expand masks to full values Follow-up to 4deea9396bc7dd25c6362fa746a57bf309c74ada #18814 Closes #18838 --- tests/unit/unit1664.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unit/unit1664.c b/tests/unit/unit1664.c index 773bd8d386cc..6903c70e9298 100644 --- a/tests/unit/unit1664.c +++ b/tests/unit/unit1664.c @@ -193,8 +193,8 @@ static CURLcode test_unit1664(const char *arg) const char *line = nums[i]; const char *orgline = line; int rc = curlx_str_number(&line, &num, 1235); - curl_mprintf("%u: (\"%s\") %d, [%u] line %d\n", - i, orgline, rc, (int)num, (int)(line - orgline)); + curl_mprintf("%u: (\"%s\") %d, [%" CURL_FORMAT_CURL_OFF_T "] line %d\n", + i, orgline, rc, num, (int)(line - orgline)); } } @@ -388,8 +388,8 @@ static CURLcode test_unit1664(const char *arg) const char *line = nums[i]; const char *orgline = line; int rc = curlx_str_hex(&line, &num, 0x1235); - curl_mprintf("%u: (\"%s\") %d, [%u] line %d\n", - i, orgline, rc, (int)num, (int)(line - orgline)); + curl_mprintf("%u: (\"%s\") %d, [%" CURL_FORMAT_CURL_OFF_T "] line %d\n", + i, orgline, rc, num, (int)(line - orgline)); } } @@ -415,8 +415,8 @@ static CURLcode test_unit1664(const char *arg) const char *line = nums[i]; const char *orgline = line; int rc = curlx_str_octal(&line, &num, 01235); - curl_mprintf("%u: (\"%s\") %d, [%u] line %d\n", - i, orgline, rc, (int)num, (int)(line - orgline)); + curl_mprintf("%u: (\"%s\") %d, [%" CURL_FORMAT_CURL_OFF_T "] line %d\n", + i, orgline, rc, num, (int)(line - orgline)); } } From c7fb5858a59dfc433d5eefa08be3db249738fd28 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 4 Oct 2025 13:04:29 +0200 Subject: [PATCH 273/465] checksrc: fix possible endless loops/errors in the banned function logic By quoting the search expression to be replaced. This avoid the issue when the code leading up to a banned function contained regex characters that the script did not explicitly handle, e.g. `+`. Assisted-by: Daniel Stenberg Ref: https://perldoc.perl.org/functions/quotemeta Follow-up to dd37d6970cfd8b4cf47ebd469f03772813b92c23 #18775 Closes #18845 --- scripts/checksrc.pl | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 637c0b7c8b5d..54800ce12d88 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -907,14 +907,9 @@ sub scanfile { checkwarn("BANNEDFUNC", $line, length($prefix), $file, $ol, "use of $bad is banned"); - my $replace = 'x' x (length($bad) + 1); - $prefix =~ s/\*/\\*/; - $prefix =~ s/\[/\\[/; - $prefix =~ s/\]/\\]/; - $prefix =~ s/\(/\\(/; - $prefix =~ s/\)/\\)/; - $suff =~ s/\(/\\(/; - $l =~ s/$prefix$bad$suff/$prefix$replace/; + my $search = quotemeta($prefix . $bad . $suff); + my $replace = $prefix . 'x' x (length($bad) + 1); + $l =~ s/$search/$replace/; goto again; } $l = $bl; # restore to pre-bannedfunc content From bb4326d72b3486181be4dccafec53f6e3567ed7c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 4 Oct 2025 23:17:32 +0200 Subject: [PATCH 274/465] GHA: remove the hacktoberfest label action No one cares about hacktoberfest anymore. Closes #18849 --- .github/workflows/hacktoberfest-accepted.yml | 71 -------------------- 1 file changed, 71 deletions(-) delete mode 100644 .github/workflows/hacktoberfest-accepted.yml diff --git a/.github/workflows/hacktoberfest-accepted.yml b/.github/workflows/hacktoberfest-accepted.yml deleted file mode 100644 index f934193a6e28..000000000000 --- a/.github/workflows/hacktoberfest-accepted.yml +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (C) Daniel Stenberg, , et al. -# -# SPDX-License-Identifier: curl - -name: 'Hacktoberfest' - -'on': - # this must not ever run on any other branch than master - push: - branches: - - master - -concurrency: - # this should not run in parallel, so just run one at a time - group: ${{ github.workflow }} - -permissions: {} - -jobs: - # add hacktoberfest-accepted label to PRs opened starting from September 30th - # till November 1st which are closed via commit reference from master branch. - merged: - name: 'Add hacktoberfest-accepted label' - runs-on: ubuntu-latest - permissions: - issues: write # To edit labels on PRs - pull-requests: write # To edit labels on PRs - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - persist-credentials: false - fetch-depth: 100 - - - name: 'Check whether repo participates in Hacktoberfest' - id: check - env: - GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}' - run: | - gh config set prompt disabled && echo "label=$( - gh repo view --json repositoryTopics --jq '.repositoryTopics[].name' | grep '^hacktoberfest$')" >> "$GITHUB_OUTPUT" - - - name: 'Search relevant commit message lines starting with Closes/Merges' - if: ${{ steps.check.outputs.label == 'hacktoberfest' }} - env: - GITHUB_EVENT_BEFORE: '${{ github.event.before }}' - GITHUB_EVENT_AFTER: '${{ github.event.after }}' - run: | - git log --format=email "${GITHUB_EVENT_BEFORE}..${GITHUB_EVENT_AFTER}" | \ - grep -Ei '^Close[sd]? ' | sort | uniq | tee log - - - name: 'Search for number-based PR references' - if: ${{ steps.check.outputs.label == 'hacktoberfest' }} - env: - GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}' - run: | - grep -Eo '#([0-9]+)' log | cut -d# -f2 | sort | uniq | xargs -t -n1 -I{} \ - gh pr view {} --json number,createdAt \ - --jq '{number, opened: .createdAt} | [.number, .opened] | join(":")' | tee /dev/stderr | \ - grep -Eo '^([0-9]+):[0-9]{4}-(09-30T|10-|11-01T)' | cut -d: -f1 | sort | uniq | xargs -t -n1 -I {} \ - gh pr edit {} --add-label 'hacktoberfest-accepted' - - - name: 'Search for URL-based PR references' - if: ${{ steps.check.outputs.label == 'hacktoberfest' }} - env: - GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}' - run: | - grep -Eo 'github.com/(.+)/(.+)/pull/([0-9]+)' log | sort | uniq | xargs -t -n1 -I{} \ - gh pr view 'https://{}' --json number,createdAt \ - --jq '{number, opened: .createdAt} | [.number, .opened] | join(":")' | tee /dev/stderr | \ - grep -Eo '^([0-9]+):[0-9]{4}-(09-30T|10-|11-01T)' | cut -d: -f1 | sort | uniq | xargs -t -n1 -I {} \ - gh pr edit {} --add-label 'hacktoberfest-accepted' From c0febf66614d1468edecf6dab48333218b130ae1 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Sun, 5 Oct 2025 10:38:14 +0800 Subject: [PATCH 275/465] cpool: make bundle->dest an array; fix UB Replace `char *dest[1]` with a proper `char dest[1]` array in cpool_bundle. This removes undefined behavior from memcpy (writing past the declared object) while keeping the same key semantics: dest_len is strlen+1 (includes NUL), and hash add/delete calls remain unchanged. Closes #18850 --- lib/conncache.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/conncache.c b/lib/conncache.c index 1393bb565be0..a8fc51c21352 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -79,7 +79,7 @@ struct cpool_bundle { struct Curl_llist conns; /* connections in the bundle */ size_t dest_len; /* total length of destination, including NUL */ - char *dest[1]; /* destination of bundle, allocated to keep dest_len bytes */ + char dest[1]; /* destination of bundle, allocated to keep dest_len bytes */ }; @@ -91,13 +91,13 @@ static void cpool_discard_conn(struct cpool *cpool, static struct cpool_bundle *cpool_bundle_create(const char *dest) { struct cpool_bundle *bundle; - size_t dest_len = strlen(dest); + size_t dest_len = strlen(dest) + 1; - bundle = calloc(1, sizeof(*bundle) + dest_len); + bundle = calloc(1, sizeof(*bundle) + dest_len - 1); if(!bundle) return NULL; Curl_llist_init(&bundle->conns, NULL); - bundle->dest_len = dest_len + 1; + bundle->dest_len = dest_len; memcpy(bundle->dest, dest, bundle->dest_len); return bundle; } @@ -320,7 +320,7 @@ static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool) struct connectdata *oldest_idle = NULL; struct cpool_bundle *bundle; struct curltime now; - timediff_t highscore =- 1; + timediff_t highscore = -1; timediff_t score; now = curlx_now(); From eb8809270336225ef0266b01ca29191b88b1a3c7 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Sun, 5 Oct 2025 10:57:29 +0800 Subject: [PATCH 276/465] telnet: use pointer[0] for "unknown" option instead of pointer[i] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i is taken from pointer[length-2] (often the IAC byte) before we do length -= 2, so using pointer[i] indexes an arbitrary/stale byte unrelated to the option code. pointer[0] is the suboption’s option code per the telnet SB format, so printing pointer[0] yields correct, stable diagnostics. Closes #18851 --- lib/telnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/telnet.c b/lib/telnet.c index 66585d6f2a30..ddc0b22cb65a 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -732,7 +732,7 @@ static void printsub(struct Curl_easy *data, } } else - infof(data, "%d (unknown)", pointer[i]); + infof(data, "%d (unknown)", pointer[0]); switch(pointer[0]) { case CURL_TELOPT_NAWS: From da8f7ae096bc540dfc53c391b28229c885c31e99 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Sun, 5 Oct 2025 11:07:54 +0800 Subject: [PATCH 277/465] telnet: print DISPlay LOCation in printsub without mutating buffer Closes #18852 --- lib/telnet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/telnet.c b/lib/telnet.c index ddc0b22cb65a..90316a446ccb 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -759,8 +759,8 @@ static void printsub(struct Curl_easy *data, switch(pointer[0]) { case CURL_TELOPT_TTYPE: case CURL_TELOPT_XDISPLOC: - pointer[length] = 0; - infof(data, " \"%s\"", &pointer[2]); + infof(data, " \"%.*s\"", + (int)((length > 2) ? (length - 2) : 0), &pointer[2]); break; case CURL_TELOPT_NEW_ENVIRON: if(pointer[1] == CURL_TELQUAL_IS) { From 08331213055abac4417bc4a470f350a41d1a7659 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 5 Oct 2025 11:08:40 +0200 Subject: [PATCH 278/465] GHA/http3-linux: cleanup cache entry name after prev To avoid duplicate `no-deprecated` in the cache entry name. Follow-up to c96bf36557ea2302e4cb838ee1e4bb9827fecee7 #18833 Closes #18853 --- .github/workflows/http3-linux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 3d0fec9efb5c..c9495fe74ea8 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -73,7 +73,7 @@ jobs: cache-name: cache-openssl-http3-no-deprecated with: path: ~/openssl/build - key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }}-no-deprecated + key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }} - name: 'cache libressl' uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 @@ -484,7 +484,7 @@ jobs: cache-name: cache-openssl-http3-no-deprecated with: path: ~/openssl/build - key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }}-no-deprecated + key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.OPENSSL_VERSION }} fail-on-cache-miss: true - name: 'cache libressl' From 1ae5e44effe36bbe136439735de49b1e8dbaca0b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 5 Oct 2025 18:36:06 +0200 Subject: [PATCH 279/465] strerror: drop workaround for SalfordC win32 header bug Follow-up to ccf43ce91dd9a56f30a4029377126e4c83c7f08a #15957 Closes #18857 --- lib/strerror.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/strerror.c b/lib/strerror.c index cf0876564f37..47c657211418 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -698,11 +698,9 @@ get_winsock_error(int err, char *buf, size_t len) case WSAEREMOTE: p = "Remote error"; break; -#ifdef WSAEDISCON /* missing in SalfordC! */ case WSAEDISCON: p = "Disconnected"; break; -#endif /* Extended Winsock errors */ case WSASYSNOTREADY: p = "Winsock library is not ready"; From b54b4697cad23fcf81577ce9e8f1ea18b8449427 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 5 Oct 2025 14:07:39 +0200 Subject: [PATCH 280/465] url: make Curl_init_userdefined return void It cannot actually return an error, so the parent function does not need to check for error and have an exit path that cannot be reached. Pointed out by CodeSonar Closes #18855 --- lib/easy.c | 2 +- lib/url.c | 23 ++++------------------- lib/url.h | 2 +- tests/unit/unit1620.c | 3 --- 4 files changed, 6 insertions(+), 24 deletions(-) diff --git a/lib/easy.c b/lib/easy.c index 0a4b6faf5256..7a36034c03e3 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -1110,7 +1110,7 @@ void curl_easy_reset(CURL *d) /* zero out UserDefined data: */ Curl_freeset(data); memset(&data->set, 0, sizeof(struct UserDefined)); - (void)Curl_init_userdefined(data); + Curl_init_userdefined(data); /* zero out Progress data: */ memset(&data->progress, 0, sizeof(struct Progress)); diff --git a/lib/url.c b/lib/url.c index 0dface920d92..ae4a6f6502ba 100644 --- a/lib/url.c +++ b/lib/url.c @@ -355,10 +355,9 @@ CURLcode Curl_close(struct Curl_easy **datap) * Initialize the UserDefined fields within a Curl_easy. * This may be safely called on a new or existing Curl_easy. */ -CURLcode Curl_init_userdefined(struct Curl_easy *data) +void Curl_init_userdefined(struct Curl_easy *data) { struct UserDefined *set = &data->set; - CURLcode result = CURLE_OK; set->out = stdout; /* default output to stdout */ set->in_set = stdin; /* default input from stdin */ @@ -476,8 +475,6 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->ws_raw_mode = FALSE; set->ws_no_auto_pong = FALSE; #endif - - return result; } /* easy->meta_hash destructor. Should never be called as elements @@ -501,7 +498,6 @@ static void easy_meta_freeentry(void *p) CURLcode Curl_open(struct Curl_easy **curl) { - CURLcode result; struct Curl_easy *data; /* simple start-up: alloc the struct, init it with zeroes and return */ @@ -532,21 +528,10 @@ CURLcode Curl_open(struct Curl_easy **curl) Curl_llist_init(&data->state.httphdrs, NULL); #endif Curl_netrc_init(&data->state.netrc); + Curl_init_userdefined(data); - result = Curl_init_userdefined(data); - - if(result) { - curlx_dyn_free(&data->state.headerb); - Curl_freeset(data); - Curl_req_free(&data->req, data); - Curl_hash_destroy(&data->meta_hash); - data->magic = 0; - free(data); - data = NULL; - } - else - *curl = data; - return result; + *curl = data; + return CURLE_OK; } void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn) diff --git a/lib/url.h b/lib/url.h index 11a69d41578c..82d869c5ff22 100644 --- a/lib/url.h +++ b/lib/url.h @@ -31,7 +31,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn); CURLcode Curl_open(struct Curl_easy **curl); -CURLcode Curl_init_userdefined(struct Curl_easy *data); +void Curl_init_userdefined(struct Curl_easy *data); void Curl_freeset(struct Curl_easy *data); CURLcode Curl_uc_to_curlcode(CURLUcode uc); diff --git a/tests/unit/unit1620.c b/tests/unit/unit1620.c index 14b377b640e9..4851602eaa71 100644 --- a/tests/unit/unit1620.c +++ b/tests/unit/unit1620.c @@ -97,9 +97,6 @@ static CURLcode test_unit1620(const char *arg) fail_unless(rc == CURLE_URL_MALFORMAT, "Curl_connect() failed to return CURLE_URL_MALFORMAT"); - rc = Curl_init_userdefined(empty); - fail_unless(rc == CURLE_OK, "Curl_userdefined() failed"); - rc = Curl_init_do(empty, empty->conn); fail_unless(rc == CURLE_OK, "Curl_init_do() failed"); From c93457f1f62568fafc844b5070d06330ca7b0f67 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sun, 5 Oct 2025 20:36:21 +0200 Subject: [PATCH 281/465] tool_filetime: replace cast with the fitting printf mask (Windows) Follow-up to d25b0503795f1fbf557632ce870298f52f2a78c1 #2204 Closes #18858 --- src/tool_filetime.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/tool_filetime.c b/src/tool_filetime.c index 5912a5aa9a52..b442fc2014df 100644 --- a/src/tool_filetime.c +++ b/src/tool_filetime.c @@ -62,16 +62,14 @@ int getfiletime(const char *filename, curl_off_t *stamp) } } else { - warnf("Failed to get filetime: " - "GetFileTime failed: GetLastError %u", - (unsigned int)GetLastError()); + warnf("Failed to get filetime: GetFileTime failed: GetLastError %lu", + GetLastError()); } CloseHandle(hfile); } else if(GetLastError() != ERROR_FILE_NOT_FOUND) { - warnf("Failed to get filetime: " - "CreateFile failed: GetLastError %u", - (unsigned int)GetLastError()); + warnf("Failed to get filetime: CreateFile failed: GetLastError %lu", + GetLastError()); } #else struct_stat statbuf; @@ -117,15 +115,15 @@ void setfiletime(curl_off_t filetime, const char *filename) ft.dwHighDateTime = (DWORD)(converted >> 32); if(!SetFileTime(hfile, NULL, &ft, &ft)) { warnf("Failed to set filetime %" CURL_FORMAT_CURL_OFF_T - " on outfile: SetFileTime failed: GetLastError %u", - filetime, (unsigned int)GetLastError()); + " on outfile: SetFileTime failed: GetLastError %lu", + filetime, GetLastError()); } CloseHandle(hfile); } else { warnf("Failed to set filetime %" CURL_FORMAT_CURL_OFF_T - " on outfile: CreateFile failed: GetLastError %u", - filetime, (unsigned int)GetLastError()); + " on outfile: CreateFile failed: GetLastError %lu", + filetime, GetLastError()); } #elif defined(HAVE_UTIMES) From 4116e1d8028b30bfb0156b9b42042e0d930656f5 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 6 Oct 2025 00:10:13 +0200 Subject: [PATCH 282/465] unit1323: sync time types and printf masks, drop casts Closes #18860 --- tests/unit/unit1323.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/unit/unit1323.c b/tests/unit/unit1323.c index 41d4fd31d307..a4e3eab2e103 100644 --- a/tests/unit/unit1323.c +++ b/tests/unit/unit1323.c @@ -30,14 +30,14 @@ static CURLcode test_unit1323(const char *arg) struct a { struct curltime first; struct curltime second; - time_t result; + timediff_t result; }; struct a tests[] = { - { {36762, 8345 }, {36761, 995926 }, 13 }, - { {36761, 995926 }, {36762, 8345 }, -13 }, - { {36761, 995926 }, {0, 0}, 36761995 }, - { {0, 0}, {36761, 995926 }, -36761995 }, + { {36762, 8345}, {36761, 995926}, 13 }, + { {36761, 995926}, {36762, 8345}, -13 }, + { {36761, 995926}, {0, 0}, 36761995 }, + { {0, 0}, {36761, 995926}, -36761995 }, }; size_t i; @@ -45,13 +45,14 @@ static CURLcode test_unit1323(const char *arg) for(i = 0; i < CURL_ARRAYSIZE(tests); i++) { timediff_t result = curlx_timediff(tests[i].first, tests[i].second); if(result != tests[i].result) { - curl_mprintf("%ld.%06u to %ld.%06u got %d, but expected %ld\n", + curl_mprintf("%ld.%06u to %ld.%06u got %" FMT_TIMEDIFF_T + ", but expected %" FMT_TIMEDIFF_T "\n", (long)tests[i].first.tv_sec, tests[i].first.tv_usec, (long)tests[i].second.tv_sec, tests[i].second.tv_usec, - (int)result, - (long)tests[i].result); + result, + tests[i].result); fail("unexpected result!"); } } From eaf66f18b72ee7c2c6e5e1120b70b14975dd66bd Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 4 Oct 2025 00:39:11 +0200 Subject: [PATCH 283/465] tests/server: replace banned functions with `curlx_str_hex` Replace an `strtol()` and `strtoul()` call, both used in hex mode, with `curlx_str_hex()`. Follow-up to 45438c8d6f8e70385d66c029568524e9e803c539 #18823 Closes #18837 --- tests/server/sockfilt.c | 11 +++++++++-- tests/server/sws.c | 14 ++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index c6536fee4a31..2ae681072e4c 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -371,13 +371,20 @@ static void lograw(unsigned char *buffer, ssize_t len) static bool read_data_block(unsigned char *buffer, ssize_t maxlen, ssize_t *buffer_len) { + curl_off_t value; + const char *endp; + if(!read_stdin(buffer, 5)) return FALSE; buffer[5] = '\0'; - /* !checksrc! disable BANNEDFUNC 1 */ - *buffer_len = (ssize_t)strtol((char *)buffer, NULL, 16); + endp = (char *)buffer; + if(curlx_str_hex(&endp, &value, 0xfffff)) { + logmsg("Failed to decode buffer size"); + return FALSE; + } + *buffer_len = (ssize_t)value; if(*buffer_len > maxlen) { logmsg("Buffer size (%zd bytes) too small for data size error " "(%zd bytes)", maxlen, *buffer_len); diff --git a/tests/server/sws.c b/tests/server/sws.c index 20d2bf763261..32e82891fe21 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -413,7 +413,7 @@ static int sws_ProcessRequest(struct sws_httprequest *req) static char doc[MAXDOCNAMELEN]; if(sscanf(req->reqbuf, "CONNECT %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d", doc, &prot_major, &prot_minor) == 3) { - char *portp = NULL; + const char *portp = NULL; logmsg("Received a CONNECT %s HTTP/%d.%d request", doc, prot_major, prot_minor); @@ -424,15 +424,13 @@ static int sws_ProcessRequest(struct sws_httprequest *req) req->open = FALSE; /* HTTP 1.0 closes connection by default */ if(doc[0] == '[') { - char *p = &doc[1]; - unsigned long part = 0; + const char *p = &doc[1]; + curl_off_t part = 0; /* scan through the hexgroups and store the value of the last group in the 'part' variable and use as test case number!! */ while(*p && (ISXDIGIT(*p) || (*p == ':') || (*p == '.'))) { - char *endp; - /* !checksrc! disable BANNEDFUNC 1 */ - part = strtoul(p, &endp, 16); - if(ISXDIGIT(*p)) + const char *endp = p; + if(!curlx_str_hex(&endp, &part, 0xffff)) p = endp; else p++; @@ -444,7 +442,7 @@ static int sws_ProcessRequest(struct sws_httprequest *req) else portp = p + 1; - req->testno = part; + req->testno = (long)part; } else portp = strchr(doc, ':'); From 34ad78da89c614aafb21033bac456a1c0f54921a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 4 Oct 2025 03:10:37 +0200 Subject: [PATCH 284/465] curlx: move Curl_strerror, use in src and tests, ban `strerror` globally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also: - tests/server: replace local `sstrerror()` with `curlx_strerror()`. - tests/server: show the error code next to the string, where missing. - curlx: use `curl_msnprintf()` when building for src and tests. (units was already using it.) - lib: drop unused includes found along the way. - curlx_strerror(): avoid compiler warning (and another similar one): ``` In file included from servers.c:14: ../../lib/../../lib/curlx/strerr.c: In function ‘curlx_strerror’: ../../lib/../../lib/curlx/strerr.c:328:32: error: ‘snprintf’ output may be truncated before the last format character [-Werror=format-truncation=] 328 | SNPRINTF(buf, buflen, "%s", msg); | ^ ../../lib/../../lib/curlx/strerr.c:47:18: note: ‘snprintf’ output 1 or more bytes (assuming 2) into a destination of size 1 47 | #define SNPRINTF snprintf | ^ ../../lib/../../lib/curlx/strerr.c:328:7: note: in expansion of macro ‘SNPRINTF’ 328 | SNPRINTF(buf, buflen, "%s", msg); | ^~~~~~~~ ``` Follow-up to 45438c8d6f8e70385d66c029568524e9e803c539 #18823 Closes #18840 --- docs/examples/.checksrc | 1 + lib/.checksrc | 1 - lib/Makefile.inc | 2 + lib/cf-socket.c | 34 ++-- lib/curl_setup.h | 4 + lib/curlx/.checksrc | 1 - lib/curlx/curlx.h | 3 + lib/curlx/strerr.c | 361 +++++++++++++++++++++++++++++++++++++ lib/curlx/strerr.h | 29 +++ lib/curlx/winapi.c | 9 +- lib/ftp.c | 16 +- lib/strerror.c | 320 +------------------------------- lib/strerror.h | 5 - lib/tftp.c | 22 +-- lib/url.c | 4 +- lib/vauth/.checksrc | 1 - lib/vquic/.checksrc | 1 - lib/vquic/curl_ngtcp2.c | 1 - lib/vquic/curl_osslq.c | 4 +- lib/vquic/curl_quiche.c | 1 - lib/vquic/vquic.c | 8 +- lib/vssh/.checksrc | 1 - lib/vtls/.checksrc | 1 - lib/vtls/openssl.c | 12 +- lib/vtls/rustls.c | 6 +- scripts/checksrc.pl | 1 + src/Makefile.inc | 8 +- src/config2setopts.c | 10 +- src/tool_cb_wrt.c | 4 +- src/tool_filetime.c | 15 +- src/tool_formparse.c | 12 +- src/tool_operate.c | 21 ++- src/var.c | 4 +- tests/libtest/Makefile.inc | 8 +- tests/libtest/first.h | 20 +- tests/libtest/lib505.c | 5 +- tests/libtest/lib518.c | 6 +- tests/libtest/lib525.c | 5 +- tests/libtest/lib537.c | 6 +- tests/libtest/lib541.c | 5 +- tests/libtest/lib556.c | 3 +- tests/libtest/lib582.c | 5 +- tests/libtest/lib591.c | 3 +- tests/server/Makefile.inc | 3 +- tests/server/dnsd.c | 16 +- tests/server/first.h | 1 - tests/server/mqttd.c | 14 +- tests/server/rtspd.c | 53 +++--- tests/server/sockfilt.c | 20 +- tests/server/socksd.c | 16 +- tests/server/sws.c | 82 +++++---- tests/server/tftpd.c | 31 ++-- tests/server/util.c | 96 +++++----- 53 files changed, 751 insertions(+), 570 deletions(-) create mode 100644 lib/curlx/strerr.c create mode 100644 lib/curlx/strerr.h diff --git a/docs/examples/.checksrc b/docs/examples/.checksrc index a83f0edb9f80..336e1928d206 100644 --- a/docs/examples/.checksrc +++ b/docs/examples/.checksrc @@ -7,6 +7,7 @@ allowfunc open allowfunc snprintf allowfunc socket allowfunc sscanf +allowfunc strerror banfunc curl_maprintf banfunc curl_mfprintf banfunc curl_mprintf diff --git a/lib/.checksrc b/lib/.checksrc index 9b8d799ea285..e69de29bb2d1 100644 --- a/lib/.checksrc +++ b/lib/.checksrc @@ -1 +0,0 @@ -banfunc strerror diff --git a/lib/Makefile.inc b/lib/Makefile.inc index ff8144fb5ac0..500c690561f4 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -31,6 +31,7 @@ LIB_CURLX_CFILES = \ curlx/inet_pton.c \ curlx/multibyte.c \ curlx/nonblock.c \ + curlx/strerr.c \ curlx/strparse.c \ curlx/timediff.c \ curlx/timeval.c \ @@ -49,6 +50,7 @@ LIB_CURLX_HFILES = \ curlx/inet_pton.h \ curlx/multibyte.h \ curlx/nonblock.h \ + curlx/strerr.h \ curlx/strparse.h \ curlx/timediff.h \ curlx/timeval.h \ diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 8ed1116c07b3..34bcda68d7b4 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -62,7 +62,6 @@ #include "bufq.h" #include "sendf.h" #include "if2ip.h" -#include "strerror.h" #include "cfilters.h" #include "cf-socket.h" #include "connect.h" @@ -80,6 +79,7 @@ #include "strdup.h" #include "system_win32.h" #include "curlx/version_win32.h" +#include "curlx/strerr.h" #include "curlx/strparse.h" /* The last 3 #include files should be in this order */ @@ -114,7 +114,7 @@ static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd) if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff, sizeof(onoff)) < 0) infof(data, "Could not set TCP_NODELAY: %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); #else (void)data; (void)sockfd; @@ -136,7 +136,7 @@ static void nosigpipe(struct Curl_easy *data, #ifndef CURL_DISABLE_VERBOSE_STRINGS char buffer[STRERROR_LEN]; infof(data, "Could not set SO_NOSIGPIPE: %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); #endif } } @@ -644,7 +644,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, char buffer[STRERROR_LEN]; data->state.os_errno = error = SOCKERRNO; failf(data, "Couldn't bind to interface '%s' with errno %d: %s", - iface, error, Curl_strerror(error, buffer, sizeof(buffer))); + iface, error, curlx_strerror(error, buffer, sizeof(buffer))); return CURLE_INTERFACE_FAILED; } break; @@ -747,8 +747,8 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, char buffer[STRERROR_LEN]; data->state.errorbuf = FALSE; data->state.os_errno = error = SOCKERRNO; - failf(data, "Couldn't bind to '%s' with errno %d: %s", - host, error, Curl_strerror(error, buffer, sizeof(buffer))); + failf(data, "Couldn't bind to '%s' with errno %d: %s", host, + error, curlx_strerror(error, buffer, sizeof(buffer))); return CURLE_INTERFACE_FAILED; } } @@ -799,7 +799,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, char buffer[STRERROR_LEN]; data->state.os_errno = error = SOCKERRNO; failf(data, "bind failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); + error, curlx_strerror(error, buffer, sizeof(buffer))); } return CURLE_INTERFACE_FAILED; @@ -900,8 +900,8 @@ static CURLcode socket_connect_result(struct Curl_easy *data, #else { char buffer[STRERROR_LEN]; - infof(data, "Immediate connect fail for %s: %s", - ipaddress, Curl_strerror(error, buffer, sizeof(buffer))); + infof(data, "Immediate connect fail for %s: %s", ipaddress, + curlx_strerror(error, buffer, sizeof(buffer))); } #endif data->state.os_errno = error; @@ -1050,13 +1050,13 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf, if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) { int error = SOCKERRNO; failf(data, "getsockname() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); + error, curlx_strerror(error, buffer, sizeof(buffer))); return CURLE_FAILED_INIT; } if(!Curl_addr2string((struct sockaddr*)&ssloc, slen, ctx->ip.local_ip, &ctx->ip.local_port)) { failf(data, "ssloc inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); + errno, curlx_strerror(errno, buffer, sizeof(buffer))); return CURLE_FAILED_INIT; } } @@ -1082,7 +1082,7 @@ static CURLcode set_remote_ip(struct Curl_cfilter *cf, ctx->error = errno; /* malformed address or bug in inet_ntop, try next address */ failf(data, "curl_sa_addr inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); + errno, curlx_strerror(errno, buffer, sizeof(buffer))); return CURLE_FAILED_INIT; } return CURLE_OK; @@ -1360,7 +1360,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf, infof(data, "connect to %s port %u from %s port %d failed: %s", ctx->ip.remote_ip, ctx->ip.remote_port, ctx->ip.local_ip, ctx->ip.local_port, - Curl_strerror(ctx->error, buffer, sizeof(buffer))); + curlx_strerror(ctx->error, buffer, sizeof(buffer))); } #endif } @@ -1498,7 +1498,7 @@ static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data, else { char buffer[STRERROR_LEN]; failf(data, "Send failure: %s", - Curl_strerror(sockerr, buffer, sizeof(buffer))); + curlx_strerror(sockerr, buffer, sizeof(buffer))); data->state.os_errno = sockerr; result = CURLE_SEND_ERROR; } @@ -1566,7 +1566,7 @@ static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, else { char buffer[STRERROR_LEN]; failf(data, "Recv failure: %s", - Curl_strerror(sockerr, buffer, sizeof(buffer))); + curlx_strerror(sockerr, buffer, sizeof(buffer))); data->state.os_errno = sockerr; result = CURLE_RECV_ERROR; } @@ -2037,13 +2037,13 @@ static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf, if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) { int error = SOCKERRNO; failf(data, "getpeername() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); + error, curlx_strerror(error, buffer, sizeof(buffer))); return; } if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, ctx->ip.remote_ip, &ctx->ip.remote_port)) { failf(data, "ssrem inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); + errno, curlx_strerror(errno, buffer, sizeof(buffer))); return; } #else diff --git a/lib/curl_setup.h b/lib/curl_setup.h index a741abde0323..f6fe6535f463 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -950,6 +950,10 @@ endings either CRLF or LF so 't' is appropriate. #define CURL_ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +/* Buffer size for error messages retrieved via + curlx_strerror() and Curl_sspi_strerror() */ +#define STRERROR_LEN 256 + #ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */ /* * The following memory function replacement typedef's are COPIED from diff --git a/lib/curlx/.checksrc b/lib/curlx/.checksrc index 9b8d799ea285..e69de29bb2d1 100644 --- a/lib/curlx/.checksrc +++ b/lib/curlx/.checksrc @@ -1 +0,0 @@ -banfunc strerror diff --git a/lib/curlx/curlx.h b/lib/curlx/curlx.h index 33ac72e8e19b..480e91950de0 100644 --- a/lib/curlx/curlx.h +++ b/lib/curlx/curlx.h @@ -58,6 +58,9 @@ #include "version_win32.h" /* provides curlx_verify_windows_version() */ +#include "strerr.h" +/* The curlx_strerror() function */ + #include "strparse.h" /* The curlx_str_* parsing functions */ diff --git a/lib/curlx/strerr.c b/lib/curlx/strerr.c new file mode 100644 index 000000000000..96dc9c83558c --- /dev/null +++ b/lib/curlx/strerr.c @@ -0,0 +1,361 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "../curl_setup.h" + +#ifdef HAVE_STRERROR_R +# if (!defined(HAVE_POSIX_STRERROR_R) && \ + !defined(HAVE_GLIBC_STRERROR_R)) || \ + (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)) +# error "strerror_r MUST be either POSIX, glibc style" +# endif +#endif + +#include + +#ifndef WITHOUT_LIBCURL +#include +#define SNPRINTF curl_msnprintf +#else +/* when built for the test servers */ + +/* adjust for old MSVC */ +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define SNPRINTF _snprintf +#else +#define SNPRINTF snprintf +#endif +#endif /* !WITHOUT_LIBCURL */ + +#include "winapi.h" +#include "strerr.h" +/* The last 2 #include files should be in this order */ +#include "../curl_memory.h" +#include "../memdebug.h" + +#ifdef USE_WINSOCK +/* This is a helper function for curlx_strerror that converts Winsock error + * codes (WSAGetLastError) to error messages. + * Returns NULL if no error message was found for error code. + */ +static const char * +get_winsock_error(int err, char *buf, size_t len) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + const char *p; + size_t alen; +#endif + + if(!len) + return NULL; + + *buf = '\0'; + +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)err; + return NULL; +#else + switch(err) { + case WSAEINTR: + p = "Call interrupted"; + break; + case WSAEBADF: + p = "Bad file"; + break; + case WSAEACCES: + p = "Bad access"; + break; + case WSAEFAULT: + p = "Bad argument"; + break; + case WSAEINVAL: + p = "Invalid arguments"; + break; + case WSAEMFILE: + p = "Out of file descriptors"; + break; + case WSAEWOULDBLOCK: + p = "Call would block"; + break; + case WSAEINPROGRESS: + case WSAEALREADY: + p = "Blocking call in progress"; + break; + case WSAENOTSOCK: + p = "Descriptor is not a socket"; + break; + case WSAEDESTADDRREQ: + p = "Need destination address"; + break; + case WSAEMSGSIZE: + p = "Bad message size"; + break; + case WSAEPROTOTYPE: + p = "Bad protocol"; + break; + case WSAENOPROTOOPT: + p = "Protocol option is unsupported"; + break; + case WSAEPROTONOSUPPORT: + p = "Protocol is unsupported"; + break; + case WSAESOCKTNOSUPPORT: + p = "Socket is unsupported"; + break; + case WSAEOPNOTSUPP: + p = "Operation not supported"; + break; + case WSAEAFNOSUPPORT: + p = "Address family not supported"; + break; + case WSAEPFNOSUPPORT: + p = "Protocol family not supported"; + break; + case WSAEADDRINUSE: + p = "Address already in use"; + break; + case WSAEADDRNOTAVAIL: + p = "Address not available"; + break; + case WSAENETDOWN: + p = "Network down"; + break; + case WSAENETUNREACH: + p = "Network unreachable"; + break; + case WSAENETRESET: + p = "Network has been reset"; + break; + case WSAECONNABORTED: + p = "Connection was aborted"; + break; + case WSAECONNRESET: + p = "Connection was reset"; + break; + case WSAENOBUFS: + p = "No buffer space"; + break; + case WSAEISCONN: + p = "Socket is already connected"; + break; + case WSAENOTCONN: + p = "Socket is not connected"; + break; + case WSAESHUTDOWN: + p = "Socket has been shut down"; + break; + case WSAETOOMANYREFS: + p = "Too many references"; + break; + case WSAETIMEDOUT: + p = "Timed out"; + break; + case WSAECONNREFUSED: + p = "Connection refused"; + break; + case WSAELOOP: + p = "Loop??"; + break; + case WSAENAMETOOLONG: + p = "Name too long"; + break; + case WSAEHOSTDOWN: + p = "Host down"; + break; + case WSAEHOSTUNREACH: + p = "Host unreachable"; + break; + case WSAENOTEMPTY: + p = "Not empty"; + break; + case WSAEPROCLIM: + p = "Process limit reached"; + break; + case WSAEUSERS: + p = "Too many users"; + break; + case WSAEDQUOT: + p = "Bad quota"; + break; + case WSAESTALE: + p = "Something is stale"; + break; + case WSAEREMOTE: + p = "Remote error"; + break; + case WSAEDISCON: + p = "Disconnected"; + break; + /* Extended Winsock errors */ + case WSASYSNOTREADY: + p = "Winsock library is not ready"; + break; + case WSANOTINITIALISED: + p = "Winsock library not initialised"; + break; + case WSAVERNOTSUPPORTED: + p = "Winsock version not supported"; + break; + + /* getXbyY() errors (already handled in herrmsg): + * Authoritative Answer: Host not found */ + case WSAHOST_NOT_FOUND: + p = "Host not found"; + break; + + /* Non-Authoritative: Host not found, or SERVERFAIL */ + case WSATRY_AGAIN: + p = "Host not found, try again"; + break; + + /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ + case WSANO_RECOVERY: + p = "Unrecoverable error in call to nameserver"; + break; + + /* Valid name, no data record of requested type */ + case WSANO_DATA: + p = "No data record of requested type"; + break; + + default: + return NULL; + } + alen = strlen(p); + if(alen < len) + strcpy(buf, p); + return buf; +#endif +} +#endif /* USE_WINSOCK */ + +/* + * Our thread-safe and smart strerror() replacement. + * + * The 'err' argument passed in to this function MUST be a true errno number + * as reported on this system. We do no range checking on the number before + * we pass it to the "number-to-message" conversion function and there might + * be systems that do not do proper range checking in there themselves. + * + * We do not do range checking (on systems other than Windows) since there is + * no good reliable and portable way to do it. + * + * On Windows different types of error codes overlap. This function has an + * order of preference when trying to match error codes: + * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError). + * + * It may be more correct to call one of the variant functions instead: + * Call Curl_sspi_strerror if the error code is definitely Windows SSPI. + * Call curlx_winapi_strerror if the error code is definitely Windows API. + */ +const char *curlx_strerror(int err, char *buf, size_t buflen) +{ +#ifdef _WIN32 + DWORD old_win_err = GetLastError(); +#endif + int old_errno = errno; + char *p; + + if(!buflen) + return NULL; + +#ifndef _WIN32 + DEBUGASSERT(err >= 0); +#endif + + *buf = '\0'; + +#ifdef _WIN32 +#ifndef UNDER_CE + /* 'sys_nerr' is the maximum errno number, it is not widely portable */ + if(err >= 0 && err < sys_nerr) + SNPRINTF(buf, buflen, "%s", sys_errlist[err]); + else +#endif + { + if( +#ifdef USE_WINSOCK + !get_winsock_error(err, buf, buflen) && +#endif + !curlx_get_winapi_error(err, buf, buflen)) + SNPRINTF(buf, buflen, "Unknown error %d (%#x)", err, err); + } +#else /* !_WIN32 */ + +#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R) + /* + * The POSIX-style strerror_r() may set errno to ERANGE if insufficient + * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated + * message string, or EINVAL if 'errnum' is not a valid error number. + */ + if(strerror_r(err, buf, buflen) && + buflen > sizeof("Unknown error ") + 20) { + if(buf[0] == '\0') + SNPRINTF(buf, buflen, "Unknown error %d", err); + } +#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R) + /* + * The glibc-style strerror_r() only *might* use the buffer we pass to + * the function, but it always returns the error message as a pointer, + * so we must copy that string unconditionally (if non-NULL). + */ + { + char buffer[256]; + char *msg = strerror_r(err, buffer, sizeof(buffer)); + if(msg && buflen > 1) + SNPRINTF(buf, buflen, "%s", msg); + else if(buflen > sizeof("Unknown error ") + 20) + SNPRINTF(buf, buflen, "Unknown error %d", err); + } +#else + { + /* !checksrc! disable BANNEDFUNC 1 */ + const char *msg = strerror(err); + if(msg && buflen > 1) + SNPRINTF(buf, buflen, "%s", msg); + else if(buflen > sizeof("Unknown error ") + 20) + SNPRINTF(buf, buflen, "Unknown error %d", err); + } +#endif + +#endif /* _WIN32 */ + + /* strip trailing '\r\n' or '\n'. */ + p = strrchr(buf, '\n'); + if(p && (p - buf) >= 2) + *p = '\0'; + p = strrchr(buf, '\r'); + if(p && (p - buf) >= 1) + *p = '\0'; + + if(errno != old_errno) + CURL_SETERRNO(old_errno); + +#ifdef _WIN32 + if(old_win_err != GetLastError()) + SetLastError(old_win_err); +#endif + + return buf; +} diff --git a/lib/curlx/strerr.h b/lib/curlx/strerr.h new file mode 100644 index 000000000000..4413e6738c54 --- /dev/null +++ b/lib/curlx/strerr.h @@ -0,0 +1,29 @@ +#ifndef HEADER_CURL_STRERR_H +#define HEADER_CURL_STRERR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +const char *curlx_strerror(int err, char *buf, size_t buflen); + +#endif /* HEADER_CURL_STRERR_H */ diff --git a/lib/curlx/winapi.c b/lib/curlx/winapi.c index 7e3d1aa9ca9a..cc008e3087a5 100644 --- a/lib/curlx/winapi.c +++ b/lib/curlx/winapi.c @@ -25,12 +25,12 @@ /* * curlx_winapi_strerror: - * Variant of Curl_strerror if the error code is definitely Windows API. + * Variant of curlx_strerror if the error code is definitely Windows API. */ #ifdef _WIN32 #include "winapi.h" -#ifdef BUILDING_LIBCURL +#ifndef WITHOUT_LIBCURL #include #define SNPRINTF curl_msnprintf #else @@ -42,10 +42,9 @@ #else #define SNPRINTF snprintf #endif +#endif /* !WITHOUT_LIBCURL */ -#endif /* !BUILDING_LIBCURL */ - -/* This is a helper function for Curl_strerror that converts Windows API error +/* This is a helper function for curlx_strerror that converts Windows API error * codes (GetLastError) to error messages. * Returns NULL if no error message was found for error code. */ diff --git a/lib/ftp.c b/lib/ftp.c index 13b613bc1e86..a3194c2a7b37 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -58,7 +58,6 @@ #include "cfilters.h" #include "cf-socket.h" #include "connect.h" -#include "strerror.h" #include "curlx/inet_ntop.h" #include "curlx/inet_pton.h" #include "select.h" @@ -71,6 +70,7 @@ #include "http_proxy.h" #include "socks.h" #include "strdup.h" +#include "curlx/strerr.h" #include "curlx/strparse.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -1007,7 +1007,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, sslen = sizeof(ss); if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { failf(data, "getsockname() failed: %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); goto out; } switch(sa->sa_family) { @@ -1054,7 +1054,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, } if(!ai) { failf(data, "socket failure: %s", - Curl_strerror(error, buffer, sizeof(buffer))); + curlx_strerror(error, buffer, sizeof(buffer))); goto out; } CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), opened socket", @@ -1081,12 +1081,12 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, * the control connection instead and restart the port loop */ infof(data, "bind(port=%hu) on non-local address failed: %s", port, - Curl_strerror(error, buffer, sizeof(buffer))); + curlx_strerror(error, buffer, sizeof(buffer))); sslen = sizeof(ss); if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { failf(data, "getsockname() failed: %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); goto out; } port = port_min; @@ -1095,7 +1095,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, } if(error != SOCKEADDRINUSE && error != SOCKEACCES) { failf(data, "bind(port=%hu) failed: %s", port, - Curl_strerror(error, buffer, sizeof(buffer))); + curlx_strerror(error, buffer, sizeof(buffer))); goto out; } } @@ -1118,7 +1118,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, sslen = sizeof(ss); if(getsockname(portsock, sa, &sslen)) { failf(data, "getsockname() failed: %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); goto out; } CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), socket bound to port %d", @@ -1128,7 +1128,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, if(listen(portsock, 1)) { failf(data, "socket failure: %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); goto out; } CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), listening on %d", diff --git a/lib/strerror.c b/lib/strerror.c index 47c657211418..c4545af88824 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -24,15 +24,8 @@ #include "curl_setup.h" -#ifdef HAVE_STRERROR_R -# if (!defined(HAVE_POSIX_STRERROR_R) && \ - !defined(HAVE_GLIBC_STRERROR_R)) || \ - (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)) -# error "strerror_r MUST be either POSIX, glibc style" -# endif -#endif - #include +#include #ifdef USE_WINDOWS_SSPI #include "curl_sspi.h" @@ -40,8 +33,8 @@ #include "curlx/winapi.h" #include "strerror.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -548,315 +541,10 @@ curl_url_strerror(CURLUcode error) #endif } -#ifdef USE_WINSOCK -/* This is a helper function for Curl_strerror that converts Winsock error - * codes (WSAGetLastError) to error messages. - * Returns NULL if no error message was found for error code. - */ -static const char * -get_winsock_error(int err, char *buf, size_t len) -{ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - const char *p; - size_t alen; -#endif - - if(!len) - return NULL; - - *buf = '\0'; - -#ifdef CURL_DISABLE_VERBOSE_STRINGS - (void)err; - return NULL; -#else - switch(err) { - case WSAEINTR: - p = "Call interrupted"; - break; - case WSAEBADF: - p = "Bad file"; - break; - case WSAEACCES: - p = "Bad access"; - break; - case WSAEFAULT: - p = "Bad argument"; - break; - case WSAEINVAL: - p = "Invalid arguments"; - break; - case WSAEMFILE: - p = "Out of file descriptors"; - break; - case WSAEWOULDBLOCK: - p = "Call would block"; - break; - case WSAEINPROGRESS: - case WSAEALREADY: - p = "Blocking call in progress"; - break; - case WSAENOTSOCK: - p = "Descriptor is not a socket"; - break; - case WSAEDESTADDRREQ: - p = "Need destination address"; - break; - case WSAEMSGSIZE: - p = "Bad message size"; - break; - case WSAEPROTOTYPE: - p = "Bad protocol"; - break; - case WSAENOPROTOOPT: - p = "Protocol option is unsupported"; - break; - case WSAEPROTONOSUPPORT: - p = "Protocol is unsupported"; - break; - case WSAESOCKTNOSUPPORT: - p = "Socket is unsupported"; - break; - case WSAEOPNOTSUPP: - p = "Operation not supported"; - break; - case WSAEAFNOSUPPORT: - p = "Address family not supported"; - break; - case WSAEPFNOSUPPORT: - p = "Protocol family not supported"; - break; - case WSAEADDRINUSE: - p = "Address already in use"; - break; - case WSAEADDRNOTAVAIL: - p = "Address not available"; - break; - case WSAENETDOWN: - p = "Network down"; - break; - case WSAENETUNREACH: - p = "Network unreachable"; - break; - case WSAENETRESET: - p = "Network has been reset"; - break; - case WSAECONNABORTED: - p = "Connection was aborted"; - break; - case WSAECONNRESET: - p = "Connection was reset"; - break; - case WSAENOBUFS: - p = "No buffer space"; - break; - case WSAEISCONN: - p = "Socket is already connected"; - break; - case WSAENOTCONN: - p = "Socket is not connected"; - break; - case WSAESHUTDOWN: - p = "Socket has been shut down"; - break; - case WSAETOOMANYREFS: - p = "Too many references"; - break; - case WSAETIMEDOUT: - p = "Timed out"; - break; - case WSAECONNREFUSED: - p = "Connection refused"; - break; - case WSAELOOP: - p = "Loop??"; - break; - case WSAENAMETOOLONG: - p = "Name too long"; - break; - case WSAEHOSTDOWN: - p = "Host down"; - break; - case WSAEHOSTUNREACH: - p = "Host unreachable"; - break; - case WSAENOTEMPTY: - p = "Not empty"; - break; - case WSAEPROCLIM: - p = "Process limit reached"; - break; - case WSAEUSERS: - p = "Too many users"; - break; - case WSAEDQUOT: - p = "Bad quota"; - break; - case WSAESTALE: - p = "Something is stale"; - break; - case WSAEREMOTE: - p = "Remote error"; - break; - case WSAEDISCON: - p = "Disconnected"; - break; - /* Extended Winsock errors */ - case WSASYSNOTREADY: - p = "Winsock library is not ready"; - break; - case WSANOTINITIALISED: - p = "Winsock library not initialised"; - break; - case WSAVERNOTSUPPORTED: - p = "Winsock version not supported"; - break; - - /* getXbyY() errors (already handled in herrmsg): - * Authoritative Answer: Host not found */ - case WSAHOST_NOT_FOUND: - p = "Host not found"; - break; - - /* Non-Authoritative: Host not found, or SERVERFAIL */ - case WSATRY_AGAIN: - p = "Host not found, try again"; - break; - - /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ - case WSANO_RECOVERY: - p = "Unrecoverable error in call to nameserver"; - break; - - /* Valid name, no data record of requested type */ - case WSANO_DATA: - p = "No data record of requested type"; - break; - - default: - return NULL; - } - alen = strlen(p); - if(alen < len) - strcpy(buf, p); - return buf; -#endif -} -#endif /* USE_WINSOCK */ - -/* - * Our thread-safe and smart strerror() replacement. - * - * The 'err' argument passed in to this function MUST be a true errno number - * as reported on this system. We do no range checking on the number before - * we pass it to the "number-to-message" conversion function and there might - * be systems that do not do proper range checking in there themselves. - * - * We do not do range checking (on systems other than Windows) since there is - * no good reliable and portable way to do it. - * - * On Windows different types of error codes overlap. This function has an - * order of preference when trying to match error codes: - * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError). - * - * It may be more correct to call one of the variant functions instead: - * Call Curl_sspi_strerror if the error code is definitely Windows SSPI. - * Call curlx_winapi_strerror if the error code is definitely Windows API. - */ -const char *Curl_strerror(int err, char *buf, size_t buflen) -{ -#ifdef _WIN32 - DWORD old_win_err = GetLastError(); -#endif - int old_errno = errno; - char *p; - - if(!buflen) - return NULL; - -#ifndef _WIN32 - DEBUGASSERT(err >= 0); -#endif - - *buf = '\0'; - -#ifdef _WIN32 -#ifndef UNDER_CE - /* 'sys_nerr' is the maximum errno number, it is not widely portable */ - if(err >= 0 && err < sys_nerr) - curl_msnprintf(buf, buflen, "%s", sys_errlist[err]); - else -#endif - { - if( -#ifdef USE_WINSOCK - !get_winsock_error(err, buf, buflen) && -#endif - !curlx_get_winapi_error(err, buf, buflen)) - curl_msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err); - } -#else /* not Windows coming up */ - -#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R) - /* - * The POSIX-style strerror_r() may set errno to ERANGE if insufficient - * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated - * message string, or EINVAL if 'errnum' is not a valid error number. - */ - if(strerror_r(err, buf, buflen)) { - if('\0' == buf[0]) - curl_msnprintf(buf, buflen, "Unknown error %d", err); - } -#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R) - /* - * The glibc-style strerror_r() only *might* use the buffer we pass to - * the function, but it always returns the error message as a pointer, - * so we must copy that string unconditionally (if non-NULL). - */ - { - char buffer[256]; - char *msg = strerror_r(err, buffer, sizeof(buffer)); - if(msg) - curl_msnprintf(buf, buflen, "%s", msg); - else - curl_msnprintf(buf, buflen, "Unknown error %d", err); - } -#else - { - /* !checksrc! disable BANNEDFUNC 1 */ - const char *msg = strerror(err); - if(msg) - curl_msnprintf(buf, buflen, "%s", msg); - else - curl_msnprintf(buf, buflen, "Unknown error %d", err); - } -#endif - -#endif /* end of not Windows */ - - /* strip trailing '\r\n' or '\n'. */ - p = strrchr(buf, '\n'); - if(p && (p - buf) >= 2) - *p = '\0'; - p = strrchr(buf, '\r'); - if(p && (p - buf) >= 1) - *p = '\0'; - - if(errno != old_errno) - CURL_SETERRNO(old_errno); - -#ifdef _WIN32 - if(old_win_err != GetLastError()) - SetLastError(old_win_err); -#endif - - return buf; -} - #ifdef USE_WINDOWS_SSPI /* * Curl_sspi_strerror: - * Variant of Curl_strerror if the error code is definitely Windows SSPI. + * Variant of curlx_strerror if the error code is definitely Windows SSPI. */ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen) { diff --git a/lib/strerror.h b/lib/strerror.h index 424fb5b7b5e1..2120726c9ff0 100644 --- a/lib/strerror.h +++ b/lib/strerror.h @@ -24,11 +24,6 @@ * ***************************************************************************/ -#include "urldata.h" - -#define STRERROR_LEN 256 /* a suitable length */ - -const char *Curl_strerror(int err, char *buf, size_t buflen); #ifdef USE_WINDOWS_SSPI const char *Curl_sspi_strerror(int err, char *buf, size_t buflen); #endif diff --git a/lib/tftp.c b/lib/tftp.c index ad2c84e6608d..b6bc5e9bdca1 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -55,7 +55,6 @@ #include "tftp.h" #include "progress.h" #include "connect.h" -#include "strerror.h" #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "multiif.h" #include "url.h" @@ -63,6 +62,7 @@ #include "speedcheck.h" #include "select.h" #include "escape.h" +#include "curlx/strerr.h" #include "curlx/strparse.h" /* The last 3 #include files should be in this order */ @@ -539,7 +539,7 @@ static CURLcode tftp_send_first(struct tftp_conn *state, free(filename); if(senddata != (ssize_t)sbytes) { char buffer[STRERROR_LEN]; - failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + failf(data, "%s", curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } break; @@ -622,7 +622,7 @@ static CURLcode tftp_rx(struct tftp_conn *state, tftp_event_t event) (struct sockaddr *)&state->remote_addr, state->remote_addrlen); if(sbytes < 0) { - failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + failf(data, "%s", curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } @@ -647,7 +647,7 @@ static CURLcode tftp_rx(struct tftp_conn *state, tftp_event_t event) (struct sockaddr *)&state->remote_addr, state->remote_addrlen); if(sbytes < 0) { - failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + failf(data, "%s", curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } @@ -673,7 +673,7 @@ static CURLcode tftp_rx(struct tftp_conn *state, tftp_event_t event) (struct sockaddr *)&state->remote_addr, state->remote_addrlen); if(sbytes < 0) { - failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + failf(data, "%s", curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } } @@ -750,8 +750,8 @@ static CURLcode tftp_tx(struct tftp_conn *state, tftp_event_t event) state->remote_addrlen); /* Check all sbytes were sent */ if(sbytes < 0) { - failf(data, "%s", Curl_strerror(SOCKERRNO, - buffer, sizeof(buffer))); + failf(data, "%s", + curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); result = CURLE_SEND_ERROR; } } @@ -795,7 +795,7 @@ static CURLcode tftp_tx(struct tftp_conn *state, tftp_event_t event) state->remote_addrlen); /* Check all sbytes were sent */ if(sbytes < 0) { - failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + failf(data, "%s", curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } /* Update the progress meter */ @@ -821,7 +821,7 @@ static CURLcode tftp_tx(struct tftp_conn *state, tftp_event_t event) state->remote_addrlen); /* Check all sbytes were sent */ if(sbytes < 0) { - failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + failf(data, "%s", curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } /* since this was a re-send, we remain at the still byte position */ @@ -1039,7 +1039,7 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done) if(rc) { char buffer[STRERROR_LEN]; failf(data, "bind() failed; %s", - Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); + curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); return CURLE_COULDNT_CONNECT; } conn->bits.bound = TRUE; @@ -1257,7 +1257,7 @@ static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done) /* bail out */ int error = SOCKERRNO; char buffer[STRERROR_LEN]; - failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer))); + failf(data, "%s", curlx_strerror(error, buffer, sizeof(buffer))); state->event = TFTP_EVENT_ERROR; } else if(rc) { diff --git a/lib/url.c b/lib/url.c index ae4a6f6502ba..2a46354c611d 100644 --- a/lib/url.c +++ b/lib/url.c @@ -80,7 +80,6 @@ #include "progress.h" #include "cookie.h" #include "strcase.h" -#include "strerror.h" #include "escape.h" #include "share.h" #include "content_encoding.h" @@ -125,6 +124,7 @@ #include "altsvc.h" #include "curlx/dynbuf.h" #include "headers.h" +#include "curlx/strerr.h" #include "curlx/strparse.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -1743,7 +1743,7 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data, #ifndef CURL_DISABLE_VERBOSE_STRINGS char buffer[STRERROR_LEN]; infof(data, "Invalid zoneid: %s; %s", zoneid, - Curl_strerror(errno, buffer, sizeof(buffer))); + curlx_strerror(errno, buffer, sizeof(buffer))); #endif } else diff --git a/lib/vauth/.checksrc b/lib/vauth/.checksrc index 9b8d799ea285..e69de29bb2d1 100644 --- a/lib/vauth/.checksrc +++ b/lib/vauth/.checksrc @@ -1 +0,0 @@ -banfunc strerror diff --git a/lib/vquic/.checksrc b/lib/vquic/.checksrc index 9b8d799ea285..e69de29bb2d1 100644 --- a/lib/vquic/.checksrc +++ b/lib/vquic/.checksrc @@ -1 +0,0 @@ -banfunc strerror diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 4a45c1f6dbff..a85c9d7609e8 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -57,7 +57,6 @@ #include "../cf-socket.h" #include "../connect.h" #include "../progress.h" -#include "../strerror.h" #include "../curlx/dynbuf.h" #include "../http1.h" #include "../select.h" diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index aea03c038fb6..1d7c3bce9960 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -42,7 +42,6 @@ #include "../cf-socket.h" #include "../connect.h" #include "../progress.h" -#include "../strerror.h" #include "../curlx/dynbuf.h" #include "../http1.h" #include "../select.h" @@ -57,6 +56,7 @@ #include "curl_osslq.h" #include "../url.h" #include "../curlx/warnless.h" +#include "../curlx/strerr.h" /* The last 3 #include files should be in this order */ #include "../curl_printf.h" @@ -552,7 +552,7 @@ static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf, Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); if(sockerr && detail == SSL_ERROR_SYSCALL) - Curl_strerror(sockerr, extramsg, sizeof(extramsg)); + curlx_strerror(sockerr, extramsg, sizeof(extramsg)); failf(data, "QUIC connect: %s in connection to %s:%d (%s)", extramsg[0] ? extramsg : osslq_SSL_ERROR_to_str(detail), ctx->peer.dispname, ip.remote_port, ip.remote_ip); diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 5fb67f69f42c..36691d09dbe8 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -39,7 +39,6 @@ #include "../multiif.h" #include "../connect.h" #include "../progress.h" -#include "../strerror.h" #include "../select.h" #include "../http1.h" #include "vquic.h" diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index 275ea8bcccdf..91680915f330 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -43,7 +43,7 @@ #include "../rand.h" #include "vquic.h" #include "vquic_int.h" -#include "../strerror.h" +#include "../curlx/strerr.h" #include "../curlx/strparse.h" /* The last 3 #include files should be in this order */ @@ -434,7 +434,7 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf, result = CURLE_COULDNT_CONNECT; goto out; } - Curl_strerror(SOCKERRNO, errstr, sizeof(errstr)); + curlx_strerror(SOCKERRNO, errstr, sizeof(errstr)); failf(data, "QUIC: recvmmsg() unexpectedly returned %d (errno=%d; %s)", mcount, SOCKERRNO, errstr); result = CURLE_RECV_ERROR; @@ -527,7 +527,7 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf, result = CURLE_COULDNT_CONNECT; goto out; } - Curl_strerror(SOCKERRNO, errstr, sizeof(errstr)); + curlx_strerror(SOCKERRNO, errstr, sizeof(errstr)); failf(data, "QUIC: recvmsg() unexpectedly returned %zd (errno=%d; %s)", rc, SOCKERRNO, errstr); result = CURLE_RECV_ERROR; @@ -602,7 +602,7 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf, result = CURLE_COULDNT_CONNECT; goto out; } - Curl_strerror(SOCKERRNO, errstr, sizeof(errstr)); + curlx_strerror(SOCKERRNO, errstr, sizeof(errstr)); failf(data, "QUIC: recvfrom() unexpectedly returned %zd (errno=%d; %s)", nread, SOCKERRNO, errstr); result = CURLE_RECV_ERROR; diff --git a/lib/vssh/.checksrc b/lib/vssh/.checksrc index 9b8d799ea285..e69de29bb2d1 100644 --- a/lib/vssh/.checksrc +++ b/lib/vssh/.checksrc @@ -1 +0,0 @@ -banfunc strerror diff --git a/lib/vtls/.checksrc b/lib/vtls/.checksrc index 9b8d799ea285..e69de29bb2d1 100644 --- a/lib/vtls/.checksrc +++ b/lib/vtls/.checksrc @@ -1 +0,0 @@ -banfunc strerror diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index fd5529f5abd5..0714ce7c6ae0 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -63,9 +63,9 @@ #include "hostcheck.h" #include "../transfer.h" #include "../multiif.h" +#include "../curlx/strerr.h" #include "../curlx/strparse.h" #include "../strdup.h" -#include "../strerror.h" #include "../curl_printf.h" #include "apple.h" @@ -4668,7 +4668,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, int sockerr = SOCKERRNO; if(sockerr && detail == SSL_ERROR_SYSCALL) - Curl_strerror(sockerr, extramsg, sizeof(extramsg)); + curlx_strerror(sockerr, extramsg, sizeof(extramsg)); failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ", extramsg[0] ? extramsg : SSL_ERROR_to_str(detail), connssl->peer.hostname, connssl->peer.port); @@ -5274,7 +5274,7 @@ static CURLcode ossl_send_earlydata(struct Curl_cfilter *cf, if(sslerror) ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)); else if(sockerr) - Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); + curlx_strerror(sockerr, error_buffer, sizeof(error_buffer)); else msnprintf(error_buffer, sizeof(error_buffer), "%s", SSL_ERROR_to_str(err)); @@ -5460,7 +5460,7 @@ static CURLcode ossl_send(struct Curl_cfilter *cf, if(sslerror) ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)); else if(sockerr) - Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); + curlx_strerror(sockerr, error_buffer, sizeof(error_buffer)); else msnprintf(error_buffer, sizeof(error_buffer), "%s", SSL_ERROR_to_str(err)); @@ -5557,7 +5557,7 @@ static CURLcode ossl_recv(struct Curl_cfilter *cf, if(sslerror) ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)); else if(sockerr && err == SSL_ERROR_SYSCALL) - Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); + curlx_strerror(sockerr, error_buffer, sizeof(error_buffer)); else msnprintf(error_buffer, sizeof(error_buffer), "%s", SSL_ERROR_to_str(err)); @@ -5580,7 +5580,7 @@ static CURLcode ossl_recv(struct Curl_cfilter *cf, * the error in case of some weirdness in the OSSL stack */ int sockerr = SOCKERRNO; if(sockerr) - Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); + curlx_strerror(sockerr, error_buffer, sizeof(error_buffer)); else { msnprintf(error_buffer, sizeof(error_buffer), "Connection closed abruptly"); diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 70e109212d36..ce7a4d5c9dcb 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -34,13 +34,13 @@ #include "../curlx/fopen.h" #include "../curlx/inet_pton.h" +#include "../curlx/strerr.h" #include "../urldata.h" #include "../sendf.h" #include "vtls.h" #include "vtls_int.h" #include "rustls.h" #include "keylog.h" -#include "../strerror.h" #include "cipher_suite.h" #include "x509asn1.h" @@ -171,7 +171,7 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf, else if(io_error) { char buffer[STRERROR_LEN]; failf(data, "reading from socket: %s", - Curl_strerror(io_error, buffer, sizeof(buffer))); + curlx_strerror(io_error, buffer, sizeof(buffer))); *err = CURLE_RECV_ERROR; return -1; } @@ -283,7 +283,7 @@ static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data, else if(io_error) { char buffer[STRERROR_LEN]; failf(data, "writing to socket: %s", - Curl_strerror(io_error, buffer, sizeof(buffer))); + curlx_strerror(io_error, buffer, sizeof(buffer))); return CURLE_SEND_ERROR; } if(tlswritten == 0) { diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 54800ce12d88..017738ecdf8a 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -58,6 +58,7 @@ "vsnprintf" => 1, "sscanf" => 1, "strcat" => 1, + "strerror" => 1, "strncat" => 1, "strncpy" => 1, "strtok_r" => 1, diff --git a/src/Makefile.inc b/src/Makefile.inc index 35f8e6fdee84..d57d6c9125f4 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -38,12 +38,14 @@ CURLX_CFILES = \ ../lib/curlx/dynbuf.c \ ../lib/curlx/fopen.c \ ../lib/curlx/nonblock.c \ + ../lib/curlx/strerr.c \ ../lib/curlx/strparse.c \ ../lib/curlx/timediff.c \ ../lib/curlx/timeval.c \ ../lib/curlx/version_win32.c \ ../lib/curlx/wait.c \ - ../lib/curlx/warnless.c + ../lib/curlx/warnless.c \ + ../lib/curlx/winapi.c CURLX_HFILES = \ ../lib/curlx/binmode.h \ @@ -52,12 +54,14 @@ CURLX_HFILES = \ ../lib/curlx/dynbuf.h \ ../lib/curlx/fopen.h \ ../lib/curlx/nonblock.h \ + ../lib/curlx/strerr.h \ ../lib/curlx/strparse.h \ ../lib/curlx/timediff.h \ ../lib/curlx/timeval.h \ ../lib/curlx/version_win32.h \ ../lib/curlx/wait.h \ - ../lib/curlx/warnless.h + ../lib/curlx/warnless.h \ + ../lib/curlx/winapi.h CURL_CFILES = \ config2setopts.c \ diff --git a/src/config2setopts.c b/src/config2setopts.c index 533fe992d34b..2a58b75772f1 100644 --- a/src/config2setopts.c +++ b/src/config2setopts.c @@ -83,9 +83,10 @@ static int sockopt_callback(void *clientp, curl_socket_t curlfd, #endif } if(result < 0) { + char buffer[STRERROR_LEN]; int error = errno; - warnf("Setting type of service to %d failed with errno %d: %s", - tos, error, strerror(error)); + warnf("Setting type of service to %d failed with errno %d: %s", tos, + error, curlx_strerror(error, buffer, sizeof(buffer))); } } #endif @@ -94,9 +95,10 @@ static int sockopt_callback(void *clientp, curl_socket_t curlfd, int priority = (int)config->vlan_priority; if(setsockopt(curlfd, SOL_SOCKET, SO_PRIORITY, (void *)&priority, sizeof(priority)) != 0) { + char buffer[STRERROR_LEN]; int error = errno; - warnf("VLAN priority %d failed with errno %d: %s", - priority, error, strerror(error)); + warnf("VLAN priority %d failed with errno %d: %s", priority, + error, curlx_strerror(error, buffer, sizeof(buffer))); } } #endif diff --git a/src/tool_cb_wrt.c b/src/tool_cb_wrt.c index 12e4417da479..724706b7a1af 100644 --- a/src/tool_cb_wrt.c +++ b/src/tool_cb_wrt.c @@ -96,7 +96,9 @@ bool tool_create_output_file(struct OutStruct *outs, } if(!file) { - warnf("Failed to open the file %s: %s", fname, strerror(errno)); + char errbuf[STRERROR_LEN]; + warnf("Failed to open the file %s: %s", fname, + curlx_strerror(errno, errbuf, sizeof(errbuf))); return FALSE; } outs->s_isreg = TRUE; diff --git a/src/tool_filetime.c b/src/tool_filetime.c index b442fc2014df..afd84c013831 100644 --- a/src/tool_filetime.c +++ b/src/tool_filetime.c @@ -77,8 +77,11 @@ int getfiletime(const char *filename, curl_off_t *stamp) *stamp = (curl_off_t)statbuf.st_mtime; rc = 0; } - else - warnf("Failed to get filetime: %s", strerror(errno)); + else { + char errbuf[STRERROR_LEN]; + warnf("Failed to get filetime: %s", + curlx_strerror(errno, errbuf, sizeof(errbuf))); + } #endif return rc; } @@ -131,8 +134,10 @@ void setfiletime(curl_off_t filetime, const char *filename) times[0].tv_sec = times[1].tv_sec = (time_t)filetime; times[0].tv_usec = times[1].tv_usec = 0; if(utimes(filename, times)) { + char errbuf[STRERROR_LEN]; warnf("Failed to set filetime %" CURL_FORMAT_CURL_OFF_T - " on '%s': %s", filetime, filename, strerror(errno)); + " on '%s': %s", filetime, filename, + curlx_strerror(errno, errbuf, sizeof(errbuf))); } #elif defined(HAVE_UTIME) @@ -140,8 +145,10 @@ void setfiletime(curl_off_t filetime, const char *filename) times.actime = (time_t)filetime; times.modtime = (time_t)filetime; if(utime(filename, ×)) { + char errbuf[STRERROR_LEN]; warnf("Failed to set filetime %" CURL_FORMAT_CURL_OFF_T - " on '%s': %s", filetime, filename, strerror(errno)); + " on '%s': %s", filetime, filename, + curlx_strerror(errno, errbuf, sizeof(errbuf))); } #endif } diff --git a/src/tool_formparse.c b/src/tool_formparse.c index f1f2f5b7e5c6..cd3cf52e3ebd 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -222,8 +222,9 @@ size_t tool_mime_stdin_read(char *buffer, /* Read from stdin. */ nitems = fread(buffer, 1, nitems, stdin); if(ferror(stdin)) { + char errbuf[STRERROR_LEN]; /* Show error only once. */ - warnf("stdin: %s", strerror(errno)); + warnf("stdin: %s", curlx_strerror(errno, errbuf, sizeof(errbuf))); return CURL_READFUNC_ABORT; } } @@ -444,8 +445,9 @@ static int read_field_headers(const char *filename, FILE *fp, switch(c) { case EOF: if(ferror(fp)) { + char errbuf[STRERROR_LEN]; errorf("Header file %s read error: %s", filename, - strerror(errno)); + curlx_strerror(errno, errbuf, sizeof(errbuf))); return -1; } return 0; /* Done. */ @@ -564,9 +566,11 @@ static int get_param_part(char endchar, sep = *p; *endpos = '\0'; fp = curlx_fopen(hdrfile, FOPEN_READTEXT); - if(!fp) + if(!fp) { + char errbuf[STRERROR_LEN]; warnf("Cannot read from %s: %s", hdrfile, - strerror(errno)); + curlx_strerror(errno, errbuf, sizeof(errbuf))); + } else { int i = read_field_headers(hdrfile, fp, &headers); diff --git a/src/tool_operate.c b/src/tool_operate.c index d4a6d4db4251..2d539de7b58c 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -604,9 +604,11 @@ static CURLcode post_per_transfer(struct per_transfer *per, /* Set file extended attributes */ if(!result && config->xattr && outs->fopened && outs->stream) { rc = fwrite_xattr(curl, per->url, fileno(outs->stream)); - if(rc) - warnf("Error setting extended attributes on '%s': %s", - outs->filename, strerror(errno)); + if(rc) { + char errbuf[STRERROR_LEN]; + warnf("Error setting extended attributes on '%s': %s", outs->filename, + curlx_strerror(errno, errbuf, sizeof(errbuf))); + } } if(!result && !outs->stream && !outs->bytes) { @@ -796,9 +798,11 @@ static CURLcode etag_compare(struct OperationConfig *config) /* open file for reading: */ FILE *file = curlx_fopen(config->etag_compare_file, FOPEN_READTEXT); - if(!file) + if(!file) { + char errbuf[STRERROR_LEN]; warnf("Failed to open %s: %s", config->etag_compare_file, - strerror(errno)); + curlx_strerror(errno, errbuf, sizeof(errbuf))); + } if((PARAM_OK == file2string(&etag_from_file, file)) && etag_from_file) { @@ -1068,8 +1072,11 @@ static void check_stdin_upload(struct OperationConfig *config, else per->infd = (int)f; #endif - if(curlx_nonblock((curl_socket_t)per->infd, TRUE) < 0) - warnf("fcntl failed on fd=%d: %s", per->infd, strerror(errno)); + if(curlx_nonblock((curl_socket_t)per->infd, TRUE) < 0) { + char errbuf[STRERROR_LEN]; + warnf("fcntl failed on fd=%d: %s", per->infd, + curlx_strerror(errno, errbuf, sizeof(errbuf))); + } } } diff --git a/src/var.c b/src/var.c index d279fdeb6e7c..79c8307248f1 100644 --- a/src/var.c +++ b/src/var.c @@ -457,7 +457,9 @@ ParameterError setvariable(const char *input) else { file = curlx_fopen(line, "rb"); if(!file) { - errorf("Failed to open %s: %s", line, strerror(errno)); + char errbuf[STRERROR_LEN]; + errorf("Failed to open %s: %s", line, + curlx_strerror(errno, errbuf, sizeof(errbuf))); err = PARAM_READ_ERROR; } } diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index c316a0526925..d8735a44e121 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -34,14 +34,16 @@ UTILS_C = memptr.c testutil.c testtrace.c UTILS_H = testutil.h testtrace.h unitcheck.h CURLX_C = \ + ../../lib/curl_threads.c \ ../../lib/curlx/fopen.c \ - ../../lib/curlx/warnless.c \ ../../lib/curlx/multibyte.c \ + ../../lib/curlx/strerr.c \ ../../lib/curlx/timediff.c \ ../../lib/curlx/timeval.c \ - ../../lib/curl_threads.c \ ../../lib/curlx/version_win32.c \ - ../../lib/curlx/wait.c + ../../lib/curlx/wait.c \ + ../../lib/curlx/warnless.c \ + ../../lib/curlx/winapi.c # All libtest programs TESTS_C = \ diff --git a/tests/libtest/first.h b/tests/libtest/first.h index a902bdb8f0ed..52a6395ad19b 100644 --- a/tests/libtest/first.h +++ b/tests/libtest/first.h @@ -427,15 +427,17 @@ void ws_close(CURL *curl); /* ---------------------------------------------------------------- */ -#define exe_select_test(A, B, C, D, E, Y, Z) do { \ - int ec; \ - if(select_wrapper((A), (B), (C), (D), (E)) == -1) { \ - ec = SOCKERRNO; \ - curl_mfprintf(stderr, "%s:%d select() failed, with " \ - "errno %d (%s)\n", \ - (Y), (Z), ec, strerror(ec)); \ - res = TEST_ERR_SELECT; \ - } \ +#define exe_select_test(A, B, C, D, E, Y, Z) do { \ + int ec; \ + if(select_wrapper((A), (B), (C), (D), (E)) == -1) { \ + char ecbuf[STRERROR_LEN]; \ + ec = SOCKERRNO; \ + curl_mfprintf(stderr, "%s:%d select() failed, with " \ + "errno %d (%s)\n", \ + (Y), (Z), \ + ec, curlx_strerror(ec, ecbuf, sizeof(ecbuf))); \ + res = TEST_ERR_SELECT; \ + } \ } while(0) #define res_select_test(A, B, C, D, E) \ diff --git a/tests/libtest/lib505.c b/tests/libtest/lib505.c index 71b79b2a244e..b4f770285137 100644 --- a/tests/libtest/lib505.c +++ b/tests/libtest/lib505.c @@ -36,6 +36,7 @@ static CURLcode test_lib505(const char *URL) { CURL *curl; CURLcode res = CURLE_OK; + char errbuf[STRERROR_LEN]; FILE *hd_src; int hd; struct_stat file_info; @@ -54,7 +55,7 @@ static CURLcode test_lib505(const char *URL) hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen failed with error (%d) %s\n", - errno, strerror(errno)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); return TEST_ERR_MAJOR_BAD; /* if this happens things are major weird */ } @@ -69,7 +70,7 @@ static CURLcode test_lib505(const char *URL) if(hd == -1) { /* can't open file, bail out */ curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", - errno, strerror(errno)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; diff --git a/tests/libtest/lib518.c b/tests/libtest/lib518.c index 007d26187012..a2cb3471bfe2 100644 --- a/tests/libtest/lib518.c +++ b/tests/libtest/lib518.c @@ -51,9 +51,11 @@ static void t518_store_errmsg(const char *msg, int err) { if(!err) curl_msnprintf(t518_msgbuff, sizeof(t518_msgbuff), "%s", msg); - else + else { + char errbuf[STRERROR_LEN]; curl_msnprintf(t518_msgbuff, sizeof(t518_msgbuff), "%s, errno %d, %s", msg, - err, strerror(err)); + err, curlx_strerror(err, errbuf, sizeof(errbuf))); + } } static void t518_close_file_descriptors(void) diff --git a/tests/libtest/lib525.c b/tests/libtest/lib525.c index b34cd261af26..55224eb76e05 100644 --- a/tests/libtest/lib525.c +++ b/tests/libtest/lib525.c @@ -29,6 +29,7 @@ static CURLcode test_lib525(const char *URL) { CURLcode res = CURLE_OK; CURL *curl = NULL; + char errbuf[STRERROR_LEN]; FILE *hd_src = NULL; int hd; struct_stat file_info; @@ -45,7 +46,7 @@ static CURLcode test_lib525(const char *URL) hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen failed with error (%d) %s\n", - errno, strerror(errno)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); return TEST_ERR_FOPEN; } @@ -60,7 +61,7 @@ static CURLcode test_lib525(const char *URL) if(hd == -1) { /* can't open file, bail out */ curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", - errno, strerror(errno)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); curlx_fclose(hd_src); return TEST_ERR_FSTAT; diff --git a/tests/libtest/lib537.c b/tests/libtest/lib537.c index b8bbfb7536c3..05d50cba7f38 100644 --- a/tests/libtest/lib537.c +++ b/tests/libtest/lib537.c @@ -48,9 +48,11 @@ static void t537_store_errmsg(const char *msg, int err) { if(!err) curl_msnprintf(t537_msgbuff, sizeof(t537_msgbuff), "%s", msg); - else + else { + char errbuf[STRERROR_LEN]; curl_msnprintf(t537_msgbuff, sizeof(t537_msgbuff), "%s, errno %d, %s", msg, - err, strerror(err)); + err, curlx_strerror(err, errbuf, sizeof(errbuf))); + } } static void t537_close_file_descriptors(void) diff --git a/tests/libtest/lib541.c b/tests/libtest/lib541.c index 5e6e3c2f333b..dfe585d9da73 100644 --- a/tests/libtest/lib541.c +++ b/tests/libtest/lib541.c @@ -33,6 +33,7 @@ static CURLcode test_lib541(const char *URL) { CURL *curl; CURLcode res = CURLE_OK; + char errbuf[STRERROR_LEN]; FILE *hd_src; int hd; struct_stat file_info; @@ -45,7 +46,7 @@ static CURLcode test_lib541(const char *URL) hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen failed with error (%d) %s\n", - errno, strerror(errno)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); return TEST_ERR_MAJOR_BAD; /* if this happens things are major weird */ } @@ -60,7 +61,7 @@ static CURLcode test_lib541(const char *URL) if(hd == -1) { /* can't open file, bail out */ curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", - errno, strerror(errno)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); curlx_fclose(hd_src); return TEST_ERR_MAJOR_BAD; diff --git a/tests/libtest/lib556.c b/tests/libtest/lib556.c index 7b155a252836..8239d2603480 100644 --- a/tests/libtest/lib556.c +++ b/tests/libtest/lib556.c @@ -83,8 +83,9 @@ static CURLcode test_lib556(const char *URL) #else if((size_t)write(STDOUT_FILENO, buf, nread) != nread) { #endif + char errbuf[STRERROR_LEN]; curl_mfprintf(stderr, "write() failed: errno %d (%s)\n", - errno, strerror(errno)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); res = TEST_ERR_FAILURE; break; } diff --git a/tests/libtest/lib582.c b/tests/libtest/lib582.c index 9671c4b52f66..187432ac0cb8 100644 --- a/tests/libtest/lib582.c +++ b/tests/libtest/lib582.c @@ -225,6 +225,7 @@ static CURLcode test_lib582(const char *URL) { CURLcode res = CURLE_OK; CURL *curl = NULL; + char errbuf[STRERROR_LEN]; FILE *hd_src = NULL; int hd; struct_stat file_info; @@ -246,7 +247,7 @@ static CURLcode test_lib582(const char *URL) hd_src = curlx_fopen(libtest_arg2, "rb"); if(!hd_src) { curl_mfprintf(stderr, "fopen() failed with error (%d) %s\n", - errno, strerror(errno)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); return TEST_ERR_FOPEN; } @@ -261,7 +262,7 @@ static CURLcode test_lib582(const char *URL) if(hd == -1) { /* can't open file, bail out */ curl_mfprintf(stderr, "fstat() failed with error (%d) %s\n", - errno, strerror(errno)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); curlx_fclose(hd_src); return TEST_ERR_FSTAT; diff --git a/tests/libtest/lib591.c b/tests/libtest/lib591.c index c85c42b0c228..c0d5b1a43686 100644 --- a/tests/libtest/lib591.c +++ b/tests/libtest/lib591.c @@ -41,8 +41,9 @@ static CURLcode test_lib591(const char *URL) upload = curlx_fopen(libtest_arg3, "rb"); if(!upload) { + char errbuf[STRERROR_LEN]; curl_mfprintf(stderr, "fopen() failed with error (%d) %s\n", - errno, strerror(errno)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg3); return TEST_ERR_FOPEN; } diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index be35fe7c4fd0..bbdacc1a17b9 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -36,10 +36,11 @@ UTILS_H = CURLX_C = \ ../../lib/curlx/base64.c \ ../../lib/curlx/fopen.c \ - ../../lib/curlx/inet_pton.c \ ../../lib/curlx/inet_ntop.c \ + ../../lib/curlx/inet_pton.c \ ../../lib/curlx/multibyte.c \ ../../lib/curlx/nonblock.c \ + ../../lib/curlx/strerr.c \ ../../lib/curlx/strparse.c \ ../../lib/curlx/timediff.c \ ../../lib/curlx/timeval.c \ diff --git a/tests/server/dnsd.c b/tests/server/dnsd.c index 2d0ce35e6f40..3f8f5b37a7d3 100644 --- a/tests/server/dnsd.c +++ b/tests/server/dnsd.c @@ -104,8 +104,10 @@ static int store_incoming(const unsigned char *data, size_t size, /* Open request dump file. */ server = fopen(dumpfile, "ab"); if(!server) { + char errbuf[STRERROR_LEN]; int error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Error opening file '%s'", dumpfile); return -1; } @@ -383,6 +385,7 @@ static int test_dnsd(int argc, char **argv) int flag; int rc; int error; + char errbuf[STRERROR_LEN]; int result = 0; pidname = ".dnsd.pid"; @@ -480,7 +483,8 @@ static int test_dnsd(int argc, char **argv) if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; - logmsg("Error creating socket (%d) %s", error, sstrerror(error)); + logmsg("Error creating socket (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); result = 1; goto dnsd_cleanup; } @@ -490,7 +494,7 @@ static int test_dnsd(int argc, char **argv) (void *)&flag, sizeof(flag))) { error = SOCKERRNO; logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); result = 1; goto dnsd_cleanup; } @@ -515,8 +519,8 @@ static int test_dnsd(int argc, char **argv) #endif /* USE_IPV6 */ if(rc) { error = SOCKERRNO; - logmsg("Error binding socket on port %hu (%d) %s", port, error, - sstrerror(error)); + logmsg("Error binding socket on port %hu (%d) %s", port, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); result = 1; goto dnsd_cleanup; } @@ -538,7 +542,7 @@ static int test_dnsd(int argc, char **argv) if(getsockname(sock, &localaddr.sa, &la_size) < 0) { error = SOCKERRNO; logmsg("getsockname() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(sock); goto dnsd_cleanup; } diff --git a/tests/server/first.h b/tests/server/first.h index 4d3ae61de7ed..8e69a2b976f6 100644 --- a/tests/server/first.h +++ b/tests/server/first.h @@ -130,7 +130,6 @@ extern void logmsg(const char *msg, ...); extern void loghex(unsigned char *buffer, ssize_t len); extern unsigned char byteval(char *value); extern int win32_init(void); -extern const char *sstrerror(int err); extern FILE *test2fopen(long testno, const char *logdir2); extern curl_off_t our_getpid(void); extern int write_pidfile(const char *filename); diff --git a/tests/server/mqttd.c b/tests/server/mqttd.c index 9414eef504f1..acb427a37c0c 100644 --- a/tests/server/mqttd.c +++ b/tests/server/mqttd.c @@ -557,8 +557,10 @@ static curl_socket_t mqttit(curl_socket_t fd) logmsg("SUBSCRIBE to '%s' [%d]", topic, packet_id); stream = test2fopen(testno, logdir); if(!stream) { + char errbuf[STRERROR_LEN]; error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Couldn't open test file %ld", testno); goto end; } @@ -658,6 +660,7 @@ static bool mqttd_incoming(curl_socket_t listenfd) do { ssize_t rc; int error = 0; + char errbuf[STRERROR_LEN]; curl_socket_t sockfd = listenfd; int maxfd = (int)sockfd; @@ -686,7 +689,7 @@ static bool mqttd_incoming(curl_socket_t listenfd) if(rc < 0) { logmsg("select() failed with error (%d) %s", - error, strerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return FALSE; } @@ -694,7 +697,8 @@ static bool mqttd_incoming(curl_socket_t listenfd) curl_socket_t newfd = accept(sockfd, NULL, NULL); if(CURL_SOCKET_BAD == newfd) { error = SOCKERRNO; - logmsg("accept() failed with error (%d) %s", error, sstrerror(error)); + logmsg("accept() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); } else { logmsg("====> Client connect, fd %ld. " @@ -720,6 +724,7 @@ static int test_mqttd(int argc, char *argv[]) int wroteportfile = 0; bool juggle_again; int error; + char errbuf[STRERROR_LEN]; int arg = 1; pidname = ".mqttd.pid"; @@ -825,7 +830,8 @@ static int test_mqttd(int argc, char *argv[]) if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; - logmsg("Error creating socket (%d) %s", error, sstrerror(error)); + logmsg("Error creating socket (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto mqttd_cleanup; } diff --git a/tests/server/rtspd.c b/tests/server/rtspd.c index 0a4f9159c054..5e8bdc15cea3 100644 --- a/tests/server/rtspd.c +++ b/tests/server/rtspd.c @@ -225,8 +225,10 @@ static int rtspd_ProcessRequest(struct rtspd_httprequest *req) stream = test2fopen(req->testno, logdir); if(!stream) { + char errbuf[STRERROR_LEN]; int error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Couldn't open test file %ld", req->testno); req->open = FALSE; /* closes connection */ return 1; /* done */ @@ -527,6 +529,7 @@ static void rtspd_storerequest(char *reqbuf, size_t totalsize) { int res; int error = 0; + char errbuf[STRERROR_LEN]; size_t written; size_t writeleft; FILE *dump; @@ -544,8 +547,8 @@ static void rtspd_storerequest(char *reqbuf, size_t totalsize) /* !checksrc! disable ERRNOVAR 1 */ } while(!dump && ((error = errno) == EINTR)); if(!dump) { - logmsg("Error opening file %s error (%d) %s", - dumpfile, error, strerror(error)); + logmsg("Error opening file %s error (%d) %s", dumpfile, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Failed to write request input to %s", dumpfile); return; } @@ -564,8 +567,8 @@ static void rtspd_storerequest(char *reqbuf, size_t totalsize) if(writeleft == 0) logmsg("Wrote request (%zu bytes) input to %s", totalsize, dumpfile); else if(writeleft > 0) { - logmsg("Error writing file %s error (%d) %s", - dumpfile, error, strerror(error)); + logmsg("Error writing file %s error (%d) %s", dumpfile, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Wrote only (%zu bytes) of (%zu bytes) request input to %s", totalsize-writeleft, totalsize, dumpfile); } @@ -574,14 +577,15 @@ static void rtspd_storerequest(char *reqbuf, size_t totalsize) res = fclose(dump); if(res) - logmsg("Error closing file %s error (%d) %s", - dumpfile, errno, strerror(errno)); + logmsg("Error closing file %s error (%d) %s", dumpfile, + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); } /* return 0 on success, non-zero on failure */ static int rtspd_get_request(curl_socket_t sock, struct rtspd_httprequest *req) { int error; + char errbuf[STRERROR_LEN]; int fail = 0; int done_processing = 0; char *reqbuf = req->reqbuf; @@ -642,7 +646,8 @@ static int rtspd_get_request(curl_socket_t sock, struct rtspd_httprequest *req) } else if(got < 0) { error = SOCKERRNO; - logmsg("recv() returned error (%d) %s", error, sstrerror(error)); + logmsg("recv() returned error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); fail = 1; } if(fail) { @@ -704,6 +709,7 @@ static int rtspd_send_doc(curl_socket_t sock, struct rtspd_httprequest *req) bool sendfailure = FALSE; size_t responsesize; int error = 0; + char errbuf[STRERROR_LEN]; int res; static char weare[256]; char responsedump[256]; @@ -788,7 +794,8 @@ static int rtspd_send_doc(curl_socket_t sock, struct rtspd_httprequest *req) snprintf(partbuf, sizeof(partbuf), "data%ld", req->partno); if(!stream) { error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Couldn't open test file"); return 0; } @@ -811,7 +818,8 @@ static int rtspd_send_doc(curl_socket_t sock, struct rtspd_httprequest *req) stream = test2fopen(req->testno, logdir); if(!stream) { error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Couldn't open test file"); free(ptr); return 0; @@ -851,7 +859,8 @@ static int rtspd_send_doc(curl_socket_t sock, struct rtspd_httprequest *req) dump = fopen(responsedump, "ab"); if(!dump) { error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Error opening file '%s'", responsedump); logmsg("couldn't create logfile '%s'", responsedump); free(ptr); @@ -907,8 +916,8 @@ static int rtspd_send_doc(curl_socket_t sock, struct rtspd_httprequest *req) res = fclose(dump); if(res) - logmsg("Error closing file %s error (%d) %s", - responsedump, errno, strerror(errno)); + logmsg("Error closing file %s error (%d) %s", responsedump, + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); if(got_exit_signal) { free(ptr); @@ -948,7 +957,7 @@ static int rtspd_send_doc(curl_socket_t sock, struct rtspd_httprequest *req) /* should not happen */ error = SOCKERRNO; logmsg("curlx_wait_ms() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); break; } } @@ -987,6 +996,7 @@ static int test_rtspd(int argc, char *argv[]) struct rtspd_httprequest req; int rc; int error; + char errbuf[STRERROR_LEN]; int arg = 1; memset(&req, 0, sizeof(req)); @@ -1092,7 +1102,8 @@ static int test_rtspd(int argc, char *argv[]) if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; - logmsg("Error creating socket (%d) %s", error, sstrerror(error)); + logmsg("Error creating socket (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto server_cleanup; } @@ -1101,7 +1112,7 @@ static int test_rtspd(int argc, char *argv[]) (void *)&flag, sizeof(flag))) { error = SOCKERRNO; logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto server_cleanup; } @@ -1125,8 +1136,8 @@ static int test_rtspd(int argc, char *argv[]) #endif /* USE_IPV6 */ if(rc) { error = SOCKERRNO; - logmsg("Error binding socket on port %hu (%d) %s", - port, error, sstrerror(error)); + logmsg("Error binding socket on port %hu (%d) %s", port, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto server_cleanup; } @@ -1147,7 +1158,7 @@ static int test_rtspd(int argc, char *argv[]) if(getsockname(sock, &localaddr.sa, &la_size) < 0) { error = SOCKERRNO; logmsg("getsockname() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(sock); goto server_cleanup; } @@ -1180,7 +1191,7 @@ static int test_rtspd(int argc, char *argv[]) if(rc) { error = SOCKERRNO; logmsg("listen() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto server_cleanup; } @@ -1207,7 +1218,7 @@ static int test_rtspd(int argc, char *argv[]) if(CURL_SOCKET_BAD == msgsock) { error = SOCKERRNO; logmsg("MAJOR ERROR, accept() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); break; } diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index 2ae681072e4c..3f4c9ef8b050 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -200,6 +200,7 @@ static ssize_t fullread(int filedes, void *buffer, size_t nbytes) } if(rc < 0) { + char errbuf[STRERROR_LEN]; error = errno; /* !checksrc! disable ERRNOVAR 1 */ if((error == EINTR) || (error == EAGAIN)) @@ -211,7 +212,7 @@ static ssize_t fullread(int filedes, void *buffer, size_t nbytes) } logmsg("reading from file descriptor: %d,", filedes); logmsg("unrecoverable read() failure (%d) %s", - error, strerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return -1; } @@ -253,13 +254,14 @@ static ssize_t fullwrite(int filedes, const void *buffer, size_t nbytes) } if(wc < 0) { + char errbuf[STRERROR_LEN]; error = errno; /* !checksrc! disable ERRNOVAR 1 */ if((error == EINTR) || (error == EAGAIN)) continue; logmsg("writing to file descriptor: %d,", filedes); logmsg("unrecoverable write() failure (%d) %s", - error, strerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return -1; } @@ -947,6 +949,7 @@ static bool juggle(curl_socket_t *sockfdp, int maxfd = -99; ssize_t rc; int error = 0; + char errbuf[STRERROR_LEN]; unsigned char buffer[BUFFER_SIZE]; char data[16]; @@ -1067,7 +1070,7 @@ static bool juggle(curl_socket_t *sockfdp, if(rc < 0) { logmsg("select() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return FALSE; } @@ -1172,7 +1175,8 @@ static bool juggle(curl_socket_t *sockfdp, curl_socket_t newfd = accept(sockfd, NULL, NULL); if(CURL_SOCKET_BAD == newfd) { error = SOCKERRNO; - logmsg("accept() failed with error (%d) %s", error, sstrerror(error)); + logmsg("accept() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); } else { logmsg("====> Client connect"); @@ -1226,6 +1230,7 @@ static int test_sockfilt(int argc, char *argv[]) bool juggle_again; int rc; int error; + char errbuf[STRERROR_LEN]; int arg = 1; enum sockmode mode = PASSIVE_LISTEN; /* default */ const char *addr = NULL; @@ -1345,7 +1350,8 @@ static int test_sockfilt(int argc, char *argv[]) if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; - logmsg("Error creating socket (%d) %s", error, sstrerror(error)); + logmsg("Error creating socket (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } @@ -1382,8 +1388,8 @@ static int test_sockfilt(int argc, char *argv[]) } if(rc) { error = SOCKERRNO; - logmsg("Error connecting to port %hu (%d) %s", - server_connectport, error, sstrerror(error)); + logmsg("Error connecting to port %hu (%d) %s", server_connectport, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } diff --git a/tests/server/socksd.c b/tests/server/socksd.c index 06283e042403..f16b1d79ed2e 100644 --- a/tests/server/socksd.c +++ b/tests/server/socksd.c @@ -209,9 +209,10 @@ static curl_socket_t socksconnect(unsigned short connectport, rc = connect(sock, &me.sa, sizeof(me.sa4)); if(rc) { + char errbuf[STRERROR_LEN]; int error = SOCKERRNO; - logmsg("Failed connecting to %s:%hu (%d) %s", - connectaddr, connectport, error, sstrerror(error)); + logmsg("Failed connecting to %s:%hu (%d) %s", connectaddr, connectport, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return CURL_SOCKET_BAD; } logmsg("Connected fine to %s:%d", connectaddr, connectport); @@ -621,6 +622,7 @@ static bool socksd_incoming(curl_socket_t listenfd) int i; ssize_t rc; int error = 0; + char errbuf[STRERROR_LEN]; curl_socket_t sockfd = listenfd; int maxfd = (int)sockfd; @@ -676,7 +678,7 @@ static bool socksd_incoming(curl_socket_t listenfd) if(rc < 0) { logmsg("select() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return FALSE; } @@ -685,7 +687,7 @@ static bool socksd_incoming(curl_socket_t listenfd) if(CURL_SOCKET_BAD == newfd) { error = SOCKERRNO; logmsg("accept() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); } else { curl_socket_t remotefd; @@ -738,6 +740,7 @@ static int test_socksd(int argc, char *argv[]) int wroteportfile = 0; bool juggle_again; int error; + char errbuf[STRERROR_LEN]; int arg = 1; const char *unix_socket = NULL; @@ -870,7 +873,7 @@ static int test_socksd(int argc, char *argv[]) if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; logmsg("Error creating socket (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto socks5_cleanup; } @@ -922,7 +925,8 @@ static int test_socksd(int argc, char *argv[]) #ifdef USE_UNIX_SOCKETS if(unlink_socket && socket_domain == AF_UNIX && unix_socket) { error = unlink(unix_socket); - logmsg("unlink(%s) = %d (%s)", unix_socket, error, strerror(error)); + logmsg("unlink(%s) = %d (%s)", unix_socket, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); } #endif diff --git a/tests/server/sws.c b/tests/server/sws.c index 32e82891fe21..1fbbb3c2478d 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -204,8 +204,10 @@ static int sws_parse_servercmd(struct sws_httprequest *req) req->connmon = FALSE; if(!stream) { + char errbuf[STRERROR_LEN]; error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg(" Couldn't open test file %ld", req->testno); req->open = FALSE; /* closes connection */ return 1; /* done */ @@ -706,6 +708,7 @@ static void sws_storerequest(const char *reqbuf, size_t totalsize) { int res; int error = 0; + char errbuf[STRERROR_LEN]; size_t written; size_t writeleft; FILE *dump; @@ -724,8 +727,8 @@ static void sws_storerequest(const char *reqbuf, size_t totalsize) /* !checksrc! disable ERRNOVAR 1 */ } while(!dump && ((error = errno) == EINTR)); if(!dump) { - logmsg("[2] Error opening file %s error (%d) %s", - dumpfile, error, strerror(error)); + logmsg("[2] Error opening file %s error (%d) %s", dumpfile, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Failed to write request input "); return; } @@ -744,8 +747,8 @@ static void sws_storerequest(const char *reqbuf, size_t totalsize) if(writeleft == 0) logmsg("Wrote request (%zu bytes) input to %s", totalsize, dumpfile); else if(writeleft > 0) { - logmsg("Error writing file %s error (%d) %s", - dumpfile, error, strerror(error)); + logmsg("Error writing file %s error (%d) %s", dumpfile, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Wrote only (%zu bytes) of (%zu bytes) request input to %s", totalsize-writeleft, totalsize, dumpfile); } @@ -754,8 +757,8 @@ static void sws_storerequest(const char *reqbuf, size_t totalsize) res = fclose(dump); if(res) - logmsg("Error closing file %s error (%d) %s", - dumpfile, errno, strerror(errno)); + logmsg("Error closing file %s error (%d) %s", dumpfile, + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); } static void init_httprequest(struct sws_httprequest *req) @@ -883,12 +886,14 @@ static int sws_get_request(curl_socket_t sock, struct sws_httprequest *req) fail = 1; } else if(got < 0) { + char errbuf[STRERROR_LEN]; int error = SOCKERRNO; if(EAGAIN == error || SOCKEWOULDBLOCK == error) { /* nothing to read at the moment */ return 0; } - logmsg("recv() returned error (%d) %s", error, sstrerror(error)); + logmsg("recv() returned error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); fail = 1; } if(fail) { @@ -947,6 +952,7 @@ static int sws_send_doc(curl_socket_t sock, struct sws_httprequest *req) bool sendfailure = FALSE; size_t responsesize; int error = 0; + char errbuf[STRERROR_LEN]; int res; static char weare[256]; char responsedump[256]; @@ -1027,7 +1033,8 @@ static int sws_send_doc(curl_socket_t sock, struct sws_httprequest *req) stream = test2fopen(req->testno, logdir); if(!stream) { error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return 0; } else { @@ -1049,7 +1056,8 @@ static int sws_send_doc(curl_socket_t sock, struct sws_httprequest *req) stream = test2fopen(req->testno, logdir); if(!stream) { error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); free(ptr); return 0; } @@ -1088,7 +1096,8 @@ static int sws_send_doc(curl_socket_t sock, struct sws_httprequest *req) dump = fopen(responsedump, "ab"); if(!dump) { error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg(" [5] Error opening file '%s'", responsedump); free(ptr); free(cmd); @@ -1140,8 +1149,8 @@ static int sws_send_doc(curl_socket_t sock, struct sws_httprequest *req) res = fclose(dump); if(res) - logmsg("Error closing file %s error (%d) %s", - responsedump, errno, strerror(errno)); + logmsg("Error closing file %s error (%d) %s", responsedump, + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); if(got_exit_signal) { free(ptr); @@ -1181,7 +1190,7 @@ static int sws_send_doc(curl_socket_t sock, struct sws_httprequest *req) /* should not happen */ error = SOCKERRNO; logmsg("curlx_wait_ms() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); break; } } @@ -1212,6 +1221,7 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) srvr_sockaddr_union_t serveraddr; curl_socket_t serverfd; int error; + char errbuf[STRERROR_LEN]; int rc = 0; const char *op_br = ""; const char *cl_br = ""; @@ -1234,7 +1244,7 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) if(CURL_SOCKET_BAD == serverfd) { error = SOCKERRNO; logmsg("Error creating socket for server connection (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return CURL_SOCKET_BAD; } @@ -1254,7 +1264,7 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) if(curlx_nonblock(serverfd, TRUE)) { error = SOCKERRNO; logmsg("curlx_nonblock(TRUE) failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(serverfd); return CURL_SOCKET_BAD; } @@ -1336,8 +1346,8 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) } } error: - logmsg("Error connecting to server port %hu (%d) %s", - port, error, sstrerror(error)); + logmsg("Error connecting to server port %hu (%d) %s", port, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(serverfd); return CURL_SOCKET_BAD; } @@ -1348,7 +1358,7 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) if(curlx_nonblock(serverfd, FALSE)) { error = SOCKERRNO; logmsg("curlx_nonblock(FALSE) failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(serverfd); return CURL_SOCKET_BAD; } @@ -1812,6 +1822,7 @@ static curl_socket_t accept_connection(curl_socket_t sock) { curl_socket_t msgsock = CURL_SOCKET_BAD; int error; + char errbuf[STRERROR_LEN]; int flag = 1; if(MAX_SOCKETS == num_sockets) { @@ -1834,14 +1845,14 @@ static curl_socket_t accept_connection(curl_socket_t sock) return 0; } logmsg("MAJOR ERROR, accept() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return CURL_SOCKET_BAD; } if(curlx_nonblock(msgsock, TRUE)) { error = SOCKERRNO; logmsg("curlx_nonblock failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(msgsock); return CURL_SOCKET_BAD; } @@ -1850,7 +1861,7 @@ static curl_socket_t accept_connection(curl_socket_t sock) (void *)&flag, sizeof(flag))) { error = SOCKERRNO; logmsg("setsockopt(SO_KEEPALIVE) failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(msgsock); return CURL_SOCKET_BAD; } @@ -1977,6 +1988,7 @@ static int test_sws(int argc, char *argv[]) struct sws_httprequest *req = NULL; int rc = 0; int error; + char errbuf[STRERROR_LEN]; int arg = 1; const char *connecthost = "127.0.0.1"; char port_str[11]; @@ -2152,7 +2164,8 @@ static int test_sws(int argc, char *argv[]) if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; - logmsg("Error creating socket (%d) %s", error, sstrerror(error)); + logmsg("Error creating socket (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto sws_cleanup; } @@ -2161,13 +2174,13 @@ static int test_sws(int argc, char *argv[]) (void *)&flag, sizeof(flag))) { error = SOCKERRNO; logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto sws_cleanup; } if(curlx_nonblock(sock, TRUE)) { error = SOCKERRNO; logmsg("curlx_nonblock failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto sws_cleanup; } @@ -2197,12 +2210,12 @@ static int test_sws(int argc, char *argv[]) error = SOCKERRNO; #ifdef USE_UNIX_SOCKETS if(socket_domain == AF_UNIX) - logmsg("Error binding socket on path %s (%d) %s", - unix_socket, error, sstrerror(error)); + logmsg("Error binding socket on path %s (%d) %s", unix_socket, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); else #endif - logmsg("Error binding socket on port %hu (%d) %s", - port, error, sstrerror(error)); + logmsg("Error binding socket on port %hu (%d) %s", port, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto sws_cleanup; } @@ -2223,7 +2236,7 @@ static int test_sws(int argc, char *argv[]) if(getsockname(sock, &localaddr.sa, &la_size) < 0) { error = SOCKERRNO; logmsg("getsockname() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(sock); goto sws_cleanup; } @@ -2261,7 +2274,8 @@ static int test_sws(int argc, char *argv[]) rc = listen(sock, 50); if(rc) { error = SOCKERRNO; - logmsg("listen() failed with error (%d) %s", error, sstrerror(error)); + logmsg("listen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto sws_cleanup; } @@ -2341,7 +2355,8 @@ static int test_sws(int argc, char *argv[]) if(rc < 0) { error = SOCKERRNO; - logmsg("select() failed with error (%d) %s", error, sstrerror(error)); + logmsg("select() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); goto sws_cleanup; } @@ -2446,7 +2461,8 @@ static int test_sws(int argc, char *argv[]) #ifdef USE_UNIX_SOCKETS if(unlink_socket && socket_domain == AF_UNIX && unix_socket) { rc = unlink(unix_socket); - logmsg("unlink(%s) = %d (%s)", unix_socket, rc, strerror(rc)); + logmsg("unlink(%s) = %d (%s)", unix_socket, + rc, curlx_strerror(rc, errbuf, sizeof(errbuf))); } #endif diff --git a/tests/server/tftpd.c b/tests/server/tftpd.c index 4c37685ab716..64f005dfe5f4 100644 --- a/tests/server/tftpd.c +++ b/tests/server/tftpd.c @@ -130,7 +130,7 @@ struct formats { struct errmsg { int e_code; - const char *e_msg; + char e_msg[STRERROR_LEN]; }; typedef union { @@ -174,7 +174,7 @@ static struct errmsg errmsgs[] = { { TFTP_EBADID, "Unknown transfer ID" }, { TFTP_EEXISTS, "File already exists" }, { TFTP_ENOUSER, "No such user" }, - { -1, 0 } + { -1, "" } }; static const struct formats formata[] = { @@ -548,6 +548,7 @@ static int test_tftpd(int argc, char **argv) int flag; int rc; int error; + char errbuf[STRERROR_LEN]; struct testcase test; int result = 0; srvr_sockaddr_union_t from; @@ -654,7 +655,8 @@ static int test_tftpd(int argc, char **argv) if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; - logmsg("Error creating socket (%d) %s", error, sstrerror(error)); + logmsg("Error creating socket (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); result = 1; goto tftpd_cleanup; } @@ -664,7 +666,7 @@ static int test_tftpd(int argc, char **argv) (void *)&flag, sizeof(flag))) { error = SOCKERRNO; logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); result = 1; goto tftpd_cleanup; } @@ -689,8 +691,8 @@ static int test_tftpd(int argc, char **argv) #endif /* USE_IPV6 */ if(rc) { error = SOCKERRNO; - logmsg("Error binding socket on port %hu (%d) %s", port, error, - sstrerror(error)); + logmsg("Error binding socket on port %hu (%d) %s", port, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); result = 1; goto tftpd_cleanup; } @@ -712,7 +714,7 @@ static int test_tftpd(int argc, char **argv) if(getsockname(sock, &localaddr.sa, &la_size) < 0) { error = SOCKERRNO; logmsg("getsockname() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(sock); goto tftpd_cleanup; } @@ -898,8 +900,10 @@ static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size) /* Open request dump file. */ server = fopen(dumpfile, "ab"); if(!server) { + char errbuf[STRERROR_LEN]; int error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Error opening file '%s'", dumpfile); return -1; } @@ -1005,8 +1009,10 @@ static int tftpd_parse_servercmd(struct testcase *req) stream = test2fopen(req->testno, logdir); if(!stream) { + char errbuf[STRERROR_LEN]; error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg(" Couldn't open test file %ld", req->testno); return 1; /* done */ } @@ -1107,7 +1113,6 @@ static int validate_access(struct testcase *test, else partno = 0; - logmsg("requested test number %ld part %ld", testno, partno); test->testno = testno; @@ -1120,8 +1125,10 @@ static int validate_access(struct testcase *test, snprintf(partbuf, sizeof(partbuf), "data%ld", partno); if(!stream) { + char errbuf[STRERROR_LEN]; int error = errno; - logmsg("fopen() failed with error (%d) %s", error, strerror(error)); + logmsg("fopen() failed with error (%d) %s", + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Couldn't open test file for test: %ld", testno); return TFTP_EACCESS; } @@ -1356,7 +1363,7 @@ static void nak(int error) if(pe->e_code == error) break; if(pe->e_code < 0) { - pe->e_msg = strerror(error - 100); + curlx_strerror(error - 100, pe->e_msg, sizeof(pe->e_msg)); tp->th_code = TFTP_EUNDEF; /* set 'undef' errorcode */ } length = (int)strlen(pe->e_msg); diff --git a/tests/server/util.c b/tests/server/util.c index f4802745c8d6..5abd30873834 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -123,9 +123,10 @@ void logmsg(const char *msg, ...) fclose(logfp); } else { + char errbuf[STRERROR_LEN]; int error = errno; fprintf(stderr, "fopen() failed with error (%d) %s\n", - error, strerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); fprintf(stderr, "Error opening file '%s'\n", serverlogfile); fprintf(stderr, "Msg not logged: %s %s\n", timebuf, buffer); } @@ -189,15 +190,6 @@ int win32_init(void) atexit(win32_cleanup); return 0; } - -/* socket-safe strerror (works on Winsock errors, too) */ -const char *sstrerror(int err) -{ - static char buf[512]; - return curlx_winapi_strerror(err, buf, sizeof(buf)); -} -#else -#define sstrerror(e) strerror(e) #endif /* _WIN32 */ /* fopens the test case file */ @@ -246,7 +238,9 @@ int write_pidfile(const char *filename) pid = our_getpid(); pidfile = fopen(filename, "wb"); if(!pidfile) { - logmsg("Couldn't write pid file: %s %s", filename, strerror(errno)); + char errbuf[STRERROR_LEN]; + logmsg("Couldn't write pid file: %s (%d) %s", filename, + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); return 0; /* fail */ } fprintf(pidfile, "%ld\n", (long)pid); @@ -260,7 +254,9 @@ int write_portfile(const char *filename, int port) { FILE *portfile = fopen(filename, "wb"); if(!portfile) { - logmsg("Couldn't write port file: %s %s", filename, strerror(errno)); + char errbuf[STRERROR_LEN]; + logmsg("Couldn't write port file: %s (%d) %s", filename, + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); return 0; /* fail */ } fprintf(portfile, "%d\n", port); @@ -273,6 +269,7 @@ void set_advisor_read_lock(const char *filename) { FILE *lockfile; int error = 0; + char errbuf[STRERROR_LEN]; int res; do { @@ -280,15 +277,15 @@ void set_advisor_read_lock(const char *filename) /* !checksrc! disable ERRNOVAR 1 */ } while(!lockfile && ((error = errno) == EINTR)); if(!lockfile) { - logmsg("Error creating lock file %s error (%d) %s", - filename, error, strerror(error)); + logmsg("Error creating lock file %s error (%d) %s", filename, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return; } res = fclose(lockfile); if(res) - logmsg("Error closing lock file %s error (%d) %s", - filename, errno, strerror(errno)); + logmsg("Error closing lock file %s error (%d) %s", filename, + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); } void clear_advisor_read_lock(const char *filename) @@ -306,9 +303,11 @@ void clear_advisor_read_lock(const char *filename) res = unlink(filename); /* !checksrc! disable ERRNOVAR 1 */ } while(res && ((error = errno) == EINTR)); - if(res) - logmsg("Error removing lock file %s error (%d) %s", - filename, error, strerror(error)); + if(res) { + char errbuf[STRERROR_LEN]; + logmsg("Error removing lock file %s error (%d) %s", filename, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); + } } /* vars used to keep around previous signal handlers */ @@ -566,6 +565,8 @@ static SIGHANDLER_T set_signal(int signum, SIGHANDLER_T handler, void install_signal_handlers(bool keep_sigalrm) { + char errbuf[STRERROR_LEN]; + (void)errbuf; #ifdef _WIN32 /* setup Windows exit event before any signal can trigger */ exit_event = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -576,20 +577,23 @@ void install_signal_handlers(bool keep_sigalrm) /* ignore SIGHUP signal */ old_sighup_handler = set_signal(SIGHUP, SIG_IGN, FALSE); if(old_sighup_handler == SIG_ERR) - logmsg("cannot install SIGHUP handler: %s", strerror(errno)); + logmsg("cannot install SIGHUP handler: (%d) %s", + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); #endif #ifdef SIGPIPE /* ignore SIGPIPE signal */ old_sigpipe_handler = set_signal(SIGPIPE, SIG_IGN, FALSE); if(old_sigpipe_handler == SIG_ERR) - logmsg("cannot install SIGPIPE handler: %s", strerror(errno)); + logmsg("cannot install SIGPIPE handler: (%d) %s", + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); #endif #ifdef SIGALRM if(!keep_sigalrm) { /* ignore SIGALRM signal */ old_sigalrm_handler = set_signal(SIGALRM, SIG_IGN, FALSE); if(old_sigalrm_handler == SIG_ERR) - logmsg("cannot install SIGALRM handler: %s", strerror(errno)); + logmsg("cannot install SIGALRM handler: (%d) %s", + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); } #else (void)keep_sigalrm; @@ -598,19 +602,22 @@ void install_signal_handlers(bool keep_sigalrm) /* handle SIGINT signal with our exit_signal_handler */ old_sigint_handler = set_signal(SIGINT, exit_signal_handler, TRUE); if(old_sigint_handler == SIG_ERR) - logmsg("cannot install SIGINT handler: %s", strerror(errno)); + logmsg("cannot install SIGINT handler: (%d) %s", + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); #endif #ifdef SIGTERM /* handle SIGTERM signal with our exit_signal_handler */ old_sigterm_handler = set_signal(SIGTERM, exit_signal_handler, TRUE); if(old_sigterm_handler == SIG_ERR) - logmsg("cannot install SIGTERM handler: %s", strerror(errno)); + logmsg("cannot install SIGTERM handler: (%d) %s", + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); #endif #if defined(SIGBREAK) && defined(_WIN32) /* handle SIGBREAK signal with our exit_signal_handler */ old_sigbreak_handler = set_signal(SIGBREAK, exit_signal_handler, TRUE); if(old_sigbreak_handler == SIG_ERR) - logmsg("cannot install SIGBREAK handler: %s", strerror(errno)); + logmsg("cannot install SIGBREAK handler: (%d) %s", + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); #endif #ifdef _WIN32 #ifndef UNDER_CE @@ -687,6 +694,7 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket, struct sockaddr_un *sau) { int error; + char errbuf[STRERROR_LEN]; int rc; size_t len = strlen(unix_socket); @@ -703,8 +711,8 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket, /* socket already exists. Perhaps it is stale? */ curl_socket_t unixfd = socket(AF_UNIX, SOCK_STREAM, 0); if(CURL_SOCKET_BAD == unixfd) { - logmsg("Failed to create socket at %s (%d) %s", - unix_socket, SOCKERRNO, sstrerror(SOCKERRNO)); + logmsg("Failed to create socket at %s (%d) %s", unix_socket, + SOCKERRNO, curlx_strerror(SOCKERRNO, errbuf, sizeof(errbuf))); return -1; } /* check whether the server is alive */ @@ -712,8 +720,8 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket, error = SOCKERRNO; sclose(unixfd); if(rc && error != SOCKECONNREFUSED) { - logmsg("Failed to connect to %s (%d) %s", - unix_socket, error, sstrerror(error)); + logmsg("Failed to connect to %s (%d) %s", unix_socket, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); return rc; } /* socket server is not alive, now check if it was actually a socket. */ @@ -724,8 +732,8 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket, rc = lstat(unix_socket, &statbuf); #endif if(rc) { - logmsg("Error binding socket, failed to stat %s (%d) %s", - unix_socket, errno, strerror(errno)); + logmsg("Error binding socket, failed to stat %s (%d) %s", unix_socket, + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); return rc; } #ifdef S_IFSOCK @@ -737,8 +745,8 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket, /* dead socket, cleanup and retry bind */ rc = unlink(unix_socket); if(rc) { - logmsg("Error binding socket, failed to unlink %s (%d) %s", - unix_socket, errno, strerror(errno)); + logmsg("Error binding socket, failed to unlink %s (%d) %s", unix_socket, + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); return rc; } /* stale socket is gone, retry bind */ @@ -762,6 +770,7 @@ curl_socket_t sockdaemon(curl_socket_t sock, int delay = 20; int attempt = 0; int error = 0; + char errbuf[STRERROR_LEN]; #ifndef USE_UNIX_SOCKETS (void)unix_socket; @@ -775,14 +784,14 @@ curl_socket_t sockdaemon(curl_socket_t sock, if(rc) { error = SOCKERRNO; logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); if(maxretr) { rc = curlx_wait_ms(delay); if(rc) { /* should not happen */ error = SOCKERRNO; logmsg("curlx_wait_ms() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(sock); return CURL_SOCKET_BAD; } @@ -799,7 +808,8 @@ curl_socket_t sockdaemon(curl_socket_t sock, if(rc) { logmsg("setsockopt(SO_REUSEADDR) failed %d times in %d ms. Error (%d) %s", - attempt, totdelay, error, strerror(error)); + attempt, totdelay, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); logmsg("Continuing anyway..."); } @@ -836,12 +846,12 @@ curl_socket_t sockdaemon(curl_socket_t sock, error = SOCKERRNO; #ifdef USE_UNIX_SOCKETS if(socket_domain == AF_UNIX) - logmsg("Error binding socket on path %s (%d) %s", - unix_socket, error, sstrerror(error)); + logmsg("Error binding socket on path %s (%d) %s", unix_socket, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); else #endif - logmsg("Error binding socket on port %hu (%d) %s", - *listenport, error, sstrerror(error)); + logmsg("Error binding socket on port %hu (%d) %s", *listenport, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(sock); return CURL_SOCKET_BAD; } @@ -865,7 +875,7 @@ curl_socket_t sockdaemon(curl_socket_t sock, if(getsockname(sock, &localaddr.sa, &la_size) < 0) { error = SOCKERRNO; logmsg("getsockname() failed with error (%d) %s", - error, sstrerror(error)); + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(sock); return CURL_SOCKET_BAD; } @@ -902,8 +912,8 @@ curl_socket_t sockdaemon(curl_socket_t sock, rc = listen(sock, 5); if(rc) { error = SOCKERRNO; - logmsg("listen(%ld, 5) failed with error (%d) %s", - (long)sock, error, sstrerror(error)); + logmsg("listen(%ld, 5) failed with error (%d) %s", (long)sock, + error, curlx_strerror(error, errbuf, sizeof(errbuf))); sclose(sock); return CURL_SOCKET_BAD; } From db98daab05aec251bcb6615d2d38dfebec291736 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 4 Oct 2025 12:24:57 +0200 Subject: [PATCH 285/465] src: stop overriding system printf symbols Also: - tool_operate: use the socket printf mask, drop cast. Follow-up to 4deea9396bc7dd25c6362fa746a57bf309c74ada #18814 Closes #18844 --- src/.checksrc | 8 ++++ src/config2setopts.c | 3 +- src/curlinfo.c | 1 + src/tool_cb_dbg.c | 33 +++++++-------- src/tool_cb_hdr.c | 16 ++++---- src/tool_cb_prg.c | 4 +- src/tool_cfgable.h | 18 --------- src/tool_easysrc.c | 20 +++++----- src/tool_findfile.c | 6 +-- src/tool_getparam.c | 12 +++--- src/tool_help.c | 56 +++++++++++++------------- src/tool_ipfs.c | 8 ++-- src/tool_main.c | 2 +- src/tool_msgs.c | 10 ++--- src/tool_operate.c | 43 ++++++++++---------- src/tool_operhlp.c | 4 +- src/tool_paramhlp.c | 14 +++---- src/tool_parsecfg.c | 4 +- src/tool_progress.c | 86 ++++++++++++++++++++-------------------- src/tool_setopt.c | 8 ++-- src/tool_urlglob.c | 8 ++-- src/tool_vms.c | 8 ++-- src/tool_writeout.c | 32 +++++++-------- src/tool_writeout_json.c | 4 +- src/tool_xattr.c | 2 +- 25 files changed, 203 insertions(+), 207 deletions(-) diff --git a/src/.checksrc b/src/.checksrc index 946367c4999f..4a6b707084cf 100644 --- a/src/.checksrc +++ b/src/.checksrc @@ -1 +1,9 @@ enable STDERR +banfunc aprintf +banfunc fprintf +banfunc msnprintf +banfunc mvsnprintf +banfunc printf +banfunc vaprintf +banfunc vfprintf +banfunc vprintf diff --git a/src/config2setopts.c b/src/config2setopts.c index 2a58b75772f1..5921cd73ce08 100644 --- a/src/config2setopts.c +++ b/src/config2setopts.c @@ -114,7 +114,8 @@ static char *ssl_backend(void) if(!already) { /* if there is no existing version */ const char *v = curl_version_info(CURLVERSION_NOW)->ssl_version; if(v) - msnprintf(ssl_ver, sizeof(ssl_ver), "%.*s", (int) strcspn(v, " "), v); + curl_msnprintf(ssl_ver, sizeof(ssl_ver), + "%.*s", (int)strcspn(v, " "), v); already = TRUE; } return ssl_ver; diff --git a/src/curlinfo.c b/src/curlinfo.c index 14eb2f88c3d8..da75a45876cf 100644 --- a/src/curlinfo.c +++ b/src/curlinfo.c @@ -246,6 +246,7 @@ int main(int argc, char **argv) (void)argv; for(i = 0; i < CURL_ARRAYSIZE(disabled); i++) + /* !checksrc! disable BANNEDFUNC 1 */ printf("%s\n", disabled[i]); return 0; diff --git a/src/tool_cb_dbg.c b/src/tool_cb_dbg.c index d9aa1ff07a1f..043daef26dd0 100644 --- a/src/tool_cb_dbg.c +++ b/src/tool_cb_dbg.c @@ -46,8 +46,8 @@ static const char *hms_for_sec(time_t tv_sec) if(tv_sec != cached_tv_sec) { /* !checksrc! disable BANNEDFUNC 1 */ struct tm *now = localtime(&tv_sec); /* not thread safe either */ - msnprintf(hms_buf, sizeof(hms_buf), "%02d:%02d:%02d", - now->tm_hour, now->tm_min, now->tm_sec); + curl_msnprintf(hms_buf, sizeof(hms_buf), "%02d:%02d:%02d", + now->tm_hour, now->tm_min, now->tm_sec); cached_tv_sec = tv_sec; } return hms_buf; @@ -64,7 +64,7 @@ static void log_line_start(FILE *log, const char *timebuf, "* ", "< ", "> ", "{ ", "} ", "{ ", "} " }; if((timebuf && *timebuf) || (idsbuf && *idsbuf)) - fprintf(log, "%s%s%s", timebuf, idsbuf, s_infotype[type]); + curl_mfprintf(log, "%s%s%s", timebuf, idsbuf, s_infotype[type]); else fputs(s_infotype[type], log); } @@ -96,8 +96,8 @@ int tool_debug_cb(CURL *handle, curl_infotype type, if(global->tracetime) { tv = tvrealnow(); - msnprintf(timebuf, sizeof(timebuf), "%s.%06ld ", - hms_for_sec(tv.tv_sec), (long)tv.tv_usec); + curl_msnprintf(timebuf, sizeof(timebuf), "%s.%06ld ", + hms_for_sec(tv.tv_sec), (long)tv.tv_usec); } else timebuf[0] = 0; @@ -106,11 +106,11 @@ int tool_debug_cb(CURL *handle, curl_infotype type, !curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) { if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) && conn_id >= 0) { - msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, - xfer_id, conn_id); + curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, + xfer_id, conn_id); } else { - msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id); + curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id); } } else @@ -184,7 +184,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type, ((output != tool_stderr) && (output != stdout))) { if(!newl) log_line_start(output, timebuf, idsbuf, type); - fprintf(output, "[%zu bytes data]\n", size); + curl_mfprintf(output, "[%zu bytes data]\n", size); newl = FALSE; traced_data = TRUE; } @@ -201,7 +201,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type, switch(type) { case CURLINFO_TEXT: - fprintf(output, "%s%s* %.*s", timebuf, idsbuf, (int)size, data); + curl_mfprintf(output, "%s%s* %.*s", timebuf, idsbuf, (int)size, data); FALLTHROUGH(); default: /* in case a new one is introduced to shock us */ return 0; @@ -244,18 +244,18 @@ static void dump(const char *timebuf, const char *idsbuf, const char *text, /* without the hex output, we can fit more on screen */ width = 0x40; - fprintf(stream, "%s%s%s, %zu bytes (0x%zx)\n", timebuf, idsbuf, - text, size, size); + curl_mfprintf(stream, "%s%s%s, %zu bytes (0x%zx)\n", timebuf, idsbuf, + text, size, size); for(i = 0; i < size; i += width) { - fprintf(stream, "%04zx: ", i); + curl_mfprintf(stream, "%04zx: ", i); if(tracetype == TRACE_BIN) { /* hex not disabled, show it */ for(c = 0; c < width; c++) if(i + c < size) - fprintf(stream, "%02x ", ptr[i + c]); + curl_mfprintf(stream, "%02x ", ptr[i + c]); else fputs(" ", stream); } @@ -269,8 +269,9 @@ static void dump(const char *timebuf, const char *idsbuf, const char *text, break; } (void)infotype; - fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ? - ptr[i + c] : UNPRINTABLE_CHAR); + curl_mfprintf(stream, "%c", + ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ? + ptr[i + c] : UNPRINTABLE_CHAR); /* check again for 0D0A, to avoid an extra \n if it is at width */ if((tracetype == TRACE_ASCII) && (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) && diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c index 7781e4dc3ccc..2ea88017051e 100644 --- a/src/tool_cb_hdr.c +++ b/src/tool_cb_hdr.c @@ -217,8 +217,8 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) } if(per->config->output_dir) { - outs->filename = aprintf("%s/%s", per->config->output_dir, - filename); + outs->filename = curl_maprintf("%s/%s", per->config->output_dir, + filename); free(filename); if(!outs->filename) return CURL_WRITEFUNC_ERROR; @@ -248,7 +248,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) hdrcbdata->config->show_headers) { /* still awaiting the Content-Disposition header, store the header in memory. Since it is not null-terminated, we need an extra dance. */ - char *clone = aprintf("%.*s", (int)cb, str); + char *clone = curl_maprintf("%.*s", (int)cb, str); if(clone) { struct curl_slist *old = hdrcbdata->headlist; hdrcbdata->headlist = curl_slist_append(old, clone); @@ -295,7 +295,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) value = memchr(ptr, ':', cb); if(value) { size_t namelen = value - ptr; - fprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", (int)namelen, ptr); + curl_mfprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", (int)namelen, ptr); #ifndef LINK fwrite(&value[1], cb - namelen - 1, 1, outs->stream); #else @@ -461,10 +461,10 @@ static void write_linked_location(CURL *curl, const char *location, !strcmp("https", scheme) || !strcmp("ftp", scheme) || !strcmp("ftps", scheme)) { - fprintf(stream, "%.*s" LINK "%s" LINKST "%.*s" LINKOFF, - space_skipped, location, - finalurl, - (int)loclen - space_skipped, loc); + curl_mfprintf(stream, "%.*s" LINK "%s" LINKST "%.*s" LINKOFF, + space_skipped, location, + finalurl, + (int)loclen - space_skipped, loc); goto locdone; } diff --git a/src/tool_cb_prg.c b/src/tool_cb_prg.c index c6ee6b2822f7..dd460a4bf6ed 100644 --- a/src/tool_cb_prg.c +++ b/src/tool_cb_prg.c @@ -208,12 +208,12 @@ int tool_progress_cb(void *clientp, num = MAX_BARLENGTH; memset(line, '#', num); line[num] = '\0'; - msnprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth); + curl_msnprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth); #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wformat-nonliteral" #endif - fprintf(bar->out, format, line, percent); + curl_mfprintf(bar->out, format, line, percent); #ifdef __clang__ #pragma clang diagnostic pop #endif diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 3b2ac93a74de..762837055106 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -39,24 +39,6 @@ #endif #endif -/* make the tool use the libcurl *printf family */ -# undef printf -# undef fprintf -# undef msnprintf -# undef vprintf -# undef vfprintf -# undef mvsnprintf -# undef aprintf -# undef vaprintf -# define printf curl_mprintf -# define fprintf curl_mfprintf -# define msnprintf curl_msnprintf -# define vprintf curl_mvprintf -# define vfprintf curl_mvfprintf -# define mvsnprintf curl_mvsnprintf -# define aprintf curl_maprintf -# define vaprintf curl_mvaprintf - #define checkprefix(a,b) curl_strnequal(b, STRCONST(a)) #define tool_safefree(ptr) \ diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c index bff251e6b03e..65d01d5f85a6 100644 --- a/src/tool_easysrc.c +++ b/src/tool_easysrc.c @@ -109,7 +109,7 @@ CURLcode easysrc_addf(struct slist_wc **plist, const char *fmt, ...) char *bufp; va_list ap; va_start(ap, fmt); - bufp = vaprintf(fmt, ap); + bufp = curl_mvaprintf(fmt, ap); va_end(ap); if(!bufp) { ret = CURLE_OUT_OF_MEMORY; @@ -190,41 +190,41 @@ void dumpeasysrc(void) const char *c; for(i = 0; ((c = srchead[i]) != NULL); i++) - fprintf(out, "%s\n", c); + curl_mfprintf(out, "%s\n", c); /* Declare variables used for complex setopt values */ if(easysrc_decl) { for(ptr = easysrc_decl->first; ptr; ptr = ptr->next) - fprintf(out, " %s\n", ptr->data); + curl_mfprintf(out, " %s\n", ptr->data); } /* Set up complex values for setopt calls */ if(easysrc_data) { - fprintf(out, "\n"); + curl_mfprintf(out, "\n"); for(ptr = easysrc_data->first; ptr; ptr = ptr->next) - fprintf(out, " %s\n", ptr->data); + curl_mfprintf(out, " %s\n", ptr->data); } - fprintf(out, "\n"); + curl_mfprintf(out, "\n"); if(easysrc_code) { for(ptr = easysrc_code->first; ptr; ptr = ptr->next) { if(ptr->data[0]) { - fprintf(out, " %s\n", ptr->data); + curl_mfprintf(out, " %s\n", ptr->data); } else { - fprintf(out, "\n"); + curl_mfprintf(out, "\n"); } } } if(easysrc_clean) { for(ptr = easysrc_clean->first; ptr; ptr = ptr->next) - fprintf(out, " %s\n", ptr->data); + curl_mfprintf(out, " %s\n", ptr->data); } for(i = 0; ((c = srcend[i]) != NULL); i++) - fprintf(out, "%s\n", c); + curl_mfprintf(out, "%s\n", c); if(fopened) curlx_fclose(out); diff --git a/src/tool_findfile.c b/src/tool_findfile.c index 7705ab7d926f..02898a8fb1b5 100644 --- a/src/tool_findfile.c +++ b/src/tool_findfile.c @@ -69,9 +69,9 @@ static char *checkhome(const char *home, const char *fname, bool dotscore) for(i = 0; i < (dotscore ? 2 : 1); i++) { char *c; if(dotscore) - c = aprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]); + c = curl_maprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]); else - c = aprintf("%s" DIR_CHAR "%s", home, fname); + c = curl_maprintf("%s" DIR_CHAR "%s", home, fname); if(c) { int fd = curlx_open(c, O_RDONLY); if(fd >= 0) { @@ -115,7 +115,7 @@ char *findfile(const char *fname, int dotscore) continue; } if(conf_list[i].append) { - char *c = aprintf("%s%s", home, conf_list[i].append); + char *c = curl_maprintf("%s%s", home, conf_list[i].append); curl_free(home); if(!c) return NULL; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 0fdd6373e566..a54d3f804c8c 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -751,8 +751,8 @@ static CURLcode set_trace_config(const char *token) } else { char buffer[64]; - msnprintf(buffer, sizeof(buffer), "%c%.*s,-lib-ids", toggle ? '+' : '-', - (int)len, name); + curl_msnprintf(buffer, sizeof(buffer), "%c%.*s,-lib-ids", + toggle ? '+' : '-', (int)len, name); result = curl_global_trace(buffer); if(result) goto out; @@ -1140,7 +1140,7 @@ static ParameterError parse_localport(struct OperationConfig *config, if(ISBLANK(*pp)) pp++; } - msnprintf(buffer, sizeof(buffer), "%.*s", (int)plen, nextarg); + curl_msnprintf(buffer, sizeof(buffer), "%.*s", (int)plen, nextarg); if(str2unummax(&config->localport, buffer, 65535)) return PARAM_BAD_USE; if(!pp) @@ -1222,7 +1222,7 @@ static ParameterError parse_ech(struct OperationConfig *config, curlx_fclose(file); if(err) return err; - config->ech_config = aprintf("ecl:%s",tmpcfg); + config->ech_config = curl_maprintf("ecl:%s",tmpcfg); free(tmpcfg); if(!config->ech_config) return PARAM_NO_MEM; @@ -1405,8 +1405,8 @@ static ParameterError parse_range(struct OperationConfig *config, char buffer[32]; warnf("A specified range MUST include at least one dash (-). " "Appending one for you"); - msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", - value); + curl_msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", + value); free(config->range); config->range = strdup(buffer); if(!config->range) diff --git a/src/tool_help.c b/src/tool_help.c index 58d3a2c1f2fc..7a3a4a3bf430 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -100,7 +100,7 @@ static void print_category(unsigned int category, unsigned int cols) else opt = 0; } - printf(" %-*s %s\n", (int)opt, helptext[i].opt, helptext[i].desc); + curl_mprintf(" %-*s %s\n", (int)opt, helptext[i].opt, helptext[i].desc); } } @@ -110,7 +110,7 @@ static int get_category_content(const char *category, unsigned int cols) unsigned int i; for(i = 0; i < CURL_ARRAYSIZE(categories); ++i) if(curl_strequal(categories[i].opt, category)) { - printf("%s: %s\n", categories[i].opt, categories[i].desc); + curl_mprintf("%s: %s\n", categories[i].opt, categories[i].desc); print_category(categories[i].category, cols); return 0; } @@ -122,7 +122,7 @@ static void get_categories(void) { unsigned int i; for(i = 0; i < CURL_ARRAYSIZE(categories); ++i) - printf(" %-11s %s\n", categories[i].opt, categories[i].desc); + curl_mprintf(" %-11s %s\n", categories[i].opt, categories[i].desc); } /* Prints all categories as a comma-separated list of given width */ @@ -135,18 +135,18 @@ static void get_categories_list(unsigned int width) if(i == CURL_ARRAYSIZE(categories) - 1) { /* final category */ if(col + len + 1 < width) - printf("%s.\n", categories[i].opt); + curl_mprintf("%s.\n", categories[i].opt); else /* start a new line first */ - printf("\n%s.\n", categories[i].opt); + curl_mprintf("\n%s.\n", categories[i].opt); } else if(col + len + 2 < width) { - printf("%s, ", categories[i].opt); + curl_mprintf("%s, ", categories[i].opt); col += len + 2; } else { /* start a new line first */ - printf("\n%s, ", categories[i].opt); + curl_mprintf("\n%s, ", categories[i].opt); col = len + 2; } } @@ -268,17 +268,17 @@ void tool_help(const char *category) else if(!category[2]) a = findshortopt(category[1]); if(!a) { - fprintf(tool_stderr, "Incorrect option name to show help for," - " see curl -h\n"); + curl_mfprintf(tool_stderr, "Incorrect option name to show help for," + " see curl -h\n"); } else { char cmdbuf[80]; if(a->letter != ' ') - msnprintf(cmdbuf, sizeof(cmdbuf), "\n -%c, --", a->letter); + curl_msnprintf(cmdbuf, sizeof(cmdbuf), "\n -%c, --", a->letter); else if(a->desc & ARG_NO) - msnprintf(cmdbuf, sizeof(cmdbuf), "\n --no-%s", a->lname); + curl_msnprintf(cmdbuf, sizeof(cmdbuf), "\n --no-%s", a->lname); else - msnprintf(cmdbuf, sizeof(cmdbuf), "\n %s", category); + curl_msnprintf(cmdbuf, sizeof(cmdbuf), "\n %s", category); #ifdef USE_MANUAL if(a->cmd == C_XATTR) /* this is the last option, which then ends when FILES starts */ @@ -288,8 +288,8 @@ void tool_help(const char *category) #endif } #else - fprintf(tool_stderr, "Cannot comply. " - "This curl was built without built-in manual\n"); + curl_mfprintf(tool_stderr, "Cannot comply. " + "This curl was built without built-in manual\n"); #endif } /* Otherwise print category and handle the case if the cat was not found */ @@ -312,15 +312,15 @@ void tool_version_info(void) { const char *const *builtin; if(is_debug()) - fprintf(tool_stderr, "WARNING: this libcurl is Debug-enabled, " - "do not use in production\n\n"); + curl_mfprintf(tool_stderr, "WARNING: this libcurl is Debug-enabled, " + "do not use in production\n\n"); - printf(CURL_ID "%s\n", curl_version()); + curl_mprintf(CURL_ID "%s\n", curl_version()); #ifdef CURL_PATCHSTAMP - printf("Release-Date: %s, security patched: %s\n", - LIBCURL_TIMESTAMP, CURL_PATCHSTAMP); + curl_mprintf("Release-Date: %s, security patched: %s\n", + LIBCURL_TIMESTAMP, CURL_PATCHSTAMP); #else - printf("Release-Date: %s\n", LIBCURL_TIMESTAMP); + curl_mprintf("Release-Date: %s\n", LIBCURL_TIMESTAMP); #endif if(built_in_protos[0]) { #ifndef CURL_DISABLE_IPFS @@ -339,15 +339,15 @@ void tool_version_info(void) } } #endif /* !CURL_DISABLE_IPFS */ - printf("Protocols:"); + curl_mprintf("Protocols:"); for(builtin = built_in_protos; *builtin; ++builtin) { /* Special case: do not list rtmp?* protocols. They may only appear together with "rtmp" */ if(!curl_strnequal(*builtin, "rtmp", 4) || !builtin[0][4]) - printf(" %s", *builtin); + curl_mprintf(" %s", *builtin); #ifndef CURL_DISABLE_IPFS if(insert && insert == *builtin) { - printf(" ipfs ipns"); + curl_mprintf(" ipfs ipns"); insert = NULL; } #endif /* !CURL_DISABLE_IPFS */ @@ -371,16 +371,16 @@ void tool_version_info(void) feat_ext[feat_ext_count] = NULL; qsort((void *)feat_ext, feat_ext_count, sizeof(*feat_ext), struplocompare4sort); - printf("Features:"); + curl_mprintf("Features:"); for(builtin = feat_ext; *builtin; ++builtin) - printf(" %s", *builtin); + curl_mprintf(" %s", *builtin); puts(""); /* newline */ free((void *)feat_ext); } } if(strcmp(CURL_VERSION, curlinfo->version)) { - printf("WARNING: curl and libcurl versions do not match. " - "Functionality may be affected.\n"); + curl_mprintf("WARNING: curl and libcurl versions do not match. " + "Functionality may be affected.\n"); } } @@ -395,7 +395,7 @@ void tool_list_engines(void) puts("Build-time engines:"); if(engines) { for(; engines; engines = engines->next) - printf(" %s\n", engines->data); + curl_mprintf(" %s\n", engines->data); } else { puts(" "); diff --git a/src/tool_ipfs.c b/src/tool_ipfs.c index c2f1b165239c..13124133eaf3 100644 --- a/src/tool_ipfs.c +++ b/src/tool_ipfs.c @@ -76,14 +76,14 @@ static char *ipfs_gateway(void) if(!ipfs_path) { char *home = getenv("HOME"); if(home && *home) - ipfs_path = aprintf("%s/.ipfs/", home); + ipfs_path = curl_maprintf("%s/.ipfs/", home); /* fallback to "~/.ipfs", as that is the default location. */ } if(!ipfs_path || ensure_trailing_slash(&ipfs_path)) goto fail; - gateway_composed_file_path = aprintf("%sgateway", ipfs_path); + gateway_composed_file_path = curl_maprintf("%sgateway", ipfs_path); if(!gateway_composed_file_path) goto fail; @@ -233,8 +233,8 @@ CURLcode ipfs_url_rewrite(CURLU *uh, const char *protocol, char **url, /* ensure the gateway path ends with a trailing slash */ ensure_trailing_slash(&gwpath); - pathbuffer = aprintf("%s%s/%s%s", gwpath, protocol, cid, - inputpath ? inputpath : ""); + pathbuffer = curl_maprintf("%s%s/%s%s", gwpath, protocol, cid, + inputpath ? inputpath : ""); if(!pathbuffer) { goto clean; } diff --git a/src/tool_main.c b/src/tool_main.c index 0ad40dc29d8f..4e70c1081cfa 100644 --- a/src/tool_main.c +++ b/src/tool_main.c @@ -165,7 +165,7 @@ int main(int argc, char *argv[]) if(argc == 2 && !_tcscmp(argv[1], _T("--dump-module-paths"))) { struct curl_slist *item, *head = GetLoadedModulePaths(); for(item = head; item; item = item->next) - printf("%s\n", item->data); + curl_mprintf("%s\n", item->data); curl_slist_free_all(head); return head ? 0 : 1; } diff --git a/src/tool_msgs.c b/src/tool_msgs.c index de0c1431e2a2..f83cdc76c1b8 100644 --- a/src/tool_msgs.c +++ b/src/tool_msgs.c @@ -49,7 +49,7 @@ static void voutf(const char *prefix, char *ptr; char *print_buffer; - print_buffer = vaprintf(fmt, ap); + print_buffer = curl_mvaprintf(fmt, ap); if(!print_buffer) return; len = strlen(print_buffer); @@ -120,15 +120,15 @@ void helpf(const char *fmt, ...) va_start(ap, fmt); DEBUGASSERT(!strchr(fmt, '\n')); fputs("curl: ", tool_stderr); /* prefix it */ - vfprintf(tool_stderr, fmt, ap); + curl_mvfprintf(tool_stderr, fmt, ap); va_end(ap); fputs("\n", tool_stderr); /* newline it */ } - fprintf(tool_stderr, "curl: try 'curl --help' " + curl_mfprintf(tool_stderr, "curl: try 'curl --help' " #ifdef USE_MANUAL - "or 'curl --manual' " + "or 'curl --manual' " #endif - "for more information\n"); + "for more information\n"); } /* diff --git a/src/tool_operate.c b/src/tool_operate.c index 2d539de7b58c..b49f45fd9904 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -584,8 +584,8 @@ static CURLcode post_per_transfer(struct per_transfer *per, if(!config->synthetic_error && result && (!global->silent || global->showerror)) { const char *msg = per->errorbuffer; - fprintf(tool_stderr, "curl: (%d) %s\n", result, - msg[0] ? msg : curl_easy_strerror(result)); + curl_mfprintf(tool_stderr, "curl: (%d) %s\n", result, + msg[0] ? msg : curl_easy_strerror(result)); if(result == CURLE_PEER_FAILED_VERIFICATION) fputs(CURL_CA_CERT_ERRORMSG, tool_stderr); } @@ -595,9 +595,9 @@ static CURLcode post_per_transfer(struct per_transfer *per, curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); if(code >= 400) { if(!global->silent || global->showerror) - fprintf(tool_stderr, - "curl: (%d) The requested URL returned error: %ld\n", - CURLE_HTTP_RETURNED_ERROR, code); + curl_mfprintf(tool_stderr, + "curl: (%d) The requested URL returned error: %ld\n", + CURLE_HTTP_RETURNED_ERROR, code); result = CURLE_HTTP_RETURNED_ERROR; } } @@ -806,11 +806,11 @@ static CURLcode etag_compare(struct OperationConfig *config) if((PARAM_OK == file2string(&etag_from_file, file)) && etag_from_file) { - header = aprintf("If-None-Match: %s", etag_from_file); + header = curl_maprintf("If-None-Match: %s", etag_from_file); tool_safefree(etag_from_file); } else - header = aprintf("If-None-Match: \"\""); + header = curl_maprintf("If-None-Match: \"\""); if(!header) { if(file) @@ -955,7 +955,7 @@ static CURLcode setup_outfile(struct OperationConfig *config, DEBUGASSERT(per->outfile); if(config->output_dir && *config->output_dir) { - char *d = aprintf("%s/%s", config->output_dir, per->outfile); + char *d = curl_maprintf("%s/%s", config->output_dir, per->outfile); if(!d) return CURLE_WRITE_ERROR; free(per->outfile); @@ -1505,7 +1505,7 @@ static void on_uv_timeout(uv_timer_t *req) { struct datauv *uv = (struct datauv *) req->data; #if DEBUG_UV - fprintf(tool_stderr, "parallel_event: on_uv_timeout\n"); + curl_mfprintf(tool_stderr, "parallel_event: on_uv_timeout\n"); #endif if(uv && uv->s) { curl_multi_socket_action(uv->s->multi, CURL_SOCKET_TIMEOUT, 0, @@ -1520,7 +1520,7 @@ static int cb_timeout(CURLM *multi, long timeout_ms, void *userp) struct datauv *uv = userp; (void)multi; #if DEBUG_UV - fprintf(tool_stderr, "parallel_event: cb_timeout=%ld\n", timeout_ms); + curl_mfprintf(tool_stderr, "parallel_event: cb_timeout=%ld\n", timeout_ms); #endif if(timeout_ms < 0) uv_timer_stop(&uv->timeout); @@ -1571,8 +1571,8 @@ static int cb_socket(CURL *easy, curl_socket_t s, int action, (void)easy; #if DEBUG_UV - fprintf(tool_stderr, "parallel_event: cb_socket, fd=%d, action=%x, p=%p\n", - (int)s, action, socketp); + curl_mfprintf(tool_stderr, "parallel_event: cb_socket, " + "fd=%" FMT_SOCKET_T ", action=%x, p=%p\n", s, action, socketp); #endif switch(action) { case CURL_POLL_IN: @@ -1632,12 +1632,13 @@ static CURLcode parallel_event(struct parastate *s) while(!s->mcode && (s->still_running || s->more_transfers)) { #if DEBUG_UV - fprintf(tool_stderr, "parallel_event: uv_run(), mcode=%d, %d running, " - "%d more\n", s->mcode, uv.s->still_running, s->more_transfers); + curl_mfprintf(tool_stderr, "parallel_event: uv_run(), " + "mcode=%d, %d running, %d more\n", + s->mcode, uv.s->still_running, s->more_transfers); #endif uv_run(uv.loop, UV_RUN_DEFAULT); #if DEBUG_UV - fprintf(tool_stderr, "parallel_event: uv_run() returned\n"); + curl_mfprintf(tool_stderr, "parallel_event: uv_run() returned\n"); #endif result = check_finished(s); @@ -1680,8 +1681,8 @@ static CURLcode parallel_event(struct parastate *s) curl_multi_cleanup(s->multi); #if DEBUG_UV - fprintf(tool_stderr, "DONE parallel_event -> %d, mcode=%d, %d running, " - "%d more\n", + curl_mfprintf(tool_stderr, "DONE parallel_event -> %d, mcode=%d, " + "%d running, %d more\n", result, s->mcode, uv.s->still_running, s->more_transfers); #endif return result; @@ -1708,9 +1709,9 @@ static CURLcode check_finished(struct parastate *s) curl_multi_remove_handle(s->multi, easy); if(ended->abort && (tres == CURLE_ABORTED_BY_CALLBACK)) { - msnprintf(ended->errorbuffer, CURL_ERROR_SIZE, - "Transfer aborted due to critical error " - "in another transfer"); + curl_msnprintf(ended->errorbuffer, CURL_ERROR_SIZE, + "Transfer aborted due to critical error " + "in another transfer"); } tres = post_per_transfer(ended, tres, &retry, &delay); progress_finalize(ended); /* before it goes away */ @@ -2190,7 +2191,7 @@ CURLcode operate(int argc, argv_item_t argv[]) /* Check if we were asked to dump the embedded CA bundle */ else if(res == PARAM_CA_EMBED_REQUESTED) { #ifdef CURL_CA_EMBED - printf("%s", curl_ca_embed); + curl_mprintf("%s", curl_ca_embed); #endif } else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL) diff --git a/src/tool_operhlp.c b/src/tool_operhlp.c index fdf647236978..a83239054089 100644 --- a/src/tool_operhlp.c +++ b/src/tool_operhlp.c @@ -134,10 +134,10 @@ CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename) char *newurl; if(ptr) /* there is a trailing slash on the path */ - newpath = aprintf("%s%s", path, encfile); + newpath = curl_maprintf("%s%s", path, encfile); else /* there is no trailing slash on the path */ - newpath = aprintf("%s/%s", path, encfile); + newpath = curl_maprintf("%s/%s", path, encfile); curl_free(encfile); diff --git a/src/tool_paramhlp.c b/src/tool_paramhlp.c index a1505115b3fa..85c24f2ea355 100644 --- a/src/tool_paramhlp.c +++ b/src/tool_paramhlp.c @@ -475,7 +475,7 @@ ParameterError proto2num(const char * const *val, char **ostr, const char *str) else { char buffer[32]; const char *p; - msnprintf(buffer, sizeof(buffer), "%.*s", (int)plen, str); + curl_msnprintf(buffer, sizeof(buffer), "%.*s", (int)plen, str); p = proto_token(buffer); @@ -584,13 +584,13 @@ static CURLcode checkpasswd(const char *kind, /* for what purpose */ /* build a nice-looking prompt */ if(!i && last) - msnprintf(prompt, sizeof(prompt), - "Enter %s password for user '%s':", - kind, *userpwd); + curl_msnprintf(prompt, sizeof(prompt), + "Enter %s password for user '%s':", + kind, *userpwd); else - msnprintf(prompt, sizeof(prompt), - "Enter %s password for user '%s' on URL #%zu:", - kind, *userpwd, i + 1); + curl_msnprintf(prompt, sizeof(prompt), + "Enter %s password for user '%s' on URL #%zu:", + kind, *userpwd, i + 1); /* get password */ getpass_r(prompt, passwd, sizeof(passwd)); diff --git a/src/tool_parsecfg.c b/src/tool_parsecfg.c index 632286530a12..5cf3527ce2a5 100644 --- a/src/tool_parsecfg.c +++ b/src/tool_parsecfg.c @@ -156,7 +156,7 @@ int parseconfig(const char *filename) *line++ = '\0'; /* null-terminate, we have a local copy of the data */ #ifdef DEBUG_CONFIG - fprintf(tool_stderr, "GOT: %s\n", option); + curl_mfprintf(tool_stderr, "GOT: %s\n", option); #endif /* pass spaces and separator(s) */ @@ -204,7 +204,7 @@ int parseconfig(const char *filename) } #ifdef DEBUG_CONFIG - fprintf(tool_stderr, "PARAM: \"%s\"\n",(param ? param : "(null)")); + curl_mfprintf(tool_stderr, "PARAM: \"%s\"\n",(param ? param : "(null)")); #endif res = getparameter(option, param, &usedarg, config); config = global->last; diff --git a/src/tool_progress.c b/src/tool_progress.c index d29bfdc4dad5..2fcc7ff85e3d 100644 --- a/src/tool_progress.c +++ b/src/tool_progress.c @@ -35,7 +35,7 @@ static char *max5data(curl_off_t bytes, char *max5) const char unit[] = { 'k', 'M', 'G', 'T', 'P', 0 }; int k = 0; if(bytes < 100000) { - msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); + curl_msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); return max5; } @@ -43,14 +43,15 @@ static char *max5data(curl_off_t bytes, char *max5) curl_off_t nbytes = bytes / 1024; if(nbytes < 100) { /* display with a decimal */ - msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" - CURL_FORMAT_CURL_OFF_T "%c", bytes/1024, - (bytes%1024) / (1024/10), unit[k]); + curl_msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + CURL_FORMAT_CURL_OFF_T "%c", bytes/1024, + (bytes%1024) / (1024/10), unit[k]); break; } else if(nbytes < 10000) { /* no decimals */ - msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "%c", nbytes, unit[k]); + curl_msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "%c", nbytes, + unit[k]); break; } bytes = nbytes; @@ -97,8 +98,9 @@ static void time2str(char *r, curl_off_t seconds) if(h <= 99) { curl_off_t m = (seconds - (h * 3600)) / 60; curl_off_t s = (seconds - (h * 3600)) - (m * 60); - msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T - ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); + curl_msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T + ":%02" CURL_FORMAT_CURL_OFF_T + ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); } else { /* this equals to more than 99 hours, switch to a more suitable output @@ -106,10 +108,10 @@ static void time2str(char *r, curl_off_t seconds) curl_off_t d = seconds / 86400; h = (seconds - (d * 86400)) / 3600; if(d <= 999) - msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T - "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); + curl_msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T + "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); else - msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); + curl_msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); } } @@ -204,16 +206,16 @@ bool progress_meter(CURLM *multi, } } if(dlknown && all_dltotal) - msnprintf(dlpercen, sizeof(dlpercen), "%3" CURL_FORMAT_CURL_OFF_T, - all_dlnow < (CURL_OFF_T_MAX/100) ? - (all_dlnow * 100 / all_dltotal) : - (all_dlnow / (all_dltotal/100))); + curl_msnprintf(dlpercen, sizeof(dlpercen), "%3" CURL_FORMAT_CURL_OFF_T, + all_dlnow < (CURL_OFF_T_MAX/100) ? + (all_dlnow * 100 / all_dltotal) : + (all_dlnow / (all_dltotal/100))); if(ulknown && all_ultotal) - msnprintf(ulpercen, sizeof(ulpercen), "%3" CURL_FORMAT_CURL_OFF_T, - all_ulnow < (CURL_OFF_T_MAX/100) ? - (all_ulnow * 100 / all_ultotal) : - (all_ulnow / (all_ultotal/100))); + curl_msnprintf(ulpercen, sizeof(ulpercen), "%3" CURL_FORMAT_CURL_OFF_T, + all_ulnow < (CURL_OFF_T_MAX/100) ? + (all_ulnow * 100 / all_ultotal) : + (all_ulnow / (all_ultotal/100))); /* get the transfer speed, the higher of the two */ @@ -266,31 +268,31 @@ bool progress_meter(CURLM *multi, (void)curl_multi_get_offt(multi, CURLMINFO_XFERS_ADDED, &xfers_added); (void)curl_multi_get_offt(multi, CURLMINFO_XFERS_RUNNING, &xfers_running); - fprintf(tool_stderr, - "\r" - "%-3s " /* percent downloaded */ - "%-3s " /* percent uploaded */ - "%s " /* Dled */ - "%s " /* Uled */ - "%5" CURL_FORMAT_CURL_OFF_T " " /* Xfers */ - "%5" CURL_FORMAT_CURL_OFF_T " " /* Live */ - " %s " /* Total time */ - "%s " /* Current time */ - "%s " /* Time left */ - "%s " /* Speed */ - "%5s" /* final newline */, + curl_mfprintf(tool_stderr, + "\r" + "%-3s " /* percent downloaded */ + "%-3s " /* percent uploaded */ + "%s " /* Dled */ + "%s " /* Uled */ + "%5" CURL_FORMAT_CURL_OFF_T " " /* Xfers */ + "%5" CURL_FORMAT_CURL_OFF_T " " /* Live */ + " %s " /* Total time */ + "%s " /* Current time */ + "%s " /* Time left */ + "%s " /* Speed */ + "%5s" /* final newline */, - dlpercen, /* 3 letters */ - ulpercen, /* 3 letters */ - max5data(all_dlnow, buffer[0]), - max5data(all_ulnow, buffer[1]), - xfers_added, - xfers_running, - time_total, - time_spent, - time_left, - max5data(speed, buffer[2]), /* speed */ - final ? "\n" :""); + dlpercen, /* 3 letters */ + ulpercen, /* 3 letters */ + max5data(all_dlnow, buffer[0]), + max5data(all_ulnow, buffer[1]), + xfers_added, + xfers_running, + time_total, + time_spent, + time_left, + max5data(speed, buffer[2]), /* speed */ + final ? "\n" :""); return TRUE; } return FALSE; diff --git a/src/tool_setopt.c b/src/tool_setopt.c index b1b3f0a8b74a..c3e7213dc85e 100644 --- a/src/tool_setopt.c +++ b/src/tool_setopt.c @@ -334,8 +334,8 @@ CURLcode tool_setopt_bitmask(CURL *curl, const char *name, CURLoption tag, char preamble[80]; unsigned long rest = (unsigned long)lval; const struct NameValueUnsigned *nv = NULL; - msnprintf(preamble, sizeof(preamble), - "curl_easy_setopt(hnd, %s, ", name); + curl_msnprintf(preamble, sizeof(preamble), + "curl_easy_setopt(hnd, %s, ", name); for(nv = nvlist; nv->name; nv++) { if((nv->value & ~ rest) == 0) { /* all value flags contained in rest */ @@ -345,8 +345,8 @@ CURLcode tool_setopt_bitmask(CURL *curl, const char *name, CURLoption tag, if(!rest || ret) break; /* handled them all */ /* replace with all spaces for continuation line */ - msnprintf(preamble, sizeof(preamble), "%*s", (int)strlen(preamble), - ""); + curl_msnprintf(preamble, sizeof(preamble), "%*s", + (int)strlen(preamble), ""); } } /* If any bits have no definition, output an explicit value. diff --git a/src/tool_urlglob.c b/src/tool_urlglob.c index ac836dcdfffc..4a28376e1444 100644 --- a/src/tool_urlglob.c +++ b/src/tool_urlglob.c @@ -466,16 +466,16 @@ CURLcode glob_url(struct URLGlob *glob, char *url, curl_off_t *urlnum, char text[512]; const char *t; if(glob->pos) { - msnprintf(text, sizeof(text), "%s in URL position %zu:\n%s\n%*s^", - glob->error, - glob->pos, url, (int)glob->pos - 1, " "); + curl_msnprintf(text, sizeof(text), "%s in URL position %zu:\n%s\n%*s^", + glob->error, + glob->pos, url, (int)glob->pos - 1, " "); t = text; } else t = glob->error; /* send error description to the error-stream */ - fprintf(error, "curl: (%d) %s\n", res, t); + curl_mfprintf(error, "curl: (%d) %s\n", res, t); } /* it failed, we cleanup */ glob_cleanup(glob); diff --git a/src/tool_vms.c b/src/tool_vms.c index 5beb89d2ecea..fac0cfc4dd72 100644 --- a/src/tool_vms.c +++ b/src/tool_vms.c @@ -176,14 +176,14 @@ static void decc_init(void) } else { /* Invalid DECC feature value. */ - printf(" INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n", - feat_value, - feat_value_min, decc_feat_array[i].name, feat_value_max); + curl_mprintf(" INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n", + feat_value, + feat_value_min, decc_feat_array[i].name, feat_value_max); } } else { /* Invalid DECC feature name. */ - printf(" UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[i].name); + curl_mprintf(" UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[i].name); } } diff --git a/src/tool_writeout.c b/src/tool_writeout.c index eaeec152e419..cdfa23a752d9 100644 --- a/src/tool_writeout.c +++ b/src/tool_writeout.c @@ -176,14 +176,14 @@ static int writeTime(FILE *stream, const struct writeoutvar *wovar, us %= 1000000; if(use_json) - fprintf(stream, "\"%s\":", wovar->name); + curl_mfprintf(stream, "\"%s\":", wovar->name); - fprintf(stream, "%" CURL_FORMAT_CURL_OFF_TU - ".%06" CURL_FORMAT_CURL_OFF_TU, secs, us); + curl_mfprintf(stream, "%" CURL_FORMAT_CURL_OFF_TU + ".%06" CURL_FORMAT_CURL_OFF_TU, secs, us); } else { if(use_json) - fprintf(stream, "\"%s\":null", wovar->name); + curl_mfprintf(stream, "\"%s\":null", wovar->name); } return 1; /* return 1 if anything was written */ @@ -414,7 +414,7 @@ static int writeString(FILE *stream, const struct writeoutvar *wovar, DEBUGASSERT(!valid || strinfo); if(valid && strinfo) { if(use_json) { - fprintf(stream, "\"%s\":", wovar->name); + curl_mfprintf(stream, "\"%s\":", wovar->name); jsonWriteString(stream, strinfo, FALSE); } else @@ -422,7 +422,7 @@ static int writeString(FILE *stream, const struct writeoutvar *wovar, } else { if(use_json) - fprintf(stream, "\"%s\":null", wovar->name); + curl_mfprintf(stream, "\"%s\":null", wovar->name); } curl_free((char *)CURL_UNCONST(freestr)); @@ -470,17 +470,17 @@ static int writeLong(FILE *stream, const struct writeoutvar *wovar, if(valid) { if(use_json) - fprintf(stream, "\"%s\":%ld", wovar->name, longinfo); + curl_mfprintf(stream, "\"%s\":%ld", wovar->name, longinfo); else { if(wovar->id == VAR_HTTP_CODE || wovar->id == VAR_HTTP_CODE_PROXY) - fprintf(stream, "%03ld", longinfo); + curl_mfprintf(stream, "%03ld", longinfo); else - fprintf(stream, "%ld", longinfo); + curl_mfprintf(stream, "%ld", longinfo); } } else { if(use_json) - fprintf(stream, "\"%s\":null", wovar->name); + curl_mfprintf(stream, "\"%s\":null", wovar->name); } return 1; /* return 1 if anything was written */ @@ -516,13 +516,13 @@ static int writeOffset(FILE *stream, const struct writeoutvar *wovar, if(valid) { if(use_json) - fprintf(stream, "\"%s\":", wovar->name); + curl_mfprintf(stream, "\"%s\":", wovar->name); - fprintf(stream, "%" CURL_FORMAT_CURL_OFF_T, offinfo); + curl_mfprintf(stream, "%" CURL_FORMAT_CURL_OFF_T, offinfo); } else { if(use_json) - fprintf(stream, "\"%s\":null", wovar->name); + curl_mfprintf(stream, "\"%s\":null", wovar->name); } return 1; /* return 1 if anything was written */ @@ -796,9 +796,9 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per, } } else { - fprintf(tool_stderr, - "curl: unknown --write-out variable: '%.*s'\n", - (int)vlen, ptr); + curl_mfprintf(tool_stderr, + "curl: unknown --write-out variable: '%.*s'\n", + (int)vlen, ptr); } ptr = end + 1; /* pass the end */ } diff --git a/src/tool_writeout_json.c b/src/tool_writeout_json.c index cfa2d1c9013d..f3175edf9502 100644 --- a/src/tool_writeout_json.c +++ b/src/tool_writeout_json.c @@ -112,9 +112,9 @@ void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[], /* The variables are sorted in alphabetical order but as a special case curl_version (which is not actually a --write-out variable) is last. */ - fprintf(stream, "\"curl_version\":"); + curl_mfprintf(stream, "\"curl_version\":"); jsonWriteString(stream, curl_version(), FALSE); - fprintf(stream, "}"); + curl_mfprintf(stream, "}"); } void headerJSON(FILE *stream, struct per_transfer *per) diff --git a/src/tool_xattr.c b/src/tool_xattr.c index 346c805a4052..fb0669106e4b 100644 --- a/src/tool_xattr.c +++ b/src/tool_xattr.c @@ -83,7 +83,7 @@ static int xattr(int fd, if(value) { #ifdef DEBUGBUILD if(getenv("CURL_FAKE_XATTR")) { - printf("%s => %s\n", attr, value); + curl_mprintf("%s => %s\n", attr, value); return 0; } #endif From e7a5184fa1ebcd68ead0e3e9b78340296acac350 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 10:39:29 +0200 Subject: [PATCH 286/465] openssl: call SSL_get_error() with proper error The error function should be called with the return code from the previous call to SSL_shutdown() as argument. Closes #18872 --- lib/vtls/openssl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 0714ce7c6ae0..409c9c09460c 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2169,14 +2169,16 @@ static CURLcode ossl_shutdown(struct Curl_cfilter *cf, /* SSL should now have started the shutdown from our side. Since it * was not complete, we are lacking the close notify from the server. */ if(send_shutdown && !(SSL_get_shutdown(octx->ssl) & SSL_SENT_SHUTDOWN)) { + int rc; ERR_clear_error(); CURL_TRC_CF(data, cf, "send SSL close notify"); - if(SSL_shutdown(octx->ssl) == 1) { + rc = SSL_shutdown(octx->ssl); + if(rc == 1) { CURL_TRC_CF(data, cf, "SSL shutdown finished"); *done = TRUE; goto out; } - if(SSL_ERROR_WANT_WRITE == SSL_get_error(octx->ssl, nread)) { + if(SSL_ERROR_WANT_WRITE == SSL_get_error(octx->ssl, rc)) { CURL_TRC_CF(data, cf, "SSL shutdown still wants to send"); connssl->io_need = CURL_SSL_IO_NEED_SEND; goto out; From e9ababe9aa4c1f7d727494d660650af934db523b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 6 Oct 2025 02:33:49 +0200 Subject: [PATCH 287/465] windows: use native error code types more - curlx_get_winapi_error: accept DWORD (was: int), move casts one level up the callstack. - sspi: bump some types to `SECURITY_STATUS` (int -> LONG). - digest_sspi: drop unnecessary cast. Closes #18868 --- lib/curlx/strerr.c | 2 +- lib/curlx/winapi.c | 6 +++--- lib/curlx/winapi.h | 2 +- lib/strerror.c | 10 +++++----- lib/strerror.h | 2 +- lib/vauth/digest_sspi.c | 3 +-- lib/vauth/spnego_sspi.c | 37 +++++++++++++++++-------------------- lib/vauth/vauth.h | 2 +- 8 files changed, 30 insertions(+), 34 deletions(-) diff --git a/lib/curlx/strerr.c b/lib/curlx/strerr.c index 96dc9c83558c..e5227554e563 100644 --- a/lib/curlx/strerr.c +++ b/lib/curlx/strerr.c @@ -298,7 +298,7 @@ const char *curlx_strerror(int err, char *buf, size_t buflen) #ifdef USE_WINSOCK !get_winsock_error(err, buf, buflen) && #endif - !curlx_get_winapi_error(err, buf, buflen)) + !curlx_get_winapi_error((DWORD)err, buf, buflen)) SNPRINTF(buf, buflen, "Unknown error %d (%#x)", err, err); } #else /* !_WIN32 */ diff --git a/lib/curlx/winapi.c b/lib/curlx/winapi.c index cc008e3087a5..6d94733bedea 100644 --- a/lib/curlx/winapi.c +++ b/lib/curlx/winapi.c @@ -48,7 +48,7 @@ * codes (GetLastError) to error messages. * Returns NULL if no error message was found for error code. */ -const char *curlx_get_winapi_error(int err, char *buf, size_t buflen) +const char *curlx_get_winapi_error(DWORD err, char *buf, size_t buflen) { char *p; wchar_t wbuf[256]; @@ -64,7 +64,7 @@ const char *curlx_get_winapi_error(int err, char *buf, size_t buflen) expect the local codepage (eg fprintf, failf, infof). FormatMessageW -> wcstombs is used for Windows CE compatibility. */ if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS), NULL, (DWORD)err, + FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err, LANG_NEUTRAL, wbuf, CURL_ARRAYSIZE(wbuf), NULL)) { size_t written = wcstombs(buf, wbuf, buflen - 1); if(written != (size_t)-1) @@ -96,7 +96,7 @@ const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen) *buf = '\0'; #ifndef CURL_DISABLE_VERBOSE_STRINGS - if(!curlx_get_winapi_error((int)err, buf, buflen)) { + if(!curlx_get_winapi_error(err, buf, buflen)) { #if defined(__GNUC__) && __GNUC__ >= 7 #pragma GCC diagnostic push #pragma GCC diagnostic warning "-Wformat-truncation=1" diff --git a/lib/curlx/winapi.h b/lib/curlx/winapi.h index 76ddcc53b8bc..d30f5efa13c7 100644 --- a/lib/curlx/winapi.h +++ b/lib/curlx/winapi.h @@ -26,7 +26,7 @@ #ifdef _WIN32 #define WINAPI_ERROR_LEN 100 -const char *curlx_get_winapi_error(int err, char *buf, size_t buflen); +const char *curlx_get_winapi_error(DWORD err, char *buf, size_t buflen); const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen); #endif diff --git a/lib/strerror.c b/lib/strerror.c index c4545af88824..8d22ac9b343b 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -546,7 +546,7 @@ curl_url_strerror(CURLUcode error) * Curl_sspi_strerror: * Variant of curlx_strerror if the error code is definitely Windows SSPI. */ -const char *Curl_sspi_strerror(int err, char *buf, size_t buflen) +const char *Curl_sspi_strerror(SECURITY_STATUS err, char *buf, size_t buflen) { #ifdef _WIN32 DWORD old_win_err = GetLastError(); @@ -656,17 +656,17 @@ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen) if(err == SEC_E_ILLEGAL_MESSAGE) { curl_msnprintf(buf, buflen, - "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually " + "SEC_E_ILLEGAL_MESSAGE (0x%08lX) - This error usually " "occurs when a fatal SSL/TLS alert is received (e.g. " "handshake failed). More detail may be available in " "the Windows System event log.", err); } else { char msgbuf[256]; - if(curlx_get_winapi_error(err, msgbuf, sizeof(msgbuf))) - curl_msnprintf(buf, buflen, "%s (0x%08X) - %s", txt, err, msgbuf); + if(curlx_get_winapi_error((DWORD)err, msgbuf, sizeof(msgbuf))) + curl_msnprintf(buf, buflen, "%s (0x%08lX) - %s", txt, err, msgbuf); else - curl_msnprintf(buf, buflen, "%s (0x%08X)", txt, err); + curl_msnprintf(buf, buflen, "%s (0x%08lX)", txt, err); } #else diff --git a/lib/strerror.h b/lib/strerror.h index 2120726c9ff0..c52503ed9316 100644 --- a/lib/strerror.h +++ b/lib/strerror.h @@ -25,7 +25,7 @@ ***************************************************************************/ #ifdef USE_WINDOWS_SSPI -const char *Curl_sspi_strerror(int err, char *buf, size_t buflen); +const char *Curl_sspi_strerror(SECURITY_STATUS err, char *buf, size_t buflen); #endif #endif /* HEADER_CURL_STRERROR_H */ diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index 2f4b8d4a1dca..f231dabc81df 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -473,8 +473,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, if(status == SEC_E_OK) output_token_len = chlg_buf[4].cbBuffer; else { /* delete the context so a new one can be made */ - infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx", - (long)status); + infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx", status); Curl_pSecFn->DeleteSecurityContext(digest->http_context); Curl_safefree(digest->http_context); } diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c index ae44523d328a..935468f3a65e 100644 --- a/lib/vauth/spnego_sspi.c +++ b/lib/vauth/spnego_sspi.c @@ -127,7 +127,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, if(!nego->output_token) { /* Query the security package for Negotiate */ - nego->status = (DWORD)Curl_pSecFn->QuerySecurityPackageInfo( + nego->status = Curl_pSecFn->QuerySecurityPackageInfo( (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NEGOTIATE)), &SecurityPackage); if(nego->status != SEC_E_OK) { @@ -167,8 +167,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; /* Acquire our credentials handle */ - nego->status = (DWORD) - Curl_pSecFn->AcquireCredentialsHandle(NULL, + nego->status = Curl_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NEGOTIATE)), SECPKG_CRED_OUTBOUND, NULL, nego->p_identity, NULL, NULL, @@ -216,11 +215,10 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, SEC_CHANNEL_BINDINGS channelBindings; SecPkgContext_Bindings pkgBindings; pkgBindings.Bindings = &channelBindings; - nego->status = (DWORD)Curl_pSecFn->QueryContextAttributes( + nego->status = Curl_pSecFn->QueryContextAttributes( nego->sslContext, SECPKG_ATTR_ENDPOINT_BINDINGS, - &pkgBindings - ); + &pkgBindings); if(nego->status == SEC_E_OK) { chlg_desc.cBuffers++; chlg_buf[1].BufferType = SECBUFFER_CHANNEL_BINDINGS; @@ -241,14 +239,14 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, /* Generate our challenge-response message */ nego->status = - (DWORD)Curl_pSecFn->InitializeSecurityContext(nego->credentials, - chlg ? nego->context : NULL, - nego->spn, - ISC_REQ_CONFIDENTIALITY, - 0, SECURITY_NATIVE_DREP, - chlg ? &chlg_desc : NULL, - 0, nego->context, - &resp_desc, &attrs, NULL); + Curl_pSecFn->InitializeSecurityContext(nego->credentials, + chlg ? nego->context : NULL, + nego->spn, + ISC_REQ_CONFIDENTIALITY, + 0, SECURITY_NATIVE_DREP, + chlg ? &chlg_desc : NULL, + 0, nego->context, + &resp_desc, &attrs, NULL); /* Free the decoded challenge as it is not required anymore */ free(chlg); @@ -256,9 +254,9 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, if(GSS_ERROR(nego->status)) { char buffer[STRERROR_LEN]; failf(data, "InitializeSecurityContext failed: %s", - Curl_sspi_strerror((int)nego->status, buffer, sizeof(buffer))); + Curl_sspi_strerror(nego->status, buffer, sizeof(buffer))); - if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY) + if(nego->status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_AUTH_ERROR; @@ -266,14 +264,13 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, if(nego->status == SEC_I_COMPLETE_NEEDED || nego->status == SEC_I_COMPLETE_AND_CONTINUE) { - nego->status = (DWORD)Curl_pSecFn->CompleteAuthToken(nego->context, - &resp_desc); + nego->status = Curl_pSecFn->CompleteAuthToken(nego->context, &resp_desc); if(GSS_ERROR(nego->status)) { char buffer[STRERROR_LEN]; failf(data, "CompleteAuthToken failed: %s", - Curl_sspi_strerror((int)nego->status, buffer, sizeof(buffer))); + Curl_sspi_strerror(nego->status, buffer, sizeof(buffer))); - if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY) + if(nego->status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; return CURLE_AUTH_ERROR; diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h index d9e73a0ed12f..57fd27a6a7f3 100644 --- a/lib/vauth/vauth.h +++ b/lib/vauth/vauth.h @@ -317,7 +317,7 @@ struct negotiatedata { #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS CtxtHandle *sslContext; #endif - DWORD status; + SECURITY_STATUS status; CredHandle *credentials; CtxtHandle *context; SEC_WINNT_AUTH_IDENTITY identity; From 762ce8801b2ff8cad340797c71b18be17b6c4de2 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 6 Oct 2025 13:05:14 +0200 Subject: [PATCH 288/465] quiche: fix possible leaks on teardown When the close of the quiche filter was never called, the destroy function did not release all allicated resources. When closing a quiche filter, set the connected flag to FALSE. Reported-by: Joshua Rogers Closes #18880 --- lib/vquic/curl_quiche.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 36691d09dbe8..6534822c769b 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -147,14 +147,22 @@ static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx) static void cf_quiche_ctx_close(struct cf_quiche_ctx *ctx) { - if(ctx->h3c) + if(ctx->h3c) { quiche_h3_conn_free(ctx->h3c); - if(ctx->h3config) + ctx->h3c = NULL; + } + if(ctx->h3config) { quiche_h3_config_free(ctx->h3config); - if(ctx->qconn) + ctx->h3config = NULL; + } + if(ctx->qconn) { quiche_conn_free(ctx->qconn); - if(ctx->cfg) + ctx->qconn = NULL; + } + if(ctx->cfg) { quiche_config_free(ctx->cfg); + ctx->cfg = NULL; + } } static CURLcode cf_flush_egress(struct Curl_cfilter *cf, @@ -1494,6 +1502,7 @@ static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data) bool done; (void)cf_quiche_shutdown(cf, data, &done); cf_quiche_ctx_close(cf->ctx); + cf->connected = FALSE; } } @@ -1501,6 +1510,7 @@ static void cf_quiche_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) { (void)data; if(cf->ctx) { + cf_quiche_ctx_close(cf->ctx); cf_quiche_ctx_free(cf->ctx); cf->ctx = NULL; } From aae18c4bdc1a3bf5b6567825ef6439756f0c5b74 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 5 Oct 2025 23:19:13 +0200 Subject: [PATCH 289/465] tool_getparam: add --knownhosts To allow users to specify a known hosts file that is not the default one: ~/.ssh/known_hosts URL: https://github.com/curl/curl/discussions/18784 Closes #18859 --- docs/cmdline-opts/Makefile.inc | 1 + docs/cmdline-opts/knownhosts.md | 31 +++++++++++++++++++++++++++++++ docs/options-in-versions | 1 + src/config2setopts.c | 6 +++--- src/tool_cfgable.c | 1 + src/tool_cfgable.h | 3 +-- src/tool_getparam.c | 4 ++++ src/tool_getparam.h | 1 + src/tool_listhelp.c | 3 +++ src/tool_operate.c | 1 - tests/data/test1459 | 10 ++-------- 11 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 docs/cmdline-opts/knownhosts.md diff --git a/docs/cmdline-opts/Makefile.inc b/docs/cmdline-opts/Makefile.inc index b8e88421a9a0..f7236af1b127 100644 --- a/docs/cmdline-opts/Makefile.inc +++ b/docs/cmdline-opts/Makefile.inc @@ -147,6 +147,7 @@ DPAGES = \ keepalive-time.md \ key-type.md \ key.md \ + knownhosts.md \ krb.md \ libcurl.md \ limit-rate.md \ diff --git a/docs/cmdline-opts/knownhosts.md b/docs/cmdline-opts/knownhosts.md new file mode 100644 index 000000000000..47095632df7a --- /dev/null +++ b/docs/cmdline-opts/knownhosts.md @@ -0,0 +1,31 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: knownhosts +Arg: +Protocols: SCP SFTP +Help: Specify knownhosts path +Category: ssh +Added: 8.17.0 +Multi: single +See-also: + - hostpubsha256 + - hostpubmd5 + - insecure + - key +Example: + - --knownhost filename --key here $URL +--- + +# `--knownhosts` + +When doing SCP and SFTP transfers, curl automatically checks a database +containing identification for all hosts it has ever been used with to verify +that the host it connects to is the same as previously. Host keys are stored +in such a known hosts file. curl uses the ~/.ssh/known_hosts in the user's +home directory by default. + +This option lets a user specify a specific file to check the host against. + +The known hosts check can be disabled with --insecure, but that makes the +transfer insecure and is strongly discouraged. diff --git a/docs/options-in-versions b/docs/options-in-versions index 6d2a9057fa7a..95d84a4bfec2 100644 --- a/docs/options-in-versions +++ b/docs/options-in-versions @@ -111,6 +111,7 @@ --keepalive-time 7.18.0 --key 7.9.3 --key-type 7.9.3 +--knownhosts 8.17.0 --krb 7.3 --libcurl 7.16.1 --limit-rate 7.10 diff --git a/src/config2setopts.c b/src/config2setopts.c index 5921cd73ce08..0a519ed04865 100644 --- a/src/config2setopts.c +++ b/src/config2setopts.c @@ -195,7 +195,7 @@ static CURLcode ssh_setopts(struct OperationConfig *config, CURL *curl) my_setopt_long(curl, CURLOPT_SSH_COMPRESSION, 1); if(!config->insecure_ok) { - char *known = global->knownhosts; + char *known = config->knownhosts; if(!known) known = findfile(".ssh/known_hosts", FALSE); @@ -203,12 +203,12 @@ static CURLcode ssh_setopts(struct OperationConfig *config, CURL *curl) /* new in curl 7.19.6 */ result = my_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, known); if(result) { - global->knownhosts = NULL; + config->knownhosts = NULL; curl_free(known); return result; } /* store it in global to avoid repeated checks */ - global->knownhosts = known; + config->knownhosts = known; } else if(!config->hostpubmd5 && !config->hostpubsha256) { errorf("Couldn't find a known_hosts file"); diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index e2df7cf91f02..48148a88ad5b 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -189,6 +189,7 @@ static void free_config_fields(struct OperationConfig *config) tool_safefree(config->ech); tool_safefree(config->ech_config); tool_safefree(config->ech_public); + tool_safefree(config->knownhosts); } void config_free(struct OperationConfig *config) diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 762837055106..3c67695124e7 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -94,6 +94,7 @@ struct OperationConfig { char *proxyuserpwd; char *proxy; char *noproxy; + char *knownhosts; char *mail_from; struct curl_slist *mail_rcpt; char *mail_auth; @@ -335,8 +336,6 @@ struct GlobalConfig { FILE *trace_stream; char *libcurl; /* Output libcurl code to this filename */ char *ssl_sessions; /* file to load/save SSL session tickets */ - char *knownhosts; /* known host path, if set. curl_free() - this */ struct tool_var *variables; struct OperationConfig *first; struct OperationConfig *current; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index a54d3f804c8c..b533f41aa7df 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -196,6 +196,7 @@ static const struct LongShort aliases[]= { {"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME}, {"key", ARG_FILE, ' ', C_KEY}, {"key-type", ARG_STRG|ARG_TLS, ' ', C_KEY_TYPE}, + {"knownhosts", ARG_FILE, ' ', C_KNOWNHOSTS}, {"krb", ARG_STRG|ARG_DEPR, ' ', C_KRB}, {"krb4", ARG_STRG|ARG_DEPR, ' ', C_KRB4}, {"libcurl", ARG_STRG, ' ', C_LIBCURL}, @@ -2224,6 +2225,9 @@ static ParameterError opt_file(struct OperationConfig *config, case C_KEY: /* --key */ err = getstr(&config->key, nextarg, DENY_BLANK); break; + case C_KNOWNHOSTS: /* --knownhosts */ + err = getstr(&config->knownhosts, nextarg, DENY_BLANK); + break; case C_NETRC_FILE: /* --netrc-file */ err = getstr(&config->netrc_file, nextarg, DENY_BLANK); break; diff --git a/src/tool_getparam.h b/src/tool_getparam.h index a08bbac7b640..6b97b9c11f45 100644 --- a/src/tool_getparam.h +++ b/src/tool_getparam.h @@ -139,6 +139,7 @@ typedef enum { C_KEEPALIVE_TIME, C_KEY, C_KEY_TYPE, + C_KNOWNHOSTS, C_KRB, C_KRB4, C_LIBCURL, diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c index bd72dbe15c51..c8e31e77a6ae 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -341,6 +341,9 @@ const struct helptxt helptext[] = { {" --key-type ", "Private key file type (DER/PEM/ENG)", CURLHELP_TLS}, + {" --knownhosts ", + "Specify knownhosts path", + CURLHELP_SSH}, {" --krb ", "Enable Kerberos with security ", CURLHELP_DEPRECATED}, diff --git a/src/tool_operate.c b/src/tool_operate.c index b49f45fd9904..38482b496e7f 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -2273,7 +2273,6 @@ CURLcode operate(int argc, argv_item_t argv[]) } varcleanup(); - curl_free(global->knownhosts); return result; } diff --git a/tests/data/test1459 b/tests/data/test1459 index 335b26576632..e4901d74f06c 100644 --- a/tests/data/test1459 +++ b/tests/data/test1459 @@ -12,9 +12,6 @@ known_hosts sftp - -mkdir -p %PWD/%LOGDIR/test%TESTNUMBER.dir/.ssh - sftp !oldlibssh @@ -23,15 +20,12 @@ sftp SFTP with corrupted known_hosts --u : sftp://%HOSTIP:%SSHPORT/ -l +-u : sftp://%HOSTIP:%SSHPORT/ -l --knownhosts %LOGDIR/known%TESTNUMBER - + |1|qy29Y1x/+/F39AzdG5515YSSw+c=|iB2WX5jrU3ZTWc+ZfGau7HHEvBc= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAynDN8cDJ3xNzRjTNNGciSHSxpubxhZ6YnkLdp1TkrGW8n\ R93Ey5VtBeBblYTRlFXBWJgKFcTKBRJ/O4qBZwbUgt10AHj31i6h8NehfT19tR8wG/YCmj3KtYLHmwdzmW1edEL9G2NdX2KiKYv7/zuly3QvmP0QA0NhWkAz0KdWNM= - -CURL_HOME=%PWD/%LOGDIR/test%TESTNUMBER.dir - # Verify data after the test has been "shot" From a80dcb04e39bbec88a4ce271de06673b2cbbc142 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 07:51:48 +0200 Subject: [PATCH 290/465] test1711: send a >64K mail with SMTP A failed attempt to reproduce #18798 Closes #18861 --- tests/data/Makefile.am | 2 +- tests/data/test1711 | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 tests/data/test1711 diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 5063e0210f42..f2c698c674aa 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -228,7 +228,7 @@ test1670 test1671 \ test1680 test1681 test1682 test1683 \ \ test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \ -test1708 test1709 test1710 \ +test1708 test1709 test1710 test1711 \ \ test1800 test1801 \ \ diff --git a/tests/data/test1711 b/tests/data/test1711 new file mode 100644 index 000000000000..077dd74be9ea --- /dev/null +++ b/tests/data/test1711 @@ -0,0 +1,51 @@ + + + +SMTP + + + +# +# Server-side + + + +# +# Client-side + + +smtp + + +Send >64K over SMTP + + +From: different +To: another + +%repeat[5000 x test in body... ]% + + +smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -T %LOGDIR/email%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + + +EHLO %TESTNUMBER +MAIL FROM: +RCPT TO: +DATA +QUIT + + +From: different +To: another + +%repeat[5000 x test in body... ]% +. + + + From c3adf63ee7a26bae6c45ba0e0ae977c4cabd394e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 09:02:09 +0200 Subject: [PATCH 291/465] libssh2: bail out on chgrp and chown number parsing errors Reported-by: Joshua Rogers Closes #18863 --- lib/vssh/libssh2.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 0b82b568b13a..390602b35aeb 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1303,11 +1303,11 @@ sftp_quote_stat(struct Curl_easy *data, if(!strncmp(cmd, "chgrp", 5)) { const char *p = sshc->quote_path1; curl_off_t gid; - (void)curlx_str_number(&p, &gid, ULONG_MAX); - sshp->quote_attrs.gid = (unsigned long)gid; - sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; - if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { + if(!curlx_str_number(&p, &gid, ULONG_MAX)) { + sshp->quote_attrs.gid = (unsigned long)gid; + sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; + } + else if(!sshc->acceptfail) { failf(data, "Syntax error: chgrp gid not a number"); goto fail; } @@ -1327,11 +1327,11 @@ sftp_quote_stat(struct Curl_easy *data, else if(!strncmp(cmd, "chown", 5)) { const char *p = sshc->quote_path1; curl_off_t uid; - (void)curlx_str_number(&p, &uid, ULONG_MAX); - sshp->quote_attrs.uid = (unsigned long)uid; - sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; - if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { + if(!curlx_str_number(&p, &uid, ULONG_MAX)) { + sshp->quote_attrs.uid = (unsigned long)uid; + sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; + } + else if(!sshc->acceptfail) { failf(data, "Syntax error: chown uid not a number"); goto fail; } From d4c033267740d8b2e65520c89f2c5b4e5a5ee174 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 09:38:30 +0200 Subject: [PATCH 292/465] libssh2: clarify that sshp->path is always at least one byte Reported-by: Joshua Rogers Closes #18864 --- lib/vssh/curl_path.c | 1 + lib/vssh/ssh.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/vssh/curl_path.c b/lib/vssh/curl_path.c index 021e85faf8e7..7a0e5bffef20 100644 --- a/lib/vssh/curl_path.c +++ b/lib/vssh/curl_path.c @@ -100,6 +100,7 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data, } else *path = working_path; + DEBUGASSERT(*path && (*path)[0]); return CURLE_OK; } diff --git a/lib/vssh/ssh.h b/lib/vssh/ssh.h index 9a5f1b7e3187..e09111e63f66 100644 --- a/lib/vssh/ssh.h +++ b/lib/vssh/ssh.h @@ -120,7 +120,7 @@ typedef enum { Everything that is strictly related to a connection is banned from this struct. */ struct SSHPROTO { - char *path; /* the path we operate on */ + char *path; /* the path we operate on, at least one byte long */ #ifdef USE_LIBSSH2 struct dynbuf readdir_link; struct dynbuf readdir; From 0d68f482052595887c2e3cc0b0fcf830a6dbf354 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 09:44:45 +0200 Subject: [PATCH 293/465] krb5_sspi: the chlg argument is NOT optional Fix the comment, add assert. Reported-by: Joshua Rogers Closes #18865 --- lib/vauth/krb5_sspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c index 985f1c38fc63..c1953e114569 100644 --- a/lib/vauth/krb5_sspi.c +++ b/lib/vauth/krb5_sspi.c @@ -238,7 +238,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, * * data [in] - The session handle. * authzid [in] - The authorization identity if some. - * chlg [in] - The optional challenge message. + * chlg [in] - The challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * out [out] - The result storage. * @@ -273,6 +273,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, #endif /* Ensure we have a valid challenge message */ + DEBUGASSERT(chlg); if(!Curl_bufref_len(chlg)) { infof(data, "GSSAPI handshake failure (empty security message)"); return CURLE_BAD_CONTENT_ENCODING; From 51b85bdc6cd48a55c75b03afcf1f057839564ae8 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 6 Oct 2025 03:02:24 +0200 Subject: [PATCH 294/465] windows: use consistent format when showing error codes For `GetLastError()` and `SECURITY_STATUS`: 0x-prefixed, 8-digit, lowercase, hex: 0x1234abcd Also: say `GetLastError()` instead of `errno` in one message. Closes #18877 --- lib/curlx/winapi.c | 2 +- lib/strerror.c | 6 +++--- lib/vauth/ntlm_sspi.c | 2 +- lib/vtls/schannel.c | 6 +++--- src/tool_doswin.c | 6 +++--- src/tool_filetime.c | 8 ++++---- tests/libtest/lib3026.c | 3 ++- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/curlx/winapi.c b/lib/curlx/winapi.c index 6d94733bedea..de1218cec7f5 100644 --- a/lib/curlx/winapi.c +++ b/lib/curlx/winapi.c @@ -103,7 +103,7 @@ const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen) #endif /* some GCC compilers cause false positive warnings if we allow this warning */ - SNPRINTF(buf, buflen, "Unknown error %lu (0x%08lX)", err, err); + SNPRINTF(buf, buflen, "Unknown error %lu (0x%08lx)", err, err); #if defined(__GNUC__) && __GNUC__ >= 7 #pragma GCC diagnostic pop #endif diff --git a/lib/strerror.c b/lib/strerror.c index 8d22ac9b343b..5b82d7f96556 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -656,7 +656,7 @@ const char *Curl_sspi_strerror(SECURITY_STATUS err, char *buf, size_t buflen) if(err == SEC_E_ILLEGAL_MESSAGE) { curl_msnprintf(buf, buflen, - "SEC_E_ILLEGAL_MESSAGE (0x%08lX) - This error usually " + "SEC_E_ILLEGAL_MESSAGE (0x%08lx) - This error usually " "occurs when a fatal SSL/TLS alert is received (e.g. " "handshake failed). More detail may be available in " "the Windows System event log.", err); @@ -664,9 +664,9 @@ const char *Curl_sspi_strerror(SECURITY_STATUS err, char *buf, size_t buflen) else { char msgbuf[256]; if(curlx_get_winapi_error((DWORD)err, msgbuf, sizeof(msgbuf))) - curl_msnprintf(buf, buflen, "%s (0x%08lX) - %s", txt, err, msgbuf); + curl_msnprintf(buf, buflen, "%s (0x%08lx) - %s", txt, err, msgbuf); else - curl_msnprintf(buf, buflen, "%s (0x%08lX)", txt, err); + curl_msnprintf(buf, buflen, "%s (0x%08lx)", txt, err); } #else diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index dff5fe8747d8..d42187916138 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -313,7 +313,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, &type_3_desc, &attrs, NULL); if(status != SEC_E_OK) { - infof(data, "NTLM handshake failure (type-3 message): Status=%lx", + infof(data, "NTLM handshake failure (type-3 message): Status=0x%08lx", status); if(status == SEC_E_INSUFFICIENT_MEMORY) diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index bf68321afe96..c0e96c93bf4c 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -659,7 +659,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, cert_showfilename_error); else failf(data, "schannel: Failed to import cert file %s, " - "last error is 0x%lx", + "last error is 0x%08lx", cert_showfilename_error, errorcode); return CURLE_SSL_CERTPROBLEM; } @@ -678,7 +678,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, if(!client_certs[0]) { failf(data, "schannel: Failed to get certificate from file %s" - ", last error is 0x%lx", + ", last error is 0x%08lx", cert_showfilename_error, GetLastError()); CertCloseStore(cert_store, 0); return CURLE_SSL_CERTPROBLEM; @@ -700,7 +700,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, char *path_utf8 = curlx_convert_tchar_to_UTF8(cert_store_path); failf(data, "schannel: Failed to open cert store %lx %s, " - "last error is 0x%lx", + "last error is 0x%08lx", cert_store_name, (path_utf8 ? path_utf8 : "(unknown)"), GetLastError()); diff --git a/src/tool_doswin.c b/src/tool_doswin.c index 51b6f341018a..5cf58405b392 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -871,7 +871,7 @@ curl_socket_t win32_stdin_read_thread(void) 0, FALSE, DUPLICATE_SAME_ACCESS); if(!r) { - errorf("DuplicateHandle error: %08lx", GetLastError()); + errorf("DuplicateHandle error: 0x%08lx", GetLastError()); break; } @@ -882,7 +882,7 @@ curl_socket_t win32_stdin_read_thread(void) stdin_thread = CreateThread(NULL, 0, win_stdin_thread_func, tdata, 0, NULL); if(!stdin_thread) { - errorf("CreateThread error: %08lx", GetLastError()); + errorf("CreateThread error: 0x%08lx", GetLastError()); break; } @@ -908,7 +908,7 @@ curl_socket_t win32_stdin_read_thread(void) /* Set the stdin handle to read from the socket. */ if(SetStdHandle(STD_INPUT_HANDLE, (HANDLE)socket_r) == 0) { - errorf("SetStdHandle error: %08lx", GetLastError()); + errorf("SetStdHandle error: 0x%08lx", GetLastError()); break; } diff --git a/src/tool_filetime.c b/src/tool_filetime.c index afd84c013831..6dc2fbbe4234 100644 --- a/src/tool_filetime.c +++ b/src/tool_filetime.c @@ -62,13 +62,13 @@ int getfiletime(const char *filename, curl_off_t *stamp) } } else { - warnf("Failed to get filetime: GetFileTime failed: GetLastError %lu", + warnf("Failed to get filetime: GetFileTime failed: GetLastError 0x%08lx", GetLastError()); } CloseHandle(hfile); } else if(GetLastError() != ERROR_FILE_NOT_FOUND) { - warnf("Failed to get filetime: CreateFile failed: GetLastError %lu", + warnf("Failed to get filetime: CreateFile failed: GetLastError 0x%08lx", GetLastError()); } #else @@ -118,14 +118,14 @@ void setfiletime(curl_off_t filetime, const char *filename) ft.dwHighDateTime = (DWORD)(converted >> 32); if(!SetFileTime(hfile, NULL, &ft, &ft)) { warnf("Failed to set filetime %" CURL_FORMAT_CURL_OFF_T - " on outfile: SetFileTime failed: GetLastError %lu", + " on outfile: SetFileTime failed: GetLastError 0x%08lx", filetime, GetLastError()); } CloseHandle(hfile); } else { warnf("Failed to set filetime %" CURL_FORMAT_CURL_OFF_T - " on outfile: CreateFile failed: GetLastError %lu", + " on outfile: CreateFile failed: GetLastError 0x%08lx", filetime, GetLastError()); } diff --git a/tests/libtest/lib3026.c b/tests/libtest/lib3026.c index 167fdd4d332f..75d419cb5875 100644 --- a/tests/libtest/lib3026.c +++ b/tests/libtest/lib3026.c @@ -59,7 +59,8 @@ static CURLcode test_lib3026(const char *URL) results[i] = CURL_LAST; /* initialize with invalid value */ th = CreateThread(NULL, 0, t3026_run_thread, &results[i], 0, NULL); if(!th) { - curl_mfprintf(stderr, "%s:%d Couldn't create thread, errno %lu\n", + curl_mfprintf(stderr, "%s:%d Couldn't create thread, " + "GetLastError 0x%08lx\n", __FILE__, __LINE__, GetLastError()); tid_count = i; test_failure = TEST_ERR_MAJOR_BAD; From decd7e157c51c6bd5599b6000f57a4ecbdd0e2f3 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 08:22:39 +0200 Subject: [PATCH 295/465] cf-socket: always check Curl_cf_socket_peek() return code Make it trigger a warning if not. Reported-by: Joshua Rogers Closes #18862 --- lib/cf-socket.h | 2 +- lib/vquic/curl_ngtcp2.c | 9 ++++----- lib/vquic/curl_osslq.c | 18 +++++++++--------- lib/vquic/curl_quiche.c | 4 +++- lib/vquic/vquic.c | 18 +++++++++--------- 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/lib/cf-socket.h b/lib/cf-socket.h index 85b7e5631b56..e5fc176ee19c 100644 --- a/lib/cf-socket.h +++ b/lib/cf-socket.h @@ -158,7 +158,7 @@ CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf, struct Curl_easy *data, curl_socket_t *psock, const struct Curl_sockaddr_ex **paddr, - struct ip_quadruple *pip); + struct ip_quadruple *pip) WARN_UNUSED_RESULT; extern struct Curl_cftype Curl_cft_tcp; extern struct Curl_cftype Curl_cft_udp; diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index a85c9d7609e8..4c7a7857b529 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2480,8 +2480,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, if(result) return result; - Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL); - if(!sockaddr) + if(Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL)) return CURLE_QUIC_CONNECT_ERROR; ctx->q.local_addrlen = sizeof(ctx->q.local_addr); rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr, @@ -2633,9 +2632,9 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, if(result) { struct ip_quadruple ip; - Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); - infof(data, "QUIC connect to %s port %u failed: %s", - ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); + if(!Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip)) + infof(data, "QUIC connect to %s port %u failed: %s", + ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); } #endif if(!result && ctx->qconn) { diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 1d7c3bce9960..351519d65aa7 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -550,12 +550,12 @@ static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf, int sockerr = SOCKERRNO; struct ip_quadruple ip; - Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); if(sockerr && detail == SSL_ERROR_SYSCALL) curlx_strerror(sockerr, extramsg, sizeof(extramsg)); - failf(data, "QUIC connect: %s in connection to %s:%d (%s)", - extramsg[0] ? extramsg : osslq_SSL_ERROR_to_str(detail), - ctx->peer.dispname, ip.remote_port, ip.remote_ip); + if(!Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip)) + failf(data, "QUIC connect: %s in connection to %s:%d (%s)", + extramsg[0] ? extramsg : osslq_SSL_ERROR_to_str(detail), + ctx->peer.dispname, ip.remote_port, ip.remote_ip); } else { /* Could be a CERT problem */ @@ -1177,8 +1177,8 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, goto out; result = CURLE_QUIC_CONNECT_ERROR; - Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &peer_addr, NULL); - if(!peer_addr) + if(Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &peer_addr, NULL) || + !peer_addr) goto out; ctx->q.local_addrlen = sizeof(ctx->q.local_addr); @@ -1857,9 +1857,9 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, if(result) { struct ip_quadruple ip; - Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); - infof(data, "QUIC connect to %s port %u failed: %s", - ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); + if(!Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip)) + infof(data, "QUIC connect to %s port %u failed: %s", + ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); } #endif if(!result) diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 6534822c769b..da67819abb2b 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1303,7 +1303,9 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf, if(result) return result; - Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL); + if(Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL)) + return CURLE_QUIC_CONNECT_ERROR; + ctx->q.local_addrlen = sizeof(ctx->q.local_addr); rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr, &ctx->q.local_addrlen); diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index 91680915f330..d7ed7927be39 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -428,9 +428,9 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf, } if(!cf->connected && SOCKERRNO == SOCKECONNREFUSED) { struct ip_quadruple ip; - Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); - failf(data, "QUIC: connection to %s port %u refused", - ip.remote_ip, ip.remote_port); + if(!Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip)) + failf(data, "QUIC: connection to %s port %u refused", + ip.remote_ip, ip.remote_port); result = CURLE_COULDNT_CONNECT; goto out; } @@ -521,9 +521,9 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf, } if(!cf->connected && SOCKERRNO == SOCKECONNREFUSED) { struct ip_quadruple ip; - Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); - failf(data, "QUIC: connection to %s port %u refused", - ip.remote_ip, ip.remote_port); + if(!Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip)) + failf(data, "QUIC: connection to %s port %u refused", + ip.remote_ip, ip.remote_port); result = CURLE_COULDNT_CONNECT; goto out; } @@ -596,9 +596,9 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf, } if(!cf->connected && SOCKERRNO == SOCKECONNREFUSED) { struct ip_quadruple ip; - Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); - failf(data, "QUIC: connection to %s port %u refused", - ip.remote_ip, ip.remote_port); + if(!Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip)) + failf(data, "QUIC: connection to %s port %u refused", + ip.remote_ip, ip.remote_port); result = CURLE_COULDNT_CONNECT; goto out; } From 2f3cf17e339bfc27c55be22c6c72703ed3e5d696 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 6 Oct 2025 13:45:38 +0200 Subject: [PATCH 296/465] cf-socket: check params and remove accept procondition - creating a socket filter with NULL addrinfo fails with CURLE_BAD_FUNCTION_ARGUMENT - remove getsockname use before accept call, serves no purpose and did not lead to proper error before Reported-by: Joshua Rogers Closes #18882 --- lib/cf-socket.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 34bcda68d7b4..aa79ac45a4f9 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1761,6 +1761,11 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf, (void)data; (void)conn; DEBUGASSERT(transport == TRNSPRT_TCP); + if(!ai) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto out; + } + ctx = calloc(1, sizeof(*ctx)); if(!ctx) { result = CURLE_OUT_OF_MEMORY; @@ -1857,6 +1862,7 @@ static CURLcode cf_udp_connect(struct Curl_cfilter *cf, *done = TRUE; return CURLE_OK; } + *done = FALSE; if(ctx->sock == CURL_SOCKET_BAD) { result = cf_socket_open(cf, data); @@ -1873,10 +1879,6 @@ static CURLcode cf_udp_connect(struct Curl_cfilter *cf, FMT_SOCKET_T " (%s:%d)", ctx->sock, ctx->ip.local_ip, ctx->ip.local_port); } - else { - CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%" - FMT_SOCKET_T " (unconnected)", ctx->sock); - } *done = TRUE; cf->connected = TRUE; } @@ -2058,6 +2060,7 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, bool *done) { struct cf_socket_ctx *ctx = cf->ctx; + char errbuf[STRERROR_LEN]; #ifdef USE_IPV6 struct Curl_sockaddr_storage add; #else @@ -2076,6 +2079,7 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, return CURLE_OK; } + *done = FALSE; timeout_ms = cf_tcp_accept_timeleft(cf, data); if(timeout_ms < 0) { /* if a timeout was already reached, bail out */ @@ -2103,23 +2107,21 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, if(!incoming) { CURL_TRC_CF(data, cf, "nothing heard from the server yet"); - *done = FALSE; return CURLE_OK; } - if(!getsockname(ctx->sock, (struct sockaddr *) &add, &size)) { - size = sizeof(add); + size = sizeof(add); #ifdef HAVE_ACCEPT4 - s_accepted = CURL_ACCEPT4(ctx->sock, (struct sockaddr *) &add, &size, - SOCK_NONBLOCK | SOCK_CLOEXEC); + s_accepted = CURL_ACCEPT4(ctx->sock, (struct sockaddr *) &add, &size, + SOCK_NONBLOCK | SOCK_CLOEXEC); #else - s_accepted = CURL_ACCEPT(ctx->sock, (struct sockaddr *) &add, &size); + s_accepted = CURL_ACCEPT(ctx->sock, (struct sockaddr *) &add, &size); #endif - } if(CURL_SOCKET_BAD == s_accepted) { - failf(data, "Error accept()ing server connect"); - return CURLE_FTP_PORT_FAILED; + failf(data, "Error accept()ing server connect: %s", + curlx_strerror(SOCKERRNO, errbuf, sizeof(errbuf))); + return CURLE_FTP_ACCEPT_FAILED; } infof(data, "Connection accepted from server"); From 9e3c35a88e9433fcc7edae4323605025f232f0bb Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 09:54:39 +0200 Subject: [PATCH 297/465] ftp: fix the 213 scanner memchr buffer limit argument Reported-by: Joshua Rogers Closes #18867 --- lib/ftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ftp.c b/lib/ftp.c index a3194c2a7b37..10a61d36891c 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -2319,7 +2319,7 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data, for all the digits at the end of the response and parse only those as a number. */ char *start = &buf[4]; - const char *fdigit = memchr(start, '\r', len); + const char *fdigit = memchr(start, '\r', len - 4); if(fdigit) { fdigit--; if(*fdigit == '\n') From 172e190c798645b9d04dd97ae0cf51b35317971e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 10:11:30 +0200 Subject: [PATCH 298/465] ftp: add extra buffer length check This adds an extra check that the buffer really has data enough (at least 4 bytes) to check for a status code before doing so. It *should* not be necessary, but this was pointed out by an analyzer and it feels better to make sure. Reported-by: Joshua Rogers Closes #18869 --- lib/ftp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/ftp.c b/lib/ftp.c index 10a61d36891c..77db98c005ad 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -479,13 +479,14 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data, infof(data, "Ctrl conn has data while waiting for data conn"); if(pp->overflow > 3) { const char *r = curlx_dyn_ptr(&pp->recvbuf); + size_t len = curlx_dyn_len(&pp->recvbuf); - DEBUGASSERT((pp->overflow + pp->nfinal) <= - curlx_dyn_len(&pp->recvbuf)); + DEBUGASSERT((pp->overflow + pp->nfinal) <= curlx_dyn_len(&pp->recvbuf)); /* move over the most recently handled response line */ r += pp->nfinal; + len -= pp->nfinal; - if(LASTLINE(r)) { + if((len > 3) && LASTLINE(r)) { curl_off_t status; if(!curlx_str_number(&r, &status, 999) && (status == 226)) { /* funny timing situation where we get the final message on the From 6ef4871f5d56d5d7e99dfb65d69bf47e9861887b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 10:20:45 +0200 Subject: [PATCH 299/465] ftp: improve fragile check for first digit > 3 In a case where rubbish would be sent in the line something that isn't a digit could be first in line and treated as less than '3'. Prevent this risk by first doing a check that the byte is a digit. Reported-by: Joshua Rogers Closes #18870 --- lib/ftp.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/ftp.c b/lib/ftp.c index 77db98c005ad..402c13a07c20 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -449,11 +449,14 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data, bool response = FALSE; /* First check whether there is a cached response from server */ - if(curlx_dyn_len(&pp->recvbuf) && (*curlx_dyn_ptr(&pp->recvbuf) > '3')) { - /* Data connection could not be established, let's return */ - infof(data, "There is negative response in cache while serv connect"); - (void)getftpresponse(data, &nread, &ftpcode); - return CURLE_FTP_ACCEPT_FAILED; + if(curlx_dyn_len(&pp->recvbuf)) { + const char *l = curlx_dyn_ptr(&pp->recvbuf); + if(!ISDIGIT(*l) || (*l > '3')) { + /* Data connection could not be established, let's return */ + infof(data, "There is negative response in cache while serv connect"); + (void)getftpresponse(data, &nread, &ftpcode); + return CURLE_FTP_ACCEPT_FAILED; + } } if(pp->overflow) From 2b0e7cb7c677cef10d4d1baf2fc2116ff909a407 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 10:34:22 +0200 Subject: [PATCH 300/465] ftp: remove misleading comments They indicated that sockets would not be closed but they are. Reported-by: Joshua Rogers Closes #18871 --- lib/ftp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ftp.c b/lib/ftp.c index 402c13a07c20..32d3c445df4e 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -2418,7 +2418,6 @@ static CURLcode ftp_state_stor_resp(struct Curl_easy *data, if(ftpcode >= 400) { failf(data, "Failed FTP upload: %0d", ftpcode); ftp_state(data, ftpc, FTP_STOP); - /* oops, we never close the sockets! */ return CURLE_UPLOAD_FAILED; } From 92a212568403d985a2614a7d206bf34b7a8fb827 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 10:56:44 +0200 Subject: [PATCH 301/465] telnet: make bad_option() consider NULL a bad option too Follow-up to a72e1552f22 Closes #18873 --- lib/telnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/telnet.c b/lib/telnet.c index 90316a446ccb..259a0c8931ce 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -930,7 +930,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data, rather just ban its use instead */ static bool bad_option(const char *data) { - return !!strchr(data, CURL_IAC); + return !data || !!strchr(data, CURL_IAC); } /* From ef1794e50e111dd4683b12875be7a685c63e44ca Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 6 Oct 2025 15:46:29 +0200 Subject: [PATCH 302/465] ldap: tidy-up types, fix error code confusion - fix `CURLcode` vs. LDAP result code confusion. Return `LDAP_NO_MEMORY` when `Curl_create_sspi_identity()` fails, since it can only return `CURLE_OUT_OF_MEMORY` as error. - use `ULONG` for result code on Windows. Drop casts. - use portable `curl_ldap_num_t`. Drop casts. - replace magic number 0 with `LDAP_SUCCESS`. - compare with `LDAP_SUCCESS` instead of assuming non-zero. (where necessary.) - add/fix `#endif` comments. - fix indentation. Closes #18888 --- lib/ldap.c | 119 +++++++++++++++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 58 deletions(-) diff --git a/lib/ldap.c b/lib/ldap.c index 66cf8916d689..8a39c1a4becf 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -98,6 +98,14 @@ #include "curl_memory.h" #include "memdebug.h" +#ifdef USE_WIN32_LDAP +#define FREE_ON_WINLDAP(x) curlx_unicodefree(x) +#define curl_ldap_num_t ULONG +#else +#define FREE_ON_WINLDAP(x) +#define curl_ldap_num_t int +#endif + #ifndef HAVE_LDAP_URL_PARSE /* Use our own implementation. */ @@ -127,14 +135,15 @@ struct ldap_urldesc { #undef LDAPURLDesc #define LDAPURLDesc struct ldap_urldesc -static int ldap_url_parse_low(struct Curl_easy *data, - const struct connectdata *conn, - LDAPURLDesc **ludp); +static curl_ldap_num_t ldap_url_parse_low(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc **ludp); static void ldap_free_urldesc_low(LDAPURLDesc *ludp); #undef ldap_free_urldesc #define ldap_free_urldesc ldap_free_urldesc_low -#endif + +#endif /* !HAVE_LDAP_URL_PARSE */ #ifdef DEBUG_LDAP #define LDAP_TRACE(x) do { \ @@ -227,12 +236,12 @@ const struct Curl_handler Curl_handler_ldaps = { #ifdef USE_WIN32_LDAP #ifdef USE_WINDOWS_SSPI -static int ldap_win_bind_auth(LDAP *server, const char *user, - const char *passwd, unsigned long authflags) +static ULONG ldap_win_bind_auth(LDAP *server, const char *user, + const char *passwd, unsigned long authflags) { ULONG method = 0; SEC_WINNT_AUTH_IDENTITY cred; - int rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; + ULONG rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; memset(&cred, 0, sizeof(cred)); @@ -260,25 +269,27 @@ static int ldap_win_bind_auth(LDAP *server, const char *user, if(method && user && passwd) { CURLcode res = Curl_create_sspi_identity(user, passwd, &cred); - rc = (int)res; - if(!rc) { - rc = (int)ldap_bind_s(server, NULL, (TCHAR *)&cred, method); + if(!res) { + rc = ldap_bind_s(server, NULL, (TCHAR *)&cred, method); Curl_sspi_free_identity(&cred); } + else { + rc = LDAP_NO_MEMORY; + } } else { /* proceed with current user credentials */ method = LDAP_AUTH_NEGOTIATE; - rc = (int)ldap_bind_s(server, NULL, NULL, method); + rc = ldap_bind_s(server, NULL, NULL, method); } return rc; } #endif /* USE_WINDOWS_SSPI */ -static int ldap_win_bind(struct Curl_easy *data, LDAP *server, - const char *user, const char *passwd) +static ULONG ldap_win_bind(struct Curl_easy *data, LDAP *server, + const char *user, const char *passwd) { - int rc = LDAP_INVALID_CREDENTIALS; + ULONG rc = LDAP_INVALID_CREDENTIALS; PTCHAR inuser = NULL; PTCHAR inpass = NULL; @@ -287,14 +298,14 @@ static int ldap_win_bind(struct Curl_easy *data, LDAP *server, inuser = curlx_convert_UTF8_to_tchar(user); inpass = curlx_convert_UTF8_to_tchar(passwd); - rc = (int)ldap_simple_bind_s(server, inuser, inpass); + rc = ldap_simple_bind_s(server, inuser, inpass); curlx_unicodefree(inuser); curlx_unicodefree(inpass); } #ifdef USE_WINDOWS_SSPI else { - rc = (int)ldap_win_bind_auth(server, user, passwd, data->set.httpauth); + rc = ldap_win_bind_auth(server, user, passwd, data->set.httpauth); } #endif @@ -302,19 +313,10 @@ static int ldap_win_bind(struct Curl_easy *data, LDAP *server, } #endif /* USE_WIN32_LDAP */ -#ifdef USE_WIN32_LDAP -#define FREE_ON_WINLDAP(x) curlx_unicodefree(x) -#define curl_ldap_num_t ULONG -#else -#define FREE_ON_WINLDAP(x) -#define curl_ldap_num_t int -#endif - - static CURLcode ldap_do(struct Curl_easy *data, bool *done) { CURLcode result = CURLE_OK; - int rc = 0; + curl_ldap_num_t rc = LDAP_SUCCESS; LDAP *server = NULL; LDAPURLDesc *ludp = NULL; LDAPMessage *ldapmsg = NULL; @@ -349,7 +351,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) rc = ldap_url_parse_low(data, conn, &ludp); #endif if(rc) { - failf(data, "Bad LDAP URL: %s", ldap_err2string((curl_ldap_num_t)rc)); + failf(data, "Bad LDAP URL: %s", ldap_err2string(rc)); result = CURLE_URL_MALFORMAT; goto quit; } @@ -391,7 +393,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) /* Win32 LDAP SDK does not support insecure mode without CA! */ server = ldap_sslinit(host, (curl_ldap_num_t)ipquad.remote_port, 1); ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); -#else +#else /* !USE_WIN32_LDAP */ int ldap_option; char *ldap_ca = conn->ssl_config.CAfile; #ifdef LDAP_OPT_X_TLS @@ -412,7 +414,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting PEM CA cert: %s", - ldap_err2string(rc)); + ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } @@ -424,7 +426,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting cert verify mode: %s", - ldap_err2string(rc)); + ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } @@ -439,31 +441,32 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s", - ldap_err2string(rc)); + ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } -/* +#if 0 rc = ldap_start_tls_s(server, NULL, NULL); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s", - ldap_err2string(rc)); + ldap_err2string(rc)); result = CURLE_SSL_CERTPROBLEM; goto quit; } -*/ -#else +#endif + +#else /* !LDAP_OPT_X_TLS */ (void)ldap_option; (void)ldap_ca; /* we should probably never come up to here since configure should check in first place if we can support LDAP SSL/TLS */ failf(data, "LDAP local: SSL/TLS not supported with this version " - "of the OpenLDAP toolkit\n"); + "of the OpenLDAP toolkit\n"); result = CURLE_SSL_CERTPROBLEM; goto quit; -#endif -#endif -#endif /* CURL_LDAP_USE_SSL */ +#endif /* LDAP_OPT_X_TLS */ +#endif /* USE_WIN32_LDAP */ +#endif /* HAVE_LDAP_SSL */ } else if(data->set.use_ssl > CURLUSESSL_TRY) { failf(data, "LDAP local: explicit TLS not supported"); @@ -485,7 +488,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #else rc = ldap_simple_bind_s(server, user, passwd); #endif - if(!ldap_ssl && rc) { + if(!ldap_ssl && rc != LDAP_SUCCESS) { ldap_proto = LDAP_VERSION2; ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); #ifdef USE_WIN32_LDAP @@ -494,10 +497,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) rc = ldap_simple_bind_s(server, user, passwd); #endif } - if(rc) { + if(rc != LDAP_SUCCESS) { #ifdef USE_WIN32_LDAP failf(data, "LDAP local: bind via ldap_win_bind %s", - ldap_err2string((ULONG)rc)); + ldap_err2string(rc)); #else failf(data, "LDAP local: bind via ldap_simple_bind_s %s", ldap_err2string(rc)); @@ -507,12 +510,12 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) } Curl_pgrsSetDownloadCounter(data, 0); - rc = (int)ldap_search_s(server, ludp->lud_dn, - (curl_ldap_num_t)ludp->lud_scope, - ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg); + rc = ldap_search_s(server, ludp->lud_dn, + (curl_ldap_num_t)ludp->lud_scope, + ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg); - if(rc && rc != LDAP_SIZELIMIT_EXCEEDED) { - failf(data, "LDAP remote: %s", ldap_err2string((curl_ldap_num_t)rc)); + if(rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED) { + failf(data, "LDAP remote: %s", ldap_err2string(rc)); result = CURLE_LDAP_SEARCH_FAILED; goto quit; } @@ -746,7 +749,7 @@ static void ldap_trace_low(const char *fmt, ...) vfprintf(stderr, fmt, args); va_end(args); } -#endif +#endif /* DEBUG_LDAP */ #ifndef HAVE_LDAP_URL_PARSE @@ -795,11 +798,11 @@ static size_t num_entries(const char *s) * * Defined in RFC4516 section 2. */ -static int ldap_url_parse2_low(struct Curl_easy *data, - const struct connectdata *conn, - LDAPURLDesc *ludp) +static curl_ldap_num_t ldap_url_parse2_low(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc *ludp) { - int rc = LDAP_SUCCESS; + curl_ldap_num_t rc = LDAP_SUCCESS; char *p; char *path; char *q = NULL; @@ -1000,12 +1003,12 @@ static int ldap_url_parse2_low(struct Curl_easy *data, return rc; } -static int ldap_url_parse_low(struct Curl_easy *data, - const struct connectdata *conn, - LDAPURLDesc **ludpp) +static curl_ldap_num_t ldap_url_parse_low(struct Curl_easy *data, + const struct connectdata *conn, + LDAPURLDesc **ludpp) { LDAPURLDesc *ludp = calloc(1, sizeof(*ludp)); - int rc; + curl_ldap_num_t rc; *ludpp = NULL; if(!ludp) @@ -1047,10 +1050,10 @@ static void ldap_free_urldesc_low(LDAPURLDesc *ludp) free(ludp); } -#endif /* !HAVE_LDAP_URL_PARSE */ +#endif /* !HAVE_LDAP_URL_PARSE */ #if defined(__GNUC__) && defined(__APPLE__) #pragma GCC diagnostic pop #endif -#endif /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */ +#endif /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */ From beeb1ae762d60ed84695d874d979e5095649d29d Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 6 Oct 2025 20:00:55 +0200 Subject: [PATCH 303/465] GHA/configure-vs-cmake: reduce windows cross-toolchain apt installs Download size: 277 MB -> 65 MB (installed: 1293 MB -> 401 MB) Also as a workaround for Azure Ubuntu mirror slowdown issues: https://github.com/curl/curl/actions/runs/18289326469/job/52072333582?pr=18866 Follow-up to 0455d8772a1af20ce63c46c5738582aa9b1b8441 #18509 Closes #18896 --- .github/workflows/configure-vs-cmake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/configure-vs-cmake.yml b/.github/workflows/configure-vs-cmake.yml index 35f5290d1898..5c35051f6a34 100644 --- a/.github/workflows/configure-vs-cmake.yml +++ b/.github/workflows/configure-vs-cmake.yml @@ -131,7 +131,7 @@ jobs: - name: 'install packages' run: | sudo rm -f /var/lib/man-db/auto-update - sudo apt-get -o Dpkg::Use-Pty=0 install mingw-w64 + sudo apt-get -o Dpkg::Use-Pty=0 install gcc-mingw-w64-x86-64-win32 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: From 13f10add17da864069dd1c1709cab7c4cdbb41cf Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 6 Oct 2025 20:35:38 +0200 Subject: [PATCH 304/465] REUSE: bump reuse to v6, add more fences to fix issues Closes #18895 Closes #18897 --- .github/scripts/requirements.txt | 2 +- scripts/cd2cd | 2 ++ scripts/cd2nroff | 2 ++ scripts/managen | 4 ++++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 7cb10c47f866..c20a74767376 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,5 +5,5 @@ cmakelang==0.6.13 codespell==2.4.1 pytype==2024.10.11 -reuse==5.1.1 +reuse==6.0.0 ruff==0.13.2 diff --git a/scripts/cd2cd b/scripts/cd2cd index f4748f5d9bfe..9356ade6e63b 100755 --- a/scripts/cd2cd +++ b/scripts/cd2cd @@ -156,7 +156,9 @@ sub single { return 2; } if(!$spdx) { + # REUSE-IgnoreStart print STDERR "$f:$line:1:ERROR: no 'SPDX-License-Identifier:' field present\n"; + # REUSE-IgnoreEnd return 2; } last; diff --git a/scripts/cd2nroff b/scripts/cd2nroff index d7a5dfe7b0af..950011173b89 100755 --- a/scripts/cd2nroff +++ b/scripts/cd2nroff @@ -320,7 +320,9 @@ sub single { return 2; } if(!$spdx) { + # REUSE-IgnoreStart print STDERR "$f:$line:1:ERROR: no 'SPDX-License-Identifier:' field present\n"; + # REUSE-IgnoreEnd return 2; } if($section == 3) { diff --git a/scripts/managen b/scripts/managen index 4849fe8378db..17c8677882d2 100755 --- a/scripts/managen +++ b/scripts/managen @@ -661,12 +661,14 @@ sub single { elsif(/^Experimental: yes/i) { $experimental=1; } + # REUSE-IgnoreStart elsif(/^C: (.*)/i) { $copyright=$1; } elsif(/^SPDX-License-Identifier: (.*)/i) { $spdx=$1; } + # REUSE-IgnoreEnd elsif(/^Help: *(.*)/i) { ; } @@ -697,7 +699,9 @@ sub single { return 2; } if(!$spdx) { + # REUSE-IgnoreStart print STDERR "$f:$line:1:ERROR: no 'SPDX-License-Identifier:' field present\n"; + # REUSE-IgnoreEnd return 2; } last; From b12da22db1f11da51082977dc21a7edee7858911 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 4 Oct 2025 12:58:49 +0200 Subject: [PATCH 305/465] lib: stop overriding system printf symbols After this patch, the codebase no longer overrides system printf functions. Instead it explicitly calls either the curl printf functions `curl_m*printf()` or the system ones using their original names. Also: - drop unused `curl_printf.h` includes. - checksrc: ban system printf functions, allow where necessary. Follow-up to db98daab05aec251bcb6615d2d38dfebec291736 #18844 Follow-up to 4deea9396bc7dd25c6362fa746a57bf309c74ada #18814 Closes #18866 --- REUSE.toml | 10 +- docs/examples/.checksrc | 2 + lib/.checksrc | 0 lib/Makefile.am | 5 +- lib/altsvc.c | 37 ++-- lib/asyn-ares.c | 5 +- lib/asyn-thrdd.c | 5 +- lib/bufq.c | 3 +- lib/cf-h1-proxy.c | 3 +- lib/cf-h2-proxy.c | 82 ++++----- lib/cf-haproxy.c | 3 +- lib/cf-https-connect.c | 3 +- lib/cf-ip-happy.c | 8 +- lib/cf-socket.c | 3 +- lib/cfilters.c | 3 +- lib/conncache.c | 11 +- lib/connect.c | 5 +- lib/content_encoding.c | 3 +- lib/cookie.c | 7 +- lib/cshutdn.c | 3 +- lib/curl_addrinfo.c | 4 +- lib/curl_fopen.c | 6 +- lib/curl_gssapi.c | 16 +- lib/curl_ntlm_core.c | 21 +-- lib/curl_printf.h | 27 --- lib/curl_rtmp.c | 9 +- lib/curl_sasl.c | 4 +- lib/curl_setup.h | 4 +- lib/curl_trc.c | 27 ++- lib/curlx/.checksrc | 0 lib/cw-out.c | 3 +- lib/cw-pause.c | 3 +- lib/dict.c | 6 +- lib/dllmain.c | 3 +- lib/doh.c | 10 +- lib/dynhds.c | 4 +- lib/easy.c | 41 +++-- lib/escape.c | 4 +- lib/fake_addrinfo.c | 5 +- lib/file.c | 26 +-- lib/formdata.c | 4 +- lib/ftp.c | 52 +++--- lib/ftplistparser.c | 3 +- lib/gopher.c | 6 +- lib/hash.c | 14 +- lib/headers.c | 3 +- lib/hostip.c | 5 +- lib/hostip4.c | 6 +- lib/hostip6.c | 15 +- lib/hsts.c | 21 ++- lib/http.c | 69 +++---- lib/http1.c | 3 +- lib/http2.c | 89 ++++----- lib/http_aws_sigv4.c | 128 ++++++------- lib/http_chunks.c | 3 +- lib/http_digest.c | 12 +- lib/http_negotiate.c | 7 +- lib/http_ntlm.c | 15 +- lib/http_proxy.c | 7 +- lib/httpsrr.c | 3 +- lib/idn.c | 3 +- lib/if2ip.c | 8 +- lib/imap.c | 9 +- lib/ldap.c | 6 +- lib/md4.c | 3 +- lib/md5.c | 3 +- lib/memdebug.c | 9 +- lib/mime.c | 6 +- lib/mqtt.c | 5 +- lib/multi.c | 26 +-- lib/multi_ev.c | 4 +- lib/netrc.c | 7 +- lib/noproxy.c | 7 +- lib/openldap.c | 16 +- lib/pingpong.c | 3 +- lib/pop3.c | 6 +- lib/progress.c | 71 ++++---- lib/psl.c | 3 +- lib/rand.c | 3 +- lib/rename.c | 3 +- lib/request.c | 3 +- lib/rtsp.c | 17 +- lib/select.c | 4 +- lib/sendf.c | 3 +- lib/setopt.c | 3 +- lib/sha256.c | 3 +- lib/share.c | 3 +- lib/smb.c | 25 ++- lib/smtp.c | 13 +- lib/socketpair.c | 3 +- lib/socks.c | 3 +- lib/socks_gssapi.c | 7 +- lib/socks_sspi.c | 7 +- lib/telnet.c | 39 ++-- lib/tftp.c | 19 +- lib/transfer.c | 5 +- lib/uint-bset.c | 3 +- lib/uint-spbset.c | 3 +- lib/uint-table.c | 3 +- lib/url.c | 35 ++-- lib/urlapi.c | 57 +++--- lib/vauth/.checksrc | 0 lib/vauth/cleartext.c | 1 - lib/vauth/cram.c | 3 +- lib/vauth/digest.c | 98 +++++----- lib/vauth/gsasl.c | 3 +- lib/vauth/krb5_gssapi.c | 1 - lib/vauth/ntlm.c | 327 +++++++++++++++++----------------- lib/vauth/oauth2.c | 11 +- lib/vauth/vauth.c | 9 +- lib/version.c | 35 ++-- lib/vquic/.checksrc | 0 lib/vquic/curl_ngtcp2.c | 11 +- lib/vquic/curl_osslq.c | 15 +- lib/vquic/curl_quiche.c | 7 +- lib/vquic/vquic-tls.c | 3 +- lib/vquic/vquic.c | 5 +- lib/vssh/.checksrc | 0 lib/vssh/libssh.c | 56 +++--- lib/vssh/libssh2.c | 63 +++---- lib/vtls/.checksrc | 0 lib/vtls/cipher_suite.c | 7 +- lib/vtls/gtls.c | 27 ++- lib/vtls/mbedtls.c | 11 +- lib/vtls/mbedtls_threadlock.c | 20 +-- lib/vtls/openssl.c | 66 +++---- lib/vtls/rustls.c | 6 +- lib/vtls/schannel.c | 7 +- lib/vtls/schannel_verify.c | 1 - lib/vtls/vtls.c | 5 +- lib/vtls/vtls_scache.c | 1 - lib/vtls/wolfssl.c | 5 +- lib/vtls/x509asn1.c | 7 +- lib/ws.c | 3 +- packages/OS400/curlcl.c | 1 + scripts/.checksrc | 1 + scripts/Makefile.am | 2 +- scripts/checksrc.pl | 8 + src/.checksrc | 8 - tests/cmake/test.c | 1 + tests/libtest/.checksrc | 8 - tests/libtest/Makefile.am | 2 +- tests/server/.checksrc | 2 + tests/tunit/.checksrc | 8 - tests/tunit/Makefile.am | 2 +- tests/unit/.checksrc | 8 - tests/unit/Makefile.am | 2 +- 147 files changed, 1050 insertions(+), 1165 deletions(-) delete mode 100644 lib/.checksrc delete mode 100644 lib/curlx/.checksrc delete mode 100644 lib/vauth/.checksrc delete mode 100644 lib/vquic/.checksrc delete mode 100644 lib/vssh/.checksrc delete mode 100644 lib/vtls/.checksrc create mode 100644 scripts/.checksrc delete mode 100644 tests/libtest/.checksrc delete mode 100644 tests/tunit/.checksrc delete mode 100644 tests/unit/.checksrc diff --git a/REUSE.toml b/REUSE.toml index 0d07c8b3e152..d3b98edb4879 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -41,17 +41,9 @@ path = [ "tests/valgrind.supp", # checksrc control files "docs/examples/.checksrc", - "lib/.checksrc", - "lib/curlx/.checksrc", - "lib/vauth/.checksrc", - "lib/vquic/.checksrc", - "lib/vssh/.checksrc", - "lib/vtls/.checksrc", + "scripts/.checksrc", "src/.checksrc", - "tests/libtest/.checksrc", "tests/server/.checksrc", - "tests/tunit/.checksrc", - "tests/unit/.checksrc", ] SPDX-FileCopyrightText = "Daniel Stenberg, , et al." SPDX-License-Identifier = "curl" diff --git a/docs/examples/.checksrc b/docs/examples/.checksrc index 336e1928d206..59899762bfde 100644 --- a/docs/examples/.checksrc +++ b/docs/examples/.checksrc @@ -1,9 +1,11 @@ allowfunc fclose allowfunc fdopen allowfunc fopen +allowfunc fprintf allowfunc gmtime allowfunc localtime allowfunc open +allowfunc printf allowfunc snprintf allowfunc socket allowfunc sscanf diff --git a/lib/.checksrc b/lib/.checksrc deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/Makefile.am b/lib/Makefile.am index 973876f50108..784b7f35d61e 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -28,12 +28,9 @@ include Makefile.inc CMAKE_DIST = CMakeLists.txt curl_config.h.cmake -CHECKSRC_DIST = .checksrc \ - curlx/.checksrc vauth/.checksrc vquic/.checksrc vssh/.checksrc vtls/.checksrc - EXTRA_DIST = config-mac.h config-os400.h config-plan9.h config-riscos.h \ config-win32.h curl_config.h.in $(LIB_RCFILES) libcurl.def \ - $(CMAKE_DIST) Makefile.soname optiontable.pl $(CHECKSRC_DIST) + $(CMAKE_DIST) Makefile.soname optiontable.pl lib_LTLIBRARIES = libcurl.la diff --git a/lib/altsvc.c b/lib/altsvc.c index 7e4c4b5c25a7..449bea8528dc 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -42,8 +42,7 @@ #include "curlx/strparse.h" #include "connect.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -270,23 +269,23 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp) } } #endif - fprintf(fp, - "%s %s%s%s %u " - "%s %s%s%s %u " - "\"%d%02d%02d " - "%02d:%02d:%02d\" " - "%u %u\n", - Curl_alpnid2str(as->src.alpnid), - src6_pre, as->src.host, src6_post, - as->src.port, - - Curl_alpnid2str(as->dst.alpnid), - dst6_pre, as->dst.host, dst6_post, - as->dst.port, - - stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, - stamp.tm_hour, stamp.tm_min, stamp.tm_sec, - as->persist, as->prio); + curl_mfprintf(fp, + "%s %s%s%s %u " + "%s %s%s%s %u " + "\"%d%02d%02d " + "%02d:%02d:%02d\" " + "%u %u\n", + Curl_alpnid2str(as->src.alpnid), + src6_pre, as->src.host, src6_post, + as->src.port, + + Curl_alpnid2str(as->dst.alpnid), + dst6_pre, as->dst.host, dst6_post, + as->dst.port, + + stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, + stamp.tm_hour, stamp.tm_min, stamp.tm_sec, + as->persist, as->prio); return CURLE_OK; } diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index a9988806ac20..236697695eda 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -105,8 +105,7 @@ #define HTTPSRR_WORKS #endif -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -782,7 +781,7 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data, * accordingly to save a call to getservbyname in inside C-Ares */ hints.ai_flags = ARES_AI_NUMERICSERV; - msnprintf(service, sizeof(service), "%d", port); + curl_msnprintf(service, sizeof(service), "%d", port); ares->num_pending = 1; ares_getaddrinfo(ares->channel, data->state.async.hostname, service, &hints, async_ares_addrinfo_cb, data); diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index 2aa16de7287c..dc13143e245d 100644 --- a/lib/asyn-thrdd.c +++ b/lib/asyn-thrdd.c @@ -73,8 +73,7 @@ #endif #endif -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -220,7 +219,7 @@ static CURL_THREAD_RETURN_T CURL_STDCALL getaddrinfo_thread(void *arg) char service[12]; int rc; - msnprintf(service, sizeof(service), "%d", addr_ctx->port); + curl_msnprintf(service, sizeof(service), "%d", addr_ctx->port); rc = Curl_getaddrinfo_ex(addr_ctx->hostname, service, &addr_ctx->hints, &addr_ctx->res); diff --git a/lib/bufq.c b/lib/bufq.c index 5cfd7520f2e6..e429ccf8e375 100644 --- a/lib/bufq.c +++ b/lib/bufq.c @@ -25,8 +25,7 @@ #include "curl_setup.h" #include "bufq.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/cf-h1-proxy.c b/lib/cf-h1-proxy.c index 798d6e9f6681..e65aa74ddb87 100644 --- a/lib/cf-h1-proxy.c +++ b/lib/cf-h1-proxy.c @@ -46,8 +46,7 @@ #include "multiif.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/cf-h2-proxy.c b/lib/cf-h2-proxy.c index 17a15c1d2ada..8baa227aac22 100644 --- a/lib/cf-h2-proxy.c +++ b/lib/cf-h2-proxy.c @@ -44,8 +44,7 @@ #include "select.h" #include "cf-h2-proxy.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -101,8 +100,8 @@ static CURLcode tunnel_stream_init(struct Curl_cfilter *cf, return result; ts->authority = /* host:port with IPv6 support */ - aprintf("%s%s%s:%d", ipv6_ip ? "[":"", hostname, - ipv6_ip ? "]" : "", port); + curl_maprintf("%s%s%s:%d", ipv6_ip ? "[":"", hostname, + ipv6_ip ? "]" : "", port); if(!ts->authority) return CURLE_OUT_OF_MEMORY; @@ -556,47 +555,47 @@ static int proxy_h2_fr_print(const nghttp2_frame *frame, { switch(frame->hd.type) { case NGHTTP2_DATA: { - return msnprintf(buffer, blen, - "FRAME[DATA, len=%d, eos=%d, padlen=%d]", - (int)frame->hd.length, - !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM), - (int)frame->data.padlen); + return curl_msnprintf(buffer, blen, + "FRAME[DATA, len=%d, eos=%d, padlen=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM), + (int)frame->data.padlen); } case NGHTTP2_HEADERS: { - return msnprintf(buffer, blen, - "FRAME[HEADERS, len=%d, hend=%d, eos=%d]", - (int)frame->hd.length, - !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS), - !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)); + return curl_msnprintf(buffer, blen, + "FRAME[HEADERS, len=%d, hend=%d, eos=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS), + !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)); } case NGHTTP2_PRIORITY: { - return msnprintf(buffer, blen, - "FRAME[PRIORITY, len=%d, flags=%d]", - (int)frame->hd.length, frame->hd.flags); + return curl_msnprintf(buffer, blen, + "FRAME[PRIORITY, len=%d, flags=%d]", + (int)frame->hd.length, frame->hd.flags); } case NGHTTP2_RST_STREAM: { - return msnprintf(buffer, blen, - "FRAME[RST_STREAM, len=%d, flags=%d, error=%u]", - (int)frame->hd.length, frame->hd.flags, - frame->rst_stream.error_code); + return curl_msnprintf(buffer, blen, + "FRAME[RST_STREAM, len=%d, flags=%d, error=%u]", + (int)frame->hd.length, frame->hd.flags, + frame->rst_stream.error_code); } case NGHTTP2_SETTINGS: { if(frame->hd.flags & NGHTTP2_FLAG_ACK) { - return msnprintf(buffer, blen, "FRAME[SETTINGS, ack=1]"); + return curl_msnprintf(buffer, blen, "FRAME[SETTINGS, ack=1]"); } - return msnprintf(buffer, blen, - "FRAME[SETTINGS, len=%d]", (int)frame->hd.length); + return curl_msnprintf(buffer, blen, + "FRAME[SETTINGS, len=%d]", (int)frame->hd.length); } case NGHTTP2_PUSH_PROMISE: - return msnprintf(buffer, blen, - "FRAME[PUSH_PROMISE, len=%d, hend=%d]", - (int)frame->hd.length, - !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS)); + return curl_msnprintf(buffer, blen, + "FRAME[PUSH_PROMISE, len=%d, hend=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS)); case NGHTTP2_PING: - return msnprintf(buffer, blen, - "FRAME[PING, len=%d, ack=%d]", - (int)frame->hd.length, - frame->hd.flags & NGHTTP2_FLAG_ACK); + return curl_msnprintf(buffer, blen, + "FRAME[PING, len=%d, ack=%d]", + (int)frame->hd.length, + frame->hd.flags & NGHTTP2_FLAG_ACK); case NGHTTP2_GOAWAY: { char scratch[128]; size_t s_len = CURL_ARRAYSIZE(scratch); @@ -605,19 +604,20 @@ static int proxy_h2_fr_print(const nghttp2_frame *frame, if(len) memcpy(scratch, frame->goaway.opaque_data, len); scratch[len] = '\0'; - return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', " - "last_stream=%d]", frame->goaway.error_code, - scratch, frame->goaway.last_stream_id); + return curl_msnprintf(buffer, blen, + "FRAME[GOAWAY, error=%d, reason='%s', " + "last_stream=%d]", frame->goaway.error_code, + scratch, frame->goaway.last_stream_id); } case NGHTTP2_WINDOW_UPDATE: { - return msnprintf(buffer, blen, - "FRAME[WINDOW_UPDATE, incr=%d]", - frame->window_update.window_size_increment); + return curl_msnprintf(buffer, blen, + "FRAME[WINDOW_UPDATE, incr=%d]", + frame->window_update.window_size_increment); } default: - return msnprintf(buffer, blen, "FRAME[%d, len=%d, flags=%d]", - frame->hd.type, (int)frame->hd.length, - frame->hd.flags); + return curl_msnprintf(buffer, blen, "FRAME[%d, len=%d, flags=%d]", + frame->hd.type, (int)frame->hd.length, + frame->hd.flags); } } diff --git a/lib/cf-haproxy.c b/lib/cf-haproxy.c index 2d66efea9040..3231791097ed 100644 --- a/lib/cf-haproxy.c +++ b/lib/cf-haproxy.c @@ -34,8 +34,7 @@ #include "multiif.h" #include "select.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/cf-https-connect.c b/lib/cf-https-connect.c index b4a460529502..5d6724dbc5e2 100644 --- a/lib/cf-https-connect.c +++ b/lib/cf-https-connect.c @@ -38,8 +38,7 @@ #include "select.h" #include "vquic/vquic.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index c0150dd08747..f6675e275db6 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -60,8 +60,7 @@ #include "select.h" #include "vquic/vquic.h" /* for quic cfilters */ -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -662,7 +661,8 @@ static CURLcode is_connected(struct Curl_cfilter *cf, #ifdef USE_UNIX_SOCKETS if(conn->unix_domain_socket) - msnprintf(viamsg, sizeof(viamsg), "over %s", conn->unix_domain_socket); + curl_msnprintf(viamsg, sizeof(viamsg), "over %s", + conn->unix_domain_socket); else #endif { @@ -673,7 +673,7 @@ static CURLcode is_connected(struct Curl_cfilter *cf, port = conn->conn_to_port; else port = conn->remote_port; - msnprintf(viamsg, sizeof(viamsg), "port %u", port); + curl_msnprintf(viamsg, sizeof(viamsg), "port %u", port); } failf(data, "Failed to connect to %s %s %s%s%safter " diff --git a/lib/cf-socket.c b/lib/cf-socket.c index aa79ac45a4f9..0182de67e80a 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -82,8 +82,7 @@ #include "curlx/strerr.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/cfilters.c b/lib/cfilters.c index 07f3c5f7b462..d0466f5fadb1 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -37,8 +37,7 @@ #include "curlx/warnless.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/conncache.c b/lib/conncache.c index a8fc51c21352..67e2a63d8a57 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -45,8 +45,7 @@ #include "curlx/strparse.h" #include "uint-table.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -895,7 +894,7 @@ void Curl_cpool_print(struct cpool *cpool) if(!cpool) return; - fprintf(stderr, "=Bundle cache=\n"); + curl_mfprintf(stderr, "=Bundle cache=\n"); Curl_hash_start_iterate(cpool->dest2bundle, &iter); @@ -906,15 +905,15 @@ void Curl_cpool_print(struct cpool *cpool) bundle = he->ptr; - fprintf(stderr, "%s -", he->key); + curl_mfprintf(stderr, "%s -", he->key); curr = Curl_llist_head(bundle->conns); while(curr) { conn = Curl_node_elem(curr); - fprintf(stderr, " [%p %d]", (void *)conn, conn->refcount); + curl_mfprintf(stderr, " [%p %d]", (void *)conn, conn->refcount); curr = Curl_node_next(curr); } - fprintf(stderr, "\n"); + curl_mfprintf(stderr, "\n"); he = Curl_hash_next_element(&iter); } diff --git a/lib/connect.c b/lib/connect.c index 4f42fef0e833..efe6248214e9 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -75,8 +75,7 @@ #include "http_proxy.h" #include "socks.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -267,7 +266,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, case AF_UNIX: if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) { su = (struct sockaddr_un*)sa; - msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path); + curl_msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path); } else addr[0] = 0; /* socket with no name */ diff --git a/lib/content_encoding.c b/lib/content_encoding.c index 3a0549c4b1a3..28cccacdb647 100644 --- a/lib/content_encoding.c +++ b/lib/content_encoding.c @@ -53,8 +53,7 @@ #include "content_encoding.h" #include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/cookie.c b/lib/cookie.c index c5fbe1344dd6..59a841a303c7 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -89,8 +89,7 @@ Example set of cookies: #include "llist.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -1479,7 +1478,7 @@ void Curl_cookie_cleanup(struct CookieInfo *ci) */ static char *get_netscape_format(const struct Cookie *co) { - return aprintf( + return curl_maprintf( "%s" /* httponly preamble */ "%s%s\t" /* domain */ "%s\t" /* tailmatch */ @@ -1575,7 +1574,7 @@ static CURLcode cookie_output(struct Curl_easy *data, error = CURLE_OUT_OF_MEMORY; goto error; } - fprintf(out, "%s\n", format_ptr); + curl_mfprintf(out, "%s\n", format_ptr); free(format_ptr); } diff --git a/lib/cshutdn.c b/lib/cshutdn.c index 1c144c6025f4..c2788e7780a4 100644 --- a/lib/cshutdn.c +++ b/lib/cshutdn.c @@ -42,8 +42,7 @@ #include "select.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index c4ad71a02e1a..e26ee656bda4 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -53,8 +53,8 @@ #include "fake_addrinfo.h" #include "curlx/inet_pton.h" #include "curlx/warnless.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/curl_fopen.c b/lib/curl_fopen.c index 5e25f0eab60e..c41cff21cde9 100644 --- a/lib/curl_fopen.c +++ b/lib/curl_fopen.c @@ -30,8 +30,8 @@ #include "urldata.h" #include "rand.h" #include "curl_fopen.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -122,7 +122,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, if(dir) { /* The temp filename should not end up too long for the target file system */ - tempstore = aprintf("%s%s.tmp", dir, randbuf); + tempstore = curl_maprintf("%s%s.tmp", dir, randbuf); free(dir); } diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c index 92b867f7753b..87f644a9084f 100644 --- a/lib/curl_gssapi.c +++ b/lib/curl_gssapi.c @@ -29,8 +29,7 @@ #include "curl_gssapi.h" #include "sendf.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -244,9 +243,10 @@ stub_gss_init_sec_context(OM_uint32 *min, } /* Token format: creds:target:type:padding */ - used = msnprintf(token, length, "%s:%.*s:%d:", creds, - (int)target_desc.length, (const char *)target_desc.value, - ctx->sent); + used = curl_msnprintf(token, length, "%s:%.*s:%d:", creds, + (int)target_desc.length, + (const char *)target_desc.value, + ctx->sent); gss_release_buffer(&minor_status, &target_desc); } @@ -387,9 +387,9 @@ static size_t display_gss_error(OM_uint32 status, int type, &status_string); if(maj_stat == GSS_S_COMPLETE && status_string.length > 0) { if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) { - len += msnprintf(buf + len, GSS_LOG_BUFFER_LEN - len, - "%.*s. ", (int)status_string.length, - (char *)status_string.value); + len += curl_msnprintf(buf + len, GSS_LOG_BUFFER_LEN - len, + "%.*s. ", (int)status_string.length, + (char *)status_string.value); } } gss_release_buffer(&min_stat, &status_string); diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c index e040db2ab659..cf0e4dc28832 100644 --- a/lib/curl_ntlm_core.c +++ b/lib/curl_ntlm_core.c @@ -119,8 +119,8 @@ #include "curl_endian.h" #include "curl_des.h" #include "curl_md4.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -567,14 +567,15 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, return CURLE_OUT_OF_MEMORY; /* Create the BLOB structure */ - msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN, - "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */ - "%c%c%c%c" /* Reserved = 0 */ - "%c%c%c%c%c%c%c%c", /* Timestamp */ - NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1], - NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3], - 0, 0, 0, 0, - LONGQUARTET(tw.dwLowDateTime), LONGQUARTET(tw.dwHighDateTime)); + curl_msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN, + "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */ + "%c%c%c%c" /* Reserved = 0 */ + "%c%c%c%c%c%c%c%c", /* Timestamp */ + NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1], + NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3], + 0, 0, 0, 0, + LONGQUARTET(tw.dwLowDateTime), + LONGQUARTET(tw.dwHighDateTime)); memcpy(ptr + 32, challenge_client, 8); if(ntlm->target_info_len) diff --git a/lib/curl_printf.h b/lib/curl_printf.h index 6e0fa1fa8d84..207ba7125d62 100644 --- a/lib/curl_printf.h +++ b/lib/curl_printf.h @@ -24,8 +24,6 @@ * ***************************************************************************/ -#include - #define MERR_OK 0 #define MERR_MEM 1 #define MERR_TOO_LARGE 2 @@ -36,29 +34,4 @@ extern const unsigned char Curl_ldigits[]; /* Upper-case digits. */ extern const unsigned char Curl_udigits[]; -#ifdef BUILDING_LIBCURL - -/* - * This header should be included by ALL code in libcurl that uses any - * *rintf() functions. - */ - -# undef printf -# undef fprintf -# undef msnprintf -# undef vprintf -# undef vfprintf -# undef mvsnprintf -# undef aprintf -# undef vaprintf -# define printf curl_mprintf -# define fprintf curl_mfprintf -# define msnprintf curl_msnprintf -# define vprintf curl_mvprintf -# define vfprintf curl_mvfprintf -# define mvsnprintf curl_mvsnprintf -# define aprintf curl_maprintf -# define vaprintf curl_mvaprintf - -#endif /* BUILDING_LIBCURL */ #endif /* HEADER_CURL_PRINTF_H */ diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c index baee79fbeecf..7006ca5eb94e 100644 --- a/lib/curl_rtmp.c +++ b/lib/curl_rtmp.c @@ -37,8 +37,7 @@ #include #include -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -386,9 +385,9 @@ void Curl_rtmp_version(char *version, size_t len) else suff[0] = '\0'; - msnprintf(version, len, "librtmp/%d.%d%s", - RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, - suff); + curl_msnprintf(version, len, "librtmp/%d.%d%s", + RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, + suff); } #endif /* USE_LIBRTMP */ diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 9c86f3ea086e..c907c2c27bb2 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -51,8 +51,8 @@ #include "curl_sasl.h" #include "curlx/warnless.h" #include "sendf.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/curl_setup.h b/lib/curl_setup.h index f6fe6535f463..694d14df4f09 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -983,6 +983,8 @@ extern curl_calloc_callback Curl_ccalloc; #define Curl_safefree(ptr) \ do { free((ptr)); (ptr) = NULL;} while(0) +#include /* for CURL_EXTERN, mprintf.h */ + #ifdef CURLDEBUG #ifdef __clang__ # define ALLOC_FUNC __attribute__((__malloc__)) @@ -1007,8 +1009,6 @@ extern curl_calloc_callback Curl_ccalloc; # define ALLOC_SIZE2(n, s) #endif -#include /* for CURL_EXTERN */ - extern FILE *curl_dbg_logfile; /* memory functions */ diff --git a/lib/curl_trc.c b/lib/curl_trc.c index e04c425b3249..7f234437f291 100644 --- a/lib/curl_trc.c +++ b/lib/curl_trc.c @@ -47,8 +47,7 @@ #include "vtls/vtls.h" #include "vquic/vquic.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -102,14 +101,14 @@ static size_t trc_print_ids(struct Curl_easy *data, char *buf, size_t maxlen) data->conn->connection_id : data->state.recent_conn_id; if(data->id >= 0) { if(cid >= 0) - return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSDC, data->id, cid); + return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSDC, data->id, cid); else - return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSD, data->id); + return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSD, data->id); } else if(cid >= 0) - return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSC, cid); + return curl_msnprintf(buf, maxlen, CURL_TRC_FMT_IDSC, cid); else { - return msnprintf(buf, maxlen, "[x-x] "); + return curl_msnprintf(buf, maxlen, "[x-x] "); } } @@ -143,8 +142,8 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type, if(CURL_TRC_IDS(data) && (size < TRC_LINE_MAX)) { len = trc_print_ids(data, buf, TRC_LINE_MAX); - len += msnprintf(buf + len, TRC_LINE_MAX - len, "%.*s", - (int)size, ptr); + len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "%.*s", + (int)size, ptr); len = trc_end_buf(buf, len, TRC_LINE_MAX, FALSE); Curl_set_in_callback(data, TRUE); (void)(*data->set.fdebug)(data, type, buf, len, data->set.debugdata); @@ -189,7 +188,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...) size_t len; char error[CURL_ERROR_SIZE + 2]; va_start(ap, fmt); - len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap); + len = curl_mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap); if(data->set.errorbuffer && !data->state.errorbuf) { strcpy(data->set.errorbuffer, error); @@ -220,15 +219,15 @@ static void trc_infof(struct Curl_easy *data, if(CURL_TRC_IDS(data)) len += trc_print_ids(data, buf + len, TRC_LINE_MAX - len); if(feat) - len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", feat->name); + len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", feat->name); if(opt_id) { if(opt_id_idx > 0) - len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s-%d] ", - opt_id, opt_id_idx); + len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s-%d] ", + opt_id, opt_id_idx); else - len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", opt_id); + len += curl_msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", opt_id); } - len += mvsnprintf(buf + len, TRC_LINE_MAX - len, fmt, ap); + len += curl_mvsnprintf(buf + len, TRC_LINE_MAX - len, fmt, ap); len = trc_end_buf(buf, len, TRC_LINE_MAX, TRUE); trc_write(data, CURLINFO_TEXT, buf, len); } diff --git a/lib/curlx/.checksrc b/lib/curlx/.checksrc deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/cw-out.c b/lib/cw-out.c index 6d988a00bf84..7a9274b5f21b 100644 --- a/lib/cw-out.c +++ b/lib/cw-out.c @@ -35,8 +35,7 @@ #include "cw-out.h" #include "cw-pause.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/cw-pause.c b/lib/cw-pause.c index 9b9554c55157..1af4e8fa4192 100644 --- a/lib/cw-pause.c +++ b/lib/cw-pause.c @@ -34,8 +34,7 @@ #include "sendf.h" #include "cw-pause.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/dict.c b/lib/dict.c index 819584f284a0..3296a45466ad 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -59,9 +59,9 @@ #include "escape.h" #include "progress.h" #include "dict.h" -#include "curl_printf.h" + +/* The last 2 #include files should be: */ #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" @@ -144,7 +144,7 @@ static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...) char *sptr; va_list ap; va_start(ap, fmt); - s = vaprintf(fmt, ap); /* returns an allocated string */ + s = curl_mvaprintf(fmt, ap); /* returns an allocated string */ va_end(ap); if(!s) return CURLE_OUT_OF_MEMORY; /* failure */ diff --git a/lib/dllmain.c b/lib/dllmain.c index 7ac457ae0552..d871a524847b 100644 --- a/lib/dllmain.c +++ b/lib/dllmain.c @@ -28,8 +28,7 @@ #include #endif -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/doh.c b/lib/doh.c index 15e01357b82c..3dd7a2872d2f 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -41,8 +41,7 @@ #include "escape.h" #include "urlapi-int.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -513,7 +512,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, /* Only use HTTPS RR for HTTP(S) transfers */ char *qname = NULL; if(port != PORT_HTTPS) { - qname = aprintf("_%d._https.%s", port, hostname); + qname = curl_maprintf("_%d._https.%s", port, hostname); if(!qname) goto error; } @@ -890,8 +889,9 @@ static void doh_show(struct Curl_easy *data, len = sizeof(buffer) - len; for(j = 0; j < 16; j += 2) { size_t l; - msnprintf(ptr, len, "%s%02x%02x", j ? ":" : "", d->addr[i].ip.v6[j], - d->addr[i].ip.v6[j + 1]); + curl_msnprintf(ptr, len, "%s%02x%02x", j ? ":" : "", + d->addr[i].ip.v6[j], + d->addr[i].ip.v6[j + 1]); l = strlen(ptr); len -= l; ptr += l; diff --git a/lib/dynhds.c b/lib/dynhds.c index dcb9193a8beb..95d415bf0b49 100644 --- a/lib/dynhds.c +++ b/lib/dynhds.c @@ -26,12 +26,12 @@ #include "dynhds.h" #include "strcase.h" -/* The last 3 #include files should be in this order */ #ifdef USE_NGHTTP2 #include #include #endif /* USE_NGHTTP2 */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/easy.c b/lib/easy.c index 7a36034c03e3..877cf13b9baf 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -80,8 +80,7 @@ #include "easy_lock.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -157,42 +156,42 @@ static CURLcode global_init(long flags, bool memoryfuncs) } if(Curl_trc_init()) { - DEBUGF(fprintf(stderr, "Error: Curl_trc_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: Curl_trc_init failed\n")); goto fail; } if(!Curl_ssl_init()) { - DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: Curl_ssl_init failed\n")); goto fail; } if(!Curl_vquic_init()) { - DEBUGF(fprintf(stderr, "Error: Curl_vquic_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: Curl_vquic_init failed\n")); goto fail; } if(Curl_win32_init(flags)) { - DEBUGF(fprintf(stderr, "Error: win32_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: win32_init failed\n")); goto fail; } if(Curl_amiga_init()) { - DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: Curl_amiga_init failed\n")); goto fail; } if(Curl_macos_init()) { - DEBUGF(fprintf(stderr, "Error: Curl_macos_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: Curl_macos_init failed\n")); goto fail; } if(Curl_async_global_init()) { - DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: resolver_global_init failed\n")); goto fail; } if(Curl_ssh_init()) { - DEBUGF(fprintf(stderr, "Error: Curl_ssh_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: Curl_ssh_init failed\n")); goto fail; } @@ -361,7 +360,7 @@ CURL *curl_easy_init(void) result = global_init(CURL_GLOBAL_DEFAULT, TRUE); if(result) { /* something in the global init failed, return nothing */ - DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: curl_global_init failed\n")); global_init_unlock(); return NULL; } @@ -371,7 +370,7 @@ CURL *curl_easy_init(void) /* We use curl_open() with undefined URL so far */ result = Curl_open(&data); if(result) { - DEBUGF(fprintf(stderr, "Error: Curl_open failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: Curl_open failed\n")); return NULL; } @@ -407,7 +406,7 @@ static int events_timer(CURLM *multi, /* multi handle */ struct events *ev = userp; (void)multi; #if DEBUG_EV_POLL - fprintf(stderr, "events_timer: set timeout %ldms\n", timeout_ms); + curl_mfprintf(stderr, "events_timer: set timeout %ldms\n", timeout_ms); #endif ev->ms = timeout_ms; ev->msbump = TRUE; @@ -559,7 +558,7 @@ static unsigned int populate_fds(struct pollfd *fds, struct events *ev) f->events = m->socket.events; f->revents = 0; #if DEBUG_EV_POLL - fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); + curl_mfprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); #endif f++; numfds++; @@ -579,19 +578,19 @@ static CURLcode poll_fds(struct events *ev, if(numfds) { /* wait for activity or timeout */ #if DEBUG_EV_POLL - fprintf(stderr, "poll(numfds=%u, timeout=%ldms)\n", numfds, ev->ms); + curl_mfprintf(stderr, "poll(numfds=%u, timeout=%ldms)\n", numfds, ev->ms); #endif *pollrc = Curl_poll(fds, numfds, ev->ms); #if DEBUG_EV_POLL - fprintf(stderr, "poll(numfds=%u, timeout=%ldms) -> %d\n", - numfds, ev->ms, *pollrc); + curl_mfprintf(stderr, "poll(numfds=%u, timeout=%ldms) -> %d\n", + numfds, ev->ms, *pollrc); #endif if(*pollrc < 0) return CURLE_UNRECOVERABLE_POLL; } else { #if DEBUG_EV_POLL - fprintf(stderr, "poll, but no fds, wait timeout=%ldms\n", ev->ms); + curl_mfprintf(stderr, "poll, but no fds, wait timeout=%ldms\n", ev->ms); #endif *pollrc = 0; if(ev->ms > 0) @@ -629,7 +628,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) if(!pollrc) { /* timeout! */ ev->ms = 0; - /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */ + /* curl_mfprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */ mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &ev->running_handles); } @@ -658,8 +657,8 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) timediff_t timediff = curlx_timediff(curlx_now(), before); if(timediff > 0) { #if DEBUG_EV_POLL - fprintf(stderr, "poll timeout %ldms not updated, decrease by " - "time spent %ldms\n", ev->ms, (long)timediff); + curl_mfprintf(stderr, "poll timeout %ldms not updated, decrease by " + "time spent %ldms\n", ev->ms, (long)timediff); #endif if(timediff > ev->ms) ev->ms = 0; diff --git a/lib/escape.c b/lib/escape.c index a292ba3b6253..e7587e49b40e 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -36,9 +36,9 @@ struct Curl_easy; #include "escape.h" #include "strdup.h" #include "curlx/strparse.h" - -/* The last 3 #include files should be in this order */ #include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/fake_addrinfo.c b/lib/fake_addrinfo.c index 20d55ba2d1bd..80edf7864857 100644 --- a/lib/fake_addrinfo.c +++ b/lib/fake_addrinfo.c @@ -31,8 +31,7 @@ #include #include -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -178,7 +177,7 @@ int r_getaddrinfo(const char *node, if(env) { rc = ares_set_servers_ports_csv(channel, env); if(rc) { - fprintf(stderr, "ares_set_servers_ports_csv failed: %d", rc); + curl_mfprintf(stderr, "ares_set_servers_ports_csv failed: %d", rc); /* Cleanup */ ares_destroy(channel); return EAI_MEMORY; /* we can't run */ diff --git a/lib/file.c b/lib/file.c index 2d5818a1db42..fe07df5d2a92 100644 --- a/lib/file.c +++ b/lib/file.c @@ -69,8 +69,8 @@ #include "curlx/fopen.h" #include "curlx/warnless.h" #include "curl_range.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -488,8 +488,8 @@ static CURLcode file_do(struct Curl_easy *data, bool *done) static const char accept_ranges[]= { "Accept-ranges: bytes\r\n" }; if(expected_size >= 0) { headerlen = - msnprintf(header, sizeof(header), "Content-Length: %" FMT_OFF_T "\r\n", - expected_size); + curl_msnprintf(header, sizeof(header), + "Content-Length: %" FMT_OFF_T "\r\n", expected_size); result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen); if(result) return result; @@ -507,15 +507,15 @@ static CURLcode file_do(struct Curl_easy *data, bool *done) /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ headerlen = - msnprintf(header, sizeof(header), - "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); + curl_msnprintf(header, sizeof(header), + "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", + Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen); if(!result) /* end of headers */ diff --git a/lib/formdata.c b/lib/formdata.c index 475ca22fc864..a98384c18ac9 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -38,8 +38,8 @@ struct Curl_easy; #include "strdup.h" #include "rand.h" #include "curlx/warnless.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/ftp.c b/lib/ftp.c index 32d3c445df4e..c3b8aafbc5d5 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -72,8 +72,8 @@ #include "strdup.h" #include "curlx/strerr.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -1209,7 +1209,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, source++; } *dest = 0; - msnprintf(dest, 20, ",%d,%d", (int)(port >> 8), (int)(port & 0xff)); + curl_msnprintf(dest, 20, ",%d,%d", (int)(port >> 8), (int)(port & 0xff)); result = Curl_pp_sendf(data, &ftpc->pp, "%s %s", mode[fcmd], target); if(result) { @@ -1422,12 +1422,12 @@ static CURLcode ftp_state_list(struct Curl_easy *data, } } - cmd = aprintf("%s%s%.*s", - data->set.str[STRING_CUSTOMREQUEST] ? - data->set.str[STRING_CUSTOMREQUEST] : - (data->state.list_only ? "NLST" : "LIST"), - lstArg ? " " : "", - lstArglen, lstArg ? lstArg : ""); + cmd = curl_maprintf("%s%s%.*s", + data->set.str[STRING_CUSTOMREQUEST] ? + data->set.str[STRING_CUSTOMREQUEST] : + (data->state.list_only ? "NLST" : "LIST"), + lstArg ? " " : "", + lstArglen, lstArg ? lstArg : ""); if(!cmd) return CURLE_OUT_OF_MEMORY; @@ -1887,7 +1887,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, ftpc->newhost = control_address_dup(data, conn); } else - ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + ftpc->newhost = curl_maprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); if(!ftpc->newhost) return CURLE_OUT_OF_MEMORY; @@ -2093,9 +2093,9 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) { /* we have a time, reformat it */ char timebuf[24]; - msnprintf(timebuf, sizeof(timebuf), - "%04d%02d%02d %02d:%02d:%02d GMT", - year, month, day, hour, minute, second); + curl_msnprintf(timebuf, sizeof(timebuf), + "%04d%02d%02d %02d:%02d:%02d GMT", + year, month, day, hour, minute, second); /* now, convert this into a time() value: */ if(!Curl_getdate_capped(timebuf, &data->info.filetime)) showtime = TRUE; @@ -2128,15 +2128,16 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, /* format: "Tue, 15 Nov 1994 12:45:26" */ headerbuflen = - msnprintf(headerbuf, sizeof(headerbuf), - "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); + curl_msnprintf(headerbuf, sizeof(headerbuf), + "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d " + "GMT\r\n", + Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); result = client_write_header(data, headerbuf, headerbuflen); if(result) return result; @@ -2349,8 +2350,9 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data, #ifdef CURL_FTP_HTTPSTYLE_HEAD if(filesize != -1) { char clbuf[128]; - int clbuflen = msnprintf(clbuf, sizeof(clbuf), - "Content-Length: %" FMT_OFF_T "\r\n", filesize); + int clbuflen = curl_msnprintf(clbuf, sizeof(clbuf), + "Content-Length: %" FMT_OFF_T "\r\n", + filesize); result = client_write_header(data, clbuf, clbuflen); if(result) return result; @@ -3937,7 +3939,7 @@ static CURLcode wc_statemach(struct Curl_easy *data, struct Curl_llist_node *head = Curl_llist_head(&wildcard->filelist); struct curl_fileinfo *finfo = Curl_node_elem(head); - char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); + char *tmp_path = curl_maprintf("%s%s", wildcard->path, finfo->filename); if(!tmp_path) return CURLE_OUT_OF_MEMORY; diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c index 360f7ae4fca0..de573d3c57b5 100644 --- a/lib/ftplistparser.c +++ b/lib/ftplistparser.c @@ -52,8 +52,7 @@ #include "multiif.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/gopher.c b/lib/gopher.c index 93db85e9d027..6ff47d58c70a 100644 --- a/lib/gopher.c +++ b/lib/gopher.c @@ -40,9 +40,9 @@ #include "url.h" #include "escape.h" #include "curlx/warnless.h" -#include "curl_printf.h" + +/* The last 2 #include files should be: */ #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* @@ -153,7 +153,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done) DEBUGASSERT(path); if(query) - gopherpath = aprintf("%s?%s", path, query); + gopherpath = curl_maprintf("%s?%s", path, query); else gopherpath = strdup(path); diff --git a/lib/hash.c b/lib/hash.c index 89f47ed71e25..8312fbf050fd 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -51,16 +51,16 @@ void Curl_hash_print(struct Curl_hash *h, if(!h) return; - fprintf(stderr, "=Hash dump=\n"); + curl_mfprintf(stderr, "=Hash dump=\n"); Curl_hash_start_iterate(h, &iter); he = Curl_hash_next_element(&iter); while(he) { if(iter.slot_index != last_index) { - fprintf(stderr, "index %d:", (int)iter.slot_index); + curl_mfprintf(stderr, "index %d:", (int)iter.slot_index); if(last_index != UINT_MAX) { - fprintf(stderr, "\n"); + curl_mfprintf(stderr, "\n"); } last_index = iter.slot_index; } @@ -68,13 +68,13 @@ void Curl_hash_print(struct Curl_hash *h, if(func) func(he->ptr); else - fprintf(stderr, " [key=%.*s, he=%p, ptr=%p]", - (int)he->key_len, (char *)he->key, - (void *)he, (void *)he->ptr); + curl_mfprintf(stderr, " [key=%.*s, he=%p, ptr=%p]", + (int)he->key_len, (char *)he->key, + (void *)he, (void *)he->ptr); he = Curl_hash_next_element(&iter); } - fprintf(stderr, "\n"); + curl_mfprintf(stderr, "\n"); } #endif diff --git a/lib/headers.c b/lib/headers.c index 426d0e57b77a..5a5725711317 100644 --- a/lib/headers.c +++ b/lib/headers.c @@ -30,8 +30,7 @@ #include "headers.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/hostip.c b/lib/hostip.c index da260d713009..ceea1897322a 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -64,8 +64,7 @@ #include "easy_lock.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -176,7 +175,7 @@ create_dnscache_id(const char *name, len = buflen - 7; /* store and lower case the name */ Curl_strntolower(ptr, name, len); - return msnprintf(&ptr[len], 7, ":%u", port) + len; + return curl_msnprintf(&ptr[len], 7, ":%u", port) + len; } struct dnscache_prune_data { diff --git a/lib/hostip4.c b/lib/hostip4.c index 2c356f3464e3..e1ed007aafa3 100644 --- a/lib/hostip4.c +++ b/lib/hostip4.c @@ -49,8 +49,8 @@ #include "hash.h" #include "share.h" #include "url.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -125,7 +125,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, hints.ai_family = PF_INET; hints.ai_socktype = SOCK_STREAM; if(port) { - msnprintf(sbuf, sizeof(sbuf), "%d", port); + curl_msnprintf(sbuf, sizeof(sbuf), "%d", port); sbufptr = sbuf; } diff --git a/lib/hostip6.c b/lib/hostip6.c index 4c05f0247e1a..9419b9e4d5fe 100644 --- a/lib/hostip6.c +++ b/lib/hostip6.c @@ -52,8 +52,8 @@ #include "url.h" #include "curlx/inet_pton.h" #include "connect.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -62,13 +62,14 @@ #ifdef DEBUG_ADDRINFO static void dump_addrinfo(const struct Curl_addrinfo *ai) { - printf("dump_addrinfo:\n"); + curl_mprintf("dump_addrinfo:\n"); for(; ai; ai = ai->ai_next) { char buf[INET6_ADDRSTRLEN]; - printf(" fam %2d, CNAME %s, ", - ai->ai_family, ai->ai_canonname ? ai->ai_canonname : ""); + curl_mprintf(" fam %2d, CNAME %s, ", + ai->ai_family, + ai->ai_canonname ? ai->ai_canonname : ""); Curl_printable_address(ai, buf, sizeof(buf)); - printf("%s\n", buf); + curl_mprintf("%s\n", buf); } } #else @@ -122,7 +123,7 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data, #endif if(port) { - msnprintf(sbuf, sizeof(sbuf), "%d", port); + curl_msnprintf(sbuf, sizeof(sbuf), "%d", port); sbufptr = sbuf; } diff --git a/lib/hsts.c b/lib/hsts.c index b84a470f90dc..28989764b90f 100644 --- a/lib/hsts.c +++ b/lib/hsts.c @@ -41,8 +41,7 @@ #include "strdup.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -308,9 +307,9 @@ static CURLcode hsts_push(struct Curl_easy *data, if(result) return result; - msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d", - stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, - stamp.tm_hour, stamp.tm_min, stamp.tm_sec); + curl_msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d", + stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, + stamp.tm_hour, stamp.tm_min, stamp.tm_sec); } else strcpy(e.expire, UNLIMITED); @@ -331,14 +330,14 @@ static CURLcode hsts_out(struct stsentry *sts, FILE *fp) CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp); if(result) return result; - fprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n", - sts->includeSubDomains ? ".": "", sts->host, - stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, - stamp.tm_hour, stamp.tm_min, stamp.tm_sec); + curl_mfprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n", + sts->includeSubDomains ? ".": "", sts->host, + stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, + stamp.tm_hour, stamp.tm_min, stamp.tm_sec); } else - fprintf(fp, "%s%s \"%s\"\n", - sts->includeSubDomains ? ".": "", sts->host, UNLIMITED); + curl_mfprintf(fp, "%s%s \"%s\"\n", + sts->includeSubDomains ? ".": "", sts->host, UNLIMITED); return CURLE_OK; } diff --git a/lib/http.c b/lib/http.c index 3479bb4ec976..aea19d5167f5 100644 --- a/lib/http.c +++ b/lib/http.c @@ -87,8 +87,7 @@ #include "curl_ctype.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -337,7 +336,7 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy) pwd = data->state.aptr.passwd; } - out = aprintf("%s:%s", user ? user : "", pwd ? pwd : ""); + out = curl_maprintf("%s:%s", user ? user : "", pwd ? pwd : ""); if(!out) return CURLE_OUT_OF_MEMORY; @@ -351,9 +350,9 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy) } free(*userp); - *userp = aprintf("%sAuthorization: Basic %s\r\n", - proxy ? "Proxy-" : "", - authorization); + *userp = curl_maprintf("%sAuthorization: Basic %s\r\n", + proxy ? "Proxy-" : "", + authorization); free(authorization); if(!*userp) { result = CURLE_OUT_OF_MEMORY; @@ -381,8 +380,8 @@ static CURLcode http_output_bearer(struct Curl_easy *data) userp = &data->state.aptr.userpwd; free(*userp); - *userp = aprintf("Authorization: Bearer %s\r\n", - data->set.str[STRING_BEARER]); + *userp = curl_maprintf("Authorization: Bearer %s\r\n", + data->set.str[STRING_BEARER]); if(!*userp) { result = CURLE_OUT_OF_MEMORY; @@ -1795,16 +1794,16 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data, */ /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ - msnprintf(datestr, sizeof(datestr), - "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - condp, - Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); + curl_msnprintf(datestr, sizeof(datestr), + "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", + condp, + Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); result = curlx_dyn_add(req, datestr); return result; @@ -1936,7 +1935,7 @@ static CURLcode http_set_aptr_host(struct Curl_easy *data) #endif if(!curl_strequal("Host:", ptr)) { - aptr->host = aprintf("Host:%s\r\n", &ptr[5]); + aptr->host = curl_maprintf("Host:%s\r\n", &ptr[5]); if(!aptr->host) return CURLE_OUT_OF_MEMORY; } @@ -1952,13 +1951,14 @@ static CURLcode http_set_aptr_host(struct Curl_easy *data) (conn->remote_port == PORT_HTTP)) ) /* if(HTTPS on port 443) OR (HTTP on port 80) then do not include the port number in the host string */ - aptr->host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip ? "[" : "", - host, conn->bits.ipv6_ip ? "]" : ""); + aptr->host = curl_maprintf("Host: %s%s%s\r\n", + conn->bits.ipv6_ip ? "[" : "", + host, conn->bits.ipv6_ip ? "]" : ""); else - aptr->host = aprintf("Host: %s%s%s:%d\r\n", - conn->bits.ipv6_ip ? "[" : "", - host, conn->bits.ipv6_ip ? "]" : "", - conn->remote_port); + aptr->host = curl_maprintf("Host: %s%s%s:%d\r\n", + conn->bits.ipv6_ip ? "[" : "", + host, conn->bits.ipv6_ip ? "]" : "", + conn->remote_port); if(!aptr->host) /* without Host: we cannot make a nice request */ @@ -2494,8 +2494,8 @@ static CURLcode http_range(struct Curl_easy *data, !Curl_checkheaders(data, STRCONST("Range"))) { /* if a line like this was already allocated, free the previous one */ free(data->state.aptr.rangeline); - data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n", - data->state.range); + data->state.aptr.rangeline = curl_maprintf("Range: bytes=%s\r\n", + data->state.range); } else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) && !Curl_checkheaders(data, STRCONST("Content-Range"))) { @@ -2508,8 +2508,8 @@ static CURLcode http_range(struct Curl_easy *data, remote part so we tell the server (and act accordingly) that we upload the whole file (again) */ data->state.aptr.rangeline = - aprintf("Content-Range: bytes 0-%" FMT_OFF_T "/%" FMT_OFF_T "\r\n", - req_clen - 1, req_clen); + curl_maprintf("Content-Range: bytes 0-%" FMT_OFF_T "/" + "%" FMT_OFF_T "\r\n", req_clen - 1, req_clen); } else if(data->state.resume_from) { @@ -2521,15 +2521,16 @@ static CURLcode http_range(struct Curl_easy *data, data->state.infilesize : (data->state.resume_from + req_clen); data->state.aptr.rangeline = - aprintf("Content-Range: bytes %s%" FMT_OFF_T "/%" FMT_OFF_T "\r\n", - data->state.range, total_len-1, total_len); + curl_maprintf("Content-Range: bytes %s%" FMT_OFF_T "/" + "%" FMT_OFF_T "\r\n", + data->state.range, total_len-1, total_len); } else { /* Range was selected and then we just pass the incoming range and append total size */ data->state.aptr.rangeline = - aprintf("Content-Range: bytes %s/%" FMT_OFF_T "\r\n", - data->state.range, req_clen); + curl_maprintf("Content-Range: bytes %s/%" FMT_OFF_T "\r\n", + data->state.range, req_clen); } if(!data->state.aptr.rangeline) return CURLE_OUT_OF_MEMORY; @@ -2931,7 +2932,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) /* setup the authentication headers, how that method and host are known */ char *pq = NULL; if(data->state.up.query) { - pq = aprintf("%s?%s", data->state.up.path, data->state.up.query); + pq = curl_maprintf("%s?%s", data->state.up.path, data->state.up.query); if(!pq) return CURLE_OUT_OF_MEMORY; } diff --git a/lib/http1.c b/lib/http1.c index 537e6db2ff98..098dd7cd64f8 100644 --- a/lib/http1.c +++ b/lib/http1.c @@ -32,8 +32,7 @@ #include "http1.h" #include "urlapi-int.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/http2.c b/lib/http2.c index c526bf0fa4c3..c33c633cf632 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -47,8 +47,8 @@ #include "transfer.h" #include "curlx/dynbuf.h" #include "headers.h" + /* The last 3 #include files should be in this order */ -#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" @@ -734,7 +734,7 @@ static CURLcode http2_send_ping(struct Curl_cfilter *cf, void Curl_http2_ver(char *p, size_t len) { nghttp2_info *h2 = nghttp2_version(0); - (void)msnprintf(p, len, "nghttp2/%s", h2->version_str); + (void)curl_msnprintf(p, len, "nghttp2/%s", h2->version_str); } static CURLcode nw_out_flush(struct Curl_cfilter *cf, @@ -1214,48 +1214,48 @@ static int fr_print(const nghttp2_frame *frame, char *buffer, size_t blen) { switch(frame->hd.type) { case NGHTTP2_DATA: { - return msnprintf(buffer, blen, - "FRAME[DATA, len=%d, eos=%d, padlen=%d]", - (int)frame->hd.length, - !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM), - (int)frame->data.padlen); + return curl_msnprintf(buffer, blen, + "FRAME[DATA, len=%d, eos=%d, padlen=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM), + (int)frame->data.padlen); } case NGHTTP2_HEADERS: { - return msnprintf(buffer, blen, - "FRAME[HEADERS, len=%d, hend=%d, eos=%d]", - (int)frame->hd.length, - !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS), - !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)); + return curl_msnprintf(buffer, blen, + "FRAME[HEADERS, len=%d, hend=%d, eos=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS), + !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)); } case NGHTTP2_PRIORITY: { - return msnprintf(buffer, blen, - "FRAME[PRIORITY, len=%d, flags=%d]", - (int)frame->hd.length, frame->hd.flags); + return curl_msnprintf(buffer, blen, + "FRAME[PRIORITY, len=%d, flags=%d]", + (int)frame->hd.length, frame->hd.flags); } case NGHTTP2_RST_STREAM: { - return msnprintf(buffer, blen, - "FRAME[RST_STREAM, len=%d, flags=%d, error=%u]", - (int)frame->hd.length, frame->hd.flags, - frame->rst_stream.error_code); + return curl_msnprintf(buffer, blen, + "FRAME[RST_STREAM, len=%d, flags=%d, error=%u]", + (int)frame->hd.length, frame->hd.flags, + frame->rst_stream.error_code); } case NGHTTP2_SETTINGS: { if(frame->hd.flags & NGHTTP2_FLAG_ACK) { - return msnprintf(buffer, blen, "FRAME[SETTINGS, ack=1]"); + return curl_msnprintf(buffer, blen, "FRAME[SETTINGS, ack=1]"); } - return msnprintf(buffer, blen, - "FRAME[SETTINGS, len=%d]", (int)frame->hd.length); + return curl_msnprintf(buffer, blen, + "FRAME[SETTINGS, len=%d]", (int)frame->hd.length); } case NGHTTP2_PUSH_PROMISE: { - return msnprintf(buffer, blen, - "FRAME[PUSH_PROMISE, len=%d, hend=%d]", - (int)frame->hd.length, - !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS)); + return curl_msnprintf(buffer, blen, + "FRAME[PUSH_PROMISE, len=%d, hend=%d]", + (int)frame->hd.length, + !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS)); } case NGHTTP2_PING: { - return msnprintf(buffer, blen, - "FRAME[PING, len=%d, ack=%d]", - (int)frame->hd.length, - frame->hd.flags&NGHTTP2_FLAG_ACK); + return curl_msnprintf(buffer, blen, + "FRAME[PING, len=%d, ack=%d]", + (int)frame->hd.length, + frame->hd.flags&NGHTTP2_FLAG_ACK); } case NGHTTP2_GOAWAY: { char scratch[128]; @@ -1265,19 +1265,20 @@ static int fr_print(const nghttp2_frame *frame, char *buffer, size_t blen) if(len) memcpy(scratch, frame->goaway.opaque_data, len); scratch[len] = '\0'; - return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', " - "last_stream=%d]", frame->goaway.error_code, - scratch, frame->goaway.last_stream_id); + return curl_msnprintf(buffer, blen, + "FRAME[GOAWAY, error=%d, reason='%s', " + "last_stream=%d]", frame->goaway.error_code, + scratch, frame->goaway.last_stream_id); } case NGHTTP2_WINDOW_UPDATE: { - return msnprintf(buffer, blen, - "FRAME[WINDOW_UPDATE, incr=%d]", - frame->window_update.window_size_increment); + return curl_msnprintf(buffer, blen, + "FRAME[WINDOW_UPDATE, incr=%d]", + frame->window_update.window_size_increment); } default: - return msnprintf(buffer, blen, "FRAME[%d, len=%d, flags=%d]", - frame->hd.type, (int)frame->hd.length, - frame->hd.flags); + return curl_msnprintf(buffer, blen, "FRAME[%d, len=%d, flags=%d]", + frame->hd.type, (int)frame->hd.length, + frame->hd.flags); } } @@ -1592,8 +1593,8 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, if(!strcmp(HTTP_PSEUDO_AUTHORITY, (const char *)name)) { /* pseudo headers are lower case */ int rc = 0; - char *check = aprintf("%s:%d", cf->conn->host.name, - cf->conn->remote_port); + char *check = curl_maprintf("%s:%d", cf->conn->host.name, + cf->conn->remote_port); if(!check) /* no memory */ return NGHTTP2_ERR_CALLBACK_FAILURE; @@ -1640,7 +1641,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, } stream->push_headers = headp; } - h = aprintf("%s:%s", name, value); + h = curl_maprintf("%s:%s", name, value); if(h) stream->push_headers[stream->push_headers_used++] = h; return 0; @@ -1671,8 +1672,8 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, cf_h2_header_error(cf, data_s, stream, result); return NGHTTP2_ERR_CALLBACK_FAILURE; } - msnprintf(buffer, sizeof(buffer), HTTP_PSEUDO_STATUS ":%u\r", - stream->status_code); + curl_msnprintf(buffer, sizeof(buffer), HTTP_PSEUDO_STATUS ":%u\r", + stream->status_code); result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO); if(result) { cf_h2_header_error(cf, data_s, stream, result); diff --git a/lib/http_aws_sigv4.c b/lib/http_aws_sigv4.c index c62db499ca19..f592f3844feb 100644 --- a/lib/http_aws_sigv4.c +++ b/lib/http_aws_sigv4.c @@ -39,8 +39,7 @@ #include -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -245,14 +244,14 @@ static CURLcode make_headers(struct Curl_easy *data, struct curl_slist *l; bool again = TRUE; - msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%.*s-Date", - (int)plen, provider1); + curl_msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%.*s-Date", + (int)plen, provider1); /* provider1 ucfirst */ Curl_strntolower(&date_hdr_key[2], provider1, plen); date_hdr_key[2] = Curl_raw_toupper(provider1[0]); - msnprintf(date_full_hdr, DATE_FULL_HDR_LEN, - "x-%.*s-date:%s", (int)plen, provider1, timestamp); + curl_msnprintf(date_full_hdr, DATE_FULL_HDR_LEN, + "x-%.*s-date:%s", (int)plen, provider1, timestamp); /* provider1 lowercase */ Curl_strntolower(&date_full_hdr[2], provider1, plen); @@ -265,7 +264,7 @@ static CURLcode make_headers(struct Curl_easy *data, fullhost = Curl_memdup0(data->state.aptr.host, pos); } else - fullhost = aprintf("host:%s", hostname); + fullhost = curl_maprintf("host:%s", hostname); if(fullhost) head = Curl_slist_append_nodup(NULL, fullhost); @@ -329,7 +328,7 @@ static CURLcode make_headers(struct Curl_easy *data, if(!tmp_head) goto fail; head = tmp_head; - *date_header = aprintf("%s: %s\r\n", date_hdr_key, timestamp); + *date_header = curl_maprintf("%s: %s\r\n", date_hdr_key, timestamp); } else { const char *value; @@ -417,8 +416,8 @@ static const char *parse_content_sha_hdr(struct Curl_easy *data, const char *value; size_t len; - key_len = msnprintf(key, sizeof(key), "x-%.*s-content-sha256", - (int)plen, provider1); + key_len = curl_msnprintf(key, sizeof(key), "x-%.*s-content-sha256", + (int)plen, provider1); value = Curl_checkheaders(data, key, key_len); if(!value) @@ -490,8 +489,8 @@ static CURLcode calc_s3_payload_hash(struct Curl_easy *data, } /* format the required content-sha256 header */ - msnprintf(header, CONTENT_SHA256_HDR_LEN, - "x-%.*s-content-sha256: %s", (int)plen, provider1, sha_hex); + curl_msnprintf(header, CONTENT_SHA256_HDR_LEN, + "x-%.*s-content-sha256: %s", (int)plen, provider1, sha_hex); ret = CURLE_OK; fail: @@ -850,38 +849,41 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data) result = CURLE_OUT_OF_MEMORY; canonical_request = - aprintf("%s\n" /* HTTPRequestMethod */ - "%s\n" /* CanonicalURI */ - "%s\n" /* CanonicalQueryString */ - "%s\n" /* CanonicalHeaders */ - "%s\n" /* SignedHeaders */ - "%.*s", /* HashedRequestPayload in hex */ - method, - curlx_dyn_ptr(&canonical_path), - curlx_dyn_ptr(&canonical_query) ? - curlx_dyn_ptr(&canonical_query) : "", - curlx_dyn_ptr(&canonical_headers), - curlx_dyn_ptr(&signed_headers), - (int)payload_hash_len, payload_hash); + curl_maprintf("%s\n" /* HTTPRequestMethod */ + "%s\n" /* CanonicalURI */ + "%s\n" /* CanonicalQueryString */ + "%s\n" /* CanonicalHeaders */ + "%s\n" /* SignedHeaders */ + "%.*s", /* HashedRequestPayload in hex */ + method, + curlx_dyn_ptr(&canonical_path), + curlx_dyn_ptr(&canonical_query) ? + curlx_dyn_ptr(&canonical_query) : "", + curlx_dyn_ptr(&canonical_headers), + curlx_dyn_ptr(&signed_headers), + (int)payload_hash_len, payload_hash); if(!canonical_request) goto fail; infof(data, "aws_sigv4: Canonical request (enclosed in []) - [%s]", canonical_request); - request_type = aprintf("%.*s4_request", - (int)curlx_strlen(&provider0), curlx_str(&provider0)); + request_type = curl_maprintf("%.*s4_request", + (int)curlx_strlen(&provider0), + curlx_str(&provider0)); if(!request_type) goto fail; - /* provider0 is lowercased *after* aprintf() so that the buffer can be - written to */ + /* provider0 is lowercased *after* curl_maprintf() so that the buffer + can be written to */ Curl_strntolower(request_type, request_type, curlx_strlen(&provider0)); - credential_scope = aprintf("%s/%.*s/%.*s/%s", date, - (int)curlx_strlen(®ion), curlx_str(®ion), - (int)curlx_strlen(&service), curlx_str(&service), - request_type); + credential_scope = curl_maprintf("%s/%.*s/%.*s/%s", date, + (int)curlx_strlen(®ion), + curlx_str(®ion), + (int)curlx_strlen(&service), + curlx_str(&service), + request_type); if(!credential_scope) goto fail; @@ -895,14 +897,15 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data) * Google allows using RSA key instead of HMAC, so this code might change * in the future. For now we only support HMAC. */ - str_to_sign = aprintf("%.*s4-HMAC-SHA256\n" /* Algorithm */ - "%s\n" /* RequestDateTime */ - "%s\n" /* CredentialScope */ - "%s", /* HashedCanonicalRequest in hex */ - (int)curlx_strlen(&provider0), curlx_str(&provider0), - timestamp, - credential_scope, - sha_hex); + str_to_sign = curl_maprintf("%.*s4-HMAC-SHA256\n" /* Algorithm */ + "%s\n" /* RequestDateTime */ + "%s\n" /* CredentialScope */ + "%s", /* HashedCanonicalRequest in hex */ + (int)curlx_strlen(&provider0), + curlx_str(&provider0), + timestamp, + credential_scope, + sha_hex); if(!str_to_sign) goto fail; @@ -913,9 +916,9 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data) infof(data, "aws_sigv4: String to sign (enclosed in []) - [%s]", str_to_sign); - secret = aprintf("%.*s4%s", (int)curlx_strlen(&provider0), - curlx_str(&provider0), data->state.aptr.passwd ? - data->state.aptr.passwd : ""); + secret = curl_maprintf("%.*s4%s", (int)curlx_strlen(&provider0), + curlx_str(&provider0), data->state.aptr.passwd ? + data->state.aptr.passwd : ""); if(!secret) goto fail; /* make provider0 part done uppercase */ @@ -933,24 +936,25 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data) infof(data, "aws_sigv4: Signature - %s", sha_hex); - auth_headers = aprintf("Authorization: %.*s4-HMAC-SHA256 " - "Credential=%s/%s, " - "SignedHeaders=%s, " - "Signature=%s\r\n" - /* - * date_header is added here, only if it was not - * user-specified (using CURLOPT_HTTPHEADER). - * date_header includes \r\n - */ - "%s" - "%s", /* optional sha256 header includes \r\n */ - (int)curlx_strlen(&provider0), curlx_str(&provider0), - user, - credential_scope, - curlx_dyn_ptr(&signed_headers), - sha_hex, - date_header ? date_header : "", - content_sha256_hdr); + auth_headers = curl_maprintf("Authorization: %.*s4-HMAC-SHA256 " + "Credential=%s/%s, " + "SignedHeaders=%s, " + "Signature=%s\r\n" + /* + * date_header is added here, only if it was not + * user-specified (using CURLOPT_HTTPHEADER). + * date_header includes \r\n + */ + "%s" + "%s", /* optional sha256 header includes \r\n */ + (int)curlx_strlen(&provider0), + curlx_str(&provider0), + user, + credential_scope, + curlx_dyn_ptr(&signed_headers), + sha_hex, + date_header ? date_header : "", + content_sha256_hdr); if(!auth_headers) { goto fail; } diff --git a/lib/http_chunks.c b/lib/http_chunks.c index f735a820c7bc..005d34e7b905 100644 --- a/lib/http_chunks.c +++ b/lib/http_chunks.c @@ -27,7 +27,6 @@ #ifndef CURL_DISABLE_HTTP #include "urldata.h" /* it includes http_chunks.h */ -#include "curl_printf.h" #include "curl_trc.h" #include "sendf.h" /* for the client write stuff */ #include "curlx/dynbuf.h" @@ -584,7 +583,7 @@ static CURLcode add_chunk(struct Curl_easy *data, int hdlen; size_t n; - hdlen = msnprintf(hd, sizeof(hd), "%zx\r\n", nread); + hdlen = curl_msnprintf(hd, sizeof(hd), "%zx\r\n", nread); if(hdlen <= 0) return CURLE_READ_ERROR; /* On a soft-limited bufq, we do not need to check that all was written */ diff --git a/lib/http_digest.c b/lib/http_digest.c index f4e920706c63..097c81fd716a 100644 --- a/lib/http_digest.c +++ b/lib/http_digest.c @@ -32,8 +32,7 @@ #include "http_digest.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -149,11 +148,11 @@ CURLcode Curl_output_digest(struct Curl_easy *data, if(tmp) { size_t urilen = tmp - (const char *)uripath; /* typecast is fine here since the value is always less than 32 bits */ - path = (unsigned char *) aprintf("%.*s", (int)urilen, uripath); + path = (unsigned char *)curl_maprintf("%.*s", (int)urilen, uripath); } } if(!tmp) - path = (unsigned char *) strdup((const char *) uripath); + path = (unsigned char *)strdup((const char *) uripath); if(!path) return CURLE_OUT_OF_MEMORY; @@ -164,9 +163,8 @@ CURLcode Curl_output_digest(struct Curl_easy *data, if(result) return result; - *allocuserpwd = aprintf("%sAuthorization: Digest %s\r\n", - proxy ? "Proxy-" : "", - response); + *allocuserpwd = curl_maprintf("%sAuthorization: Digest %s\r\n", + proxy ? "Proxy-" : "", response); free(response); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c index 2c0b7e16d76a..8a19c1ad8738 100644 --- a/lib/http_negotiate.c +++ b/lib/http_negotiate.c @@ -34,8 +34,7 @@ #include "vtls/vtls.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -219,8 +218,8 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data, if(result) return result; - userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", - base64); + userp = curl_maprintf("%sAuthorization: Negotiate %s\r\n", + proxy ? "Proxy-" : "", base64); if(proxy) { #ifndef CURL_DISABLE_PROXY diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c index a172eb848dd9..fa375b49bfc6 100644 --- a/lib/http_ntlm.c +++ b/lib/http_ntlm.c @@ -49,8 +49,7 @@ #include "curl_sspi.h" #endif -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -210,9 +209,9 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) Curl_bufref_len(&ntlmmsg), &base64, &len); if(!result) { free(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy ? "Proxy-" : "", - base64); + *allocuserpwd = curl_maprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + base64); free(base64); if(!*allocuserpwd) result = CURLE_OUT_OF_MEMORY; @@ -229,9 +228,9 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) Curl_bufref_len(&ntlmmsg), &base64, &len); if(!result) { free(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy ? "Proxy-" : "", - base64); + *allocuserpwd = curl_maprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + base64); free(base64); if(!*allocuserpwd) result = CURLE_OUT_OF_MEMORY; diff --git a/lib/http_proxy.c b/lib/http_proxy.c index b756efe711b4..845ba2e8f8da 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -44,8 +44,7 @@ #include "vauth/vauth.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -236,8 +235,8 @@ CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq, if(result) goto out; - authority = aprintf("%s%s%s:%d", ipv6_ip ? "[" : "", hostname, - ipv6_ip ?"]" : "", port); + authority = curl_maprintf("%s%s%s:%d", ipv6_ip ? "[" : "", hostname, + ipv6_ip ?"]" : "", port); if(!authority) { result = CURLE_OUT_OF_MEMORY; goto out; diff --git a/lib/httpsrr.c b/lib/httpsrr.c index 8aa7f3b26e47..ae2c106bcef2 100644 --- a/lib/httpsrr.c +++ b/lib/httpsrr.c @@ -33,8 +33,7 @@ #include "sendf.h" #include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/idn.c b/lib/idn.c index bb6fd2cffc25..7e324db6c4b0 100644 --- a/lib/idn.c +++ b/lib/idn.c @@ -45,8 +45,7 @@ #endif #endif /* USE_LIBIDN2 */ -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/if2ip.c b/lib/if2ip.c index e501921d067b..79b0599106de 100644 --- a/lib/if2ip.c +++ b/lib/if2ip.c @@ -54,8 +54,8 @@ #include "curlx/inet_ntop.h" #include "if2ip.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -153,7 +153,7 @@ if2ip_result_t Curl_if2ip(int af, } if(scopeid) - msnprintf(scope, sizeof(scope), "%%%u", scopeid); + curl_msnprintf(scope, sizeof(scope), "%%%u", scopeid); #endif } else @@ -162,7 +162,7 @@ if2ip_result_t Curl_if2ip(int af, &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr; res = IF2IP_FOUND; ip = curlx_inet_ntop(af, addr, ipstr, sizeof(ipstr)); - msnprintf(buf, buf_size, "%s%s", ip, scope); + curl_msnprintf(buf, buf_size, "%s%s", ip, scope); break; } } diff --git a/lib/imap.c b/lib/imap.c index 41aec8ffab73..69e4e0c2c608 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -78,8 +78,7 @@ #include "curlx/warnless.h" #include "curl_ctype.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -1943,9 +1942,9 @@ static CURLcode imap_sendf(struct Curl_easy *data, DEBUGASSERT(fmt); /* Calculate the tag based on the connection ID and command ID */ - msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", - 'A' + curlx_sltosi((long)(data->conn->connection_id % 26)), - ++imapc->cmdid); + curl_msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", + 'A' + curlx_sltosi((long)(data->conn->connection_id % 26)), + ++imapc->cmdid); /* start with a blank buffer */ curlx_dyn_reset(&imapc->dyn); diff --git a/lib/ldap.c b/lib/ldap.c index 8a39c1a4becf..be65ea2055c2 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -93,8 +93,8 @@ #include "curlx/multibyte.h" #include "curlx/base64.h" #include "connect.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -746,7 +746,7 @@ static void ldap_trace_low(const char *fmt, ...) return; va_start(args, fmt); - vfprintf(stderr, fmt, args); + curl_mvfprintf(stderr, fmt, args); va_end(args); } #endif /* DEBUG_LDAP */ diff --git a/lib/md4.c b/lib/md4.c index 241aadf14e7a..9db85786e125 100644 --- a/lib/md4.c +++ b/lib/md4.c @@ -82,8 +82,7 @@ #include #endif -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/md5.c b/lib/md5.c index e7d42ec1c0f1..091924034055 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -77,8 +77,7 @@ #include #endif -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/memdebug.c b/lib/memdebug.c index 0c9d15671583..7ded52c1e97c 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -31,8 +31,7 @@ #include "urldata.h" #include "curlx/fopen.h" /* for CURLX_FOPEN_LOW() */ -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -114,8 +113,8 @@ static bool countcheck(const char *func, int line, const char *source) curl_dbg_log("LIMIT %s:%d %s reached memlimit\n", source, line, func); /* log to stderr also */ - fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n", - source, line, func); + curl_mfprintf(stderr, "LIMIT %s:%d %s reached memlimit\n", + source, line, func); fflush(curl_dbg_logfile); /* because it might crash now */ /* !checksrc! disable ERRNOVAR 1 */ CURL_SETERRNO(ENOMEM); @@ -469,7 +468,7 @@ void curl_dbg_log(const char *format, ...) return; va_start(ap, format); - nchars = mvsnprintf(buf, sizeof(buf), format, ap); + nchars = curl_mvsnprintf(buf, sizeof(buf), format, ap); va_end(ap); if(nchars > (int)sizeof(buf) - 1) diff --git a/lib/mime.c b/lib/mime.c index fe632604ed9d..b403d29b1fd9 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -49,8 +49,8 @@ struct Curl_easy; #include "rand.h" #include "slist.h" #include "curlx/dynbuf.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -1688,7 +1688,7 @@ CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) va_list ap; va_start(ap, fmt); - s = vaprintf(fmt, ap); + s = curl_mvaprintf(fmt, ap); va_end(ap); if(s) { diff --git a/lib/mqtt.c b/lib/mqtt.c index 01dd4e0a0d44..c76ce0a229b7 100644 --- a/lib/mqtt.c +++ b/lib/mqtt.c @@ -38,12 +38,11 @@ #include "url.h" #include "escape.h" #include "curlx/warnless.h" -#include "curl_printf.h" -#include "curl_memory.h" #include "multiif.h" #include "rand.h" -/* The last #include file should be: */ +/* The last 2 #includes file should be: */ +#include "curl_memory.h" #include "memdebug.h" /* first byte is command. diff --git a/lib/multi.c b/lib/multi.c index 91d2f56d4732..ced03eea9fbf 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -54,8 +54,8 @@ #include "socketpair.h" #include "socks.h" #include "urlapi-int.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -522,8 +522,8 @@ static void debug_print_sock_hash(void *p) { struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p; - fprintf(stderr, " [readers %u][writers %u]", - sh->readers, sh->writers); + curl_mfprintf(stderr, " [readers %u][writers %u]", + sh->readers, sh->writers); } #endif @@ -4004,12 +4004,14 @@ static void multi_xfer_dump(struct Curl_multi *multi, unsigned int mid, (void)multi; if(!data) { - fprintf(stderr, "mid=%u, entry=NULL, bug in xfer table?\n", mid); + curl_mfprintf(stderr, "mid=%u, entry=NULL, bug in xfer table?\n", mid); } else { - fprintf(stderr, "mid=%u, magic=%s, p=%p, id=%" FMT_OFF_T ", url=%s\n", - mid, (data->magic == CURLEASY_MAGIC_NUMBER) ? "GOOD" : "BAD!", - (void *)data, data->id, data->state.url); + curl_mfprintf(stderr, "mid=%u, magic=%s, p=%p, id=%" FMT_OFF_T + ", url=%s\n", + mid, + (data->magic == CURLEASY_MAGIC_NUMBER) ? "GOOD" : "BAD!", + (void *)data, data->id, data->state.url); } } @@ -4017,15 +4019,15 @@ static void multi_xfer_tbl_dump(struct Curl_multi *multi) { unsigned int mid; void *entry; - fprintf(stderr, "=== multi xfer table (count=%u, capacity=%u\n", - Curl_uint_tbl_count(&multi->xfers), - Curl_uint_tbl_capacity(&multi->xfers)); + curl_mfprintf(stderr, "=== multi xfer table (count=%u, capacity=%u\n", + Curl_uint_tbl_count(&multi->xfers), + Curl_uint_tbl_capacity(&multi->xfers)); if(Curl_uint_tbl_first(&multi->xfers, &mid, &entry)) { multi_xfer_dump(multi, mid, entry); while(Curl_uint_tbl_next(&multi->xfers, mid, &mid, &entry)) multi_xfer_dump(multi, mid, entry); } - fprintf(stderr, "===\n"); + curl_mfprintf(stderr, "===\n"); fflush(stderr); } #endif /* DEBUGBUILD */ diff --git a/lib/multi_ev.c b/lib/multi_ev.c index f43423510ff9..ff755caa6aa3 100644 --- a/lib/multi_ev.c +++ b/lib/multi_ev.c @@ -40,8 +40,8 @@ #include "curlx/warnless.h" #include "multihandle.h" #include "socks.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/netrc.c b/lib/netrc.c index a227ffefcd95..f06dff8ed515 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -42,8 +42,7 @@ #include "curlx/fopen.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -437,7 +436,7 @@ NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host, return NETRC_FILE_MISSING; /* no home directory found (or possibly out of memory) */ - filealloc = aprintf("%s%s.netrc", home, DIR_CHAR); + filealloc = curl_maprintf("%s%s.netrc", home, DIR_CHAR); if(!filealloc) { free(homea); return NETRC_OUT_OF_MEMORY; @@ -448,7 +447,7 @@ NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host, #ifdef _WIN32 if(retcode == NETRC_FILE_MISSING) { /* fallback to the old-style "_netrc" file */ - filealloc = aprintf("%s%s_netrc", home, DIR_CHAR); + filealloc = curl_maprintf("%s%s_netrc", home, DIR_CHAR); if(!filealloc) { free(homea); return NETRC_OUT_OF_MEMORY; diff --git a/lib/noproxy.c b/lib/noproxy.c index 22b067ad1b02..2983fa4a3aa7 100644 --- a/lib/noproxy.c +++ b/lib/noproxy.c @@ -64,9 +64,10 @@ UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */ unsigned int haddr = htonl(address); unsigned int hcheck = htonl(check); #if 0 - fprintf(stderr, "Host %s (%x) network %s (%x) bits %u mask %x => %x\n", - ipv4, haddr, network, hcheck, bits, mask, - (haddr ^ hcheck) & mask); + curl_mfprintf(stderr, "Host %s (%x) network %s (%x) " + "bits %u mask %x => %x\n", + ipv4, haddr, network, hcheck, bits, mask, + (haddr ^ hcheck) & mask); #endif if((haddr ^ hcheck) & mask) return FALSE; diff --git a/lib/openldap.c b/lib/openldap.c index 6aa74e028f8b..72cfdc7039a8 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -52,8 +52,8 @@ #include "connect.h" #include "curl_sasl.h" #include "strcase.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -619,12 +619,12 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done) if(result) goto out; - hosturl = aprintf("%s://%s%s%s:%d", - conn->handler->scheme, - conn->bits.ipv6_ip ? "[" : "", - conn->host.name, - conn->bits.ipv6_ip ? "]" : "", - conn->remote_port); + hosturl = curl_maprintf("%s://%s%s%s:%d", + conn->handler->scheme, + conn->bits.ipv6_ip ? "[" : "", + conn->host.name, + conn->bits.ipv6_ip ? "]" : "", + conn->remote_port); if(!hosturl) { result = CURLE_OUT_OF_MEMORY; goto out; diff --git a/lib/pingpong.c b/lib/pingpong.c index 195e059ed1f4..ddd402089447 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -39,8 +39,7 @@ #include "vtls/vtls.h" #include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/pop3.c b/lib/pop3.c index f5ecfd178ba6..ce9f81e3d5aa 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -77,8 +77,8 @@ #include "curl_md5.h" #include "curlx/warnless.h" #include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -600,7 +600,7 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data, /* Convert the calculated 16 octet digest into a 32 byte hex string */ for(i = 0; i < MD5_DIGEST_LEN; i++) - msnprintf(&secret[2 * i], 3, "%02x", digest[i]); + curl_msnprintf(&secret[2 * i], 3, "%02x", digest[i]); result = Curl_pp_sendf(data, &pop3c->pp, "APOP %s %s", conn->user, secret); diff --git a/lib/progress.c b/lib/progress.c index 2fa0fa122886..7b473ef3ae93 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -29,7 +29,6 @@ #include "multiif.h" #include "progress.h" #include "curlx/timeval.h" -#include "curl_printf.h" /* check rate limits within this many recent milliseconds, at minimum. */ #define MIN_RATE_LIMIT_PERIOD 3000 @@ -48,7 +47,8 @@ static void time2str(char *r, curl_off_t seconds) if(h <= 99) { curl_off_t m = (seconds - (h * 3600)) / 60; curl_off_t s = (seconds - (h * 3600)) - (m * 60); - msnprintf(r, 9, "%2" FMT_OFF_T ":%02" FMT_OFF_T ":%02" FMT_OFF_T, h, m, s); + curl_msnprintf(r, 9, "%2" FMT_OFF_T ":%02" FMT_OFF_T ":%02" FMT_OFF_T, + h, m, s); } else { /* this equals to more than 99 hours, switch to a more suitable output @@ -56,9 +56,9 @@ static void time2str(char *r, curl_off_t seconds) curl_off_t d = seconds / 86400; h = (seconds - (d * 86400)) / 3600; if(d <= 999) - msnprintf(r, 9, "%3" FMT_OFF_T "d %02" FMT_OFF_T "h", d, h); + curl_msnprintf(r, 9, "%3" FMT_OFF_T "d %02" FMT_OFF_T "h", d, h); else - msnprintf(r, 9, "%7" FMT_OFF_T "d", d); + curl_msnprintf(r, 9, "%7" FMT_OFF_T "d", d); } } @@ -71,7 +71,7 @@ static char *max6data(curl_off_t bytes, char *max6) const char unit[] = { 'k', 'M', 'G', 'T', 'P', 0 }; int k = 0; if(bytes < 1000000) { - msnprintf(max6, 7, "%5" CURL_FORMAT_CURL_OFF_T, bytes); + curl_msnprintf(max6, 7, "%5" CURL_FORMAT_CURL_OFF_T, bytes); return max6; } @@ -79,14 +79,15 @@ static char *max6data(curl_off_t bytes, char *max6) curl_off_t nbytes = bytes / 1024; if(nbytes < 1000) { /* xxx.yU */ - msnprintf(max6, 7, "%3" CURL_FORMAT_CURL_OFF_T - ".%" CURL_FORMAT_CURL_OFF_T "%c", nbytes, - (bytes%1024) / (1024/10), unit[k]); + curl_msnprintf(max6, 7, "%3" CURL_FORMAT_CURL_OFF_T + ".%" CURL_FORMAT_CURL_OFF_T "%c", nbytes, + (bytes%1024) / (1024/10), unit[k]); break; } else if(nbytes < 100000) { /* xxxxxU */ - msnprintf(max6, 7, "%5" CURL_FORMAT_CURL_OFF_T "%c", nbytes, unit[k]); + curl_msnprintf(max6, 7, "%5" CURL_FORMAT_CURL_OFF_T "%c", + nbytes, unit[k]); break; } bytes = nbytes; @@ -122,7 +123,7 @@ int Curl_pgrsDone(struct Curl_easy *data) if(!data->progress.hide && !data->progress.callback) /* only output if we do not use a progress callback and we are not * hidden */ - fprintf(data->set.err, "\n"); + curl_mfprintf(data->set.err, "\n"); data->progress.speeder_c = 0; /* reset the progress meter display */ return 0; @@ -500,15 +501,15 @@ static void progress_meter(struct Curl_easy *data) if(!p->headers_out) { if(data->state.resume_from) { - fprintf(data->set.err, - "** Resuming transfer from byte position %" FMT_OFF_T "\n", - data->state.resume_from); + curl_mfprintf(data->set.err, + "** Resuming transfer from byte position %" FMT_OFF_T "\n", + data->state.resume_from); } - fprintf(data->set.err, - " %% Total %% Received %% Xferd Average Speed " - "Time Time Time Current\n" - " Dload Upload " - "Total Spent Left Speed\n"); + curl_mfprintf(data->set.err, + " %% Total %% Received %% Xferd Average Speed " + "Time Time Time Current\n" + " Dload Upload " + "Total Spent Left Speed\n"); p->headers_out = TRUE; /* headers are shown */ } @@ -542,23 +543,23 @@ static void progress_meter(struct Curl_easy *data) /* Get the percentage of data transferred so far */ total_estm.percent = pgrs_est_percent(total_expected_size, total_cur_size); - fprintf(data->set.err, - "\r" - "%3" FMT_OFF_T " %s " - "%3" FMT_OFF_T " %s " - "%3" FMT_OFF_T " %s %s %s %s %s %s %s", - total_estm.percent, /* 3 letters */ /* total % */ - max6data(total_expected_size, max6[2]), /* total size */ - dl_estm.percent, /* 3 letters */ /* rcvd % */ - max6data(p->dl.cur_size, max6[0]), /* rcvd size */ - ul_estm.percent, /* 3 letters */ /* xfer % */ - max6data(p->ul.cur_size, max6[1]), /* xfer size */ - max6data(p->dl.speed, max6[3]), /* avrg dl speed */ - max6data(p->ul.speed, max6[4]), /* avrg ul speed */ - time_total, /* 8 letters */ /* total time */ - time_spent, /* 8 letters */ /* time spent */ - time_left, /* 8 letters */ /* time left */ - max6data(p->current_speed, max6[5]) + curl_mfprintf(data->set.err, + "\r" + "%3" FMT_OFF_T " %s " + "%3" FMT_OFF_T " %s " + "%3" FMT_OFF_T " %s %s %s %s %s %s %s", + total_estm.percent, /* 3 letters */ /* total % */ + max6data(total_expected_size, max6[2]), /* total size */ + dl_estm.percent, /* 3 letters */ /* rcvd % */ + max6data(p->dl.cur_size, max6[0]), /* rcvd size */ + ul_estm.percent, /* 3 letters */ /* xfer % */ + max6data(p->ul.cur_size, max6[1]), /* xfer size */ + max6data(p->dl.speed, max6[3]), /* avrg dl speed */ + max6data(p->ul.speed, max6[4]), /* avrg ul speed */ + time_total, /* 8 letters */ /* total time */ + time_spent, /* 8 letters */ /* time spent */ + time_left, /* 8 letters */ /* time left */ + max6data(p->current_speed, max6[5]) ); /* we flush the output stream to make it appear as soon as possible */ diff --git a/lib/psl.c b/lib/psl.c index a488a46e9315..832d6d21b94a 100644 --- a/lib/psl.c +++ b/lib/psl.c @@ -31,8 +31,7 @@ #include "psl.h" #include "share.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/rand.c b/lib/rand.c index 8b7f07ae4055..cbfcbf27409b 100644 --- a/lib/rand.c +++ b/lib/rand.c @@ -38,8 +38,7 @@ #include "rand.h" #include "escape.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/rename.c b/lib/rename.c index d3a46e0e6a76..4c66ce4ed0eb 100644 --- a/lib/rename.c +++ b/lib/rename.c @@ -32,8 +32,7 @@ #include "curlx/multibyte.h" #include "curlx/timeval.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/request.c b/lib/request.c index 2d5ad9521209..1fa568325bbf 100644 --- a/lib/request.c +++ b/lib/request.c @@ -36,8 +36,7 @@ #include "url.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/rtsp.c b/lib/rtsp.c index 1d5f44f91b24..3ede0fe62ddc 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -41,8 +41,8 @@ #include "cfilters.h" #include "strdup.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -482,8 +482,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) if(data->set.str[STRING_RTSP_TRANSPORT]) { free(data->state.aptr.rtsp_transport); data->state.aptr.rtsp_transport = - aprintf("Transport: %s\r\n", - data->set.str[STRING_RTSP_TRANSPORT]); + curl_maprintf("Transport: %s\r\n", + data->set.str[STRING_RTSP_TRANSPORT]); if(!data->state.aptr.rtsp_transport) return CURLE_OUT_OF_MEMORY; } @@ -508,7 +508,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) data->set.str[STRING_ENCODING]) { free(data->state.aptr.accept_encoding); data->state.aptr.accept_encoding = - aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); + curl_maprintf("Accept-Encoding: %s\r\n", + data->set.str[STRING_ENCODING]); if(!data->state.aptr.accept_encoding) { result = CURLE_OUT_OF_MEMORY; @@ -545,7 +546,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) /* Referrer */ Curl_safefree(data->state.aptr.ref); if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) - data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer); + data->state.aptr.ref = curl_maprintf("Referer: %s\r\n", + data->state.referer); p_referrer = data->state.aptr.ref; @@ -561,7 +563,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) /* Check to see if there is a range set in the custom headers */ if(!Curl_checkheaders(data, STRCONST("Range")) && data->state.range) { free(data->state.aptr.rangeline); - data->state.aptr.rangeline = aprintf("Range: %s\r\n", data->state.range); + data->state.aptr.rangeline = curl_maprintf("Range: %s\r\n", + data->state.range); p_range = data->state.aptr.rangeline; } } diff --git a/lib/select.c b/lib/select.c index af78cb836b0b..7818082e7543 100644 --- a/lib/select.c +++ b/lib/select.c @@ -45,8 +45,8 @@ #include "curlx/timediff.h" #include "curlx/wait.h" #include "curlx/warnless.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/sendf.c b/lib/sendf.c index a262d9036fd9..c6d84127620b 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -56,8 +56,7 @@ #include "curlx/warnless.h" #include "ws.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/setopt.c b/lib/setopt.c index 1c9ee42d41b9..5558bded0a11 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -55,8 +55,7 @@ #include "strdup.h" #include "escape.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/sha256.c b/lib/sha256.c index c5ed8b9c8f69..2d0357189a0e 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -52,8 +52,7 @@ #include #endif -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/share.c b/lib/share.c index d1ab55eb2769..711622a170a2 100644 --- a/lib/share.c +++ b/lib/share.c @@ -34,8 +34,7 @@ #include "hsts.h" #include "url.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/smb.c b/lib/smb.c index bf02119ea1db..f7d06eb4900e 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -42,8 +42,7 @@ #include "escape.h" #include "curl_endian.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -718,12 +717,12 @@ static CURLcode smb_send_setup(struct Curl_easy *data) p += sizeof(lm); memcpy(p, nt, sizeof(nt)); p += sizeof(nt); - p += msnprintf(p, byte_count - sizeof(nt) - sizeof(lm), - "%s%c" /* user */ - "%s%c" /* domain */ - "%s%c" /* OS */ - "%s", /* client name */ - smbc->user, 0, smbc->domain, 0, CURL_OS, 0, CLIENTNAME); + p += curl_msnprintf(p, byte_count - sizeof(nt) - sizeof(lm), + "%s%c" /* user */ + "%s%c" /* domain */ + "%s%c" /* OS */ + "%s", /* client name */ + smbc->user, 0, smbc->domain, 0, CURL_OS, 0, CLIENTNAME); p++; /* count the final null-termination */ DEBUGASSERT(byte_count == (size_t)(p - msg.bytes)); msg.byte_count = smb_swap16((unsigned short)byte_count); @@ -750,11 +749,11 @@ static CURLcode smb_send_tree_connect(struct Curl_easy *data, msg.andx.command = SMB_COM_NO_ANDX_COMMAND; msg.pw_len = 0; - p += msnprintf(p, byte_count, - "\\\\%s\\" /* hostname */ - "%s%c" /* share */ - "%s", /* service */ - conn->host.name, smbc->share, 0, SERVICENAME); + p += curl_msnprintf(p, byte_count, + "\\\\%s\\" /* hostname */ + "%s%c" /* share */ + "%s", /* service */ + conn->host.name, smbc->share, 0, SERVICENAME); p++; /* count the final null-termination */ DEBUGASSERT(byte_count == (size_t)(p - msg.bytes)); msg.byte_count = smb_swap16((unsigned short)byte_count); diff --git a/lib/smtp.c b/lib/smtp.c index 84ff693a3c4e..8daf0ad89de3 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -81,8 +81,7 @@ #include "idn.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -712,14 +711,14 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data, (!Curl_is_ASCII_name(host.name))); if(host.name) { - from = aprintf("<%s@%s>%s", address, host.name, suffix); + from = curl_maprintf("<%s@%s>%s", address, host.name, suffix); Curl_free_idnconverted_hostname(&host); } else /* An invalid mailbox was provided but we will simply let the server worry about that and reply with a 501 error */ - from = aprintf("<%s>%s", address, suffix); + from = curl_maprintf("<%s>%s", address, suffix); free(address); } @@ -754,14 +753,14 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data, utf8 = TRUE; if(host.name) { - auth = aprintf("<%s@%s>%s", address, host.name, suffix); + auth = curl_maprintf("<%s@%s>%s", address, host.name, suffix); Curl_free_idnconverted_hostname(&host); } else /* An invalid mailbox was provided but we will simply let the server worry about it */ - auth = aprintf("<%s>%s", address, suffix); + auth = curl_maprintf("<%s>%s", address, suffix); free(address); } else @@ -806,7 +805,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data, /* Calculate the optional SIZE parameter */ if(smtpc->size_supported && data->state.infilesize > 0) { - size = aprintf("%" FMT_OFF_T, data->state.infilesize); + size = curl_maprintf("%" FMT_OFF_T, data->state.infilesize); if(!size) { result = CURLE_OUT_OF_MEMORY; diff --git a/lib/socketpair.c b/lib/socketpair.c index d2fd41141b24..45e908bbf3a9 100644 --- a/lib/socketpair.c +++ b/lib/socketpair.c @@ -134,8 +134,7 @@ int Curl_socketpair(int domain, int type, int protocol, #include "curlx/timeval.h" /* needed before select.h */ #include "select.h" /* for Curl_poll */ -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/socks.c b/lib/socks.c index da974ad6d8d7..ba7b28d04a01 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -45,8 +45,7 @@ #include "curlx/inet_pton.h" #include "url.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index a88b6f7b75f7..5ad93441a830 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -37,8 +37,7 @@ #include "curlx/warnless.h" #include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -160,8 +159,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, return CURLE_OUT_OF_MEMORY; service.length = serviceptr_length + strlen(conn->socks_proxy.host.name) + 1; - msnprintf(service.value, service.length + 1, "%s@%s", - serviceptr, conn->socks_proxy.host.name); + curl_msnprintf(service.value, service.length + 1, "%s@%s", + serviceptr, conn->socks_proxy.host.name); gss_major_status = gss_import_name(&gss_minor_status, &service, GSS_C_NT_HOSTBASED_SERVICE, &server); diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 16e22d1f39f5..69b000421944 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -38,8 +38,8 @@ #include "curlx/multibyte.h" #include "curlx/warnless.h" #include "strdup.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -104,7 +104,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(strchr(service, '/')) service_name = strdup(service); else - service_name = aprintf("%s/%s", service, conn->socks_proxy.host.name); + service_name = curl_maprintf("%s/%s", + service, conn->socks_proxy.host.name); if(!service_name) return CURLE_OUT_OF_MEMORY; diff --git a/lib/telnet.c b/lib/telnet.c index 259a0c8931ce..1ae15d3704bd 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -60,8 +60,7 @@ #include "curlx/warnless.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -814,7 +813,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data, DEBUGF(infof(data, "set a non ASCII username in telnet")); return CURLE_BAD_FUNCTION_ARGUMENT; } - msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user); + curl_msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user); beg = curl_slist_append(tn->telnet_vars, buffer); if(!beg) { curl_slist_free_all(tn->telnet_vars); @@ -957,9 +956,10 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) failf(data, "Tool long telnet TTYPE"); return CURLE_SEND_ERROR; } - len = msnprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", - CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, - CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); + len = curl_msnprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", + CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, + CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, + CURL_SE); bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { @@ -976,9 +976,10 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) failf(data, "Tool long telnet XDISPLOC"); return CURLE_SEND_ERROR; } - len = msnprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", - CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, - CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); + len = curl_msnprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", + CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, + CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, + CURL_SE); bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { err = SOCKERRNO; @@ -987,9 +988,9 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_NEW_ENVIRON: - len = msnprintf((char *)temp, sizeof(temp), "%c%c%c%c", - CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, - CURL_TELQUAL_IS); + len = curl_msnprintf((char *)temp, sizeof(temp), "%c%c%c%c", + CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, + CURL_TELQUAL_IS); for(v = tn->telnet_vars; v; v = v->next) { size_t tmplen = (strlen(v->data) + 1); if(bad_option(v->data)) @@ -998,18 +999,18 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) if(len + tmplen < (int)sizeof(temp)-6) { char *s = strchr(v->data, ','); if(!s) - len += msnprintf((char *)&temp[len], sizeof(temp) - len, - "%c%s", CURL_NEW_ENV_VAR, v->data); + len += curl_msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s", CURL_NEW_ENV_VAR, v->data); else { size_t vlen = s - v->data; - len += msnprintf((char *)&temp[len], sizeof(temp) - len, - "%c%.*s%c%s", CURL_NEW_ENV_VAR, - (int)vlen, v->data, CURL_NEW_ENV_VALUE, ++s); + len += curl_msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%.*s%c%s", CURL_NEW_ENV_VAR, + (int)vlen, v->data, CURL_NEW_ENV_VALUE, ++s); } } } - msnprintf((char *)&temp[len], sizeof(temp) - len, - "%c%c", CURL_IAC, CURL_SE); + curl_msnprintf((char *)&temp[len], sizeof(temp) - len, + "%c%c", CURL_IAC, CURL_SE); len += 2; bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); if(bytes_written < 0) { diff --git a/lib/tftp.c b/lib/tftp.c index b6bc5e9bdca1..b81fd3ee14b5 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -65,8 +65,7 @@ #include "curlx/strerr.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -474,18 +473,18 @@ static CURLcode tftp_send_first(struct tftp_conn *state, return CURLE_TFTP_ILLEGAL; /* too long filename field */ } - msnprintf((char *)state->spacket.data + 2, - state->blksize, - "%s%c%s%c", filename, '\0', mode, '\0'); + curl_msnprintf((char *)state->spacket.data + 2, + state->blksize, + "%s%c%s%c", filename, '\0', mode, '\0'); sbytes = 4 + strlen(filename) + strlen(mode); /* optional addition of TFTP options */ if(!data->set.tftp_no_options) { char buf[64]; /* add tsize option */ - msnprintf(buf, sizeof(buf), "%" FMT_OFF_T, - data->state.upload && (data->state.infilesize != -1) ? - data->state.infilesize : 0); + curl_msnprintf(buf, sizeof(buf), "%" FMT_OFF_T, + data->state.upload && (data->state.infilesize != -1) ? + data->state.infilesize : 0); result = tftp_option_add(state, &sbytes, (char *)state->spacket.data + sbytes, @@ -495,7 +494,7 @@ static CURLcode tftp_send_first(struct tftp_conn *state, (char *)state->spacket.data + sbytes, buf); /* add blksize option */ - msnprintf(buf, sizeof(buf), "%d", state->requested_blksize); + curl_msnprintf(buf, sizeof(buf), "%d", state->requested_blksize); if(result == CURLE_OK) result = tftp_option_add(state, &sbytes, (char *)state->spacket.data + sbytes, @@ -505,7 +504,7 @@ static CURLcode tftp_send_first(struct tftp_conn *state, (char *)state->spacket.data + sbytes, buf); /* add timeout option */ - msnprintf(buf, sizeof(buf), "%d", state->retry_time); + curl_msnprintf(buf, sizeof(buf), "%d", state->retry_time); if(result == CURLE_OK) result = tftp_option_add(state, &sbytes, (char *)state->spacket.data + sbytes, diff --git a/lib/transfer.c b/lib/transfer.c index 62528d227577..e8c030687a5e 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -83,8 +83,7 @@ #include "setopt.h" #include "headers.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -623,7 +622,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) if(data->set.str[STRING_USERAGENT]) { free(data->state.aptr.uagent); data->state.aptr.uagent = - aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]); + curl_maprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]); if(!data->state.aptr.uagent) return CURLE_OUT_OF_MEMORY; } diff --git a/lib/uint-bset.c b/lib/uint-bset.c index 1c60f22adff2..7b822344c1f6 100644 --- a/lib/uint-bset.c +++ b/lib/uint-bset.c @@ -25,8 +25,7 @@ #include "curl_setup.h" #include "uint-bset.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/uint-spbset.c b/lib/uint-spbset.c index d12cdcb4aa1f..2e8e2a139e74 100644 --- a/lib/uint-spbset.c +++ b/lib/uint-spbset.c @@ -26,8 +26,7 @@ #include "uint-bset.h" #include "uint-spbset.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/uint-table.c b/lib/uint-table.c index 21bcb6e1cf38..5077363ab0f3 100644 --- a/lib/uint-table.c +++ b/lib/uint-table.c @@ -25,8 +25,7 @@ #include "curl_setup.h" #include "uint-table.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/lib/url.c b/lib/url.c index 2a46354c611d..6a433b09efd1 100644 --- a/lib/url.c +++ b/lib/url.c @@ -126,8 +126,8 @@ #include "headers.h" #include "curlx/strerr.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -504,7 +504,7 @@ CURLcode Curl_open(struct Curl_easy **curl) data = calloc(1, sizeof(struct Curl_easy)); if(!data) { /* this is a serious error */ - DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: calloc of Curl_easy failed\n")); return CURLE_OUT_OF_MEMORY; } @@ -1785,8 +1785,9 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, if(data->set.str[STRING_DEFAULT_PROTOCOL] && !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) { - char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL], - data->state.url); + char *url = curl_maprintf("%s://%s", + data->set.str[STRING_DEFAULT_PROTOCOL], + data->state.url); if(!url) return CURLE_OUT_OF_MEMORY; if(data->state.url_alloc) @@ -1997,7 +1998,7 @@ static CURLcode setup_range(struct Curl_easy *data) free(s->range); if(s->resume_from) - s->range = aprintf("%" FMT_OFF_T "-", s->resume_from); + s->range = curl_maprintf("%" FMT_OFF_T "-", s->resume_from); else s->range = strdup(data->set.str[STRING_SET_RANGE]); @@ -2055,9 +2056,10 @@ static CURLcode setup_connection_internals(struct Curl_easy *data, } #ifdef USE_IPV6 - conn->destination = aprintf("%u/%d/%s", conn->scope_id, port, hostname); + conn->destination = curl_maprintf("%u/%d/%s", conn->scope_id, port, + hostname); #else - conn->destination = aprintf("%d/%s", port, hostname); + conn->destination = curl_maprintf("%d/%s", port, hostname); #endif if(!conn->destination) return CURLE_OUT_OF_MEMORY; @@ -2105,7 +2107,8 @@ static char *detect_proxy(struct Curl_easy *data, (void)data; #endif - msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy", conn->handler->scheme); + curl_msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy", + conn->handler->scheme); /* read the protocol proxy: */ proxy = curl_getenv(proxy_env); @@ -2323,7 +2326,7 @@ static CURLcode parse_proxy(struct Curl_easy *data, if(strcmp("/", path)) { is_unix_proxy = TRUE; free(host); - host = aprintf(UNIX_SOCKET_PREFIX"%s", path); + host = curl_maprintf(UNIX_SOCKET_PREFIX"%s", path); if(!host) { result = CURLE_OUT_OF_MEMORY; goto error; @@ -2671,7 +2674,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data, char portbuf[16]; CURLUcode uc; conn->remote_port = data->set.use_port; - msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port); + curl_msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port); uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0); if(uc) return CURLE_OUT_OF_MEMORY; @@ -2982,10 +2985,10 @@ static CURLcode parse_connect_to_string(struct Curl_easy *data, else { /* check whether the URL's hostname matches */ size_t hostname_to_match_len; - char *hostname_to_match = aprintf("%s%s%s", - conn->bits.ipv6_ip ? "[" : "", - conn->host.name, - conn->bits.ipv6_ip ? "]" : ""); + char *hostname_to_match = curl_maprintf("%s%s%s", + conn->bits.ipv6_ip ? "[" : "", + conn->host.name, + conn->bits.ipv6_ip ? "]" : ""); if(!hostname_to_match) return CURLE_OUT_OF_MEMORY; hostname_to_match_len = strlen(hostname_to_match); @@ -3703,7 +3706,7 @@ static CURLcode create_conn(struct Curl_easy *data, */ result = Curl_ssl_conn_config_init(data, conn); if(result) { - DEBUGF(fprintf(stderr, "Error: init connection ssl config\n")); + DEBUGF(curl_mfprintf(stderr, "Error: init connection ssl config\n")); goto out; } diff --git a/lib/urlapi.c b/lib/urlapi.c index 7776645b4a0b..0a6ae5ba1a7c 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -37,8 +37,7 @@ #include "curlx/strparse.h" #include "curl_memrchr.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -461,7 +460,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, u->portnum = (unsigned short) port; /* generate a new port number string to get rid of leading zeroes etc */ free(u->port); - u->port = aprintf("%" CURL_FORMAT_CURL_OFF_T, port); + u->port = curl_maprintf("%" CURL_FORMAT_CURL_OFF_T, port); if(!u->port) return CURLUE_OUT_OF_MEMORY; } @@ -1430,12 +1429,12 @@ static CURLUcode urlget_url(const CURLU *u, char **part, unsigned int flags) bool urlencode = (flags & CURLU_URLENCODE) ? 1 : 0; char portbuf[7]; if(u->scheme && curl_strequal("file", u->scheme)) { - url = aprintf("file://%s%s%s%s%s", - u->path, - show_query ? "?": "", - u->query ? u->query : "", - show_fragment ? "#": "", - u->fragment ? u->fragment : ""); + url = curl_maprintf("file://%s%s%s%s%s", + u->path, + show_query ? "?": "", + u->query ? u->query : "", + show_fragment ? "#": "", + u->fragment ? u->fragment : ""); } else if(!u->host) return CURLUE_NO_HOST; @@ -1454,7 +1453,7 @@ static CURLUcode urlget_url(const CURLU *u, char **part, unsigned int flags) /* there is no stored port number, but asked to deliver a default one for the scheme */ if(h) { - msnprintf(portbuf, sizeof(portbuf), "%u", h->defport); + curl_msnprintf(portbuf, sizeof(portbuf), "%u", h->defport); port = portbuf; } } @@ -1502,26 +1501,26 @@ static CURLUcode urlget_url(const CURLU *u, char **part, unsigned int flags) } if(!(flags & CURLU_NO_GUESS_SCHEME) || !u->guessed_scheme) - msnprintf(schemebuf, sizeof(schemebuf), "%s://", scheme); + curl_msnprintf(schemebuf, sizeof(schemebuf), "%s://", scheme); else schemebuf[0] = 0; - url = aprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", - schemebuf, - u->user ? u->user : "", - u->password ? ":": "", - u->password ? u->password : "", - options ? ";" : "", - options ? options : "", - (u->user || u->password || options) ? "@": "", - allochost ? allochost : u->host, - port ? ":": "", - port ? port : "", - u->path ? u->path : "/", - show_query ? "?": "", - u->query ? u->query : "", - show_fragment ? "#": "", - u->fragment ? u->fragment : ""); + url = curl_maprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + schemebuf, + u->user ? u->user : "", + u->password ? ":": "", + u->password ? u->password : "", + options ? ";" : "", + options ? options : "", + (u->user || u->password || options) ? "@": "", + allochost ? allochost : u->host, + port ? ":": "", + port ? port : "", + u->path ? u->path : "/", + show_query ? "?": "", + u->query ? u->query : "", + show_fragment ? "#": "", + u->fragment ? u->fragment : ""); free(allochost); } if(!url) @@ -1580,7 +1579,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, a default one for the scheme */ const struct Curl_handler *h = Curl_get_scheme_handler(u->scheme); if(h) { - msnprintf(portbuf, sizeof(portbuf), "%u", h->defport); + curl_msnprintf(portbuf, sizeof(portbuf), "%u", h->defport); ptr = portbuf; } } @@ -1665,7 +1664,7 @@ static CURLUcode set_url_port(CURLU *u, const char *provided_port) if(curlx_str_number(&provided_port, &port, 0xffff) || *provided_port) /* weirdly provided number, not good! */ return CURLUE_BAD_PORT_NUMBER; - tmp = aprintf("%" CURL_FORMAT_CURL_OFF_T, port); + tmp = curl_maprintf("%" CURL_FORMAT_CURL_OFF_T, port); if(!tmp) return CURLUE_OUT_OF_MEMORY; free(u->port); diff --git a/lib/vauth/.checksrc b/lib/vauth/.checksrc deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/vauth/cleartext.c b/lib/vauth/cleartext.c index ebf026fcf5ff..dcfb13912d27 100644 --- a/lib/vauth/cleartext.c +++ b/lib/vauth/cleartext.c @@ -37,7 +37,6 @@ #include "vauth.h" #include "../curlx/warnless.h" #include "../sendf.h" -#include "../curl_printf.h" /* The last #include files should be: */ #include "../curl_memory.h" diff --git a/lib/vauth/cram.c b/lib/vauth/cram.c index 3586e1012d0a..2754ddc4a29f 100644 --- a/lib/vauth/cram.c +++ b/lib/vauth/cram.c @@ -35,7 +35,6 @@ #include "../curl_hmac.h" #include "../curl_md5.h" #include "../curlx/warnless.h" -#include "../curl_printf.h" /* The last #include files should be: */ #include "../curl_memory.h" @@ -82,7 +81,7 @@ CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg, Curl_HMAC_final(ctxt, digest); /* Generate the response */ - response = aprintf( + response = curl_maprintf( "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", userp, digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c index 898629a958f1..4196ae725c1d 100644 --- a/lib/vauth/digest.c +++ b/lib/vauth/digest.c @@ -42,7 +42,6 @@ #include "../vtls/vtls.h" #include "../curlx/warnless.h" #include "../curlx/strparse.h" -#include "../curl_printf.h" #include "../rand.h" /* The last #include files should be: */ @@ -147,7 +146,7 @@ static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ { int i; for(i = 0; i < 16; i++) - msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]); + curl_msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]); } /* Convert sha256 or SHA-512/256 chunk to RFC7616 -suitable ASCII string */ @@ -156,7 +155,7 @@ static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */ { int i; for(i = 0; i < 32; i++) - msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]); + curl_msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]); } /* Perform quoted-string escaping as described in RFC2616 and its errata */ @@ -404,7 +403,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, /* Convert calculated 16 octet hex into 32 bytes string */ for(i = 0; i < MD5_DIGEST_LEN; i++) - msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); + curl_msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); /* Generate our SPN */ spn = Curl_auth_build_spn(service, data->conn->host.name, NULL); @@ -427,7 +426,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, Curl_MD5_final(ctxt, digest); for(i = 0; i < MD5_DIGEST_LEN; i++) - msnprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); + curl_msnprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); /* Now calculate the response hash */ ctxt = Curl_MD5_init(&Curl_DIGEST_MD5); @@ -457,14 +456,14 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, Curl_MD5_final(ctxt, digest); for(i = 0; i < MD5_DIGEST_LEN; i++) - msnprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); + curl_msnprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); /* Generate the response */ - response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," - "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s," - "qop=%s", - userp, realm, nonce, - cnonce, nonceCount, spn, resp_hash_hex, qop); + response = curl_maprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," + "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\"," + "response=%s,qop=%s", + userp, realm, nonce, + cnonce, nonceCount, spn, resp_hash_hex, qop); free(spn); if(!response) return CURLE_OUT_OF_MEMORY; @@ -707,7 +706,8 @@ static CURLcode auth_create_digest_http_message( } if(digest->userhash) { - hashthis = aprintf("%s:%s", userp, digest->realm ? digest->realm : ""); + hashthis = curl_maprintf("%s:%s", userp, + digest->realm ? digest->realm : ""); if(!hashthis) return CURLE_OUT_OF_MEMORY; @@ -729,8 +729,8 @@ static CURLcode auth_create_digest_http_message( unq(nonce-value) ":" unq(cnonce-value) */ - hashthis = aprintf("%s:%s:%s", userp, digest->realm ? digest->realm : "", - passwdp); + hashthis = curl_maprintf("%s:%s:%s", userp, + digest->realm ? digest->realm : "", passwdp); if(!hashthis) return CURLE_OUT_OF_MEMORY; @@ -742,7 +742,7 @@ static CURLcode auth_create_digest_http_message( if(digest->algo & SESSION_ALGO) { /* nonce and cnonce are OUTSIDE the hash */ - tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); + tmp = curl_maprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); if(!tmp) return CURLE_OUT_OF_MEMORY; @@ -766,7 +766,7 @@ static CURLcode auth_create_digest_http_message( 5.1.1 of RFC 2616) */ - hashthis = aprintf("%s:%s", request, uripath); + hashthis = curl_maprintf("%s:%s", request, uripath); if(!hashthis) return CURLE_OUT_OF_MEMORY; @@ -782,7 +782,7 @@ static CURLcode auth_create_digest_http_message( } convert_to_ascii(hashbuf, (unsigned char *)hashed); - hashthis2 = aprintf("%s:%s", hashthis, hashed); + hashthis2 = curl_maprintf("%s:%s", hashthis, hashed); free(hashthis); hashthis = hashthis2; } @@ -797,11 +797,11 @@ static CURLcode auth_create_digest_http_message( convert_to_ascii(hashbuf, ha2); if(digest->qop) { - hashthis = aprintf("%s:%s:%08x:%s:%s:%s", ha1, digest->nonce, digest->nc, - digest->cnonce, digest->qop, ha2); + hashthis = curl_maprintf("%s:%s:%08x:%s:%s:%s", ha1, digest->nonce, + digest->nc, digest->cnonce, digest->qop, ha2); } else { - hashthis = aprintf("%s:%s:%s", ha1, digest->nonce, ha2); + hashthis = curl_maprintf("%s:%s:%s", ha1, digest->nonce, ha2); } if(!hashthis) @@ -848,37 +848,37 @@ static CURLcode auth_create_digest_http_message( } if(digest->qop) { - response = aprintf("username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "cnonce=\"%s\", " - "nc=%08x, " - "qop=%s, " - "response=\"%s\"", - userp_quoted, - realm_quoted, - nonce_quoted, - uripath, - digest->cnonce, - digest->nc, - digest->qop, - request_digest); + response = curl_maprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "cnonce=\"%s\", " + "nc=%08x, " + "qop=%s, " + "response=\"%s\"", + userp_quoted, + realm_quoted, + nonce_quoted, + uripath, + digest->cnonce, + digest->nc, + digest->qop, + request_digest); /* Increment nonce-count to use another nc value for the next request */ digest->nc++; } else { - response = aprintf("username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "response=\"%s\"", - userp_quoted, - realm_quoted, - nonce_quoted, - uripath, - request_digest); + response = curl_maprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "response=\"%s\"", + userp_quoted, + realm_quoted, + nonce_quoted, + uripath, + request_digest); } free(nonce_quoted); free(realm_quoted); @@ -895,7 +895,7 @@ static CURLcode auth_create_digest_http_message( free(response); return CURLE_OUT_OF_MEMORY; } - tmp = aprintf("%s, opaque=\"%s\"", response, opaque_quoted); + tmp = curl_maprintf("%s, opaque=\"%s\"", response, opaque_quoted); free(response); free(opaque_quoted); if(!tmp) @@ -906,7 +906,7 @@ static CURLcode auth_create_digest_http_message( if(digest->algorithm) { /* Append the algorithm */ - tmp = aprintf("%s, algorithm=%s", response, digest->algorithm); + tmp = curl_maprintf("%s, algorithm=%s", response, digest->algorithm); free(response); if(!tmp) return CURLE_OUT_OF_MEMORY; @@ -916,7 +916,7 @@ static CURLcode auth_create_digest_http_message( if(digest->userhash) { /* Append the userhash */ - tmp = aprintf("%s, userhash=true", response); + tmp = curl_maprintf("%s, userhash=true", response); free(response); if(!tmp) return CURLE_OUT_OF_MEMORY; diff --git a/lib/vauth/gsasl.c b/lib/vauth/gsasl.c index 3684c8f4b247..8fbb62af80d6 100644 --- a/lib/vauth/gsasl.c +++ b/lib/vauth/gsasl.c @@ -36,8 +36,7 @@ #include -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" diff --git a/lib/vauth/krb5_gssapi.c b/lib/vauth/krb5_gssapi.c index fd46619d846b..70144e5514ad 100644 --- a/lib/vauth/krb5_gssapi.c +++ b/lib/vauth/krb5_gssapi.c @@ -36,7 +36,6 @@ #include "../urldata.h" #include "../curl_gssapi.h" #include "../sendf.h" -#include "../curl_printf.h" /* The last #include files should be: */ #include "../curl_memory.h" diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c index 6164cd388be8..791fc87d1153 100644 --- a/lib/vauth/ntlm.c +++ b/lib/vauth/ntlm.c @@ -48,7 +48,6 @@ #include "vauth.h" #include "../curl_endian.h" -#include "../curl_printf.h" /* The last #include files should be: */ #include "../curl_memory.h" @@ -168,67 +167,67 @@ static void ntlm_print_flags(FILE *handle, unsigned long flags) { if(flags & NTLMFLAG_NEGOTIATE_UNICODE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); if(flags & NTLMFLAG_NEGOTIATE_OEM) - fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); if(flags & NTLMFLAG_REQUEST_TARGET) - fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); + curl_mfprintf(handle, "NTLMFLAG_REQUEST_TARGET "); if(flags & (1 << 3)) - fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); + curl_mfprintf(handle, "NTLMFLAG_UNKNOWN_3 "); if(flags & NTLMFLAG_NEGOTIATE_SIGN) - fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); if(flags & NTLMFLAG_NEGOTIATE_SEAL) - fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); if(flags & (1 << 10)) - fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); + curl_mfprintf(handle, "NTLMFLAG_UNKNOWN_10 "); if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS) - fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) - fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) - fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) - fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) - fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); + curl_mfprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); if(flags & NTLMFLAG_TARGET_TYPE_SERVER) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); + curl_mfprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); if(flags & NTLMFLAG_TARGET_TYPE_SHARE) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); + curl_mfprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) - fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); + curl_mfprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) - fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); + curl_mfprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) - fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); + curl_mfprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) - fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); if(flags & (1 << 24)) - fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); + curl_mfprintf(handle, "NTLMFLAG_UNKNOWN_24 "); if(flags & (1 << 25)) - fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); + curl_mfprintf(handle, "NTLMFLAG_UNKNOWN_25 "); if(flags & (1 << 26)) - fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); + curl_mfprintf(handle, "NTLMFLAG_UNKNOWN_26 "); if(flags & (1 << 27)) - fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); + curl_mfprintf(handle, "NTLMFLAG_UNKNOWN_27 "); if(flags & (1 << 28)) - fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); + curl_mfprintf(handle, "NTLMFLAG_UNKNOWN_28 "); if(flags & NTLMFLAG_NEGOTIATE_128) - fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); if(flags & NTLMFLAG_NEGOTIATE_56) - fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); + curl_mfprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); } static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) @@ -237,9 +236,9 @@ static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) (void)handle; - fprintf(stderr, "0x"); + curl_mfprintf(stderr, "0x"); while(len-- > 0) - fprintf(stderr, "%02.2x", (unsigned int)*p++); + curl_mfprintf(stderr, "%02.2x", (unsigned int)*p++); } #else # define DEBUG_OUT(x) Curl_nop_stmt @@ -394,12 +393,12 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, } DEBUG_OUT({ - fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); + curl_mfprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); ntlm_print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n nonce="); + curl_mfprintf(stderr, "\n nonce="); ntlm_print_hex(stderr, (char *)ntlm->nonce, 8); - fprintf(stderr, "\n****\n"); - fprintf(stderr, "**** Header %s\n ", header); + curl_mfprintf(stderr, "\n****\n"); + curl_mfprintf(stderr, "**** Header %s\n ", header); }); return result; @@ -475,37 +474,37 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, /* Clean up any former leftovers and initialise to defaults */ Curl_auth_cleanup_ntlm(ntlm); - ntlmbuf = aprintf(NTLMSSP_SIGNATURE "%c" - "\x01%c%c%c" /* 32-bit type = 1 */ - "%c%c%c%c" /* 32-bit NTLM flag field */ - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* hostname offset */ - "%c%c" /* 2 zeroes */ - "%s" /* hostname */ - "%s", /* domain string */ - 0, /* trailing zero */ - 0, 0, 0, /* part of type-1 long */ - - LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | - NTLMFLAG_REQUEST_TARGET | - NTLMFLAG_NEGOTIATE_NTLM_KEY | - NTLMFLAG_NEGOTIATE_NTLM2_KEY | - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0, 0, - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0, 0, - host, /* this is empty */ - domain /* this is empty */); + ntlmbuf = curl_maprintf(NTLMSSP_SIGNATURE "%c" + "\x01%c%c%c" /* 32-bit type = 1 */ + "%c%c%c%c" /* 32-bit NTLM flag field */ + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* hostname offset */ + "%c%c" /* 2 zeroes */ + "%s" /* hostname */ + "%s", /* domain string */ + 0, /* trailing zero */ + 0, 0, 0, /* part of type-1 long */ + + LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLMFLAG_NEGOTIATE_NTLM2_KEY | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0, 0, + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0, 0, + host, /* this is empty */ + domain /* this is empty */); if(!ntlmbuf) return CURLE_OUT_OF_MEMORY; @@ -514,25 +513,25 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, size = 32 + hostlen + domlen; DEBUG_OUT({ - fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " - "0x%08.8x ", - LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | - NTLMFLAG_REQUEST_TARGET | - NTLMFLAG_NEGOTIATE_NTLM_KEY | - NTLMFLAG_NEGOTIATE_NTLM2_KEY | - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), - NTLMFLAG_NEGOTIATE_OEM | - NTLMFLAG_REQUEST_TARGET | - NTLMFLAG_NEGOTIATE_NTLM_KEY | - NTLMFLAG_NEGOTIATE_NTLM2_KEY | - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + curl_mfprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " + "0x%08.8x ", + LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLMFLAG_NEGOTIATE_NTLM2_KEY | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLMFLAG_NEGOTIATE_NTLM2_KEY | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); ntlm_print_flags(stderr, NTLMFLAG_NEGOTIATE_OEM | NTLMFLAG_REQUEST_TARGET | NTLMFLAG_NEGOTIATE_NTLM_KEY | NTLMFLAG_NEGOTIATE_NTLM2_KEY | NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - fprintf(stderr, "\n****\n"); + curl_mfprintf(stderr, "\n****\n"); }); Curl_bufref_set(out, ntlmbuf, size, curl_free); @@ -693,82 +692,84 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, hostoff = useroff + userlen; /* Create the big type-3 message binary blob */ - size = msnprintf((char *)ntlmbuf, NTLM_BUFSIZE, - NTLMSSP_SIGNATURE "%c" - "\x03%c%c%c" /* 32-bit type = 3 */ - - "%c%c" /* LanManager length */ - "%c%c" /* LanManager allocated space */ - "%c%c" /* LanManager offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* NT-response length */ - "%c%c" /* NT-response allocated space */ - "%c%c" /* NT-response offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* user length */ - "%c%c" /* user allocated space */ - "%c%c" /* user offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* session key length (unknown purpose) */ - "%c%c" /* session key allocated space (unknown purpose) */ - "%c%c" /* session key offset (unknown purpose) */ - "%c%c" /* 2 zeroes */ - - "%c%c%c%c", /* flags */ - - /* domain string */ - /* user string */ - /* host string */ - /* LanManager response */ - /* NT response */ - - 0, /* null-termination */ - 0, 0, 0, /* type-3 long, the 24 upper bits */ - - SHORTPAIR(0x18), /* LanManager response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(lmrespoff), - 0x0, 0x0, - - SHORTPAIR(ntresplen), /* NT-response length, twice */ - SHORTPAIR(ntresplen), - SHORTPAIR(ntrespoff), - 0x0, 0x0, - - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0x0, 0x0, - - SHORTPAIR(userlen), - SHORTPAIR(userlen), - SHORTPAIR(useroff), - 0x0, 0x0, - - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0x0, 0x0, - - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - - LONGQUARTET(ntlm->flags)); + size = curl_msnprintf((char *)ntlmbuf, NTLM_BUFSIZE, + NTLMSSP_SIGNATURE "%c" + "\x03%c%c%c" /* 32-bit type = 3 */ + + "%c%c" /* LanManager length */ + "%c%c" /* LanManager allocated space */ + "%c%c" /* LanManager offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* NT-response length */ + "%c%c" /* NT-response allocated space */ + "%c%c" /* NT-response offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* user length */ + "%c%c" /* user allocated space */ + "%c%c" /* user offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* session key length (unknown purpose) */ + "%c%c" /* session key allocated space + (unknown purpose) */ + "%c%c" /* session key offset (unknown purpose) */ + "%c%c" /* 2 zeroes */ + + "%c%c%c%c", /* flags */ + + /* domain string */ + /* user string */ + /* host string */ + /* LanManager response */ + /* NT response */ + + 0, /* null-termination */ + 0, 0, 0, /* type-3 long, the 24 upper bits */ + + SHORTPAIR(0x18), /* LanManager response length, + twice */ + SHORTPAIR(0x18), + SHORTPAIR(lmrespoff), + 0x0, 0x0, + + SHORTPAIR(ntresplen), /* NT-response length, twice */ + SHORTPAIR(ntresplen), + SHORTPAIR(ntrespoff), + 0x0, 0x0, + + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0x0, 0x0, + + SHORTPAIR(userlen), + SHORTPAIR(userlen), + SHORTPAIR(useroff), + 0x0, 0x0, + + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0x0, 0x0, + + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + + LONGQUARTET(ntlm->flags)); DEBUGASSERT(size == 64); DEBUGASSERT(size == (size_t)lmrespoff); @@ -780,7 +781,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, } DEBUG_OUT({ - fprintf(stderr, "**** TYPE3 header lmresp="); + curl_mfprintf(stderr, "**** TYPE3 header lmresp="); ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); }); @@ -794,17 +795,17 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, size += ntresplen; DEBUG_OUT({ - fprintf(stderr, "\n ntresp="); + curl_mfprintf(stderr, "\n ntresp="); ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen); }); free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */ DEBUG_OUT({ - fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", - LONGQUARTET(ntlm->flags), ntlm->flags); + curl_mfprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", + LONGQUARTET(ntlm->flags), ntlm->flags); ntlm_print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n****\n"); + curl_mfprintf(stderr, "\n****\n"); }); /* Make sure that the domain, user and host strings fit in the diff --git a/lib/vauth/oauth2.c b/lib/vauth/oauth2.c index a84dc60dafd1..cf7addf53597 100644 --- a/lib/vauth/oauth2.c +++ b/lib/vauth/oauth2.c @@ -35,7 +35,6 @@ #include "vauth.h" #include "../curlx/warnless.h" -#include "../curl_printf.h" /* The last #include files should be: */ #include "../curl_memory.h" @@ -67,11 +66,11 @@ CURLcode Curl_auth_create_oauth_bearer_message(const char *user, /* Generate the message */ if(port == 0 || port == 80) - oauth = aprintf("n,a=%s,\1host=%s\1auth=Bearer %s\1\1", user, host, - bearer); + oauth = curl_maprintf("n,a=%s,\1host=%s\1auth=Bearer %s\1\1", user, host, + bearer); else - oauth = aprintf("n,a=%s,\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user, - host, port, bearer); + oauth = curl_maprintf("n,a=%s,\1host=%s\1port=%ld\1auth=Bearer %s\1\1", + user, host, port, bearer); if(!oauth) return CURLE_OUT_OF_MEMORY; @@ -98,7 +97,7 @@ CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, struct bufref *out) { /* Generate the message */ - char *xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); + char *xoauth = curl_maprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); if(!xoauth) return CURLE_OUT_OF_MEMORY; diff --git a/lib/vauth/vauth.c b/lib/vauth/vauth.c index c6cf4285725a..6ee687dcab22 100644 --- a/lib/vauth/vauth.c +++ b/lib/vauth/vauth.c @@ -30,7 +30,6 @@ #include "../strdup.h" #include "../urldata.h" #include "../curlx/multibyte.h" -#include "../curl_printf.h" #include "../url.h" /* The last #include files should be: */ @@ -62,11 +61,11 @@ char *Curl_auth_build_spn(const char *service, const char *host, /* Generate our SPN */ if(host && realm) - spn = aprintf("%s/%s@%s", service, host, realm); + spn = curl_maprintf("%s/%s@%s", service, host, realm); else if(host) - spn = aprintf("%s/%s", service, host); + spn = curl_maprintf("%s/%s", service, host); else if(realm) - spn = aprintf("%s@%s", service, realm); + spn = curl_maprintf("%s@%s", service, realm); /* Return our newly allocated SPN */ return spn; @@ -89,7 +88,7 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, formulate the SPN instead. */ /* Generate our UTF8 based SPN */ - utf8_spn = aprintf("%s/%s", service, host); + utf8_spn = curl_maprintf("%s/%s", service, host); if(!utf8_spn) return NULL; diff --git a/lib/version.c b/lib/version.c index 8158f26e735b..3798fed6e1d9 100644 --- a/lib/version.c +++ b/lib/version.c @@ -34,7 +34,6 @@ #include "http2.h" #include "vssh/ssh.h" #include "vquic/vquic.h" -#include "curl_printf.h" #include "easy_lock.h" #ifdef USE_ARES @@ -89,7 +88,7 @@ static void brotli_version(char *buf, size_t bufsz) unsigned int major = brotli_version >> 24; unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12; unsigned int patch = brotli_version & 0x00000FFF; - (void)msnprintf(buf, bufsz, "brotli/%u.%u.%u", major, minor, patch); + (void)curl_msnprintf(buf, bufsz, "brotli/%u.%u.%u", major, minor, patch); } #endif @@ -100,7 +99,7 @@ static void zstd_version(char *buf, size_t bufsz) unsigned int major = version / (100 * 100); unsigned int minor = (version - (major * 100 * 100)) / 100; unsigned int patch = version - (major * 100 * 100) - (minor * 100); - (void)msnprintf(buf, bufsz, "zstd/%u.%u.%u", major, minor, patch); + (void)curl_msnprintf(buf, bufsz, "zstd/%u.%u.%u", major, minor, patch); } #endif @@ -116,13 +115,13 @@ static void oldap_version(char *buf, size_t bufsz) unsigned int minor = (((unsigned int)api.ldapai_vendor_version - major * 10000) - patch) / 100; - msnprintf(buf, bufsz, "%s/%u.%u.%u", - api.ldapai_vendor_name, major, minor, patch); + curl_msnprintf(buf, bufsz, "%s/%u.%u.%u", + api.ldapai_vendor_name, major, minor, patch); ldap_memfree(api.ldapai_vendor_name); ber_memvfree((void **)api.ldapai_extensions); } else - msnprintf(buf, bufsz, "OpenLDAP"); + curl_msnprintf(buf, bufsz, "OpenLDAP"); } #endif @@ -132,10 +131,10 @@ static void psl_version(char *buf, size_t bufsz) #if defined(PSL_VERSION_MAJOR) && (PSL_VERSION_MAJOR > 0 || \ PSL_VERSION_MINOR >= 11) int num = psl_check_version_number(0); - msnprintf(buf, bufsz, "libpsl/%d.%d.%d", - num >> 16, (num >> 8) & 0xff, num & 0xff); + curl_msnprintf(buf, bufsz, "libpsl/%d.%d.%d", + num >> 16, (num >> 8) & 0xff, num & 0xff); #else - msnprintf(buf, bufsz, "libpsl/%s", psl_get_version()); + curl_msnprintf(buf, bufsz, "libpsl/%s", psl_get_version()); #endif } #endif @@ -148,11 +147,11 @@ static void psl_version(char *buf, size_t bufsz) static void idn_version(char *buf, size_t bufsz) { #ifdef USE_LIBIDN2 - msnprintf(buf, bufsz, "libidn2/%s", idn2_check_version(NULL)); + curl_msnprintf(buf, bufsz, "libidn2/%s", idn2_check_version(NULL)); #elif defined(USE_WIN32_IDN) - msnprintf(buf, bufsz, "WinIDN"); + curl_msnprintf(buf, bufsz, "WinIDN"); #elif defined(USE_APPLE_IDN) - msnprintf(buf, bufsz, "AppleIDN"); + curl_msnprintf(buf, bufsz, "AppleIDN"); #endif } #endif @@ -219,7 +218,7 @@ char *curl_version(void) /* Override version string when environment variable CURL_VERSION is set */ const char *debugversion = getenv("CURL_VERSION"); if(debugversion) { - msnprintf(out, sizeof(out), "%s", debugversion); + curl_msnprintf(out, sizeof(out), "%s", debugversion); return out; } #endif @@ -230,7 +229,7 @@ char *curl_version(void) src[i++] = ssl_version; #endif #ifdef HAVE_LIBZ - msnprintf(z_version, sizeof(z_version), "zlib/%s", zlibVersion()); + curl_msnprintf(z_version, sizeof(z_version), "zlib/%s", zlibVersion()); src[i++] = z_version; #endif #ifdef HAVE_BROTLI @@ -242,8 +241,8 @@ char *curl_version(void) src[i++] = zstd_ver; #endif #ifdef USE_ARES - msnprintf(cares_version, sizeof(cares_version), - "c-ares/%s", ares_version(NULL)); + curl_msnprintf(cares_version, sizeof(cares_version), + "c-ares/%s", ares_version(NULL)); src[i++] = cares_version; #endif #ifdef USE_IDN @@ -271,8 +270,8 @@ char *curl_version(void) src[i++] = rtmp_version; #endif #ifdef USE_GSASL - msnprintf(gsasl_buf, sizeof(gsasl_buf), "libgsasl/%s", - gsasl_check_version(NULL)); + curl_msnprintf(gsasl_buf, sizeof(gsasl_buf), "libgsasl/%s", + gsasl_check_version(NULL)); src[i++] = gsasl_buf; #endif #ifdef USE_OPENLDAP diff --git a/lib/vquic/.checksrc b/lib/vquic/.checksrc deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 4c7a7857b529..3a301f1b71fb 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -72,8 +72,7 @@ #include "../curlx/warnless.h" -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" @@ -111,8 +110,8 @@ void Curl_ngtcp2_ver(char *p, size_t len) { const ngtcp2_info *ng2 = ngtcp2_version(0); const nghttp3_info *ht3 = nghttp3_version(0); - (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s", - ng2->version_str, ht3->version_str); + (void)curl_msnprintf(p, len, "ngtcp2/%s nghttp3/%s", + ng2->version_str, ht3->version_str); } struct cf_ngtcp2_ctx { @@ -389,9 +388,9 @@ static void quic_printf(void *user_data, const char *fmt, ...) (void)ctx; /* need an easy handle to infof() message */ va_list ap; va_start(ap, fmt); - vfprintf(stderr, fmt, ap); + curl_mvfprintf(stderr, fmt, ap); va_end(ap); - fprintf(stderr, "\n"); + curl_mfprintf(stderr, "\n"); } #endif diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 351519d65aa7..0862d688444f 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -58,8 +58,7 @@ #include "../curlx/warnless.h" #include "../curlx/strerr.h" -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" @@ -511,9 +510,9 @@ static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf, lerr = SSL_get_verify_result(ctx->tls.ossl.ssl); if(lerr != X509_V_OK) { ssl_config->certverifyresult = lerr; - msnprintf(ebuf, sizeof(ebuf), - "SSL certificate problem: %s", - X509_verify_cert_error_string(lerr)); + curl_msnprintf(ebuf, sizeof(ebuf), + "SSL certificate problem: %s", + X509_verify_cert_error_string(lerr)); } else err_descr = "SSL certificate verification failed"; @@ -867,8 +866,8 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid, (const char *)h3val.base, h3val.len); if(result) return -1; - ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", - stream->status_code); + ncopy = curl_msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", + stream->status_code); CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] status: %s", stream_id, line); result = write_resp_raw(cf, data, line, ncopy, FALSE); if(result) { @@ -2465,7 +2464,7 @@ bool Curl_conn_is_osslq(const struct Curl_easy *data, void Curl_osslq_ver(char *p, size_t len) { const nghttp3_info *ht3 = nghttp3_version(0); - (void)msnprintf(p, len, "nghttp3/%s", ht3->version_str); + (void)curl_msnprintf(p, len, "nghttp3/%s", ht3->version_str); } #endif /* !CURL_DISABLE_HTTP && USE_OPENSSL_QUIC && USE_NGHTTP3 */ diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index da67819abb2b..f5fd20fccbf1 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -52,8 +52,7 @@ #include "../vtls/keylog.h" #include "../vtls/vtls.h" -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" @@ -80,7 +79,7 @@ */ void Curl_quiche_ver(char *p, size_t len) { - (void)msnprintf(p, len, "quiche/%s", quiche_version()); + (void)curl_msnprintf(p, len, "quiche/%s", quiche_version()); } struct cf_quiche_ctx { @@ -109,7 +108,7 @@ static int debug_log_init = 0; static void quiche_debug_log(const char *line, void *argp) { (void)argp; - fprintf(stderr, "%s\n", line); + curl_mfprintf(stderr, "%s\n", line); } #endif diff --git a/lib/vquic/vquic-tls.c b/lib/vquic/vquic-tls.c index 6576c5cd454a..fa89c0b80967 100644 --- a/lib/vquic/vquic-tls.c +++ b/lib/vquic/vquic-tls.c @@ -53,8 +53,7 @@ #include "../vtls/vtls_scache.h" #include "vquic-tls.h" -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index d7ed7927be39..f722c7e127a2 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -46,8 +46,7 @@ #include "../curlx/strerr.h" #include "../curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" @@ -675,7 +674,7 @@ CURLcode Curl_qlogdir(struct Curl_easy *data, result = curlx_dyn_add(&fname, "/"); for(i = 0; (i < scidlen) && !result; i++) { char hex[3]; - msnprintf(hex, 3, "%02x", scid[i]); + curl_msnprintf(hex, 3, "%02x", scid[i]); result = curlx_dyn_add(&fname, hex); } if(!result) diff --git a/lib/vssh/.checksrc b/lib/vssh/.checksrc deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 0f51137e8c72..78d7986a9ecd 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -76,8 +76,7 @@ #include #endif -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" @@ -358,7 +357,7 @@ static int myssh_is_known(struct Curl_easy *data, struct ssh_conn *sshc) } for(i = 0; i < 16; i++) - msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]); + curl_msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]); infof(data, "SSH MD5 fingerprint: %s", md5buffer); @@ -602,7 +601,7 @@ static int myssh_in_SFTP_READDIR(struct Curl_easy *data, if(data->set.list_only) { char *tmpLine; - tmpLine = aprintf("%s\n", sshc->readdir_filename); + tmpLine = curl_maprintf("%s\n", sshc->readdir_filename); if(!tmpLine) { myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; @@ -628,8 +627,8 @@ static int myssh_in_SFTP_READDIR(struct Curl_easy *data, if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) && ((sshc->readdir_attrs->permissions & SSH_S_IFMT) == SSH_S_IFLNK)) { - sshc->readdir_linkPath = aprintf("%s%s", sshp->path, - sshc->readdir_filename); + sshc->readdir_linkPath = curl_maprintf("%s%s", sshp->path, + sshc->readdir_filename); if(!sshc->readdir_linkPath) { myssh_to(data, sshc, SSH_SFTP_CLOSE); @@ -766,24 +765,24 @@ static int myssh_in_SFTP_QUOTE_STATVFS(struct Curl_easy *data, #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64 #endif CURLcode result = CURLE_OK; - char *tmp = aprintf("statvfs:\n" - "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n", - statvfs->f_bsize, statvfs->f_frsize, - statvfs->f_blocks, statvfs->f_bfree, - statvfs->f_bavail, statvfs->f_files, - statvfs->f_ffree, statvfs->f_favail, - statvfs->f_fsid, statvfs->f_flag, - statvfs->f_namemax); + char *tmp = curl_maprintf("statvfs:\n" + "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n", + statvfs->f_bsize, statvfs->f_frsize, + statvfs->f_blocks, statvfs->f_bfree, + statvfs->f_bavail, statvfs->f_files, + statvfs->f_ffree, statvfs->f_favail, + statvfs->f_fsid, statvfs->f_flag, + statvfs->f_namemax); sftp_statvfs_free(statvfs); if(!tmp) @@ -1577,7 +1576,8 @@ static int myssh_in_SFTP_QUOTE(struct Curl_easy *data, if(curl_strequal("pwd", cmd)) { /* output debug output if that is requested */ - char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path); + char *tmp = curl_maprintf("257 \"%s\" is current directory.\n", + sshp->path); if(!tmp) { sshc->actualcode = CURLE_OUT_OF_MEMORY; myssh_to(data, sshc, SSH_SFTP_CLOSE); @@ -2564,7 +2564,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) if(conn->bits.ipv6_ip) { char ipv6[MAX_IPADR_LEN]; - msnprintf(ipv6, sizeof(ipv6), "[%s]", conn->host.name); + curl_msnprintf(ipv6, sizeof(ipv6), "[%s]", conn->host.name); rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST, ipv6); } else @@ -3150,7 +3150,7 @@ static CURLcode sftp_recv(struct Curl_easy *data, int sockindex, CURLcode Curl_ssh_init(void) { if(ssh_init()) { - DEBUGF(fprintf(stderr, "Error: libssh_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: libssh_init failed\n")); return CURLE_FAILED_INIT; } return CURLE_OK; @@ -3163,7 +3163,7 @@ void Curl_ssh_cleanup(void) void Curl_ssh_version(char *buffer, size_t buflen) { - (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0)); + (void)curl_msnprintf(buffer, buflen, "libssh/%s", ssh_version(0)); } #endif /* USE_LIBSSH */ diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 390602b35aeb..8ad263e7f3e9 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -71,8 +71,7 @@ #include "../curlx/base64.h" /* for base64 encoding/decoding */ #include "../curl_sha256.h" -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" @@ -174,11 +173,11 @@ kbd_callback(const char *name, int name_len, const char *instruction, struct Curl_easy *data = (struct Curl_easy *)*abstract; #ifdef CURL_LIBSSH2_DEBUG - fprintf(stderr, "name=%s\n", name); - fprintf(stderr, "name_len=%d\n", name_len); - fprintf(stderr, "instruction=%s\n", instruction); - fprintf(stderr, "instruction_len=%d\n", instruction_len); - fprintf(stderr, "num_prompts=%d\n", num_prompts); + curl_mfprintf(stderr, "name=%s\n", name); + curl_mfprintf(stderr, "name_len=%d\n", name_len); + curl_mfprintf(stderr, "instruction=%s\n", instruction); + curl_mfprintf(stderr, "instruction_len=%d\n", instruction_len); + curl_mfprintf(stderr, "num_prompts=%d\n", num_prompts); #else (void)name; (void)name_len; @@ -662,7 +661,8 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data, /* The fingerprint points to static storage (!), do not free() it. */ int i; for(i = 0; i < 16; i++) { - msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]); + curl_msnprintf(&md5buffer[i*2], 3, "%02x", + (unsigned char)fingerprint[i]); } infof(data, "SSH MD5 fingerprint: %s", md5buffer); @@ -871,7 +871,8 @@ static CURLcode sftp_quote(struct Curl_easy *data, if(curl_strequal("pwd", cmd)) { /* output debug output if that is requested */ - char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path); + char *tmp = curl_maprintf("257 \"%s\" is current directory.\n", + sshp->path); if(!tmp) return CURLE_OUT_OF_MEMORY; Curl_debug(data, CURLINFO_HEADER_OUT, "PWD\n", 4); @@ -1193,12 +1194,12 @@ static CURLcode ssh_state_pkey_init(struct Curl_easy *data, /* If no private key file is specified, try some common paths. */ if(home) { /* Try ~/.ssh first. */ - sshc->rsa = aprintf("%s/.ssh/id_rsa", home); + sshc->rsa = curl_maprintf("%s/.ssh/id_rsa", home); if(!sshc->rsa) out_of_memory = TRUE; else if(curlx_stat(sshc->rsa, &sbuf)) { free(sshc->rsa); - sshc->rsa = aprintf("%s/.ssh/id_dsa", home); + sshc->rsa = curl_maprintf("%s/.ssh/id_dsa", home); if(!sshc->rsa) out_of_memory = TRUE; else if(curlx_stat(sshc->rsa, &sbuf)) { @@ -2234,24 +2235,24 @@ static CURLcode ssh_state_sftp_quote_statvfs(struct Curl_easy *data, #define CURL_LIBSSH2_VFS_SIZE_MASK "llu" #endif CURLcode result; - char *tmp = aprintf("statvfs:\n" - "f_bsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" - "f_frsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" - "f_blocks: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" - "f_bfree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" - "f_bavail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" - "f_files: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" - "f_ffree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" - "f_favail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" - "f_fsid: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" - "f_flag: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" - "f_namemax: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n", - statvfs.f_bsize, statvfs.f_frsize, - statvfs.f_blocks, statvfs.f_bfree, - statvfs.f_bavail, statvfs.f_files, - statvfs.f_ffree, statvfs.f_favail, - statvfs.f_fsid, statvfs.f_flag, - statvfs.f_namemax); + char *tmp = curl_maprintf("statvfs:\n" + "f_bsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_frsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_blocks: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_bfree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_bavail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_files: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_ffree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_favail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_fsid: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_flag: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_namemax: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n", + statvfs.f_bsize, statvfs.f_frsize, + statvfs.f_blocks, statvfs.f_bfree, + statvfs.f_bavail, statvfs.f_files, + statvfs.f_ffree, statvfs.f_favail, + statvfs.f_fsid, statvfs.f_flag, + statvfs.f_namemax); if(!tmp) { myssh_state(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; @@ -3974,7 +3975,7 @@ static const char *sftp_libssh2_strerror(unsigned long err) CURLcode Curl_ssh_init(void) { if(libssh2_init(0)) { - DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: libssh2_init failed\n")); return CURLE_FAILED_INIT; } return CURLE_OK; @@ -3987,7 +3988,7 @@ void Curl_ssh_cleanup(void) void Curl_ssh_version(char *buffer, size_t buflen) { - (void)msnprintf(buffer, buflen, "libssh2/%s", libssh2_version(0)); + (void)curl_msnprintf(buffer, buflen, "libssh2/%s", libssh2_version(0)); } /* The SSH session is associated with the *CONNECTION* but the callback user diff --git a/lib/vtls/.checksrc b/lib/vtls/.checksrc deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/vtls/cipher_suite.c b/lib/vtls/cipher_suite.c index 4bf60c1a4abb..23fb3a3c5d16 100644 --- a/lib/vtls/cipher_suite.c +++ b/lib/vtls/cipher_suite.c @@ -25,7 +25,6 @@ #if defined(USE_MBEDTLS) || defined(USE_RUSTLS) #include "cipher_suite.h" -#include "../curl_printf.h" #include /* @@ -630,9 +629,9 @@ static int cs_zip_to_str(const uint8_t zip[6], /* append the part string to the buffer */ if(i > 0) - r = msnprintf(&buf[len], buf_size - len, "%c%s", separator, entry); + r = curl_msnprintf(&buf[len], buf_size - len, "%c%s", separator, entry); else - r = msnprintf(&buf[len], buf_size - len, "%s", entry); + r = curl_msnprintf(&buf[len], buf_size - len, "%s", entry); if(r < 0) return -1; @@ -703,7 +702,7 @@ int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size, r = cs_zip_to_str(cs_list[j].zip, buf, buf_size); if(r < 0) - msnprintf(buf, buf_size, "TLS_UNKNOWN_0x%04x", id); + curl_msnprintf(buf, buf_size, "TLS_UNKNOWN_0x%04x", id); return r; } diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 3d69ab1d1cab..43edbd57ad2b 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -59,7 +59,6 @@ #include "../curlx/warnless.h" #include "x509asn1.h" #include "../multiif.h" -#include "../curl_printf.h" #include "../curl_memory.h" /* The last #include file should be: */ #include "../memdebug.h" @@ -70,7 +69,7 @@ #ifdef GTLSDEBUG static void tls_log_func(int level, const char *str) { - fprintf(stderr, "|<%d>| %s", level, str); + curl_mfprintf(stderr, "|<%d>| %s", level, str); } #endif static bool gtls_inited = FALSE; @@ -191,17 +190,17 @@ static void showtime(struct Curl_easy *data, if(result) return; - msnprintf(str, - sizeof(str), - " %s: %s, %02d %s %4d %02d:%02d:%02d GMT", - text, - Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); + curl_msnprintf(str, + sizeof(str), + " %s: %s, %02d %s %4d %02d:%02d:%02d GMT", + text, + Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); infof(data, "%s", str); } #endif @@ -2272,7 +2271,7 @@ static CURLcode gtls_recv(struct Curl_cfilter *cf, size_t Curl_gtls_version(char *buffer, size_t size) { - return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); + return curl_msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); } /* data might be NULL! */ diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index aa7e8d67ef4d..3ff131b441a0 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -67,8 +67,7 @@ #include "mbedtls_threadlock.h" #include "../strdup.h" -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" @@ -307,7 +306,7 @@ mbed_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size, bool prefer_rfc) { if(id == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8) - msnprintf(buf, buf_size, "%s", "TLS_ECJPAKE_WITH_AES_128_CCM_8"); + curl_msnprintf(buf, buf_size, "%s", "TLS_ECJPAKE_WITH_AES_128_CCM_8"); else return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc); return 0; @@ -1336,10 +1335,10 @@ static size_t mbedtls_version(char *buffer, size_t size) #ifdef MBEDTLS_VERSION_C /* if mbedtls_version_get_number() is available it is better */ unsigned int version = mbedtls_version_get_number(); - return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version >> 24, - (version >> 16) & 0xff, (version >> 8) & 0xff); + return curl_msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version >> 24, + (version >> 16) & 0xff, (version >> 8) & 0xff); #else - return msnprintf(buffer, size, "mbedTLS/%s", MBEDTLS_VERSION_STRING); + return curl_msnprintf(buffer, size, "mbedTLS/%s", MBEDTLS_VERSION_STRING); #endif } diff --git a/lib/vtls/mbedtls_threadlock.c b/lib/vtls/mbedtls_threadlock.c index 682c221852c8..ed70308b739d 100644 --- a/lib/vtls/mbedtls_threadlock.c +++ b/lib/vtls/mbedtls_threadlock.c @@ -36,9 +36,9 @@ #endif #include "mbedtls_threadlock.h" -#include "../curl_printf.h" + +/* The last 2 #include files should be: */ #include "../curl_memory.h" -/* The last #include file should be: */ #include "../memdebug.h" /* number of thread locks */ @@ -96,14 +96,14 @@ int Curl_mbedtlsthreadlock_lock_function(int n) if(n < NUMT) { #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) if(pthread_mutex_lock(&mutex_buf[n])) { - DEBUGF(fprintf(stderr, - "Error: mbedtlsthreadlock_lock_function failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: " + "mbedtlsthreadlock_lock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #elif defined(_WIN32) if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) { - DEBUGF(fprintf(stderr, - "Error: mbedtlsthreadlock_lock_function failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: " + "mbedtlsthreadlock_lock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ @@ -116,14 +116,14 @@ int Curl_mbedtlsthreadlock_unlock_function(int n) if(n < NUMT) { #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) if(pthread_mutex_unlock(&mutex_buf[n])) { - DEBUGF(fprintf(stderr, - "Error: mbedtlsthreadlock_unlock_function failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: " + "mbedtlsthreadlock_unlock_function failed\n")); return 0; /* pthread_mutex_unlock failed */ } #elif defined(_WIN32) if(!ReleaseMutex(mutex_buf[n])) { - DEBUGF(fprintf(stderr, - "Error: mbedtlsthreadlock_unlock_function failed\n")); + DEBUGF(curl_mfprintf(stderr, "Error: " + "mbedtlsthreadlock_unlock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 409c9c09460c..3145d4d20315 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -66,7 +66,6 @@ #include "../curlx/strerr.h" #include "../curlx/strparse.h" #include "../strdup.h" -#include "../curl_printf.h" #include "apple.h" #include @@ -274,7 +273,7 @@ static CURLcode pubkey_show(struct Curl_easy *data, { char namebuf[32]; - msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); + curl_msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); if(bn) BN_print(mem, bn); @@ -2803,7 +2802,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, case 0: break; default: - msnprintf(unknown, sizeof(unknown), "(%x)", ssl_ver); + curl_msnprintf(unknown, sizeof(unknown), "(%x)", ssl_ver); verstr = unknown; break; } @@ -2850,10 +2849,10 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, msg_name = ssl_msg_type(ssl_ver, msg_type); } - txt_len = msnprintf(ssl_buf, sizeof(ssl_buf), - "%s (%s), %s, %s (%d):\n", - verstr, direction ? "OUT" : "IN", - tls_rt_name, msg_name, msg_type); + txt_len = curl_msnprintf(ssl_buf, sizeof(ssl_buf), + "%s (%s), %s, %s (%d):\n", + verstr, direction ? "OUT" : "IN", + tls_rt_name, msg_name, msg_type); Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len); } @@ -4866,7 +4865,8 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl) char group_name[80] = ""; get_group_name = EVP_PKEY_get_group_name(current_pkey, group_name, sizeof(group_name), NULL); - msnprintf(group_name_final, sizeof(group_name_final), "/%s", group_name); + curl_msnprintf(group_name_final, sizeof(group_name_final), "/%s", + group_name); } type_name = current_pkey ? EVP_PKEY_get0_type_name(current_pkey) : NULL; #else @@ -5278,8 +5278,8 @@ static CURLcode ossl_send_earlydata(struct Curl_cfilter *cf, else if(sockerr) curlx_strerror(sockerr, error_buffer, sizeof(error_buffer)); else - msnprintf(error_buffer, sizeof(error_buffer), "%s", - SSL_ERROR_to_str(err)); + curl_msnprintf(error_buffer, sizeof(error_buffer), "%s", + SSL_ERROR_to_str(err)); failf(data, OSSL_PACKAGE " SSL_write:early_data: %s, errno %d", error_buffer, sockerr); @@ -5464,8 +5464,8 @@ static CURLcode ossl_send(struct Curl_cfilter *cf, else if(sockerr) curlx_strerror(sockerr, error_buffer, sizeof(error_buffer)); else - msnprintf(error_buffer, sizeof(error_buffer), "%s", - SSL_ERROR_to_str(err)); + curl_msnprintf(error_buffer, sizeof(error_buffer), "%s", + SSL_ERROR_to_str(err)); failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d", error_buffer, sockerr); @@ -5561,8 +5561,8 @@ static CURLcode ossl_recv(struct Curl_cfilter *cf, else if(sockerr && err == SSL_ERROR_SYSCALL) curlx_strerror(sockerr, error_buffer, sizeof(error_buffer)); else - msnprintf(error_buffer, sizeof(error_buffer), "%s", - SSL_ERROR_to_str(err)); + curl_msnprintf(error_buffer, sizeof(error_buffer), "%s", + SSL_ERROR_to_str(err)); failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d", error_buffer, sockerr); result = CURLE_RECV_ERROR; @@ -5584,8 +5584,8 @@ static CURLcode ossl_recv(struct Curl_cfilter *cf, if(sockerr) curlx_strerror(sockerr, error_buffer, sizeof(error_buffer)); else { - msnprintf(error_buffer, sizeof(error_buffer), - "Connection closed abruptly"); + curl_msnprintf(error_buffer, sizeof(error_buffer), + "Connection closed abruptly"); } failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d", error_buffer, sockerr); @@ -5705,7 +5705,7 @@ size_t Curl_ossl_version(char *buffer, size_t size) if(curl_strnequal(ver, expected, sizeof(expected) - 1)) { ver += sizeof(expected) - 1; } - count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver); + count = curl_msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver); for(p = buffer; *p; ++p) { if(ISBLANK(*p)) *p = '_'; @@ -5713,17 +5713,17 @@ size_t Curl_ossl_version(char *buffer, size_t size) return count; #elif defined(OPENSSL_IS_BORINGSSL) #ifdef CURL_BORINGSSL_VERSION - return msnprintf(buffer, size, "%s/%s", - OSSL_PACKAGE, CURL_BORINGSSL_VERSION); + return curl_msnprintf(buffer, size, "%s/%s", + OSSL_PACKAGE, CURL_BORINGSSL_VERSION); #else - return msnprintf(buffer, size, OSSL_PACKAGE); + return curl_msnprintf(buffer, size, OSSL_PACKAGE); #endif #elif defined(OPENSSL_IS_AWSLC) - return msnprintf(buffer, size, "%s/%s", - OSSL_PACKAGE, AWSLC_VERSION_NUMBER_STRING); + return curl_msnprintf(buffer, size, "%s/%s", + OSSL_PACKAGE, AWSLC_VERSION_NUMBER_STRING); #elif defined(OPENSSL_VERSION_STRING) /* OpenSSL 3+ */ - return msnprintf(buffer, size, "%s/%s", - OSSL_PACKAGE, OpenSSL_version(OPENSSL_VERSION_STRING)); + return curl_msnprintf(buffer, size, "%s/%s", + OSSL_PACKAGE, OpenSSL_version(OPENSSL_VERSION_STRING)); #else /* not LibreSSL, BoringSSL and not using OpenSSL_version */ @@ -5746,16 +5746,16 @@ size_t Curl_ossl_version(char *buffer, size_t size) else sub[0]='\0'; - return msnprintf(buffer, size, "%s/%lx.%lx.%lx%s" + return curl_msnprintf(buffer, size, "%s/%lx.%lx.%lx%s" #ifdef OPENSSL_FIPS - "-fips" -#endif - , - OSSL_PACKAGE, - (ssleay_value >> 28) & 0xf, - (ssleay_value >> 20) & 0xff, - (ssleay_value >> 12) & 0xff, - sub); + "-fips" +#endif + , + OSSL_PACKAGE, + (ssleay_value >> 28) & 0xf, + (ssleay_value >> 20) & 0xff, + (ssleay_value >> 12) & 0xff, + sub); #endif } diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index ce7a4d5c9dcb..a3ab49a101ea 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -28,8 +28,6 @@ #ifdef USE_RUSTLS -#include "../curl_printf.h" - #include #include "../curlx/fopen.h" @@ -520,7 +518,7 @@ cr_keylog_log_cb(struct rustls_str label, (void)client_random_len; DEBUGASSERT(client_random_len == CLIENT_RANDOM_SIZE); /* Turning a "rustls_str" into a null delimited "c" string */ - msnprintf(clabel, label.len + 1, "%.*s", (int)label.len, label.data); + curl_msnprintf(clabel, label.len + 1, "%.*s", (int)label.len, label.data); Curl_tls_keylog_write(clabel, client_random, secret, secret_len); } @@ -1389,7 +1387,7 @@ cr_close(struct Curl_cfilter *cf, struct Curl_easy *data) static size_t cr_version(char *buffer, size_t size) { const struct rustls_str ver = rustls_version(); - return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data); + return curl_msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data); } static CURLcode diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index c0e96c93bf4c..ae5834d84342 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -52,7 +52,6 @@ #include "../curlx/multibyte.h" #include "../curlx/warnless.h" #include "x509asn1.h" -#include "../curl_printf.h" #include "../multiif.h" #include "../system_win32.h" #include "../curlx/version_win32.h" @@ -110,8 +109,8 @@ #define CERT_THUMBPRINT_DATA_LEN 20 /* Uncomment to force verbose output - * #define infof(x, y, ...) printf(y, __VA_ARGS__) - * #define failf(x, y, ...) printf(y, __VA_ARGS__) + * #define infof(x, y, ...) curl_mprintf(y, __VA_ARGS__) + * #define failf(x, y, ...) curl_mprintf(y, __VA_ARGS__) */ /* Offered when targeting Vista (XP SP2+) */ @@ -2586,7 +2585,7 @@ static void schannel_cleanup(void) static size_t schannel_version(char *buffer, size_t size) { - return msnprintf(buffer, size, "Schannel"); + return curl_msnprintf(buffer, size, "Schannel"); } static CURLcode schannel_random(struct Curl_easy *data, diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index f73d758ba196..e64a113ff2b6 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -46,7 +46,6 @@ #include "../strerror.h" #include "../curlx/winapi.h" #include "../curlx/multibyte.h" -#include "../curl_printf.h" #include "hostcheck.h" #include "../curlx/version_win32.h" diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index ccd567cd864c..b715dab035d2 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -71,7 +71,6 @@ #include "../curl_sha256.h" #include "../curlx/warnless.h" #include "../curlx/base64.h" -#include "../curl_printf.h" #include "../curlx/inet_pton.h" #include "../connect.h" #include "../select.h" @@ -1094,8 +1093,8 @@ static size_t multissl_version(char *buffer, size_t size) bool paren = (selected != available_backends[i]); if(available_backends[i]->version(vb, sizeof(vb))) { - p += msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""), - (paren ? "(" : ""), vb, (paren ? ")" : "")); + p += curl_msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""), + (paren ? "(" : ""), vb, (paren ? ")" : "")); } } diff --git a/lib/vtls/vtls_scache.c b/lib/vtls/vtls_scache.c index 16e3f0314f64..763b474cfc7d 100644 --- a/lib/vtls/vtls_scache.c +++ b/lib/vtls/vtls_scache.c @@ -46,7 +46,6 @@ #include "../curl_sha256.h" #include "../rand.h" #include "../curlx/warnless.h" -#include "../curl_printf.h" #include "../strdup.h" /* The last #include files should be: */ diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index ed024356766e..6186ce985be7 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -69,7 +69,6 @@ #include "../select.h" #include "../strdup.h" #include "x509asn1.h" -#include "../curl_printf.h" #include "../multiif.h" #include @@ -2056,9 +2055,9 @@ static CURLcode wssl_recv(struct Curl_cfilter *cf, size_t Curl_wssl_version(char *buffer, size_t size) { #if LIBWOLFSSL_VERSION_HEX >= 0x03006000 - return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version()); + return curl_msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version()); #elif defined(WOLFSSL_VERSION) - return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION); + return curl_msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION); #endif } diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c index 96b7f5bd630c..c5fc86351524 100644 --- a/lib/vtls/x509asn1.c +++ b/lib/vtls/x509asn1.c @@ -49,8 +49,7 @@ #include "x509asn1.h" #include "../curlx/dynbuf.h" -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" @@ -998,7 +997,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, infof(data, " ECC Public Key (%zu bits)", len); if(data->set.ssl.certinfo) { char q[sizeof(len) * 8 / 3 + 1]; - (void)msnprintf(q, sizeof(q), "%zu", len); + (void)curl_msnprintf(q, sizeof(q), "%zu", len); if(ssl_push_certinfo(data, certnum, "ECC Public Key", q)) return 1; } @@ -1033,7 +1032,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, infof(data, " RSA Public Key (%zu bits)", len); if(data->set.ssl.certinfo) { char r[sizeof(len) * 8 / 3 + 1]; - msnprintf(r, sizeof(r), "%zu", len); + curl_msnprintf(r, sizeof(r), "%zu", len); if(ssl_push_certinfo(data, certnum, "RSA Public Key", r)) return 1; } diff --git a/lib/ws.c b/lib/ws.c index 36c9c91f6542..d3379c650237 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -42,8 +42,7 @@ #include "curlx/nonblock.h" #include "curlx/strparse.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" diff --git a/packages/OS400/curlcl.c b/packages/OS400/curlcl.c index 02edcd63c0c1..ca497b351d43 100644 --- a/packages/OS400/curlcl.c +++ b/packages/OS400/curlcl.c @@ -107,6 +107,7 @@ parse_command_line(const char *cmdargs, size_t len, } if(quote) { + /* !checksrc! disable BANNEDFUNC 1 */ fprintf(stderr, "Unterminated quote: %c\n", quote); return -1; } diff --git a/scripts/.checksrc b/scripts/.checksrc new file mode 100644 index 000000000000..84d62d2b750c --- /dev/null +++ b/scripts/.checksrc @@ -0,0 +1 @@ +allowfunc printf diff --git a/scripts/Makefile.am b/scripts/Makefile.am index a52581155d46..da9b6b4b7723 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -26,7 +26,7 @@ EXTRA_DIST = coverage.sh completion.pl firefox-db2pem.sh checksrc.pl checksrc-al mk-ca-bundle.pl mk-unity.pl schemetable.c cd2nroff nroff2cd cdall cd2cd managen \ dmaketgz maketgz release-tools.sh verify-release cmakelint.sh mdlinkcheck \ CMakeLists.txt perlcheck.sh pythonlint.sh randdisable wcurl top-complexity \ - extract-unit-protos + extract-unit-protos .checksrc dist_bin_SCRIPTS = wcurl diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 017738ecdf8a..5a8c80ebfe5b 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -56,6 +56,14 @@ "snprintf" => 1, "vsprintf" => 1, "vsnprintf" => 1, + "aprintf" => 1, + "fprintf" => 1, + "msnprintf" => 1, + "mvsnprintf" => 1, + "printf" => 1, + "vaprintf" => 1, + "vfprintf" => 1, + "vprintf" => 1, "sscanf" => 1, "strcat" => 1, "strerror" => 1, diff --git a/src/.checksrc b/src/.checksrc index 4a6b707084cf..946367c4999f 100644 --- a/src/.checksrc +++ b/src/.checksrc @@ -1,9 +1 @@ enable STDERR -banfunc aprintf -banfunc fprintf -banfunc msnprintf -banfunc mvsnprintf -banfunc printf -banfunc vaprintf -banfunc vfprintf -banfunc vprintf diff --git a/tests/cmake/test.c b/tests/cmake/test.c index 32f8826df03e..72450eca630b 100644 --- a/tests/cmake/test.c +++ b/tests/cmake/test.c @@ -27,6 +27,7 @@ int main(int argc, char **argv) { (void)argc; + /* !checksrc! disable BANNEDFUNC 1 */ printf("libcurl test: |%s|%s|\n", argv[0], curl_version()); return 0; } diff --git a/tests/libtest/.checksrc b/tests/libtest/.checksrc deleted file mode 100644 index a3f8f307e792..000000000000 --- a/tests/libtest/.checksrc +++ /dev/null @@ -1,8 +0,0 @@ -banfunc aprintf -banfunc fprintf -banfunc msnprintf -banfunc mvsnprintf -banfunc printf -banfunc vaprintf -banfunc vfprintf -banfunc vprintf diff --git a/tests/libtest/Makefile.am b/tests/libtest/Makefile.am index 482e09d098a4..b62a359eabef 100644 --- a/tests/libtest/Makefile.am +++ b/tests/libtest/Makefile.am @@ -41,7 +41,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ # Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TESTS_C variables include Makefile.inc -EXTRA_DIST = CMakeLists.txt .checksrc $(FIRST_C) $(FIRST_H) $(UTILS_C) $(UTILS_H) $(TESTS_C) \ +EXTRA_DIST = CMakeLists.txt $(FIRST_C) $(FIRST_H) $(UTILS_C) $(UTILS_H) $(TESTS_C) \ test307.pl test610.pl test613.pl test1013.pl test1022.pl mk-lib1521.pl CFLAGS += @CURL_CFLAG_EXTRAS@ diff --git a/tests/server/.checksrc b/tests/server/.checksrc index d6506e14020a..d4be12473ac4 100644 --- a/tests/server/.checksrc +++ b/tests/server/.checksrc @@ -1,9 +1,11 @@ allowfunc accept allowfunc fclose allowfunc fopen +allowfunc fprintf allowfunc freeaddrinfo allowfunc getaddrinfo allowfunc open +allowfunc printf allowfunc recv allowfunc send allowfunc snprintf diff --git a/tests/tunit/.checksrc b/tests/tunit/.checksrc deleted file mode 100644 index a3f8f307e792..000000000000 --- a/tests/tunit/.checksrc +++ /dev/null @@ -1,8 +0,0 @@ -banfunc aprintf -banfunc fprintf -banfunc msnprintf -banfunc mvsnprintf -banfunc printf -banfunc vaprintf -banfunc vfprintf -banfunc vprintf diff --git a/tests/tunit/Makefile.am b/tests/tunit/Makefile.am index fea9d51152ae..219b7a10579c 100644 --- a/tests/tunit/Makefile.am +++ b/tests/tunit/Makefile.am @@ -43,7 +43,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ # Get BUNDLE, FIRST_C, TESTS_C variables include Makefile.inc -EXTRA_DIST = CMakeLists.txt .checksrc README.md $(TESTS_C) +EXTRA_DIST = CMakeLists.txt README.md $(TESTS_C) CFLAGS += @CURL_CFLAG_EXTRAS@ diff --git a/tests/unit/.checksrc b/tests/unit/.checksrc deleted file mode 100644 index a3f8f307e792..000000000000 --- a/tests/unit/.checksrc +++ /dev/null @@ -1,8 +0,0 @@ -banfunc aprintf -banfunc fprintf -banfunc msnprintf -banfunc mvsnprintf -banfunc printf -banfunc vaprintf -banfunc vfprintf -banfunc vprintf diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 1e9940f48a0c..32c2f3895594 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -42,7 +42,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ # Get BUNDLE, FIRST_C, TESTS_C variables include Makefile.inc -EXTRA_DIST = CMakeLists.txt .checksrc README.md $(TESTS_C) +EXTRA_DIST = CMakeLists.txt README.md $(TESTS_C) CFLAGS += @CURL_CFLAG_EXTRAS@ From 6f0e212f6e2746005fe63aab81f04d479bb8d01b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 29 Sep 2025 12:36:14 +0200 Subject: [PATCH 306/465] tidy-up: miscellaneous (cont.) - examples: replace magic numbers with `sizeof()`. - typos: drop rules no longer needed after excluding tests/data. - typos: move an exception inline. - alpha-sort lists. - fix indentation, whitespace. Closes #18898 --- .github/scripts/typos.toml | 11 ++++------- .github/workflows/label.yml | 1 + configure.ac | 2 +- docs/examples/multi-event.c | 2 +- docs/examples/multi-uv.c | 2 +- lib/amigaos.c | 4 ++-- lib/cf-ip-happy.c | 6 +++--- lib/curl_trc.c | 1 + lib/rtsp.c | 2 +- lib/vauth/digest_sspi.c | 2 +- lib/vauth/ntlm_sspi.c | 2 +- lib/vquic/curl_ngtcp2.c | 4 ++-- lib/vtls/openssl.c | 6 +++--- src/Makefile.inc | 6 +++--- src/tool_operate.c | 2 +- tests/libtest/lib517.c | 2 +- tests/server/sockfilt.c | 4 ++-- 17 files changed, 29 insertions(+), 30 deletions(-) diff --git a/.github/scripts/typos.toml b/.github/scripts/typos.toml index 97c682b5b6ee..a84017cf5303 100644 --- a/.github/scripts/typos.toml +++ b/.github/scripts/typos.toml @@ -9,13 +9,10 @@ extend-ignore-identifiers-re = [ "^(ECT0|ECT1|HELO|htpt|PASE)$", "^[A-Za-z0-9_-]*(EDE|GOST)[A-Z0-9_-]*$", # ciphers "^0x[0-9a-fA-F]+FUL$", # unsigned long hex literals ending with 'F' - "^[0-9a-zA-Z+]{64,}$", # possibly base64 - "^(Januar|eyeballers|HELO_smtp|kno22|MkTypLibCompatible|optin|passin|perfec|__SecURE|SMTP_HELO|v_alue)$", - "^(clen|req_clen|smtp_perform_helo|smtp_state_helo_resp|_stati64)$", - "^Tru64$", + "^(eyeballers|HELO_smtp|optin|passin|perfec|SMTP_HELO)$", + "^(clen|req_clen|smtp_perform_helo|smtp_state_helo_resp|Tru64|_stati64)$", "secur32", - # this should be limited to tests/http/*. Short for secure proxy. - "proxys", + "proxys", # this should be limited to tests/http/*. Short for secure proxy. ] extend-ignore-re = [ @@ -28,8 +25,8 @@ extend-exclude = [ ".github/scripts/spellcheck.words", "docs/THANKS", "packages/*", - "scripts/wcurl", "projects/Windows/tmpl/curl.vcxproj", "projects/Windows/tmpl/libcurl.vcxproj", + "scripts/wcurl", "tests/data/test*", ] diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index f2050bd2cedb..a5f42f9d409b 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -10,6 +10,7 @@ # https://github.com/actions/labeler name: 'Labeler' + 'on': [pull_request_target] # zizmor: ignore[dangerous-triggers] permissions: {} diff --git a/configure.ac b/configure.ac index 5dde9f6c96f2..c90606f50780 100644 --- a/configure.ac +++ b/configure.ac @@ -281,7 +281,7 @@ OPT_APPLE_SECTRUST=$curl_cv_apple AC_ARG_WITH(apple-sectrust,dnl AS_HELP_STRING([--with-apple-sectrust],[enable Apple OS native certificate verification]),[ OPT_APPLE_SECTRUST=$withval - ]) +]) AC_PATH_PROG(PERL, perl,, $PATH:/usr/local/bin/perl:/usr/bin/:/usr/local/bin) AC_SUBST(PERL) diff --git a/docs/examples/multi-event.c b/docs/examples/multi-event.c index f2c3e87c2b3c..23dff05ed2b4 100644 --- a/docs/examples/multi-event.c +++ b/docs/examples/multi-event.c @@ -69,7 +69,7 @@ static void add_download(const char *url, int num) FILE *file; CURL *handle; - snprintf(filename, 50, "%d.download", num); + snprintf(filename, sizeof(filename), "%d.download", num); file = fopen(filename, "wb"); if(!file) { diff --git a/docs/examples/multi-uv.c b/docs/examples/multi-uv.c index 1a61745dfa3f..ee0ac0e1b33f 100644 --- a/docs/examples/multi-uv.c +++ b/docs/examples/multi-uv.c @@ -85,7 +85,7 @@ static void add_download(const char *url, int num, CURLM *multi) FILE *file; CURL *handle; - snprintf(filename, 50, "%d.download", num); + snprintf(filename, sizeof(filename), "%d.download", num); file = fopen(filename, "wb"); if(!file) { diff --git a/lib/amigaos.c b/lib/amigaos.c index cc5d49f9b8e7..e51236d1260a 100644 --- a/lib/amigaos.c +++ b/lib/amigaos.c @@ -222,8 +222,8 @@ CURLcode Curl_amiga_init(void) return CURLE_FAILED_INIT; } - if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, - SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl", + if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG)&errno, + SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG)"curl", TAG_DONE)) { CURL_AMIGA_REQUEST("SocketBaseTags ERROR"); return CURLE_FAILED_INIT; diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index f6675e275db6..6b7130be83f5 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -412,9 +412,9 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, if(!more_possible) more_possible = cf_ai_iter_has_more(&bs->ipv6_iter); #endif - do_more = more_possible && - (curlx_timediff(now, bs->last_attempt_started) >= - bs->attempt_delay_ms); + do_more = more_possible && + (curlx_timediff(now, bs->last_attempt_started) >= + bs->attempt_delay_ms); if(do_more) CURL_TRC_CF(data, cf, "happy eyeballs timeout expired, " "start next attempt"); diff --git a/lib/curl_trc.c b/lib/curl_trc.c index 7f234437f291..0b91315e3668 100644 --- a/lib/curl_trc.c +++ b/lib/curl_trc.c @@ -312,6 +312,7 @@ void Curl_trc_timer(struct Curl_easy *data, int tid, const char *fmt, ...) va_end(ap); } } + void Curl_trc_easy_timers(struct Curl_easy *data) { if(CURL_TRC_TIMER_is_verbose(data)) { diff --git a/lib/rtsp.c b/lib/rtsp.c index 3ede0fe62ddc..1f952a07cccb 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -558,7 +558,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) * Go ahead and use the Range stuff supplied for HTTP */ if(data->state.use_range && - (rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) { + (rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) { /* Check to see if there is a range set in the custom headers */ if(!Curl_checkheaders(data, STRCONST("Range")) && data->state.range) { diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index f231dabc81df..5bf37705653a 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -364,7 +364,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, } /* Store the challenge for use later */ - digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1); + digest->input_token = (BYTE *)Curl_memdup(chlg, chlglen + 1); if(!digest->input_token) return CURLE_OUT_OF_MEMORY; diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index d42187916138..071617182e7e 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -175,7 +175,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, ntlm->context, &type_1_desc, &attrs, NULL); if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) + status == SEC_I_COMPLETE_AND_CONTINUE) Curl_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); else if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 3a301f1b71fb..7a26e2bf08c8 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -143,8 +143,8 @@ struct cf_ngtcp2_ctx { uint64_t max_bidi_streams; /* max bidi streams we can open */ size_t earlydata_max; /* max amount of early data supported by server on session reuse */ - size_t earlydata_skip; /* sending bytes to skip when earlydata - * is accepted by peer */ + size_t earlydata_skip; /* sending bytes to skip when earlydata + is accepted by peer */ CURLcode tls_vrfy_result; /* result of TLS peer verification */ int qlogfd; BIT(initialized); diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 3145d4d20315..039eb51c9ad4 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3358,9 +3358,9 @@ static CURLcode ossl_windows_load_anchors(struct Curl_cfilter *cf, #endif /* USE_WIN32_CRYPTO */ static CURLcode ossl_load_trust_anchors(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct ossl_ctx *octx, - X509_STORE *store) + struct Curl_easy *data, + struct ossl_ctx *octx, + X509_STORE *store) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); diff --git a/src/Makefile.inc b/src/Makefile.inc index d57d6c9125f4..fa5583755203 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -34,9 +34,9 @@ # the official API, but we reuse the code here to avoid duplication. CURLX_CFILES = \ ../lib/curlx/base64.c \ - ../lib/curlx/multibyte.c \ ../lib/curlx/dynbuf.c \ ../lib/curlx/fopen.c \ + ../lib/curlx/multibyte.c \ ../lib/curlx/nonblock.c \ ../lib/curlx/strerr.c \ ../lib/curlx/strparse.c \ @@ -48,11 +48,11 @@ CURLX_CFILES = \ ../lib/curlx/winapi.c CURLX_HFILES = \ - ../lib/curlx/binmode.h \ - ../lib/curlx/multibyte.h \ ../lib/curl_setup.h \ + ../lib/curlx/binmode.h \ ../lib/curlx/dynbuf.h \ ../lib/curlx/fopen.h \ + ../lib/curlx/multibyte.h \ ../lib/curlx/nonblock.h \ ../lib/curlx/strerr.h \ ../lib/curlx/strparse.h \ diff --git a/src/tool_operate.c b/src/tool_operate.c index 38482b496e7f..3c29d28ec3a0 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -999,7 +999,7 @@ static CURLcode setup_outfile(struct OperationConfig *config, /* open file for output, forcing VMS output format into stream mode which is needed for stat() call above to always work. */ FILE *file = curlx_fopen(outfile, "ab", - "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0"); + "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0"); #else /* open file for output: */ FILE *file = curlx_fopen(per->outfile, "ab"); diff --git a/tests/libtest/lib517.c b/tests/libtest/lib517.c index 85950dd866bc..01d3ac4bad1a 100644 --- a/tests/libtest/lib517.c +++ b/tests/libtest/lib517.c @@ -80,7 +80,7 @@ static CURLcode test_lib517(const char *URL) {"Sat, 15-Apr-17\"21:01:22\"GMT", 1492290082 }, {"Partyday, 18- April-07 22:50:12", -1 }, {"Partyday, 18 - Apri-07 22:50:12", -1 }, - {"Wednes, 1-Januar-2003 00:00:00 GMT", -1 }, + {"Wednes, 1-Januar-2003 00:00:00 GMT", -1 },/* spellchecker:disable-line */ {"Sat, 15-Apr-17 21:01:22", 1492290082 }, {"Sat, 15-Apr-17 21:01:22 GMT-2", 1492290082 }, {"Sat, 15-Apr-17 21:01:22 GMT BLAH", 1492290082 }, diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index 3f4c9ef8b050..48728bfd01a4 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -461,13 +461,13 @@ static DWORD WINAPI select_ws_wait_thread(void *lpParameter) size.QuadPart = 0; size.LowPart = GetFileSize(handle, &length); if((size.LowPart != INVALID_FILE_SIZE) || - (GetLastError() == NO_ERROR)) { + (GetLastError() == NO_ERROR)) { size.HighPart = (LONG)length; /* get the current position within the file */ pos.QuadPart = 0; pos.LowPart = SetFilePointer(handle, 0, &pos.HighPart, FILE_CURRENT); if((pos.LowPart != INVALID_SET_FILE_POINTER) || - (GetLastError() == NO_ERROR)) { + (GetLastError() == NO_ERROR)) { /* compare position with size, abort if not equal */ if(size.QuadPart == pos.QuadPart) { /* sleep and continue waiting */ From 5090cce01c259ec6d01d907f71be9c27ac960f91 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 11:03:35 +0200 Subject: [PATCH 307/465] libssh2: fix return code for EAGAIN In disconnect Closes #18874 --- lib/vssh/libssh2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 8ad263e7f3e9..9f6fb8354a31 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -2574,7 +2574,7 @@ static CURLcode ssh_state_session_disconnect(struct Curl_easy *data, if(sshc->ssh_channel) { rc = libssh2_channel_free(sshc->ssh_channel); if(rc == LIBSSH2_ERROR_EAGAIN) - return CURLE_OK; + return CURLE_AGAIN; if(rc < 0) { char *err_msg = NULL; From 22ae8ac8743beb396ed21bbf0a7245de87b81c29 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 11:07:47 +0200 Subject: [PATCH 308/465] libssh2/sftp_realpath: change state consistently Change the state in this function at a single spot independent of success or not to simplify. Reported-by: Joshua Rogers Closes #18875 --- lib/vssh/libssh2.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 9f6fb8354a31..c73ecec94960 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1943,13 +1943,12 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data, if(rc == LIBSSH2_ERROR_EAGAIN) return CURLE_AGAIN; + myssh_state(data, sshc, SSH_STOP); if(rc > 0) { free(sshc->homedir); sshc->homedir = strdup(sshp->readdir_filename); - if(!sshc->homedir) { - myssh_state(data, sshc, SSH_SFTP_CLOSE); + if(!sshc->homedir) return CURLE_OUT_OF_MEMORY; - } free(data->state.most_recent_ftp_entrypath); data->state.most_recent_ftp_entrypath = strdup(sshc->homedir); if(!data->state.most_recent_ftp_entrypath) @@ -1962,21 +1961,19 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data, if(sftperr) result = sftp_libssh2_error_to_CURLE(sftperr); else - /* in this case, the error was not in the SFTP level but for example - a time-out or similar */ + /* in this case, the error was not in the SFTP level but for example a + time-out or similar */ result = CURLE_SSH; DEBUGF(infof(data, "error = %lu makes libcurl = %d", sftperr, (int)result)); - myssh_state(data, sshc, SSH_STOP); return result; } - /* This is the last step in the SFTP connect phase. Do note that while - we get the homedir here, we get the "workingpath" in the DO action - since the homedir will remain the same between request but the - working path will not. */ + /* This is the last step in the SFTP connect phase. Do note that while we + get the homedir here, we get the "workingpath" in the DO action since the + homedir will remain the same between request but the working path will + not. */ DEBUGF(infof(data, "SSH CONNECT phase done")); - myssh_state(data, sshc, SSH_STOP); return CURLE_OK; } From 3517053cf7d452e9be921ddfe58dfcd408216eb7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 12:27:36 +0200 Subject: [PATCH 309/465] curl_osslq: error out properly if BIO_ADDR_rawmake() fails Reported-by: Joshua Rogers Closes #18878 --- lib/vquic/curl_osslq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 0862d688444f..cda239a57d84 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -185,6 +185,7 @@ static CURLcode make_bio_addr(BIO_ADDR **pbio_addr, (struct sockaddr_in6 * const)CURL_UNCONST(&addr->curl_sa_addr); if(!BIO_ADDR_rawmake(bio_addr, AF_INET6, &sin->sin6_addr, sizeof(sin->sin6_addr), sin->sin6_port)) { + goto out; } result = CURLE_OK; break; From 66f4c5699e8d1edc43717f11e203968db34b0a19 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 12:43:40 +0200 Subject: [PATCH 310/465] test766: verify CURLOPT_SOCKOPTFUNCTION error on accept This test does active FTP with a socketopt callback that returns error for the CURLSOCKTYPE_ACCEPT "purpose" to make sure we test and exercise this error path - without leaks. Closes #18879 --- docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md | 14 +++-- tests/data/Makefile.am | 2 +- tests/data/test766 | 58 +++++++++++++++++ tests/libtest/Makefile.inc | 1 + tests/libtest/lib766.c | 66 ++++++++++++++++++++ 5 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 tests/data/test766 create mode 100644 tests/libtest/lib766.c diff --git a/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md index a2ded45692c8..3467acf77f65 100644 --- a/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md +++ b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md @@ -64,12 +64,14 @@ CURLOPT_SOCKOPTDATA(3) function. Return *CURL_SOCKOPT_OK* from the callback on success. Return *CURL_SOCKOPT_ERROR* from the callback function to signal an unrecoverable error to the library and it closes the socket and returns -*CURLE_COULDNT_CONNECT*. Alternatively, the callback function can return -*CURL_SOCKOPT_ALREADY_CONNECTED*, to tell libcurl that the socket is -already connected and then libcurl does no attempt to connect. This allows an -application to pass in an already connected socket with -CURLOPT_OPENSOCKETFUNCTION(3) and then have this function make libcurl -not attempt to connect (again). +*CURLE_COULDNT_CONNECT* for *CURLSOCKTYPE_IPCXN* and +*CURLE_ABORTED_BY_CALLBACK* for *CURLSOCKTYPE_ACCEPT*. + +The callback function may return *CURL_SOCKOPT_ALREADY_CONNECTED* for +*CURLSOCKTYPE_IPCXN*, to tell libcurl that the socket is already connected and +then libcurl does no attempt to connect. This allows an application to pass in +an already connected socket with CURLOPT_OPENSOCKETFUNCTION(3) and then have +this function make libcurl not attempt to connect (again). # DEFAULT diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index f2c698c674aa..0d2d47c99ab5 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -109,7 +109,7 @@ 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 test758 test759 test760 test761 test762 \ -test763 test764 test765 \ +test763 test764 test765 test766 \ \ test780 test781 test782 test783 test784 test785 test786 test787 test788 \ test789 test790 test791 test792 test793 test794 test796 test797 \ diff --git a/tests/data/test766 b/tests/data/test766 new file mode 100644 index 000000000000..9db96b7c0535 --- /dev/null +++ b/tests/data/test766 @@ -0,0 +1,58 @@ + + + +FTP +PORT +CURLOPT_SOCKOPTFUNCTION + + + +# Server-side + + +hello + + + +# Client-side + + +ftp + + +lib%TESTNUMBER + + +FTP PORT with sockopt callback refusing the accept + + +ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER + + + +# Verify data after the test has been "shot" + +# Strip off parts of the EPRT command that might differ + +s/^EPRT \|1\|(.*)/EPRT \|1\|/ + +# The TYPE command might get sent so we ignore that + +^TYPE + + + +USER anonymous +PASS ftp@example.com +PWD +CWD path +EPRT |1| + + +# 42 == CURLE_ABORTED_BY_CALLBACK + +42 + + + + diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index d8735a44e121..cac833f26f7d 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -76,6 +76,7 @@ TESTS_C = \ lib694.c lib695.c \ lib751.c lib753.c lib758.c \ lib757.c \ + lib766.c \ lib1156.c \ lib1301.c lib1308.c \ lib1485.c \ diff --git a/tests/libtest/lib766.c b/tests/libtest/lib766.c new file mode 100644 index 000000000000..5cfc6bb270f3 --- /dev/null +++ b/tests/libtest/lib766.c @@ -0,0 +1,66 @@ +/*************************************************************************** + * _ _ ____ _ + * 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 "memdebug.h" + +static int sockopt_766(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose) +{ + (void)clientp; + (void)curlfd; + if(purpose == CURLSOCKTYPE_ACCEPT) { + curl_mfprintf(stderr, + "Return error from CURLOPT_SOCKOPTFUNCTION callback\n"); + return 1; /* force error */ + } + return 0; +} + +static CURLcode test_lib766(const char *URL) +{ + CURL *easy = NULL; + CURLcode res = CURLE_OK; + + start_test_timing(); + + res_global_init(CURL_GLOBAL_ALL); + + easy_init(easy); + easy_setopt(easy, CURLOPT_VERBOSE, 1L); + easy_setopt(easy, CURLOPT_URL, URL); + easy_setopt(easy, CURLOPT_FTPPORT, "-"); + easy_setopt(easy, CURLOPT_SOCKOPTFUNCTION, sockopt_766); + + res = curl_easy_perform(easy); + +test_cleanup: + + curl_easy_cleanup(easy); + curl_global_cleanup(); + + return res; +} From 6c7fc22f9dc43ded7a952e66597a379f294f9d29 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 13:05:01 +0200 Subject: [PATCH 311/465] pingpong: remove two old leftover debug infof() calls --- lib/pingpong.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/pingpong.c b/lib/pingpong.c index ddd402089447..3f6da71eae2c 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -98,7 +98,6 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } - DEBUGF(infof(data, "pp_statematch, timeout=%" FMT_TIMEDIFF_T, timeout_ms)); if(block) { interval_ms = 1000; /* use 1 second timeout intervals */ if(timeout_ms < interval_ms) @@ -116,9 +115,6 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, /* We are receiving and there is data ready in the SSL library */ rc = 1; else { - DEBUGF(infof(data, "pp_statematch, select, timeout=%" FMT_TIMEDIFF_T - ", sendleft=%zu", - timeout_ms, pp->sendleft)); rc = Curl_socket_check(pp->sendleft ? CURL_SOCKET_BAD : sock, /* reading */ CURL_SOCKET_BAD, pp->sendleft ? sock : CURL_SOCKET_BAD, /* writing */ From 3b18aeb8bdba4bcc7eb942e39c542778d1cffbfa Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 14:41:14 +0200 Subject: [PATCH 312/465] managen: verify the options used in example lines Also fix the --knownhosts typo Follow-up to aae18c4bdc1a3bf5 Reported-by: Daniel Terhorst-North URL: https://mas.to/@tastapod/115327102344617386 Closes #18884 --- docs/cmdline-opts/knownhosts.md | 2 +- scripts/managen | 23 +++++++++++++++++++++++ tests/data/test1705 | 4 ++-- tests/data/test1706 | 4 ++-- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/docs/cmdline-opts/knownhosts.md b/docs/cmdline-opts/knownhosts.md index 47095632df7a..4b6386dd24ec 100644 --- a/docs/cmdline-opts/knownhosts.md +++ b/docs/cmdline-opts/knownhosts.md @@ -14,7 +14,7 @@ See-also: - insecure - key Example: - - --knownhost filename --key here $URL + - --knownhosts filename --key here $URL --- # `--knownhosts` diff --git a/scripts/managen b/scripts/managen index 17c8677882d2..0c75148fd170 100755 --- a/scripts/managen +++ b/scripts/managen @@ -880,6 +880,29 @@ sub single { if($examples[0]) { my $s =""; $s="s" if($examples[1]); + foreach my $e (@examples) { + my $check = $e; + # verify the used options + for my $e (split(/ /, $check)) { + if($e =~ /^-([^- ])/) { + my $opt = $1; + if(!$optshort{$opt}) { + print STDERR "$f:$line:1:ERROR: unknown option in ". + "example: -$opt\n"; + return 2; + } + } + elsif($e =~ /^--([^ =]*)/) { + my $opt = $1; + $opt =~ s/^expand-//g; + if(!$helplong{$opt}) { + print STDERR "$f:$line:1:ERROR: unknown option in ". + "example: '--$opt'\n"; + return 2; + } + } + } + } if($manpage) { print "\nExample$s:\n"; print ".nf\n"; diff --git a/tests/data/test1705 b/tests/data/test1705 index 7c21ffa34939..26ddf3d4ad19 100644 --- a/tests/data/test1705 +++ b/tests/data/test1705 @@ -52,7 +52,7 @@ See-also: - trace - trace-ascii Example: - - --verbose $URL + - --fakeitreal $URL --- # `--verbose` @@ -231,7 +231,7 @@ Disable it again with \-\-no-fakeitreal. Example: .nf -curl --verbose https://example.com +curl --fakeitreal https://example.com .fi This option is mutually exclusive with \fI\-\-trace\fP and \fI\-\-trace\-ascii\fP. diff --git a/tests/data/test1706 b/tests/data/test1706 index 6362678e9adf..f821618d277a 100644 --- a/tests/data/test1706 +++ b/tests/data/test1706 @@ -52,7 +52,7 @@ See-also: - trace - trace-ascii Example: - - --verbose $URL + - --fakeitreal $URL --- # `--verbose` @@ -196,7 +196,7 @@ DESCRIPTION effect. Disable it again with --no-fakeitreal. Example: - curl --verbose https://example.com + curl --fakeitreal https://example.com This option is mutually exclusive with --trace and --trace-ascii. See also --include, --silent, --trace and --trace-ascii. From 6d9636abd1deea39c7a79f042ca60652a815ddc8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 14:59:53 +0200 Subject: [PATCH 313/465] telnet: return error if WSAEventSelect fails Reported-by: Joshua Rogers Closes #18886 --- lib/telnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/telnet.c b/lib/telnet.c index 1ae15d3704bd..5144a1afa11e 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -1371,7 +1371,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) /* Tell Winsock what events we want to listen to */ if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { WSACloseEvent(event_handle); - return CURLE_OK; + return CURLE_RECV_ERROR; } /* The get the Windows file handle for stdin */ From e214b1450186538e1336aa1f9c7b90e197bed092 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 15:01:48 +0200 Subject: [PATCH 314/465] telnet: send failure logged but not returned Return error correctly when sending fails. Reported-by: Joshua Rogers Closes #18887 --- lib/telnet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/telnet.c b/lib/telnet.c index 5144a1afa11e..6eb60706c980 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -984,6 +984,7 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) if(bytes_written < 0) { err = SOCKERRNO; failf(data,"Sending data failed (%d)",err); + return CURLE_SEND_ERROR; } printsub(data, '>', &temp[2], len-2); break; From 71b5e025903e2e6a7f4f2309a7e2930fed96fc0a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 16:10:27 +0200 Subject: [PATCH 315/465] mdlinkcheck: reject URLs containing quotes Those would be illegal anyway and would make the script misbehave Reported-by: Stanislav Fort Closes #18889 --- scripts/mdlinkcheck | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/mdlinkcheck b/scripts/mdlinkcheck index 925edc52944a..bbd6ac46022b 100755 --- a/scripts/mdlinkcheck +++ b/scripts/mdlinkcheck @@ -140,6 +140,10 @@ sub checkurl { print "check $url\n"; my $curlcmd="curl -ILfsm10 --retry 2 --retry-delay 5 -A \"Mozilla/curl.se link-probe\""; $url =~ s/\+/%2B/g; + if($url =~ /[\"\'\n]/) { + print STDERR "Bad URL in markdown: %s\n", $url{$url}; + return 1; # fail + } my @content = `$curlcmd \"$url\"`; if(!$content[0]) { print STDERR "FAIL\n"; From 1a3a5cb72038a0b70cb5721e9762734f1691aa6d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 16:53:27 +0200 Subject: [PATCH 316/465] noproxy: fix the IPV6 network mask pattern match It would mismatch if the network prefix length with was not divisible by 8. Extended test 1614 to verify Reported-by: Stanislav Fort Closes #18891 --- lib/noproxy.c | 2 +- tests/unit/unit1614.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/noproxy.c b/lib/noproxy.c index 2983fa4a3aa7..20a335993da1 100644 --- a/lib/noproxy.c +++ b/lib/noproxy.c @@ -99,7 +99,7 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6, return FALSE; if(bytes && memcmp(address, check, bytes)) return FALSE; - if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest)))) + if(rest && ((address[bytes] ^ check[bytes]) & (0xff << (8 - rest)))) return FALSE; return TRUE; diff --git a/tests/unit/unit1614.c b/tests/unit/unit1614.c index 4ee18df72f17..9ba5f95ebb62 100644 --- a/tests/unit/unit1614.c +++ b/tests/unit/unit1614.c @@ -111,6 +111,28 @@ static CURLcode test_unit1614(const char *arg) { "[::1]", "foo, bar, ::1/64", TRUE}, { "[::1]", "::1/64", TRUE}, { "[::1]", "::1/96", TRUE}, + { "[::1]", "::1/127", TRUE}, + { "[::1]", "::1/126", TRUE}, + { "[::1]", "::1/125", TRUE}, + { "[::1]", "::1/124", TRUE}, + { "[::1]", "::1/123", TRUE}, + { "[::1]", "::1/122", TRUE}, + { "[2001:db8:8000::1]", "2001:db8::/65", FALSE}, + { "[2001:db8:8000::1]", "2001:db8::/66", FALSE}, + { "[2001:db8:8000::1]", "2001:db8::/67", FALSE}, + { "[2001:db8:8000::1]", "2001:db8::/68", FALSE}, + { "[2001:db8:8000::1]", "2001:db8::/69", FALSE}, + { "[2001:db8:8000::1]", "2001:db8::/70", FALSE}, + { "[2001:db8:8000::1]", "2001:db8::/71", FALSE}, + { "[2001:db8:8000::1]", "2001:db8::/72", FALSE}, + { "[2001:db8::1]", "2001:db8::/65", TRUE}, + { "[2001:db8::1]", "2001:db8::/66", TRUE}, + { "[2001:db8::1]", "2001:db8::/67", TRUE}, + { "[2001:db8::1]", "2001:db8::/68", TRUE}, + { "[2001:db8::1]", "2001:db8::/69", TRUE}, + { "[2001:db8::1]", "2001:db8::/70", TRUE}, + { "[2001:db8::1]", "2001:db8::/71", TRUE}, + { "[2001:db8::1]", "2001:db8::/72", TRUE}, { "[::1]", "::1/129", FALSE}, { "bar", "foo, bar, ::1/64", TRUE}, { "BAr", "foo, bar, ::1/64", TRUE}, From f1ed50a51707847825eb988cfc739f79b5ceadc9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 17:23:18 +0200 Subject: [PATCH 317/465] tftp: don't pin or check address if recvfrom returns error Follow-up to c4f9977c66bbb05a837a7eb0300 Reported-by: Joshua Rogers Closes #18892 --- lib/tftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tftp.c b/lib/tftp.c index b81fd3ee14b5..baebe466a10b 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -1105,7 +1105,7 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data, 0, (struct sockaddr *)&remote_addr, &fromlen); - if(fromlen) { + if((state->rbytes >= 0) && fromlen) { if(state->remote_pinned) { /* pinned, verify that it comes from the same address */ if((state->remote_addrlen != fromlen) || From bc90f80556a731d31a60cbe76b82b3060bda48bc Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 17:32:50 +0200 Subject: [PATCH 318/465] tftp: default timeout per block is now 15 seconds Down from the previous (rather ridiculous) 3600. Reported-by: Joshua Rogers Closes #18893 --- lib/tftp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/tftp.c b/lib/tftp.c index baebe466a10b..56b7afda5201 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -206,7 +206,7 @@ const struct Curl_handler Curl_handler_tftp = { **********************************************************/ static CURLcode tftp_set_timeouts(struct tftp_conn *state) { - time_t maxtime, timeout; + time_t timeout; timediff_t timeout_ms; bool start = (state->state == TFTP_STATE_START); @@ -219,13 +219,11 @@ static CURLcode tftp_set_timeouts(struct tftp_conn *state) return CURLE_OPERATION_TIMEDOUT; } + /* Set per-block timeout to total */ if(timeout_ms > 0) - maxtime = (time_t)(timeout_ms + 500) / 1000; + timeout = (time_t)(timeout_ms + 500) / 1000; else - maxtime = 3600; /* use for calculating block timeouts */ - - /* Set per-block timeout to total */ - timeout = maxtime; + timeout = 15; /* Average reposting an ACK after 5 seconds */ state->retry_max = (int)timeout/5; From 3660e6da80764b7dc184af51556d158d5a352a48 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 18:25:55 +0200 Subject: [PATCH 319/465] tftp: return error if it hits an illegal state Reported-by: Joshua Rogers Closes #18894 --- lib/tftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tftp.c b/lib/tftp.c index 56b7afda5201..8279f29e650e 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -564,7 +564,7 @@ static CURLcode tftp_send_first(struct tftp_conn *state, default: failf(state->data, "tftp_send_first: internal error"); - break; + return CURLE_TFTP_ILLEGAL; } return result; From 33380fa214d6ff9a0c1dc29b61aa6650b4ed3fa7 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 23:05:10 +0200 Subject: [PATCH 320/465] telnet: ignore empty suboptions To avoid printing from en empty buffer Reported-by: Joshua Rogers Closes #18899 --- lib/telnet.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/telnet.c b/lib/telnet.c index 6eb60706c980..5c25bc2eaa36 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -947,6 +947,9 @@ static CURLcode suboption(struct Curl_easy *data, struct TELNET *tn) int err; struct connectdata *conn = data->conn; + if(!CURL_SB_LEN(tn)) /* ignore empty suboption */ + return CURLE_OK; + printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); switch(CURL_SB_GET(tn)) { case CURL_TELOPT_TTYPE: From 5e3725a7afe46fac093412f64193c807fcff1440 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 23:59:33 +0200 Subject: [PATCH 321/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 117 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 11 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index b638b559c4cd..846340aee1da 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -1,16 +1,19 @@ curl and libcurl 8.17.0 Public curl releases: 271 - Command line options: 272 + Command line options: 273 curl_easy_setopt() options: 308 Public functions in libcurl: 98 - Contributors: 3513 + Contributors: 3514 This release includes the following changes: o build: drop the winbuild build system [81] o krb5: drop support for Kerberos FTP [43] o libssh2: up the minimum requirement to 1.9.0 [85] + o progress: expand to use 6 characters per size [234] + o ssl: support Apple SecTrust configurations [240] + o tool_getparam: add --knownhosts [204] o vssh: drop support for wolfSSH [58] o wcurl: import v2025.09.27 [182] o write-out: make %header{} able to output *all* occurrences of a header [25] @@ -34,11 +37,16 @@ This release includes the following bugfixes: o build: show llvm/clang in platform flags and `buildinfo.txt` [126] o cf-h2-proxy: break loop on edge case [140] o cf-ip-happy: mention unix domain path, not port number [161] + o cf-socket: always check Curl_cf_socket_peek() return code [198] + o cf-socket: check params and remove accept procondition [197] o cf-socket: tweak a memcpy() to read better [177] o cf-socket: use the right byte order for ports in bindlocal [61] o cfilter: unlink and discard [46] o checksrc: catch banned functions when preceded by `(` [146] o checksrc: fix possible endless loop when detecting `BANNEDFUNC` [149] + o checksrc: fix possible endless loops/errors in the banned function logic [220] + o checksrc: fix to handle `)` predecing a banned function [229] + o checksrc: reduce directory-specific exceptions [228] o cmake: add `CURL_CODE_COVERAGE` option [78] o cmake: clang detection tidy-ups [116] o cmake: drop exclamation in comment looking like a name [160] @@ -49,8 +57,10 @@ This release includes the following bugfixes: o cmdline-opts/_PROGRESS.md: explain the suffixes [154] o configure: add "-mt" for pthread support on HP-UX [52] o cookie: avoid saving a cookie file if no transfer was done [11] + o cpool: make bundle->dest an array; fix UB [218] o curl_easy_getinfo: error code on NULL arg [2] o curl_mem_undef.h: limit to `CURLDEBUG` for non-memalloc overrides [19] + o curl_osslq: error out properly if BIO_ADDR_rawmake() fails [184] o curl_slist_append.md: clarify that a NULL pointer is not acceptable [72] o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] o CURLOPT_HEADER/WRITEFUNCTION.md: drop '* size' since size is always 1 [63] @@ -59,16 +69,23 @@ This release includes the following bugfixes: o CURLOPT_TIMECONDITION.md: works for FILE and FTP as well [27] o digest_sspi: fix two memory leaks in error branches [77] o dist: do not distribute `CI.md` [29] + o docs/cmdline-opts: drop double quotes from GLOBBING and URL examples [238] o docs/libcurl: clarify some timeout option behavior [15] o docs/libcurl: remove ancient version references [7] o docs/libcurl: use lowercase must [5] o docs: fix/tidy code fences [87] o easy_getinfo: check magic, Curl_close safety [3] + o examples: drop unused `curl/mprintf.h` includes [224] + o examples: fix two build issues surfaced with WinCE [223] o examples: fix two issues found by CodeQL [35] o examples: fix two more cases of `stat()` TOCTOU [147] o form.md: drop reference to MANUAL [178] + o ftp: add extra buffer length check [195] o ftp: fix ftp_do_more returning with *completep unset [122] o ftp: fix port number range loop for PORT commands [66] + o ftp: fix the 213 scanner memchr buffer limit argument [196] + o ftp: improve fragile check for first digit > 3 [194] + o ftp: remove misleading comments [193] o gtls: avoid potential use of uninitialized variable in trace output [83] o hostip: remove leftover INT_MAX check in Curl_dnscache_prune [88] o http: handle user-defined connection headers [165] @@ -78,14 +95,21 @@ This release includes the following bugfixes: o ip-happy: do not set unnecessary timeout [95] o ip-happy: prevent event-based stall on retry [155] o krb5: return appropriate error on send failures [22] + o krb5_sspi: the chlg argument is NOT optional [200] o ldap: do not base64 encode zero length string [42] + o ldap: tidy-up types, fix error code confusion [191] + o lib: drop unused include and duplicate guards [226] o lib: fix build error and compiler warnings with verbose strings disabled [173] o lib: remove personal names from comments [168] o lib: upgrade/multiplex handling [136] o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] + o libssh2/sftp_realpath: change state consistently [185] + o libssh2: bail out on chgrp and chown number parsing errors [202] + o libssh2: clarify that sshp->path is always at least one byte [201] o libssh2: drop two redundant null-terminations [26] o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] + o libssh2: fix return code for EAGAIN [186] o libssh: acknowledge SSH_AGAIN in the SFTP state machine [89] o libssh: clarify myssh_block2waitfor [92] o libssh: drop two unused assignments [104] @@ -94,30 +118,38 @@ This release includes the following bugfixes: o libssh: fix range parsing error handling mistake [120] o libssh: react on errors from ssh_scp_read [24] o libssh: return out of memory correctly if aprintf fails [60] + o Makefile.example: fix option order [231] o Makefile.example: simplify and make it configurable [20] o managen: ignore version mentions < 7.66.0 [55] o managen: render better manpage references/links [54] o managen: strict protocol check [109] + o managen: verify the options used in example lines [181] o mbedtls: check result of setting ALPN [127] o mbedtls: handle WANT_WRITE from mbedtls_ssl_read() [145] + o mdlinkcheck: reject URLs containing quotes [174] o multi.h: add CURLMINFO_LASTENTRY [51] o multi_ev: remove unnecessary data check that confuses analysers [167] o ngtcp2: check error code on connect failure [13] o ngtcp2: fix early return [131] + o noproxy: fix the IPV6 network mask pattern match [166] o openldap: avoid indexing the result at -1 for blank responses [44] o openldap: check ber_sockbuf_add_io() return code [163] o openldap: check ldap_get_option() return codes [119] o openssl-quic: check results better [132] o openssl-quic: handle error in SSL_get_stream_read_error_code [129] o openssl-quic: ignore unexpected streams opened by server [176] + o openssl: call SSL_get_error() with proper error [207] o openssl: clear retry flag on x509 error [130] o openssl: fail the transfer if ossl_certchain() fails [23] + o openssl: fix build for v1.0.2 [225] o openssl: make the asn1_object_dump name null terminated [56] o openssl: set io_need always [99] o OS400: fix a use-after-free/double-free case [142] + o pingpong: remove two old leftover debug infof() calls o pytest: skip specific tests for no-verbose builds [171] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o quiche: fix possible leaks on teardown [205] o quiche: fix verbose message when ip quadruple cannot be obtained. [128] o quiche: when ingress processing fails, return that error code [103] o runtests: tag tests that require curl verbose strings [172] @@ -143,16 +175,25 @@ This release includes the following bugfixes: o socks_sspi: fix memory cleanup calls [40] o socks_sspi: restore non-blocking socket on error paths [48] o ssl-sessions.md: mark option experimental [12] + o strerror: drop workaround for SalfordC win32 header bug [214] o sws: fix checking `sscanf()` return value [17] o tcp-nodelay.md: expand the documentation [153] + o telnet: ignore empty suboptions [86] + o telnet: make bad_option() consider NULL a bad option too [192] o telnet: make printsub require another byte input [21] + o telnet: print DISPlay LOCation in printsub without mutating buffer [216] o telnet: refuse IAC codes in content [111] + o telnet: return error if WSAEventSelect fails [180] o telnet: return error on crazy TTYPE or XDISPLOC lengths [123] + o telnet: send failure logged but not returned [175] + o telnet: use pointer[0] for "unknown" option instead of pointer[i] [217] o tests/server: drop unsafe `open()` override in signal handler (Windows) [151] o tftp: check and act on tftp_set_timeouts() returning error [38] + o tftp: default timeout per block is now 15 seconds [156] o tftp: handle tftp_multi_statemach() return code [65] o tftp: pin the first used address [110] o tftp: propagate expired timer from tftp_state_timeout() [39] + o tftp: return error if it hits an illegal state [138] o tftp: return error when sendto() fails [59] o tidy-up: `fcntl.h` includes [98] o tidy-up: assortment of small fixes [115] @@ -166,6 +207,7 @@ This release includes the following bugfixes: o tool_cb_hdr: fix fwrite check in header callback [49] o tool_cb_hdr: size is always 1 [70] o tool_doswin: fix to use curl socket functions [108] + o tool_filetime: replace cast with the fitting printf mask (Windows) [212] o tool_getparam/set_rate: skip the multiplication on overflow [84] o tool_getparam: always disable "lib-ids" for tracing [169] o tool_getparam: warn if provided header looks malformed [179] @@ -174,12 +216,18 @@ This release includes the following bugfixes: o tool_progress: handle possible integer overflows [164] o tool_progress: make max5data() use an algorithm [170] o transfer: avoid busy loop with tiny speed limit [100] + o unit1323: sync time types and printf masks, drop casts [211] + o unit1664: drop casts, expand masks to full values [221] + o url: make Curl_init_userdefined return void [213] o urldata: FILE is not a list-only protocol [9] + o vquic: handling of io improvements [239] o vtls: alpn setting, check proto parameter [134] o vtls_int.h: clarify data_pending [124] o vtls_scache: fix race condition [157] o windows: replace `_beginthreadex()` with `CreateThread()` [80] o windows: stop passing unused, optional argument for Win9x compatibility [75] + o windows: use consistent format when showing error codes [199] + o windows: use native error code types more [206] o wolfssl: check BIO read parameters [133] o wolfssl: fix error check in shutdown [105] o ws: clarify an error message [125] @@ -209,15 +257,15 @@ advice from friends like these: Adam Light, Alice Lee Poetics, Andrew Kirillov, Andrew Olsen, BobodevMm on github, Christian Schmitz, Dan Fandrich, Daniel Stenberg, - dependabot[bot], divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, - Evgeny Grin (Karlson2k), fds242 on github, Howard Chu, Javier Blazquez, - Jicea, jmaggard10 on github, Johannes Schindelin, Joseph Birr-Pixton, - Joshua Rogers, kapsiR on github, kuchara on github, Marcel Raad, - Michael Osipov, MichaÅ‚ Petryka, Mohamed Daahir, Nir Azkiel, Patrick Monnerat, - Pocs Norbert, Ray Satiro, renovate[bot], rinsuki on github, - Samuel Dionne-Riel, Samuel Henrique, Stanislav Fort, Stefan Eissing, - Viktor Szakats - (38 contributors) + Daniel Terhorst-North, dependabot[bot], divinity76 on github, + Emilio Pozuelo Monfort, Ethan Everett, Evgeny Grin (Karlson2k), + fds242 on github, Howard Chu, Javier Blazquez, Jicea, jmaggard10 on github, + Johannes Schindelin, Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, + kuchara on github, Marcel Raad, Michael Osipov, MichaÅ‚ Petryka, + Mohamed Daahir, Nir Azkiel, Patrick Monnerat, Pocs Norbert, Ray Satiro, + renovate[bot], rinsuki on github, Samuel Dionne-Riel, Samuel Henrique, + Stanislav Fort, Stefan Eissing, Viktor Szakats + (39 contributors) References to bug reports and discussions on issues: @@ -306,6 +354,7 @@ References to bug reports and discussions on issues: [83] = https://curl.se/bug/?i=18620 [84] = https://curl.se/bug/?i=18624 [85] = https://curl.se/bug/?i=18612 + [86] = https://curl.se/bug/?i=18899 [87] = https://curl.se/bug/?i=18707 [88] = https://curl.se/bug/?i=18680 [89] = https://curl.se/bug/?i=18740 @@ -357,6 +406,7 @@ References to bug reports and discussions on issues: [135] = https://curl.se/bug/?i=18401 [136] = https://curl.se/bug/?i=18227 [137] = https://curl.se/bug/?i=18719 + [138] = https://curl.se/bug/?i=18894 [139] = https://curl.se/bug/?i=18714 [140] = https://curl.se/bug/?i=18715 [141] = https://curl.se/bug/?i=18776 @@ -374,6 +424,7 @@ References to bug reports and discussions on issues: [153] = https://curl.se/bug/?i=18811 [154] = https://curl.se/bug/?i=18817 [155] = https://curl.se/bug/?i=18815 + [156] = https://curl.se/bug/?i=18893 [157] = https://curl.se/bug/?i=18806 [158] = https://curl.se/bug/?i=18809 [160] = https://curl.se/bug/?i=18810 @@ -382,6 +433,7 @@ References to bug reports and discussions on issues: [163] = https://curl.se/bug/?i=18747 [164] = https://curl.se/bug/?i=18744 [165] = https://curl.se/bug/?i=18662 + [166] = https://curl.se/bug/?i=18891 [167] = https://curl.se/bug/?i=18804 [168] = https://curl.se/bug/?i=18803 [169] = https://curl.se/bug/?i=18805 @@ -389,8 +441,51 @@ References to bug reports and discussions on issues: [171] = https://curl.se/bug/?i=18801 [172] = https://curl.se/bug/?i=18800 [173] = https://curl.se/bug/?i=18799 + [174] = https://curl.se/bug/?i=18889 + [175] = https://curl.se/bug/?i=18887 [176] = https://curl.se/bug/?i=18780 [177] = https://curl.se/bug/?i=18787 [178] = https://curl.se/bug/?i=18790 [179] = https://curl.se/bug/?i=18793 + [180] = https://curl.se/bug/?i=18886 + [181] = https://curl.se/bug/?i=18884 [182] = https://curl.se/bug/?i=18754 + [184] = https://curl.se/bug/?i=18878 + [185] = https://curl.se/bug/?i=18875 + [186] = https://curl.se/bug/?i=18874 + [191] = https://curl.se/bug/?i=18888 + [192] = https://curl.se/bug/?i=18873 + [193] = https://curl.se/bug/?i=18871 + [194] = https://curl.se/bug/?i=18870 + [195] = https://curl.se/bug/?i=18869 + [196] = https://curl.se/bug/?i=18867 + [197] = https://curl.se/bug/?i=18882 + [198] = https://curl.se/bug/?i=18862 + [199] = https://curl.se/bug/?i=18877 + [200] = https://curl.se/bug/?i=18865 + [201] = https://curl.se/bug/?i=18864 + [202] = https://curl.se/bug/?i=18863 + [204] = https://curl.se/bug/?i=18859 + [205] = https://curl.se/bug/?i=18880 + [206] = https://curl.se/bug/?i=18868 + [207] = https://curl.se/bug/?i=18872 + [211] = https://curl.se/bug/?i=18860 + [212] = https://curl.se/bug/?i=18858 + [213] = https://curl.se/bug/?i=18855 + [214] = https://curl.se/bug/?i=18857 + [216] = https://curl.se/bug/?i=18852 + [217] = https://curl.se/bug/?i=18851 + [218] = https://curl.se/bug/?i=18850 + [220] = https://curl.se/bug/?i=18845 + [221] = https://curl.se/bug/?i=18838 + [223] = https://curl.se/bug/?i=18843 + [224] = https://curl.se/bug/?i=18842 + [225] = https://curl.se/bug/?i=18841 + [226] = https://curl.se/bug/?i=18839 + [228] = https://curl.se/bug/?i=18823 + [229] = https://curl.se/bug/?i=18836 + [231] = https://curl.se/bug/?i=18835 + [234] = https://curl.se/bug/?i=18828 + [238] = https://curl.se/bug/?i=18829 + [239] = https://curl.se/bug/?i=18812 + [240] = https://curl.se/bug/?i=18703 From 752090b9638dcec16d9a773eaa62651681f093b2 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 6 Oct 2025 16:19:21 +0200 Subject: [PATCH 322/465] examples/synctime: make the sscanf not overflow the local buffer If the incoming Date: header has a funky format. Bonus: remove bad null terminator assumptions for header Reported-by: Stanislav Fort Closes #18890 --- docs/examples/synctime.c | 60 ++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c index d8264d012e15..591761fe1c2c 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -55,20 +55,6 @@ * Usage: * This software synchronises your computer clock only when you issue * it with --synctime. By default, it only display the webserver's clock. - * - * Written by: Frank (contributed to libcurl) - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL THE AUTHOR OF THIS SOFTWARE BE LIABLE FOR - * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, - * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF - * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - * */ #include @@ -147,43 +133,39 @@ static size_t SyncTime_CURL_WriteHeader(void *ptr, size_t size, size_t nmemb, (void)stream; if(ShowAllHeader == 1) - fprintf(stderr, "%s", (char *)(ptr)); + fprintf(stderr, "%.*s", (int)nmemb, (char *)ptr); - if(strncmp((char *)(ptr), "Date:", 5) == 0) { + if(strncmp((char *)ptr, "Date:", 5) == 0) { if(ShowAllHeader == 0) - fprintf(stderr, "HTTP Server. %s", (char *)(ptr)); + fprintf(stderr, "HTTP Server. %.*s", (int)nmemb, (char *)ptr); if(AutoSyncTime == 1) { + int RetVal; *TmpStr1 = 0; *TmpStr2 = 0; - if(strlen((char *)(ptr)) > 50) /* Can prevent buffer overflow to - TmpStr1 & 2? */ - AutoSyncTime = 0; - else { - int RetVal = sscanf((char *)(ptr), "Date: %25s %hu %s %hu %hu:%hu:%hu", - TmpStr1, &SYSTime.wDay, TmpStr2, &SYSTime.wYear, - &SYSTime.wHour, &SYSTime.wMinute, - &SYSTime.wSecond); - - if(RetVal == 7) { - int i; - SYSTime.wMilliseconds = 500; /* adjust to midpoint, 0.5 sec */ - for(i = 0; i < 12; i++) { - if(strcmp(MthStr[i], TmpStr2) == 0) { - SYSTime.wMonth = (WORD)(i + 1); - break; - } + RetVal = sscanf((char *)ptr, "Date: %25s %hu %25s %hu %hu:%hu:%hu", + TmpStr1, &SYSTime.wDay, TmpStr2, &SYSTime.wYear, + &SYSTime.wHour, &SYSTime.wMinute, + &SYSTime.wSecond); + + if(RetVal == 7) { + int i; + SYSTime.wMilliseconds = 500; /* adjust to midpoint, 0.5 sec */ + for(i = 0; i < 12; i++) { + if(strcmp(MthStr[i], TmpStr2) == 0) { + SYSTime.wMonth = (WORD)(i + 1); + break; } - AutoSyncTime = 3; /* Computer clock is adjusted */ - } - else { - AutoSyncTime = 0; /* Error in sscanf() fields conversion */ } + AutoSyncTime = 3; /* Computer clock is adjusted */ + } + else { + AutoSyncTime = 0; /* Error in sscanf() fields conversion */ } } } - if(strncmp((char *)(ptr), "X-Cache: HIT", 12) == 0) { + if(strncmp((char *)ptr, "X-Cache: HIT", 12) == 0) { fprintf(stderr, "ERROR: HTTP Server data is cached." " Server Date is no longer valid.\n"); AutoSyncTime = 0; From f4e83a0adcc86abb9ecc8673e3abd91c215a6649 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 6 Oct 2025 13:16:55 +0200 Subject: [PATCH 323/465] ngtcp2: fix returns when TLS verify failed In both send/recv functions of the ngtcp2 filter, when TLS verification has failed, jump out by skipping ingress/egress handling. Reported-by: Joshua Rogers Closes #18881 --- lib/vquic/curl_ngtcp2.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 7a26e2bf08c8..f397ec85aecf 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -1329,7 +1329,7 @@ static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, /* handshake verification failed in callback, do not recv anything */ if(ctx->tls_vrfy_result) { result = ctx->tls_vrfy_result; - goto out; + goto denied; } pktx_init(&pktx, cf, data); @@ -1361,7 +1361,7 @@ static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, out: result = Curl_1st_err(result, cf_progress_egress(cf, data, &pktx)); result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); - +denied: CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %d, %zu", stream ? stream->id : -1, blen, result, *pnread); CF_DATA_RESTORE(cf, save); @@ -1616,8 +1616,10 @@ static CURLcode cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, *pnwritten = 0; /* handshake verification failed in callback, do not send anything */ - if(ctx->tls_vrfy_result) - return ctx->tls_vrfy_result; + if(ctx->tls_vrfy_result) { + result = ctx->tls_vrfy_result; + goto denied; + } (void)eos; /* use for stream EOF and block handling */ result = cf_progress_ingress(cf, data, &pktx); @@ -1684,7 +1686,7 @@ static CURLcode cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, out: result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); - +denied: CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %d, %zu", stream ? stream->id : -1, len, result, *pnwritten); CF_DATA_RESTORE(cf, save); From 357808f4addef44c2c48f17d067c114bc168a56d Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 1 Sep 2025 11:58:16 +0200 Subject: [PATCH 324/465] multi: add notifications API Add infrastructure to colled and dispatch notifications for transfers and the multi handle in general. Applications can register a callback and en-/disable notification type the are interested in. Without a callback installed, notifications are not collected. Same when a notification type has not been enabled. Memory allocation failures on adding notifications lead to a general multi failure state and result in CURLM_OUT_OF_MEMORY returned from curl_multi_perform() and curl_multi_socket*() invocations. Closes #18432 --- .github/scripts/spellcheck.curl | 3 +- docs/libcurl/Makefile.inc | 2 + docs/libcurl/curl_multi_notify_disable.md | 66 ++++++ docs/libcurl/curl_multi_notify_enable.md | 66 ++++++ docs/libcurl/curl_multi_setopt.md | 8 + docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md | 72 +++++++ docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md | 129 +++++++++++ docs/libcurl/opts/Makefile.inc | 2 + docs/libcurl/symbols-in-versions | 4 + include/curl/multi.h | 27 +++ include/curl/typecheck-gcc.h | 13 +- lib/Makefile.inc | 2 + lib/libcurl.def | 2 + lib/multi.c | 63 +++++- lib/multi_ntfy.c | 212 +++++++++++++++++++ lib/multi_ntfy.h | 57 +++++ lib/multihandle.h | 4 + scripts/singleuse.pl | 2 + src/tool_operate.c | 66 +++--- tests/data/test1135 | 2 + tests/data/test3207 | 2 +- tests/data/test500 | 2 +- tests/http/testenv/curl.py | 3 + tests/unit/unit3214.c | 2 +- 24 files changed, 767 insertions(+), 44 deletions(-) create mode 100644 docs/libcurl/curl_multi_notify_disable.md create mode 100644 docs/libcurl/curl_multi_notify_enable.md create mode 100644 docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md create mode 100644 docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md create mode 100644 lib/multi_ntfy.c create mode 100644 lib/multi_ntfy.h diff --git a/.github/scripts/spellcheck.curl b/.github/scripts/spellcheck.curl index c24edf2b3bc8..1d8be5ed3eee 100644 --- a/.github/scripts/spellcheck.curl +++ b/.github/scripts/spellcheck.curl @@ -133,9 +133,10 @@ curl_multi_setopt curl_multi_assign curl_multi_get_handles curl_multi_get_offt +curl_multi_notify_disable +curl_multi_notify_enable curl_pushheader_bynum curl_pushheader_byname -curl_multi_waitfds curl_easy_option_by_name curl_easy_option_by_id curl_easy_option_next diff --git a/docs/libcurl/Makefile.inc b/docs/libcurl/Makefile.inc index 9bc665d1c625..6ac49d9fb29c 100644 --- a/docs/libcurl/Makefile.inc +++ b/docs/libcurl/Makefile.inc @@ -78,6 +78,8 @@ man_MANS = \ curl_multi_get_offt.3 \ curl_multi_info_read.3 \ curl_multi_init.3 \ + curl_multi_notify_disable.3 \ + curl_multi_notify_enable.3 \ curl_multi_perform.3 \ curl_multi_poll.3 \ curl_multi_remove_handle.3 \ diff --git a/docs/libcurl/curl_multi_notify_disable.md b/docs/libcurl/curl_multi_notify_disable.md new file mode 100644 index 000000000000..f4f28ebbd3bb --- /dev/null +++ b/docs/libcurl/curl_multi_notify_disable.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_notify_disable +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_NOTIFYFUNCTION (3) + - CURLMOPT_NOTIFYDATA (3) + - curl_multi_notify_enable (3) +Protocol: + - All +Added-in: 8.17.0 +--- + +# NAME + +curl_multi_notify_disable - disable a notification type + +# SYNOPSIS + +~~~c +#include +CURLMcode curl_multi_notify_disable(CURLM *multi_handle, + unsigned int notification); +~~~ + +# DESCRIPTION + +Disables collecting the given notification type in the multi handle. A +callback function installed via CURLMOPT_NOTIFYFUNCTION(3) is no longer +called when this notification happens. + +Only when a notification callback is installed *and* a notification +is enabled are these collected and dispatched to the callback. + +Several notification types can be enabled at the same time. Disabling +an already disabled notification is not an error. + +A notification can be enabled again via curl_multi_notify_enable(3). + +# %PROTOCOLS% + +# EXAMPLE + +~~~c +int main(void) +{ + int rc; + CURLM *multi = curl_multi_init(); + + rc = curl_multi_notify_disable(multi, CURLM_NTFY_INFO_READ); +} +~~~ + +# %AVAILABILITY% + +# RETURN VALUE + +This function returns a CURLMcode indicating success or error. + +CURLM_OK (0) means everything was OK, non-zero means an error occurred, see +libcurl-errors(3). + +The return code is for the whole multi stack. Problems still might have +occurred on individual transfers even when one of these functions return OK. diff --git a/docs/libcurl/curl_multi_notify_enable.md b/docs/libcurl/curl_multi_notify_enable.md new file mode 100644 index 000000000000..d3ab02d2c756 --- /dev/null +++ b/docs/libcurl/curl_multi_notify_enable.md @@ -0,0 +1,66 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: curl_multi_notify_enable +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_NOTIFYFUNCTION (3) + - CURLMOPT_NOTIFYDATA (3) + - curl_multi_notify_disable (3) +Protocol: + - All +Added-in: 8.17.0 +--- + +# NAME + +curl_multi_notify_enable - enable a notification type + +# SYNOPSIS + +~~~c +#include +CURLMcode curl_multi_notify_enable(CURLM *multi_handle, + unsigned int notification); +~~~ + +# DESCRIPTION + +Enables collecting the given notification type in the multi handle. A +callback function installed via CURLMOPT_NOTIFYFUNCTION(3) is called +when this notification happens. + +Only when a notification callback is installed *and* a notification +is enabled are these collected and dispatched to the callback. + +Several notification types can be enabled at the same time. Enabling +an already enabled notification is not an error. + +A notification can be disabled again via curl_multi_notify_disable(3). + +# %PROTOCOLS% + +# EXAMPLE + +~~~c +int main(void) +{ + int rc; + CURLM *multi = curl_multi_init(); + + rc = curl_multi_notify_enable(multi, CURLM_NTFY_INFO_READ); +} +~~~ + +# %AVAILABILITY% + +# RETURN VALUE + +This function returns a CURLMcode indicating success or error. + +CURLM_OK (0) means everything was OK, non-zero means an error occurred, see +libcurl-errors(3). + +The return code is for the whole multi stack. Problems still might have +occurred on individual transfers even when one of these functions return OK. diff --git a/docs/libcurl/curl_multi_setopt.md b/docs/libcurl/curl_multi_setopt.md index e646eced62c7..adb38e0de5d0 100644 --- a/docs/libcurl/curl_multi_setopt.md +++ b/docs/libcurl/curl_multi_setopt.md @@ -72,6 +72,14 @@ Max simultaneously open connections. See CURLMOPT_MAX_TOTAL_CONNECTIONS(3) Signal that the network has changed. See CURLMOPT_NETWORK_CHANGED(3) +## CURLMOPT_NOTIFYDATA + +Custom pointer passed to the notify callback. See CURLMOPT_NOTIFYDATA(3) + +## CURLMOPT_NOTIFYFUNCTION + +Callback that receives notifications. See CURLMOPT_NOTIFYFUNCTION(3) + ## CURLMOPT_PIPELINING Enable HTTP multiplexing. See CURLMOPT_PIPELINING(3) diff --git a/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md b/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md new file mode 100644 index 000000000000..3349c77fbeda --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md @@ -0,0 +1,72 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_NOTIFYDATA +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_NOTIFYFUNCTION (3) + - curl_multi_notify_disable (3) + - curl_multi_notify_enable (3) +Protocol: + - All +Added-in: 8.17.0 +--- + +# NAME + +CURLMOPT_NOTIFYDATA - custom pointer passed to the notification callback + +# SYNOPSIS + +~~~c +#include + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_NOTIFYDATA, void *pointer); +~~~ + +# DESCRIPTION + +A data *pointer* to pass to the notification callback set with the +CURLMOPT_NOTIFYFUNCTION(3) option. + +This pointer is not touched by libcurl but is only passed in as the +notification callback's **clientp** argument. + +# DEFAULT + +NULL + +# %PROTOCOLS% + +# EXAMPLE + +~~~c +struct priv { + void *ours; +}; + +static void ntfy_cb(CURLM *multi, unsigned int notification, + CURL *easy, void *ntfyp) +{ + struct priv *p = ntfyp; + printf("my ptr: %p\n", p->ours); + /* ... */ +} + +int main(void) +{ + struct priv setup; + CURLM *multi = curl_multi_init(); + /* ... use socket callback and custom pointer */ + curl_multi_setopt(multi, CURLMOPT_NOTIFYFUNCTION, ntfy_cb); + curl_multi_setopt(multi, CURLMOPT_NOTIFYDATA, &setup); + curl_multi_notify_enable(multi, CURLM_NTFY_INFO_READ); +} +~~~ + +# %AVAILABILITY% + +# RETURN VALUE + +Returns CURLM_OK. diff --git a/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md new file mode 100644 index 000000000000..979fea89a704 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md @@ -0,0 +1,129 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Title: CURLMOPT_NOTIFYFUNCTION +Section: 3 +Source: libcurl +See-also: + - CURLMOPT_NOTIFYDATA (3) + - curl_multi_socket_action (3) + - curl_multi_notify_disable (3) + - curl_multi_notify_enable (3) +Protocol: + - All +Added-in: 8.17.0 +--- + +# NAME + +CURLMOPT_NOTIFYFUNCTION - callback receiving notifications + +# SYNOPSIS + +~~~c +#include + +void ntfy_callback(CURLM *multi, /* multi handle */ + unsigned int notification, /* notification type */ + CURL *easy, /* easy handle */ + void *ntfyp); /* private ntfy pointer */ + +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_NOTIFYFUNCTION, ntfy_callback); +~~~ + +# DESCRIPTION + +Pass a pointer to your callback function, which should match the prototype +shown above. + +When the multi handle processes transfers, changes can be observed +by receiving notifications about them. This can eliminate the need to +constantly interrogate the multi handle to observe such changes to +act on them. + +Notifications are collected and dispatched to the application's callback +function at an appropriate time. + +The notify callback is different from other callbacks in that it +can use more libcurl API functions. Apart from curl_multi_perform(3), +curl_multi_socket(3), curl_multi_socket_action(3), curl_multi_socket_all(3) +and curl_multi_cleanup(3) it may call all other methods on the +multi and easy handles. This includes adding and removing easy +handles to/from the multi handle. + +This callback may get invoked at any time when interacting with libcurl. +This may even happen after all transfers are done and *may also* +happen *during* a call to curl_multi_cleanup(3) when cached connections +are shut down. + +# CALLBACK ARGUMENTS + +*multi* identifies the multi handle that triggered the notification. + +**notification** is the type of notification, e.g. what happened. The +following types are available: + +## CURLM_NTFY_INFO_READ + +When enabled via curl_multi_notify_enable(3), this informs the application +that there are new messages to be processed via curl_multi_info_read(3). + +This notification happens whenever a message is added to an empty +message stack in the multi handle and not for subsequent additions. The +notification callback is then expected to read all available message, +emptying the stack, so a subsequent addition triggers the notification +again. + +The *easy* handle passed is an internal handle. + +## CURLM_NTFY_EASY_DONE + +When enabled via curl_multi_notify_enable(3), this notification is triggered +when a an easy handle has finished. This happens both for +successful and failed transfers. + +The *easy* handle passed is the transfer that is done. This *may* be +an internal handle when DoH or other features are used. + +*easy* identifies the transfer involved. This may be one of the +application's own easy handle or an internal handle. + +**ntfyp** is set with CURLMOPT_NOTIFYDATA(3). + +# DEFAULT + +NULL (no callback) + +# %PROTOCOLS% + +# EXAMPLE + +~~~c +struct priv { + void *ours; +}; + +static void ntfy_cb(CURLM *multi, unsigned int notification, + CURL *easy, void *ntfyp) +{ + struct priv *p = ntfyp; + printf("my ptr: %p\n", p->ours); + /* ... */ +} + +int main(void) +{ + struct priv setup; + CURLM *multi = curl_multi_init(); + /* ... use socket callback and custom pointer */ + curl_multi_setopt(multi, CURLMOPT_NOTIFYFUNCTION, ntfy_cb); + curl_multi_setopt(multi, CURLMOPT_NOTIFYDATA, &setup); + curl_multi_notify_enable(multi, CURLM_NTFY_INFO_READ); +} +~~~ + +# %AVAILABILITY% + +# RETURN VALUE + +Returns CURLM_OK. diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc index 98691cac3cc1..39192b639280 100644 --- a/docs/libcurl/opts/Makefile.inc +++ b/docs/libcurl/opts/Makefile.inc @@ -114,6 +114,8 @@ man_MANS = \ CURLMOPT_MAX_TOTAL_CONNECTIONS.3 \ CURLMOPT_MAXCONNECTS.3 \ CURLMOPT_NETWORK_CHANGED.3 \ + CURLMOPT_NOTIFYDATA.3 \ + CURLMOPT_NOTIFYFUNCTION.3 \ CURLMOPT_PIPELINING.3 \ CURLMOPT_PIPELINING_SERVER_BL.3 \ CURLMOPT_PIPELINING_SITE_BL.3 \ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 43435cb16b5b..75db554e2a05 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -545,6 +545,8 @@ CURLM_BAD_SOCKET 7.15.4 CURLM_CALL_MULTI_PERFORM 7.9.6 CURLM_CALL_MULTI_SOCKET 7.15.5 CURLM_INTERNAL_ERROR 7.9.6 +CURLM_NTFY_EASY_DONE 8.17.0 +CURLM_NTFY_INFO_READ 8.17.0 CURLM_OK 7.9.6 CURLM_OUT_OF_MEMORY 7.9.6 CURLM_RECURSIVE_API_CALL 7.59.0 @@ -568,6 +570,8 @@ CURLMOPT_MAX_PIPELINE_LENGTH 7.30.0 CURLMOPT_MAX_TOTAL_CONNECTIONS 7.30.0 CURLMOPT_MAXCONNECTS 7.16.3 CURLMOPT_NETWORK_CHANGED 8.16.0 +CURLMOPT_NOTIFYDATA 8.17.0 +CURLMOPT_NOTIFYFUNCTION 8.17.0 CURLMOPT_PIPELINING 7.16.0 CURLMOPT_PIPELINING_SERVER_BL 7.30.0 CURLMOPT_PIPELINING_SITE_BL 7.30.0 diff --git a/include/curl/multi.h b/include/curl/multi.h index 99e4413c9fe9..c486a3a5cc40 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -398,6 +398,12 @@ typedef enum { /* network has changed, adjust caches/connection reuse */ CURLOPT(CURLMOPT_NETWORK_CHANGED, CURLOPTTYPE_LONG, 17), + /* This is the notify callback function pointer */ + CURLOPT(CURLMOPT_NOTIFYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 18), + + /* This is the argument passed to the notify callback */ + CURLOPT(CURLMOPT_NOTIFYDATA, CURLOPTTYPE_OBJECTPOINT, 19), + CURLMOPT_LASTENTRY /* the last unused */ } CURLMoption; @@ -520,6 +526,27 @@ CURL_EXTERN CURLMcode curl_multi_waitfds(CURLM *multi, unsigned int size, unsigned int *fd_count); +/* + * Notifications dispatched by a multi handle, when enabled. + */ +#define CURLM_NTFY_INFO_READ 0 +#define CURLM_NTFY_EASY_DONE 1 + +/* + * Callback to install via CURLMOPT_NOTIFYFUNCTION. + */ +typedef void (*curl_notify_callback)(CURLM *multi, + unsigned int notification, + CURL *easy, + void *user_data); + + +CURL_EXTERN CURLMcode curl_multi_notify_disable(CURLM *multi, + unsigned int notification); + +CURL_EXTERN CURLMcode curl_multi_notify_enable(CURLM *multi, + unsigned int notification); + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index 07fba246d4c4..de2cfb715a67 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -208,6 +208,9 @@ if(curlcheck_charpp_option(option)) \ if(!curlcheck_ptrptr(value, char)) \ Wcurl_multi_setopt_err_charpp(); \ + if((option) == CURLMOPT_NOTIFYFUNCTION) \ + if(!curlcheck_multintfy_cb(value)) \ + Wcurl_multi_setopt_err_ntfycb(); \ if((option) == CURLMOPT_PUSHFUNCTION) \ if(!curlcheck_multipush_cb(value)) \ Wcurl_multi_setopt_err_pushcb(); \ @@ -224,7 +227,8 @@ /* evaluates to true if the option takes a data argument to pass to a callback */ #define curlcheck_multicb_data_option(option) \ - ((option) == CURLMOPT_PUSHDATA || \ + ((option) == CURLMOPT_NOTIFYDATA || \ + (option) == CURLMOPT_PUSHDATA || \ (option) == CURLMOPT_SOCKETDATA || \ (option) == CURLMOPT_TIMERDATA || \ 0) @@ -250,6 +254,11 @@ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_push_callback)) +/* evaluates to true if expr is of type curl_push_callback */ +#define curlcheck_multintfy_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_notify_callback)) + /* * For now, just make sure that the functions are called with three arguments */ @@ -275,6 +284,8 @@ CURLWARNING(Wcurl_multi_setopt_err_charpp, "curl_multi_setopt expects a 'char **' argument") CURLWARNING(Wcurl_multi_setopt_err_pushcb, "curl_multi_setopt expects a curl_push_callback argument") +CURLWARNING(Wcurl_multi_setopt_err_ntfycb, + "curl_multi_setopt expects a curl_notify_callback argument") CURLWARNING(Wcurl_multi_setopt_err_socketcb, "curl_multi_setopt expects a curl_socket_callback argument") CURLWARNING(Wcurl_multi_setopt_err_timercb, diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 500c690561f4..f06af2ca70e3 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -225,6 +225,7 @@ LIB_CFILES = \ mqtt.c \ multi.c \ multi_ev.c \ + multi_ntfy.c \ netrc.c \ noproxy.c \ openldap.c \ @@ -357,6 +358,7 @@ LIB_HFILES = \ mqtt.h \ multihandle.h \ multi_ev.h \ + multi_ntfy.h \ multiif.h \ netrc.h \ noproxy.h \ diff --git a/lib/libcurl.def b/lib/libcurl.def index d2f5d8318f2b..803f372041a0 100644 --- a/lib/libcurl.def +++ b/lib/libcurl.def @@ -57,6 +57,8 @@ curl_multi_get_handles curl_multi_get_offt curl_multi_info_read curl_multi_init +curl_multi_notify_disable +curl_multi_notify_enable curl_multi_perform curl_multi_poll curl_multi_remove_handle diff --git a/lib/multi.c b/lib/multi.c index ced03eea9fbf..58e384b68ae9 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -171,8 +171,15 @@ static void mstate(struct Curl_easy *data, CURLMstate state #endif data->mstate = state; - - if(state == MSTATE_COMPLETED) { + switch(state) { + case MSTATE_DONE: + CURLM_NTFY(data, CURLM_NTFY_EASY_DONE); + break; + case MSTATE_COMPLETED: + /* we sometimes directly jump to COMPLETED, trigger also a notification + * in that case. */ + if(oldstate < MSTATE_DONE) + CURLM_NTFY(data, CURLM_NTFY_EASY_DONE); /* changing to COMPLETED means it is in process and needs to go */ DEBUGASSERT(Curl_uint_bset_contains(&data->multi->process, data->mid)); Curl_uint_bset_remove(&data->multi->process, data->mid); @@ -182,6 +189,9 @@ static void mstate(struct Curl_easy *data, CURLMstate state /* free the transfer buffer when we have no more active transfers */ multi_xfer_bufs_free(data->multi); } + break; + default: + break; } /* if this state has an init-function, run it */ @@ -215,6 +225,8 @@ static void ph_freeentry(void *p) */ static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg) { + if(!Curl_llist_count(&multi->msglist)) + CURLM_NTFY(multi->admin, CURLM_NTFY_INFO_READ); Curl_llist_append(&multi->msglist, msg, &msg->list); } @@ -232,6 +244,7 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size, multi->magic = CURL_MULTI_HANDLE; Curl_dnscache_init(&multi->dnscache, dnssize); + Curl_mntfy_init(multi); Curl_multi_ev_init(multi, ev_hashsize); Curl_uint_tbl_init(&multi->xfers, NULL); Curl_uint_bset_init(&multi->process); @@ -246,7 +259,8 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size, multi->max_concurrent_streams = 100; multi->last_timeout_ms = -1; - if(Curl_uint_bset_resize(&multi->process, xfer_table_size) || + if(Curl_mntfy_resize(multi) || + Curl_uint_bset_resize(&multi->process, xfer_table_size) || Curl_uint_bset_resize(&multi->pending, xfer_table_size) || Curl_uint_bset_resize(&multi->dirty, xfer_table_size) || Curl_uint_bset_resize(&multi->msgsent, xfer_table_size) || @@ -305,6 +319,7 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size, multi->admin->multi = NULL; Curl_close(&multi->admin); } + Curl_mntfy_cleanup(multi); Curl_uint_bset_destroy(&multi->process); Curl_uint_bset_destroy(&multi->dirty); @@ -2754,6 +2769,9 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles) if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; + if(multi->in_ntfy_callback) + return CURLM_RECURSIVE_API_CALL; + sigpipe_init(&pipe_st); if(Curl_uint_bset_first(&multi->process, &mid)) { CURL_TRC_M(multi->admin, "multi_perform(running=%u)", @@ -2785,6 +2803,9 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles) if(multi_ischanged(m, TRUE)) process_pending_handles(m); + if(!returncode) + returncode = Curl_mntfy_dispatch_all(multi); + /* * Simply remove all expired timers from the splay since handles are dealt * with unconditionally by this function and curl_multi_timeout() requires @@ -2831,6 +2852,8 @@ CURLMcode curl_multi_cleanup(CURLM *m) unsigned int mid; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; + if(multi->in_ntfy_callback) + return CURLM_RECURSIVE_API_CALL; /* First remove all remaining easy handles, * close internal ones. admin handle is special */ @@ -2900,6 +2923,7 @@ CURLMcode curl_multi_cleanup(CURLM *m) #endif multi_xfer_bufs_free(multi); + Curl_mntfy_cleanup(multi); #ifdef DEBUGBUILD if(Curl_uint_tbl_count(&multi->xfers)) { multi_xfer_tbl_dump(multi); @@ -3180,6 +3204,9 @@ static CURLMcode multi_socket(struct Curl_multi *multi, if(multi_ischanged(multi, TRUE)) process_pending_handles(multi); + if(!result) + result = Curl_mntfy_dispatch_all(multi); + if(running_handles) { unsigned int running = Curl_multi_xfers_running(multi); *running_handles = (running < INT_MAX) ? (int)running : INT_MAX; @@ -3269,6 +3296,12 @@ CURLMcode curl_multi_setopt(CURLM *m, } break; } + case CURLMOPT_NOTIFYFUNCTION: + multi->ntfy.ntfy_cb = va_arg(param, curl_notify_callback); + break; + case CURLMOPT_NOTIFYDATA: + multi->ntfy.ntfy_cb_data = va_arg(param, void *); + break; default: res = CURLM_UNKNOWN_OPTION; break; @@ -3285,6 +3318,8 @@ CURLMcode curl_multi_socket(CURLM *m, curl_socket_t s, int *running_handles) struct Curl_multi *multi = m; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; + if(multi->in_ntfy_callback) + return CURLM_RECURSIVE_API_CALL; return multi_socket(multi, FALSE, s, 0, running_handles); } @@ -3294,6 +3329,8 @@ CURLMcode curl_multi_socket_action(CURLM *m, curl_socket_t s, struct Curl_multi *multi = m; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; + if(multi->in_ntfy_callback) + return CURLM_RECURSIVE_API_CALL; return multi_socket(multi, FALSE, s, ev_bitmask, running_handles); } @@ -3302,6 +3339,8 @@ CURLMcode curl_multi_socket_all(CURLM *m, int *running_handles) struct Curl_multi *multi = m; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; + if(multi->in_ntfy_callback) + return CURLM_RECURSIVE_API_CALL; return multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles); } @@ -3996,6 +4035,24 @@ void Curl_multi_clear_dirty(struct Curl_easy *data) Curl_uint_bset_remove(&data->multi->dirty, data->mid); } +CURLMcode curl_multi_notify_enable(CURLM *m, unsigned int notification) +{ + struct Curl_multi *multi = m; + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + return Curl_mntfy_enable(multi, notification); +} + +CURLMcode curl_multi_notify_disable(CURLM *m, unsigned int notification) +{ + struct Curl_multi *multi = m; + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + return Curl_mntfy_disable(multi, notification); +} + #ifdef DEBUGBUILD static void multi_xfer_dump(struct Curl_multi *multi, unsigned int mid, void *entry) diff --git a/lib/multi_ntfy.c b/lib/multi_ntfy.c new file mode 100644 index 000000000000..95ce82f57dbc --- /dev/null +++ b/lib/multi_ntfy.c @@ -0,0 +1,212 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "urldata.h" +#include "curl_trc.h" +#include "multihandle.h" +#include "multiif.h" +#include "multi_ntfy.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +struct mntfy_entry { + unsigned int mid; + unsigned int type; +}; + +#define CURL_MNTFY_CHUNK_SIZE 128 + +struct mntfy_chunk { + struct mntfy_chunk *next; + size_t r_offset; + size_t w_offset; + struct mntfy_entry entries[CURL_MNTFY_CHUNK_SIZE]; +}; + +static struct mntfy_chunk *mnfty_chunk_create(void) +{ + return calloc(1, sizeof(struct mntfy_chunk)); +} + +static void mnfty_chunk_destroy(struct mntfy_chunk *chunk) +{ + free(chunk); +} + +static void mnfty_chunk_reset(struct mntfy_chunk *chunk) +{ + memset(chunk, 0, sizeof(*chunk)); +} + +static bool mntfy_chunk_append(struct mntfy_chunk *chunk, + struct Curl_easy *data, + unsigned int type) +{ + struct mntfy_entry *e; + + if(chunk->w_offset >= CURL_MNTFY_CHUNK_SIZE) + return FALSE; + e = &chunk->entries[chunk->w_offset++]; + e->mid = data->mid; + e->type = type; + return TRUE; +} + +static struct mntfy_chunk *mntfy_non_full_tail(struct curl_multi_ntfy *mntfy) +{ + struct mntfy_chunk *chunk; + if(!mntfy->tail) { + chunk = mnfty_chunk_create(); + if(!chunk) + return NULL; + DEBUGASSERT(!mntfy->head); + mntfy->head = mntfy->tail = chunk; + return chunk; + } + else if(mntfy->tail->w_offset < CURL_MNTFY_CHUNK_SIZE) + return mntfy->tail; + else { /* tail is full. */ + chunk = mnfty_chunk_create(); + if(!chunk) + return NULL; + DEBUGASSERT(mntfy->head); + mntfy->tail->next = chunk; + mntfy->tail = chunk; + return chunk; + } +} + +static void mntfy_chunk_dispatch_all(struct Curl_multi *multi, + struct mntfy_chunk *chunk) +{ + struct mntfy_entry *e; + struct Curl_easy *data; + + if(multi->ntfy.ntfy_cb) { + while((chunk->r_offset < chunk->w_offset) && !multi->ntfy.failure) { + e = &chunk->entries[chunk->r_offset]; + data = e->mid ? Curl_multi_get_easy(multi, e->mid) : multi->admin; + /* only when notification has not been disabled in the meantime */ + if(data && Curl_uint_bset_contains(&multi->ntfy.enabled, e->type)) { + /* this may cause new notifications to be added! */ + CURL_TRC_M(multi->admin, "[NTFY] dispatch %d to xfer %u", + e->type, e->mid); + multi->ntfy.ntfy_cb(multi, e->type, data, multi->ntfy.ntfy_cb_data); + } + /* once dispatched, safe to increment */ + chunk->r_offset++; + } + } + mnfty_chunk_reset(chunk); +} + +void Curl_mntfy_init(struct Curl_multi *multi) +{ + memset(&multi->ntfy, 0, sizeof(multi->ntfy)); + Curl_uint_bset_init(&multi->ntfy.enabled); +} + +CURLMcode Curl_mntfy_resize(struct Curl_multi *multi) +{ + if(Curl_uint_bset_resize(&multi->ntfy.enabled, CURLM_NTFY_EASY_DONE + 1)) + return CURLM_OUT_OF_MEMORY; + return CURLM_OK; +} + +void Curl_mntfy_cleanup(struct Curl_multi *multi) +{ + while(multi->ntfy.head) { + struct mntfy_chunk *chunk = multi->ntfy.head; + multi->ntfy.head = chunk->next; + mnfty_chunk_destroy(chunk); + } + multi->ntfy.tail = NULL; + Curl_uint_bset_destroy(&multi->ntfy.enabled); +} + +CURLMcode Curl_mntfy_enable(struct Curl_multi *multi, unsigned int type) +{ + if(type > CURLM_NTFY_EASY_DONE) + return CURLM_UNKNOWN_OPTION; + Curl_uint_bset_add(&multi->ntfy.enabled, type); + return CURLM_OK; +} + +CURLMcode Curl_mntfy_disable(struct Curl_multi *multi, unsigned int type) +{ + if(type > CURLM_NTFY_EASY_DONE) + return CURLM_UNKNOWN_OPTION; + Curl_uint_bset_remove(&multi->ntfy.enabled, type); + return CURLM_OK; +} + +void Curl_mntfy_add(struct Curl_easy *data, unsigned int type) +{ + struct Curl_multi *multi = data ? data->multi : NULL; + if(multi && multi->ntfy.ntfy_cb && !multi->ntfy.failure && + Curl_uint_bset_contains(&multi->ntfy.enabled, type)) { + /* append to list of outstanding notifications */ + struct mntfy_chunk *tail = mntfy_non_full_tail(&multi->ntfy); + CURL_TRC_M(data, "[NTFY] add %d for xfer %u", type, data->mid); + if(tail) + mntfy_chunk_append(tail, data, type); + else + multi->ntfy.failure = CURLM_OUT_OF_MEMORY; + } +} + +CURLMcode Curl_mntfy_dispatch_all(struct Curl_multi *multi) +{ + DEBUGASSERT(!multi->in_ntfy_callback); + multi->in_ntfy_callback = TRUE; + while(multi->ntfy.head && !multi->ntfy.failure) { + struct mntfy_chunk *chunk = multi->ntfy.head; + /* this may cause new notifications to be added! */ + mntfy_chunk_dispatch_all(multi, chunk); + DEBUGASSERT(chunk->r_offset == chunk->w_offset); + + if(chunk == multi->ntfy.tail) /* last one, keep */ + break; + DEBUGASSERT(chunk->next); + DEBUGASSERT(multi->ntfy.head != multi->ntfy.tail); + multi->ntfy.head = chunk->next; + mnfty_chunk_destroy(chunk); + } + multi->in_ntfy_callback = FALSE; + + if(multi->ntfy.failure) { + CURLMcode result = multi->ntfy.failure; + multi->ntfy.failure = CURLM_OK; /* reset, once delivered */ + return result; + } + return CURLM_OK; +} diff --git a/lib/multi_ntfy.h b/lib/multi_ntfy.h new file mode 100644 index 000000000000..d920b3295d4b --- /dev/null +++ b/lib/multi_ntfy.h @@ -0,0 +1,57 @@ +#ifndef HEADER_CURL_MULTI_NTFY_H +#define HEADER_CURL_MULTI_NTFY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "uint-bset.h" + +struct Curl_easy; +struct Curl_multi; + +struct curl_multi_ntfy { + curl_notify_callback ntfy_cb; + void *ntfy_cb_data; + struct uint_bset enabled; + CURLMcode failure; + struct mntfy_chunk *head; + struct mntfy_chunk *tail; +}; + +void Curl_mntfy_init(struct Curl_multi *multi); +CURLMcode Curl_mntfy_resize(struct Curl_multi *multi); +void Curl_mntfy_cleanup(struct Curl_multi *multi); + +CURLMcode Curl_mntfy_enable(struct Curl_multi *multi, unsigned int type); +CURLMcode Curl_mntfy_disable(struct Curl_multi *multi, unsigned int type); + +void Curl_mntfy_add(struct Curl_easy *data, unsigned int type); + +#define CURLM_NTFY(d,t) \ + do { if((d) && (d)->multi && (d)->multi->ntfy.ntfy_cb) \ + Curl_mntfy_add((d), (t)); } while(0) + +CURLMcode Curl_mntfy_dispatch_all(struct Curl_multi *multi); + + +#endif /* HEADER_CURL_MULTI_NTFY_H */ diff --git a/lib/multihandle.h b/lib/multihandle.h index ae41044adc2e..69f977bb94ed 100644 --- a/lib/multihandle.h +++ b/lib/multihandle.h @@ -30,6 +30,7 @@ #include "cshutdn.h" #include "hostip.h" #include "multi_ev.h" +#include "multi_ntfy.h" #include "psl.h" #include "socketpair.h" #include "uint-bset.h" @@ -134,6 +135,8 @@ struct Curl_multi { /* multi event related things */ struct curl_multi_ev ev; + /* multi notification related things */ + struct curl_multi_ntfy ntfy; /* `proto_hash` is a general key-value store for protocol implementations * with the lifetime of the multi handle. The number of elements kept here @@ -178,6 +181,7 @@ struct Curl_multi { BIT(multiplexing); /* multiplexing wanted */ BIT(recheckstate); /* see Curl_multi_connchanged */ BIT(in_callback); /* true while executing a callback */ + BIT(in_ntfy_callback); /* true while dispatching notifications */ #ifdef USE_OPENSSL BIT(ssl_seeded); #endif diff --git a/scripts/singleuse.pl b/scripts/singleuse.pl index 2e8a8e0afd22..b4cbe3ff4a12 100755 --- a/scripts/singleuse.pl +++ b/scripts/singleuse.pl @@ -116,6 +116,8 @@ 'curl_multi_get_offt' => 'API', 'curl_multi_info_read' => 'API', 'curl_multi_init' => 'API', + 'curl_multi_notify_disable' => 'API', + 'curl_multi_notify_enable' => 'API', 'curl_multi_perform' => 'API', 'curl_multi_remove_handle' => 'API', 'curl_multi_setopt' => 'API', diff --git a/src/tool_operate.c b/src/tool_operate.c index 3c29d28ec3a0..fc5a9656252f 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1464,26 +1464,8 @@ struct contextuv { struct datauv *uv; }; -static CURLcode check_finished(struct parastate *s); - -static void check_multi_info(struct datauv *uv) -{ - CURLcode result; - - result = check_finished(uv->s); - if(result && !uv->s->result) - uv->s->result = result; - - if(uv->s->more_transfers) { - result = add_parallel_transfers(uv->s->multi, uv->s->share, - &uv->s->more_transfers, - &uv->s->added_transfers); - if(result && !uv->s->result) - uv->s->result = result; - if(result) - uv_stop(uv->loop); - } -} +static void mnotify(CURLM *multi, unsigned int notification, + CURL *easy, void *user_data); /* callback from libuv on socket activity */ static void on_uv_socket(uv_poll_t *req, int status, int events) @@ -1510,7 +1492,6 @@ static void on_uv_timeout(uv_timer_t *req) if(uv && uv->s) { curl_multi_socket_action(uv->s->multi, CURL_SOCKET_TIMEOUT, 0, &uv->s->still_running); - check_multi_info(uv); } } @@ -1596,8 +1577,6 @@ static int cb_socket(CURL *easy, curl_socket_t s, int action, uv_poll_stop(&c->poll_handle); destroy_context(c); curl_multi_assign(uv->s->multi, s, NULL); - /* check if we can do more now */ - check_multi_info(uv); } break; default: @@ -1641,10 +1620,6 @@ static CURLcode parallel_event(struct parastate *s) curl_mfprintf(tool_stderr, "parallel_event: uv_run() returned\n"); #endif - result = check_finished(s); - if(result && !s->result) - s->result = result; - /* early exit called */ if(s->wrapitup) { if(s->still_running && !s->wrapitup_processed) { @@ -1657,13 +1632,6 @@ static CURLcode parallel_event(struct parastate *s) } break; } - - if(s->more_transfers) { - result = add_parallel_transfers(s->multi, s->share, &s->more_transfers, - &s->added_transfers); - if(result && !s->result) - s->result = result; - } } result = s->result; @@ -1758,6 +1726,27 @@ static CURLcode check_finished(struct parastate *s) return result; } +static void mnotify(CURLM *multi, unsigned int notification, + CURL *easy, void *user_data) +{ + struct parastate *s = user_data; + CURLcode result; + + (void)multi; + (void)easy; + + switch(notification) { + case CURLM_NTFY_INFO_READ: + result = check_finished(s); + /* remember first failure */ + if(result && !s->result) + s->result = result; + break; + default: + break; + } +} + static CURLcode parallel_transfers(CURLSH *share) { CURLcode result; @@ -1775,6 +1764,10 @@ static CURLcode parallel_transfers(CURLSH *share) if(!s->multi) return CURLE_OUT_OF_MEMORY; + (void)curl_multi_setopt(s->multi, CURLMOPT_NOTIFYFUNCTION, mnotify); + (void)curl_multi_setopt(s->multi, CURLMOPT_NOTIFYDATA, s); + (void)curl_multi_notify_enable(s->multi, CURLM_NTFY_INFO_READ); + result = add_parallel_transfers(s->multi, s->share, &s->more_transfers, &s->added_transfers); if(result) { @@ -1813,13 +1806,14 @@ static CURLcode parallel_transfers(CURLSH *share) s->mcode = curl_multi_poll(s->multi, NULL, 0, 1000, NULL); if(!s->mcode) s->mcode = curl_multi_perform(s->multi, &s->still_running); - if(!s->mcode) - result = check_finished(s); } (void)progress_meter(s->multi, &s->start, TRUE); } + /* Result is the first failed transfer - if there was one. */ + result = s->result; + /* Make sure to return some kind of error if there was a multi problem */ if(s->mcode) { result = (s->mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : diff --git a/tests/data/test1135 b/tests/data/test1135 index 405d4b8fc36e..51ec53e4d3f1 100644 --- a/tests/data/test1135 +++ b/tests/data/test1135 @@ -109,6 +109,8 @@ curl_multi_get_offt curl_pushheader_bynum curl_pushheader_byname curl_multi_waitfds +curl_multi_notify_disable +curl_multi_notify_enable curl_easy_option_by_name curl_easy_option_by_id curl_easy_option_next diff --git a/tests/data/test3207 b/tests/data/test3207 index 4c223699ee58..7902d0ae298f 100644 --- a/tests/data/test3207 +++ b/tests/data/test3207 @@ -172,7 +172,7 @@ https://localhost:%HTTPSPORT/%TESTNUMBER %CERTDIR/certs/test-ca.crt # Verify data after the test has been "shot" -Allocations: 13500 +Allocations: 13600 diff --git a/tests/data/test500 b/tests/data/test500 index 0b084ac003b1..7904110c7e0a 100644 --- a/tests/data/test500 +++ b/tests/data/test500 @@ -55,7 +55,7 @@ Accept: */* -Allocations: 81 +Allocations: 82 Maximum allocated: 33400 diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py index f8e7b12a2641..dcff774a63ae 100644 --- a/tests/http/testenv/curl.py +++ b/tests/http/testenv/curl.py @@ -126,6 +126,9 @@ def start(self): '-n', f'profile-97 /pid == {self._pid}/ {{ @[ustack()] = count(); }} tick-60s {{ exit(0); }}', '-o', f'{self._file}' ] + if sys.platform.startswith('darwin'): + # macOS seems to like this for producing symbols in user stacks + args.extend(['-p', f'{self._pid}']) self._proc = subprocess.Popen(args, text=True, cwd=self._run_dir, shell=False) assert self._proc diff --git a/tests/unit/unit3214.c b/tests/unit/unit3214.c index 08ce6fff3944..d992a35dc0db 100644 --- a/tests/unit/unit3214.c +++ b/tests/unit/unit3214.c @@ -43,7 +43,7 @@ static void checksize(const char *name, size_t size, size_t allowed) /* the maximum sizes we allow specific structs to grow to */ #define MAX_CURL_EASY 5800 #define MAX_CONNECTDATA 1300 -#define MAX_CURL_MULTI 750 +#define MAX_CURL_MULTI 850 #define MAX_CURL_HTTPPOST 112 #define MAX_CURL_SLIST 16 #define MAX_CURL_KHKEY 24 From 0061b2bfaabd29a10cf63898a3cceb3ef4ad914a Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Tue, 7 Oct 2025 13:34:26 +0800 Subject: [PATCH 325/465] vquic: fix idle-timeout checks (ngtcp2 ms<-->ns), 64-bit log & honor 0=no-timeout (osslquic) Closes #18903 --- lib/vquic/curl_ngtcp2.c | 5 +++-- lib/vquic/curl_osslq.c | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index f397ec85aecf..9851a087c1b1 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2744,8 +2744,9 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf, * it will close the connection when it expires. */ rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); if(rp && rp->max_idle_timeout) { - timediff_t idletime = curlx_timediff(curlx_now(), ctx->q.last_io); - if(idletime > 0 && (uint64_t)idletime > rp->max_idle_timeout) + timediff_t idletime_ms = curlx_timediff(curlx_now(), ctx->q.last_io); + if(idletime_ms > 0 && + ((uint64_t)idletime_ms * NGTCP2_MILLISECONDS) > rp->max_idle_timeout) goto out; } diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index cda239a57d84..474ed595cb66 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -2251,10 +2251,11 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf, "assume connection is dead."); goto out; } - CURL_TRC_CF(data, cf, "negotiated idle timeout: %zums", (size_t)idle_ms); + CURL_TRC_CF(data, cf, "negotiated idle timeout: %" FMT_PRIu64 "ms", + (curl_uint64_t)idle_ms); idletime = curlx_timediff(curlx_now(), ctx->q.last_io); - if(idletime > 0 && (uint64_t)idletime > idle_ms) - goto out; + if(idle_ms != 0 && idletime > 0 && (uint64_t)idletime > idle_ms) + goto out; } #endif From 783df22e596f46c989cadba016d144514b68654c Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Tue, 7 Oct 2025 15:48:36 +0800 Subject: [PATCH 326/465] vquic/ngtcp2: compare idle timeout in ms to avoid overflow Closes #18903 --- lib/vquic/curl_ngtcp2.c | 9 ++++++--- lib/vquic/curl_osslq.c | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 9851a087c1b1..af7f26eb3988 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2745,9 +2745,12 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf, rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); if(rp && rp->max_idle_timeout) { timediff_t idletime_ms = curlx_timediff(curlx_now(), ctx->q.last_io); - if(idletime_ms > 0 && - ((uint64_t)idletime_ms * NGTCP2_MILLISECONDS) > rp->max_idle_timeout) - goto out; + if(idletime_ms > 0) { + uint64_t max_idle_ms = + (uint64_t)(rp->max_idle_timeout / NGTCP2_MILLISECONDS); + if((uint64_t)idletime_ms > max_idle_ms) + goto out; + } } if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 474ed595cb66..3fd2daf92fbd 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -2254,8 +2254,8 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf, CURL_TRC_CF(data, cf, "negotiated idle timeout: %" FMT_PRIu64 "ms", (curl_uint64_t)idle_ms); idletime = curlx_timediff(curlx_now(), ctx->q.last_io); - if(idle_ms != 0 && idletime > 0 && (uint64_t)idletime > idle_ms) - goto out; + if(idle_ms && idletime > 0 && (uint64_t)idletime > idle_ms) + goto out; } #endif From 4a6bdd5899005c25ce222dc21dcfd1a779544330 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 7 Oct 2025 12:04:03 +0200 Subject: [PATCH 327/465] examples/usercertinmem: avoid stripping const This API started accepting a const somewhere between OpenSSL 1.0.2b and 1.0.2t. It means this example, like the other similar one now works best with those versions or newer: ``` docs/examples/usercertinmem.c:100:33: error: cast from 'const char *' to 'char *' drops const qualifier [-Werror,-Wcast-qual] 100 | bio = BIO_new_mem_buf((char *)mypem, -1); | ^ docs/examples/usercertinmem.c:121:34: error: cast from 'const char *' to 'char *' drops const qualifier [-Werror,-Wcast-qual] 121 | kbio = BIO_new_mem_buf((char *)mykey, -1); | ^ ``` Closes #18908 --- docs/examples/usercertinmem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/examples/usercertinmem.c b/docs/examples/usercertinmem.c index 670ae4dc718e..50537ae25fdc 100644 --- a/docs/examples/usercertinmem.c +++ b/docs/examples/usercertinmem.c @@ -97,7 +97,7 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer) (void)pointer; /* get a BIO */ - bio = BIO_new_mem_buf((char *)mypem, -1); + bio = BIO_new_mem_buf(mypem, -1); if(!bio) { printf("BIO_new_mem_buf failed\n"); @@ -118,7 +118,7 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer) } /* create a bio for the RSA key */ - kbio = BIO_new_mem_buf((char *)mykey, -1); + kbio = BIO_new_mem_buf(mykey, -1); if(!kbio) { printf("BIO_new_mem_buf failed\n"); } From 089afd78cb5897adf5a42d8ccff01d7c32c8fada Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 6 Oct 2025 14:08:07 +0200 Subject: [PATCH 328/465] socks: handle premature close When expecting to receive a number of bytes during socks connect, treat an early connection close as error. Reported-by: Joshua Rogers Closes #18883 --- lib/socks.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/socks.c b/lib/socks.c index ba7b28d04a01..e7e545442a9a 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -254,8 +254,14 @@ static CURLproxycode socks_recv(struct socks_state *sx, curl_easy_strerror(result)); return CURLPX_RECV_CONNECT; } - else if(!nread) /* EOF */ + else if(!nread) { /* EOF */ + if(Curl_bufq_len(&sx->iobuf) < min_bytes) { + failf(data, "Failed to receive SOCKS response, " + "proxy closed connection"); + return CURLPX_RECV_CONNECT; + } break; + } } *done = TRUE; return CURLPX_OK; From 7ddbde4f731d6694f940320fe50a80b7f351229d Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 7 Oct 2025 14:04:12 +0200 Subject: [PATCH 329/465] cmake: build the "all" examples source list dynamically To allow building conditional examples, and to simplify by avoiding cmake-version dependent code. Follow-up to fe5225b5eaf3a1a0ce149023d38a9922a114798b #18209 Cherry-picked from #18909 Closes #18911 --- docs/examples/CMakeLists.txt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/examples/CMakeLists.txt b/docs/examples/CMakeLists.txt index bc0f3ce359b8..d86494c8708b 100644 --- a/docs/examples/CMakeLists.txt +++ b/docs/examples/CMakeLists.txt @@ -28,15 +28,14 @@ add_custom_target(curl-examples) curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") +set(_all_src "") set(_all_canary "") set(_all "all") foreach(_target IN LISTS check_PROGRAMS _all) # keep '_all' last set(_target_name "curl-example-${_target}") if(_target STREQUAL "all") if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) - set(_examples_c "${check_PROGRAMS}") - list(TRANSFORM _examples_c APPEND ".c") - add_library(${_target_name} OBJECT EXCLUDE_FROM_ALL ${_examples_c}) + add_library(${_target_name} OBJECT EXCLUDE_FROM_ALL ${_all_src}) if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") # MSVC but exclude clang-cl # CMake generates a static library for the OBJECT target. Silence these 'lib.exe' warnings: # warning LNK4006: main already defined in ....obj; second definition ignored @@ -49,16 +48,13 @@ foreach(_target IN LISTS check_PROGRAMS _all) # keep '_all' last endif() endif() else() - set(_examples_c "") - foreach(_src IN LISTS check_PROGRAMS) - list(APPEND _examples_c "${_src}.c") - endforeach() - add_library(${_target_name} STATIC EXCLUDE_FROM_ALL ${_examples_c}) + add_library(${_target_name} STATIC EXCLUDE_FROM_ALL ${_all_src}) endif() add_custom_target(curl-examples-build) # Special target to compile all tests quickly and build a single test to probe linkage add_dependencies(curl-examples-build ${_target_name} ${_all_canary}) # Include a full build of a single test else() set(_all_canary ${_target_name}) # Save the last test for the curl-examples-build target + list(APPEND _all_src "${_target}.c") add_executable(${_target_name} EXCLUDE_FROM_ALL "${_target}.c") add_dependencies(curl-examples ${_target_name}) endif() From 53be8166b2b16d9682a173f505188a79ca30fb11 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 7 Oct 2025 13:40:05 +0200 Subject: [PATCH 330/465] multi: notify rename, remove the last stragglers in the public API. Follow-up to 357808f4addef44c2c48f17d Closes #18910 --- docs/libcurl/curl_multi_notify_disable.md | 2 +- docs/libcurl/curl_multi_notify_enable.md | 2 +- docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md | 2 +- docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md | 6 +++--- docs/libcurl/symbols-in-versions | 8 ++++---- include/curl/multi.h | 4 ++-- lib/multi.c | 6 +++--- lib/multi_ntfy.c | 6 +++--- src/tool_operate.c | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/libcurl/curl_multi_notify_disable.md b/docs/libcurl/curl_multi_notify_disable.md index f4f28ebbd3bb..7228bfe89e5c 100644 --- a/docs/libcurl/curl_multi_notify_disable.md +++ b/docs/libcurl/curl_multi_notify_disable.md @@ -49,7 +49,7 @@ int main(void) int rc; CURLM *multi = curl_multi_init(); - rc = curl_multi_notify_disable(multi, CURLM_NTFY_INFO_READ); + rc = curl_multi_notify_disable(multi, CURLM_NOTIFY_INFO_READ); } ~~~ diff --git a/docs/libcurl/curl_multi_notify_enable.md b/docs/libcurl/curl_multi_notify_enable.md index d3ab02d2c756..095780dd0909 100644 --- a/docs/libcurl/curl_multi_notify_enable.md +++ b/docs/libcurl/curl_multi_notify_enable.md @@ -49,7 +49,7 @@ int main(void) int rc; CURLM *multi = curl_multi_init(); - rc = curl_multi_notify_enable(multi, CURLM_NTFY_INFO_READ); + rc = curl_multi_notify_enable(multi, CURLM_NOTIFY_INFO_READ); } ~~~ diff --git a/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md b/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md index 3349c77fbeda..539e4ce2989e 100644 --- a/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md +++ b/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md @@ -61,7 +61,7 @@ int main(void) /* ... use socket callback and custom pointer */ curl_multi_setopt(multi, CURLMOPT_NOTIFYFUNCTION, ntfy_cb); curl_multi_setopt(multi, CURLMOPT_NOTIFYDATA, &setup); - curl_multi_notify_enable(multi, CURLM_NTFY_INFO_READ); + curl_multi_notify_enable(multi, CURLM_NOTIFY_INFO_READ); } ~~~ diff --git a/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md index 979fea89a704..8e5206521729 100644 --- a/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md +++ b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md @@ -63,7 +63,7 @@ are shut down. **notification** is the type of notification, e.g. what happened. The following types are available: -## CURLM_NTFY_INFO_READ +## CURLM_NOTIFY_INFO_READ When enabled via curl_multi_notify_enable(3), this informs the application that there are new messages to be processed via curl_multi_info_read(3). @@ -76,7 +76,7 @@ again. The *easy* handle passed is an internal handle. -## CURLM_NTFY_EASY_DONE +## CURLM_NOTIFY_EASY_DONE When enabled via curl_multi_notify_enable(3), this notification is triggered when a an easy handle has finished. This happens both for @@ -118,7 +118,7 @@ int main(void) /* ... use socket callback and custom pointer */ curl_multi_setopt(multi, CURLMOPT_NOTIFYFUNCTION, ntfy_cb); curl_multi_setopt(multi, CURLMOPT_NOTIFYDATA, &setup); - curl_multi_notify_enable(multi, CURLM_NTFY_INFO_READ); + curl_multi_notify_enable(multi, CURLM_NOTIFY_INFO_READ); } ~~~ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 75db554e2a05..c9b0d24e37bf 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -545,8 +545,8 @@ CURLM_BAD_SOCKET 7.15.4 CURLM_CALL_MULTI_PERFORM 7.9.6 CURLM_CALL_MULTI_SOCKET 7.15.5 CURLM_INTERNAL_ERROR 7.9.6 -CURLM_NTFY_EASY_DONE 8.17.0 -CURLM_NTFY_INFO_READ 8.17.0 +CURLM_NOTIFY_EASY_DONE 8.17.0 +CURLM_NOTIFY_INFO_READ 8.17.0 CURLM_OK 7.9.6 CURLM_OUT_OF_MEMORY 7.9.6 CURLM_RECURSIVE_API_CALL 7.59.0 @@ -570,8 +570,8 @@ CURLMOPT_MAX_PIPELINE_LENGTH 7.30.0 CURLMOPT_MAX_TOTAL_CONNECTIONS 7.30.0 CURLMOPT_MAXCONNECTS 7.16.3 CURLMOPT_NETWORK_CHANGED 8.16.0 -CURLMOPT_NOTIFYDATA 8.17.0 -CURLMOPT_NOTIFYFUNCTION 8.17.0 +CURLMOPT_NOTIFYDATA 8.17.0 +CURLMOPT_NOTIFYFUNCTION 8.17.0 CURLMOPT_PIPELINING 7.16.0 CURLMOPT_PIPELINING_SERVER_BL 7.30.0 CURLMOPT_PIPELINING_SITE_BL 7.30.0 diff --git a/include/curl/multi.h b/include/curl/multi.h index c486a3a5cc40..38c44e3b5aff 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -529,8 +529,8 @@ CURL_EXTERN CURLMcode curl_multi_waitfds(CURLM *multi, /* * Notifications dispatched by a multi handle, when enabled. */ -#define CURLM_NTFY_INFO_READ 0 -#define CURLM_NTFY_EASY_DONE 1 +#define CURLM_NOTIFY_INFO_READ 0 +#define CURLM_NOTIFY_EASY_DONE 1 /* * Callback to install via CURLMOPT_NOTIFYFUNCTION. diff --git a/lib/multi.c b/lib/multi.c index 58e384b68ae9..168d584cfb8f 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -173,13 +173,13 @@ static void mstate(struct Curl_easy *data, CURLMstate state data->mstate = state; switch(state) { case MSTATE_DONE: - CURLM_NTFY(data, CURLM_NTFY_EASY_DONE); + CURLM_NTFY(data, CURLM_NOTIFY_EASY_DONE); break; case MSTATE_COMPLETED: /* we sometimes directly jump to COMPLETED, trigger also a notification * in that case. */ if(oldstate < MSTATE_DONE) - CURLM_NTFY(data, CURLM_NTFY_EASY_DONE); + CURLM_NTFY(data, CURLM_NOTIFY_EASY_DONE); /* changing to COMPLETED means it is in process and needs to go */ DEBUGASSERT(Curl_uint_bset_contains(&data->multi->process, data->mid)); Curl_uint_bset_remove(&data->multi->process, data->mid); @@ -226,7 +226,7 @@ static void ph_freeentry(void *p) static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg) { if(!Curl_llist_count(&multi->msglist)) - CURLM_NTFY(multi->admin, CURLM_NTFY_INFO_READ); + CURLM_NTFY(multi->admin, CURLM_NOTIFY_INFO_READ); Curl_llist_append(&multi->msglist, msg, &msg->list); } diff --git a/lib/multi_ntfy.c b/lib/multi_ntfy.c index 95ce82f57dbc..24a09176f241 100644 --- a/lib/multi_ntfy.c +++ b/lib/multi_ntfy.c @@ -137,7 +137,7 @@ void Curl_mntfy_init(struct Curl_multi *multi) CURLMcode Curl_mntfy_resize(struct Curl_multi *multi) { - if(Curl_uint_bset_resize(&multi->ntfy.enabled, CURLM_NTFY_EASY_DONE + 1)) + if(Curl_uint_bset_resize(&multi->ntfy.enabled, CURLM_NOTIFY_EASY_DONE + 1)) return CURLM_OUT_OF_MEMORY; return CURLM_OK; } @@ -155,7 +155,7 @@ void Curl_mntfy_cleanup(struct Curl_multi *multi) CURLMcode Curl_mntfy_enable(struct Curl_multi *multi, unsigned int type) { - if(type > CURLM_NTFY_EASY_DONE) + if(type > CURLM_NOTIFY_EASY_DONE) return CURLM_UNKNOWN_OPTION; Curl_uint_bset_add(&multi->ntfy.enabled, type); return CURLM_OK; @@ -163,7 +163,7 @@ CURLMcode Curl_mntfy_enable(struct Curl_multi *multi, unsigned int type) CURLMcode Curl_mntfy_disable(struct Curl_multi *multi, unsigned int type) { - if(type > CURLM_NTFY_EASY_DONE) + if(type > CURLM_NOTIFY_EASY_DONE) return CURLM_UNKNOWN_OPTION; Curl_uint_bset_remove(&multi->ntfy.enabled, type); return CURLM_OK; diff --git a/src/tool_operate.c b/src/tool_operate.c index fc5a9656252f..3ee64c3b844f 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1736,7 +1736,7 @@ static void mnotify(CURLM *multi, unsigned int notification, (void)easy; switch(notification) { - case CURLM_NTFY_INFO_READ: + case CURLM_NOTIFY_INFO_READ: result = check_finished(s); /* remember first failure */ if(result && !s->result) @@ -1766,7 +1766,7 @@ static CURLcode parallel_transfers(CURLSH *share) (void)curl_multi_setopt(s->multi, CURLMOPT_NOTIFYFUNCTION, mnotify); (void)curl_multi_setopt(s->multi, CURLMOPT_NOTIFYDATA, s); - (void)curl_multi_notify_enable(s->multi, CURLM_NTFY_INFO_READ); + (void)curl_multi_notify_enable(s->multi, CURLM_NOTIFY_INFO_READ); result = add_parallel_transfers(s->multi, s->share, &s->more_transfers, &s->added_transfers); From 6bb77140322565ca17f5a66aa5d8500d8d469cca Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 7 Oct 2025 13:54:17 +0200 Subject: [PATCH 331/465] examples: fix build issues in 'complicated' examples - cacertinmem: build cleanly with BoringSSL/AWS-LC. - cacertinmem: silence `-Wcast-function-type-strict`. - multi-uv: fix callback prototypes. - multithread, threaded-ssl: do not pass const as thread arg. - sessioninfo: fix suppressing deprecated feature warning. - usercertinmem: sync formatting with cacertinmem. Follow-up to 4a6bdd5899005c25ce222dc21dcfd1a779544330 #18908 Cherry-picked from #18909 Closes #18914 --- docs/examples/cacertinmem.c | 15 +++++++++++++-- docs/examples/multi-uv.c | 8 ++++---- docs/examples/multithread.c | 7 ++++--- docs/examples/sessioninfo.c | 7 +++++-- docs/examples/threaded-ssl.c | 7 ++++--- docs/examples/usercertinmem.c | 16 ++++++---------- 6 files changed, 36 insertions(+), 24 deletions(-) diff --git a/docs/examples/cacertinmem.c b/docs/examples/cacertinmem.c index ec12df58bf18..6a2649b29b79 100644 --- a/docs/examples/cacertinmem.c +++ b/docs/examples/cacertinmem.c @@ -34,6 +34,17 @@ #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic ignored "-Woverlength-strings" #endif +/* Silence warning when calling sk_X509_INFO_pop_free() */ +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-strict" +#endif + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +typedef size_t ossl_valsize_t; +#else +typedef int ossl_valsize_t; +#endif static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) { @@ -68,8 +79,8 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer) "-----END CERTIFICATE-----\n"; BIO *cbio = BIO_new_mem_buf(mypem, sizeof(mypem)); - X509_STORE *cts = SSL_CTX_get_cert_store((SSL_CTX *)sslctx); - int i; + X509_STORE *cts = SSL_CTX_get_cert_store((SSL_CTX *)sslctx); + ossl_valsize_t i; STACK_OF(X509_INFO) *inf; (void)curl; diff --git a/docs/examples/multi-uv.c b/docs/examples/multi-uv.c index ee0ac0e1b33f..07774c93eb90 100644 --- a/docs/examples/multi-uv.c +++ b/docs/examples/multi-uv.c @@ -167,9 +167,9 @@ static void on_uv_timeout(uv_timer_t *req) } /* callback from libcurl to update the timeout expiry */ -static int cb_timeout(CURLM *multi, long timeout_ms, - struct datauv *uv) +static int cb_timeout(CURLM *multi, long timeout_ms, void *userp) { + struct datauv *uv = (struct datauv *)userp; (void)multi; if(timeout_ms < 0) uv_timer_stop(&uv->timeout); @@ -185,9 +185,9 @@ static int cb_timeout(CURLM *multi, long timeout_ms, /* callback from libcurl to update socket activity to wait for */ static int cb_socket(CURL *easy, curl_socket_t s, int action, - struct datauv *uv, - void *socketp) + void *userp, void *socketp) { + struct datauv *uv = (struct datauv *)userp; struct curl_context *curl_context; int events = 0; (void)easy; diff --git a/docs/examples/multithread.c b/docs/examples/multithread.c index ceee94022a39..4cdb74fbe444 100644 --- a/docs/examples/multithread.c +++ b/docs/examples/multithread.c @@ -48,12 +48,13 @@ static const char * const urls[NUMT]= { "www.example" }; -static void *pull_one_url(void *url) +static void *pull_one_url(void *pindex) { + int i = *(int *)pindex; CURL *curl; curl = curl_easy_init(); - curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_URL, urls[i]); curl_easy_perform(curl); /* ignores error */ curl_easy_cleanup(curl); @@ -79,7 +80,7 @@ int main(void) int error = pthread_create(&tid[i], NULL, /* default attributes please */ pull_one_url, - (void *)urls[i]); + (void *)&i); if(error) fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error); else diff --git a/docs/examples/sessioninfo.c b/docs/examples/sessioninfo.c index 225b1ae5a516..5fbc1cc4df7a 100644 --- a/docs/examples/sessioninfo.c +++ b/docs/examples/sessioninfo.c @@ -29,6 +29,10 @@ /* Note that this example currently requires curl to be linked against GnuTLS (and this program must also be linked against -lgnutls). */ +#ifndef CURL_DISABLE_DEPRECATION +#define CURL_DISABLE_DEPRECATION +#endif + #include #include @@ -47,8 +51,7 @@ static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) (void)stream; (void)ptr; - res = CURL_IGNORE_DEPRECATION( - curl_easy_getinfo(curl, CURLINFO_TLS_SESSION, &info)); + res = curl_easy_getinfo(curl, CURLINFO_TLS_SESSION, &info); if(!res) { switch(info->backend) { diff --git a/docs/examples/threaded-ssl.c b/docs/examples/threaded-ssl.c index 161182eec1e1..6590e8b202b9 100644 --- a/docs/examples/threaded-ssl.c +++ b/docs/examples/threaded-ssl.c @@ -52,12 +52,13 @@ static const char * const urls[]= { "https://www4.example.com/", }; -static void *pull_one_url(void *url) +static void *pull_one_url(void *pindex) { + int i = *(int *)pindex; CURL *curl; curl = curl_easy_init(); - curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_URL, urls[i]); /* this example does not verify the server's certificate, which means we might be downloading stuff from an impostor */ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); @@ -82,7 +83,7 @@ int main(int argc, char **argv) int error = pthread_create(&tid[i], NULL, /* default attributes please */ pull_one_url, - (void *)urls[i]); + (void *)&i); if(error) fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error); else diff --git a/docs/examples/usercertinmem.c b/docs/examples/usercertinmem.c index 50537ae25fdc..899895592e04 100644 --- a/docs/examples/usercertinmem.c +++ b/docs/examples/usercertinmem.c @@ -22,7 +22,7 @@ * ***************************************************************************/ /* - * Use an in-memory user certificate and RSA key and retrieve an https page. + * Use an in-memory user certificate and RSA key and retrieve an HTTPS page. * */ /* Written by Ishan SinghLevett, based on Theo Borm's cacertinmem.c. @@ -47,7 +47,7 @@ static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) { - fwrite(ptr, size, nmemb, stream); + fwrite(ptr, size, nmemb, (FILE *)stream); return nmemb * size; } @@ -179,12 +179,10 @@ int main(void) /* first try: retrieve page without user certificate and key -> fails */ rv = curl_easy_perform(ch); - if(rv == CURLE_OK) { + if(rv == CURLE_OK) printf("*** transfer succeeded ***\n"); - } - else { + else printf("*** transfer failed ***\n"); - } /* second try: retrieve page using user certificate and key -> succeeds * load the certificate and key by installing a function doing the necessary @@ -192,12 +190,10 @@ int main(void) */ curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); rv = curl_easy_perform(ch); - if(rv == CURLE_OK) { + if(rv == CURLE_OK) printf("*** transfer succeeded ***\n"); - } - else { + else printf("*** transfer failed ***\n"); - } curl_easy_cleanup(ch); curl_global_cleanup(); From 496802fdcf1b249bedb381b25d0c3b544dea569d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 7 Oct 2025 16:00:59 +0200 Subject: [PATCH 332/465] multi: use CURLMNOTIFY_ as notification id prefix Since CURLM_ is already used as prefix for multi error codes, it makes it easier to detect and understand the difference between identifiers - and allows for scripts on the website and elsewhere to separate them properly. Follow-up to 53be8166b2b16d9682 Closes #18912 --- docs/libcurl/curl_multi_notify_disable.md | 2 +- docs/libcurl/curl_multi_notify_enable.md | 2 +- docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md | 2 +- docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md | 6 ++-- docs/libcurl/symbols-in-versions | 30 ++++++++++---------- include/curl/multi.h | 5 ++-- lib/multi.c | 6 ++-- lib/multi_ntfy.c | 6 ++-- src/tool_operate.c | 4 +-- 9 files changed, 31 insertions(+), 32 deletions(-) diff --git a/docs/libcurl/curl_multi_notify_disable.md b/docs/libcurl/curl_multi_notify_disable.md index 7228bfe89e5c..11113a5898dd 100644 --- a/docs/libcurl/curl_multi_notify_disable.md +++ b/docs/libcurl/curl_multi_notify_disable.md @@ -49,7 +49,7 @@ int main(void) int rc; CURLM *multi = curl_multi_init(); - rc = curl_multi_notify_disable(multi, CURLM_NOTIFY_INFO_READ); + rc = curl_multi_notify_disable(multi, CURLMNOTIFY_INFO_READ); } ~~~ diff --git a/docs/libcurl/curl_multi_notify_enable.md b/docs/libcurl/curl_multi_notify_enable.md index 095780dd0909..4a0da77714c2 100644 --- a/docs/libcurl/curl_multi_notify_enable.md +++ b/docs/libcurl/curl_multi_notify_enable.md @@ -49,7 +49,7 @@ int main(void) int rc; CURLM *multi = curl_multi_init(); - rc = curl_multi_notify_enable(multi, CURLM_NOTIFY_INFO_READ); + rc = curl_multi_notify_enable(multi, CURLMNOTIFY_INFO_READ); } ~~~ diff --git a/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md b/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md index 539e4ce2989e..deb4b5b95c50 100644 --- a/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md +++ b/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md @@ -61,7 +61,7 @@ int main(void) /* ... use socket callback and custom pointer */ curl_multi_setopt(multi, CURLMOPT_NOTIFYFUNCTION, ntfy_cb); curl_multi_setopt(multi, CURLMOPT_NOTIFYDATA, &setup); - curl_multi_notify_enable(multi, CURLM_NOTIFY_INFO_READ); + curl_multi_notify_enable(multi, CURLMNOTIFY_INFO_READ); } ~~~ diff --git a/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md index 8e5206521729..7ff2cb12e51f 100644 --- a/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md +++ b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md @@ -63,7 +63,7 @@ are shut down. **notification** is the type of notification, e.g. what happened. The following types are available: -## CURLM_NOTIFY_INFO_READ +## CURLMNOTIFY_INFO_READ When enabled via curl_multi_notify_enable(3), this informs the application that there are new messages to be processed via curl_multi_info_read(3). @@ -76,7 +76,7 @@ again. The *easy* handle passed is an internal handle. -## CURLM_NOTIFY_EASY_DONE +## CURLMNOTIFY_EASY_DONE When enabled via curl_multi_notify_enable(3), this notification is triggered when a an easy handle has finished. This happens both for @@ -118,7 +118,7 @@ int main(void) /* ... use socket callback and custom pointer */ curl_multi_setopt(multi, CURLMOPT_NOTIFYFUNCTION, ntfy_cb); curl_multi_setopt(multi, CURLMOPT_NOTIFYDATA, &setup); - curl_multi_notify_enable(multi, CURLM_NOTIFY_INFO_READ); + curl_multi_notify_enable(multi, CURLMNOTIFY_INFO_READ); } ~~~ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index c9b0d24e37bf..e0e0a8e63a4c 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -234,6 +234,7 @@ CURLE_CONV_REQD 7.15.4 7.82.0 CURLE_COULDNT_CONNECT 7.1 CURLE_COULDNT_RESOLVE_HOST 7.1 CURLE_COULDNT_RESOLVE_PROXY 7.1 +CURLE_ECH_REQUIRED 8.8.0 CURLE_FAILED_INIT 7.1 CURLE_FILE_COULDNT_READ_FILE 7.1 CURLE_FILESIZE_EXCEEDED 7.10.8 @@ -337,7 +338,6 @@ CURLE_UNRECOVERABLE_POLL 7.84.0 CURLE_UNSUPPORTED_PROTOCOL 7.1 CURLE_UPLOAD_FAILED 7.16.3 CURLE_URL_MALFORMAT 7.1 -CURLE_ECH_REQUIRED 8.8.0 CURLE_URL_MALFORMAT_USER 7.1 7.17.0 CURLE_USE_SSL_FAILED 7.17.0 CURLE_WEIRD_SERVER_REPLY 7.51.0 @@ -360,8 +360,8 @@ CURLFINFOFLAG_KNOWN_SIZE 7.21.0 CURLFINFOFLAG_KNOWN_TIME 7.21.0 CURLFINFOFLAG_KNOWN_UID 7.21.0 CURLFOLLOW_ALL 8.13.0 -CURLFOLLOW_OBEYCODE 8.13.0 CURLFOLLOW_FIRSTONLY 8.13.0 +CURLFOLLOW_OBEYCODE 8.13.0 CURLFORM_ARRAY 7.9.1 7.56.0 CURLFORM_ARRAY_END 7.9.1 7.9.5 7.9.6 CURLFORM_ARRAY_START 7.9.1 7.9.5 7.9.6 @@ -466,9 +466,9 @@ CURLINFO_NONE 7.4.1 CURLINFO_NUM_CONNECTS 7.12.3 CURLINFO_OFF_T 7.55.0 CURLINFO_OS_ERRNO 7.12.2 +CURLINFO_POSTTRANSFER_TIME_T 8.10.0 CURLINFO_PRETRANSFER_TIME 7.4.1 CURLINFO_PRETRANSFER_TIME_T 7.61.0 -CURLINFO_POSTTRANSFER_TIME_T 8.10.0 CURLINFO_PRIMARY_IP 7.19.0 CURLINFO_PRIMARY_PORT 7.21.0 CURLINFO_PRIVATE 7.10.3 @@ -545,8 +545,6 @@ CURLM_BAD_SOCKET 7.15.4 CURLM_CALL_MULTI_PERFORM 7.9.6 CURLM_CALL_MULTI_SOCKET 7.15.5 CURLM_INTERNAL_ERROR 7.9.6 -CURLM_NOTIFY_EASY_DONE 8.17.0 -CURLM_NOTIFY_INFO_READ 8.17.0 CURLM_OK 7.9.6 CURLM_OUT_OF_MEMORY 7.9.6 CURLM_RECURSIVE_API_CALL 7.59.0 @@ -560,6 +558,8 @@ CURLMINFO_XFERS_CURRENT 8.16.0 CURLMINFO_XFERS_DONE 8.16.0 CURLMINFO_XFERS_PENDING 8.16.0 CURLMINFO_XFERS_RUNNING 8.16.0 +CURLMNOTIFY_EASY_DONE 8.17.0 +CURLMNOTIFY_INFO_READ 8.17.0 CURLMNWC_CLEAR_CONNS 8.16.0 CURLMNWC_CLEAR_DNS 8.16.0 CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE 7.30.0 @@ -594,10 +594,10 @@ CURLOPT_APPEND 7.17.0 CURLOPT_AUTOREFERER 7.1 CURLOPT_AWS_SIGV4 7.75.0 CURLOPT_BUFFERSIZE 7.10 +CURLOPT_CA_CACHE_TIMEOUT 7.87.0 CURLOPT_CAINFO 7.4.2 CURLOPT_CAINFO_BLOB 7.77.0 CURLOPT_CAPATH 7.9.8 -CURLOPT_CA_CACHE_TIMEOUT 7.87.0 CURLOPT_CERTINFO 7.19.1 CURLOPT_CHUNK_BGN_FUNCTION 7.21.0 CURLOPT_CHUNK_DATA 7.21.0 @@ -670,8 +670,8 @@ CURLOPT_FTPPORT 7.1 CURLOPT_FTPSSLAUTH 7.12.2 CURLOPT_GSSAPI_DELEGATION 7.22.0 CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS 7.59.0 -CURLOPT_HAPROXYPROTOCOL 7.60.0 CURLOPT_HAPROXY_CLIENT_IP 8.2.0 +CURLOPT_HAPROXYPROTOCOL 7.60.0 CURLOPT_HEADER 7.1 CURLOPT_HEADERDATA 7.10 CURLOPT_HEADERFUNCTION 7.7.2 @@ -719,7 +719,6 @@ CURLOPT_MAIL_FROM 7.20.0 CURLOPT_MAIL_RCPT 7.20.0 CURLOPT_MAIL_RCPT_ALLLOWFAILS 7.69.0 8.2.0 CURLOPT_MAIL_RCPT_ALLOWFAILS 8.2.0 -CURLOPT_QUICK_EXIT 7.87.0 CURLOPT_MAX_RECV_SPEED_LARGE 7.15.5 CURLOPT_MAX_SEND_SPEED_LARGE 7.15.5 CURLOPT_MAXAGE_CONN 7.65.0 @@ -800,6 +799,7 @@ CURLOPT_PROXYTYPE 7.10 CURLOPT_PROXYUSERNAME 7.19.1 CURLOPT_PROXYUSERPWD 7.1 CURLOPT_PUT 7.1 7.12.1 +CURLOPT_QUICK_EXIT 7.87.0 CURLOPT_QUOTE 7.1 CURLOPT_RANDOM_FILE 7.7 7.84.0 CURLOPT_RANGE 7.1 @@ -884,9 +884,9 @@ CURLOPT_STREAM_WEIGHT 7.46.0 CURLOPT_SUPPRESS_CONNECT_HEADERS 7.54.0 CURLOPT_TCP_FASTOPEN 7.49.0 CURLOPT_TCP_KEEPALIVE 7.25.0 +CURLOPT_TCP_KEEPCNT 8.9.0 CURLOPT_TCP_KEEPIDLE 7.25.0 CURLOPT_TCP_KEEPINTVL 7.25.0 -CURLOPT_TCP_KEEPCNT 8.9.0 CURLOPT_TCP_NODELAY 7.11.2 CURLOPT_TELNETOPTIONS 7.7 CURLOPT_TFTP_BLKSIZE 7.19.4 @@ -1072,11 +1072,11 @@ CURLSSLBACKEND_SECURETRANSPORT 7.64.1 8.15.0 CURLSSLBACKEND_WOLFSSL 7.49.0 CURLSSLOPT_ALLOW_BEAST 7.25.0 CURLSSLOPT_AUTO_CLIENT_CERT 7.77.0 +CURLSSLOPT_EARLYDATA 8.11.0 CURLSSLOPT_NATIVE_CA 7.71.0 CURLSSLOPT_NO_PARTIALCHAIN 7.68.0 CURLSSLOPT_NO_REVOKE 7.44.0 CURLSSLOPT_REVOKE_BEST_EFFORT 7.70.0 -CURLSSLOPT_EARLYDATA 8.11.0 CURLSSLSET_NO_BACKENDS 7.56.0 CURLSSLSET_OK 7.56.0 CURLSSLSET_TOO_LATE 7.56.0 @@ -1132,6 +1132,11 @@ CURLUE_UNKNOWN_PART 7.62.0 CURLUE_UNSUPPORTED_SCHEME 7.62.0 CURLUE_URLDECODE 7.62.0 CURLUE_USER_NOT_ALLOWED 7.62.0 +CURLULFLAG_ANSWERED 8.13.0 +CURLULFLAG_DELETED 8.13.0 +CURLULFLAG_DRAFT 8.13.0 +CURLULFLAG_FLAGGED 8.13.0 +CURLULFLAG_SEEN 8.13.0 CURLUPART_FRAGMENT 7.62.0 CURLUPART_HOST 7.62.0 CURLUPART_OPTIONS 7.62.0 @@ -1143,11 +1148,6 @@ CURLUPART_SCHEME 7.62.0 CURLUPART_URL 7.62.0 CURLUPART_USER 7.62.0 CURLUPART_ZONEID 7.65.0 -CURLULFLAG_ANSWERED 8.13.0 -CURLULFLAG_DELETED 8.13.0 -CURLULFLAG_DRAFT 8.13.0 -CURLULFLAG_FLAGGED 8.13.0 -CURLULFLAG_SEEN 8.13.0 CURLUSESSL_ALL 7.17.0 CURLUSESSL_CONTROL 7.17.0 CURLUSESSL_NONE 7.17.0 diff --git a/include/curl/multi.h b/include/curl/multi.h index 38c44e3b5aff..4e30637ef565 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -529,8 +529,8 @@ CURL_EXTERN CURLMcode curl_multi_waitfds(CURLM *multi, /* * Notifications dispatched by a multi handle, when enabled. */ -#define CURLM_NOTIFY_INFO_READ 0 -#define CURLM_NOTIFY_EASY_DONE 1 +#define CURLMNOTIFY_INFO_READ 0 +#define CURLMNOTIFY_EASY_DONE 1 /* * Callback to install via CURLMOPT_NOTIFYFUNCTION. @@ -540,7 +540,6 @@ typedef void (*curl_notify_callback)(CURLM *multi, CURL *easy, void *user_data); - CURL_EXTERN CURLMcode curl_multi_notify_disable(CURLM *multi, unsigned int notification); diff --git a/lib/multi.c b/lib/multi.c index 168d584cfb8f..9ea8e9bc7f51 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -173,13 +173,13 @@ static void mstate(struct Curl_easy *data, CURLMstate state data->mstate = state; switch(state) { case MSTATE_DONE: - CURLM_NTFY(data, CURLM_NOTIFY_EASY_DONE); + CURLM_NTFY(data, CURLMNOTIFY_EASY_DONE); break; case MSTATE_COMPLETED: /* we sometimes directly jump to COMPLETED, trigger also a notification * in that case. */ if(oldstate < MSTATE_DONE) - CURLM_NTFY(data, CURLM_NOTIFY_EASY_DONE); + CURLM_NTFY(data, CURLMNOTIFY_EASY_DONE); /* changing to COMPLETED means it is in process and needs to go */ DEBUGASSERT(Curl_uint_bset_contains(&data->multi->process, data->mid)); Curl_uint_bset_remove(&data->multi->process, data->mid); @@ -226,7 +226,7 @@ static void ph_freeentry(void *p) static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg) { if(!Curl_llist_count(&multi->msglist)) - CURLM_NTFY(multi->admin, CURLM_NOTIFY_INFO_READ); + CURLM_NTFY(multi->admin, CURLMNOTIFY_INFO_READ); Curl_llist_append(&multi->msglist, msg, &msg->list); } diff --git a/lib/multi_ntfy.c b/lib/multi_ntfy.c index 24a09176f241..fe7cc0503a76 100644 --- a/lib/multi_ntfy.c +++ b/lib/multi_ntfy.c @@ -137,7 +137,7 @@ void Curl_mntfy_init(struct Curl_multi *multi) CURLMcode Curl_mntfy_resize(struct Curl_multi *multi) { - if(Curl_uint_bset_resize(&multi->ntfy.enabled, CURLM_NOTIFY_EASY_DONE + 1)) + if(Curl_uint_bset_resize(&multi->ntfy.enabled, CURLMNOTIFY_EASY_DONE + 1)) return CURLM_OUT_OF_MEMORY; return CURLM_OK; } @@ -155,7 +155,7 @@ void Curl_mntfy_cleanup(struct Curl_multi *multi) CURLMcode Curl_mntfy_enable(struct Curl_multi *multi, unsigned int type) { - if(type > CURLM_NOTIFY_EASY_DONE) + if(type > CURLMNOTIFY_EASY_DONE) return CURLM_UNKNOWN_OPTION; Curl_uint_bset_add(&multi->ntfy.enabled, type); return CURLM_OK; @@ -163,7 +163,7 @@ CURLMcode Curl_mntfy_enable(struct Curl_multi *multi, unsigned int type) CURLMcode Curl_mntfy_disable(struct Curl_multi *multi, unsigned int type) { - if(type > CURLM_NOTIFY_EASY_DONE) + if(type > CURLMNOTIFY_EASY_DONE) return CURLM_UNKNOWN_OPTION; Curl_uint_bset_remove(&multi->ntfy.enabled, type); return CURLM_OK; diff --git a/src/tool_operate.c b/src/tool_operate.c index 3ee64c3b844f..ca0d2e77f593 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1736,7 +1736,7 @@ static void mnotify(CURLM *multi, unsigned int notification, (void)easy; switch(notification) { - case CURLM_NOTIFY_INFO_READ: + case CURLMNOTIFY_INFO_READ: result = check_finished(s); /* remember first failure */ if(result && !s->result) @@ -1766,7 +1766,7 @@ static CURLcode parallel_transfers(CURLSH *share) (void)curl_multi_setopt(s->multi, CURLMOPT_NOTIFYFUNCTION, mnotify); (void)curl_multi_setopt(s->multi, CURLMOPT_NOTIFYDATA, s); - (void)curl_multi_notify_enable(s->multi, CURLM_NOTIFY_INFO_READ); + (void)curl_multi_notify_enable(s->multi, CURLMNOTIFY_INFO_READ); result = add_parallel_transfers(s->multi, s->share, &s->more_transfers, &s->added_transfers); From 352d1dc6ab0af5bc7f88746cd059ceca6c1e9c0a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 7 Oct 2025 16:18:22 +0200 Subject: [PATCH 333/465] CURLMOPT_NOTIFYFUNCTION.md: minor language polish - mention the possibility of new types in the future - s/a an/an Closes #18913 --- docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md index 7ff2cb12e51f..4091b1ae6841 100644 --- a/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md +++ b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md @@ -61,7 +61,8 @@ are shut down. *multi* identifies the multi handle that triggered the notification. **notification** is the type of notification, e.g. what happened. The -following types are available: +following types are available right now. In the future, new ones might be +added. ## CURLMNOTIFY_INFO_READ @@ -79,8 +80,8 @@ The *easy* handle passed is an internal handle. ## CURLMNOTIFY_EASY_DONE When enabled via curl_multi_notify_enable(3), this notification is triggered -when a an easy handle has finished. This happens both for -successful and failed transfers. +when an easy handle has finished. This happens both for successful and failed +transfers. The *easy* handle passed is the transfer that is done. This *may* be an internal handle when DoH or other features are used. From 0d573969de269cb58d85c73ad12d63cccf7b33dd Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 7 Oct 2025 12:05:08 +0200 Subject: [PATCH 334/465] osslq: set out idle timeout to 0 Similar to our ngtcp2 backend, set our idle timeout for the connection to 0, meaning we have no such timeout from our side. The effective idle timeout is then the one announced by the peer. Closes #18907 --- lib/vquic/curl_osslq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 3fd2daf92fbd..4d72797199c5 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -288,7 +288,6 @@ struct cf_osslq_ctx { struct bufc_pool stream_bufcp; /* chunk pool for streams */ struct uint_hash streams; /* hash `data->mid` to `h3_stream_ctx` */ size_t max_stream_window; /* max flow window for one stream */ - uint64_t max_idle_ms; /* max idle time for QUIC connection */ SSL_POLL_ITEM *poll_items; /* Array for polling on writable state */ struct Curl_easy **curl_items; /* Array of easy objs */ size_t items_max; /* max elements in poll/curl_items */ @@ -1228,6 +1227,9 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, SSL_set_connect_state(ctx->tls.ossl.ssl); SSL_set_incoming_stream_policy(ctx->tls.ossl.ssl, SSL_INCOMING_STREAM_POLICY_ACCEPT, 0); + /* from our side, there is no idle timeout */ + SSL_set_value_uint(ctx->tls.ossl.ssl, + SSL_VALUE_CLASS_FEATURE_REQUEST, SSL_VALUE_QUIC_IDLE_TIMEOUT, 0); /* setup the H3 things on top of the QUIC connection */ result = cf_osslq_h3conn_init(ctx, ctx->tls.ossl.ssl, cf); @@ -2243,7 +2245,7 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf, /* Added in OpenSSL v3.3.x */ { timediff_t idletime; - uint64_t idle_ms = ctx->max_idle_ms; + uint64_t idle_ms = 0; if(!SSL_get_value_uint(ctx->tls.ossl.ssl, SSL_VALUE_CLASS_FEATURE_NEGOTIATED, SSL_VALUE_QUIC_IDLE_TIMEOUT, &idle_ms)) { From 88a1ab511ce0883c0c0429a74af754036cff5df8 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 7 Oct 2025 11:30:46 +0200 Subject: [PATCH 335/465] ngtcp2: fix handling of blocked stream data The stream blocking might not be the one of the current easy handle. Look up the stream to be marked as blocking via its stream_id in the internal hash. Theoretically, this does not have to be one of the h3 streams, so not finding it is not an error. Fixes #18905 Reported-by: Joshua Rogers Closes #18906 --- lib/vquic/curl_ngtcp2.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index af7f26eb3988..b48d1af555ac 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -300,6 +300,35 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf, return CURLE_OK; } +struct cf_ngtcp2_sfind_ctx { + curl_int64_t stream_id; + struct h3_stream_ctx *stream; + unsigned int mid; +}; + +static bool cf_ngtcp2_sfind(unsigned int mid, void *value, void *user_data) +{ + struct cf_ngtcp2_sfind_ctx *fctx = user_data; + struct h3_stream_ctx *stream = value; + + if(fctx->stream_id == stream->id) { + fctx->mid = mid; + fctx->stream = stream; + return FALSE; + } + return TRUE; /* continue */ +} + +static struct h3_stream_ctx * +cf_ngtcp2_get_stream(struct cf_ngtcp2_ctx *ctx, curl_int64_t stream_id) +{ + struct cf_ngtcp2_sfind_ctx fctx; + fctx.stream_id = stream_id; + fctx.stream = NULL; + Curl_uint_hash_visit(&ctx->streams, cf_ngtcp2_sfind, &fctx); + return fctx.stream; +} + static void cf_ngtcp2_stream_close(struct Curl_cfilter *cf, struct Curl_easy *data, struct h3_stream_ctx *stream) @@ -1808,13 +1837,13 @@ static CURLcode read_pkt_to_send(void *userp, else if(n < 0) { switch(n) { case NGTCP2_ERR_STREAM_DATA_BLOCKED: { - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data); + struct h3_stream_ctx *stream; DEBUGASSERT(ndatalen == -1); nghttp3_conn_block_stream(ctx->h3conn, stream_id); CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] block quic flow", (curl_int64_t)stream_id); - DEBUGASSERT(stream); - if(stream) + stream = cf_ngtcp2_get_stream(ctx, stream_id); + if(stream) /* it might be not one of our h3 streams? */ stream->quic_flow_blocked = TRUE; n = 0; break; From df70a68984308952dcacf33d11593cb22ad80464 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 7 Oct 2025 12:36:49 +0200 Subject: [PATCH 336/465] cmake: support building some complicated examples, build them in CI Build these examples when the necessary dependencies are present: - cacertinmem, usercertinmem (OpenSSL/fork) - multi-uv (libuv) - multithread, threaded-ssl (pthread) - sessioninfo (GnuTLS) Indicate the necessary dependency via a `Required:` comment placed in the source file. A single dependency per source is supported as of now. The name of the dependency should match the variable used within the cmake scripts, which in turn matches the macro used in the config header. E.g. for GnuTLS it's `USE_GNUTLS`. Also: - GHA/macos: build examples in two job to test GnuTLS and pthread ones. - GHA/linux: enable libuv to test it with examples. Follow-up to 6bb77140322565ca17f5a66aa5d8500d8d469cca #18914 Closes #18909 --- .github/workflows/linux.yml | 4 ++-- .github/workflows/macos.yml | 4 ++-- docs/examples/CMakeLists.txt | 34 +++++++++++++++++++++++++++++++--- docs/examples/Makefile.am | 5 +++-- docs/examples/Makefile.inc | 16 ++++++++++------ docs/examples/cacertinmem.c | 2 ++ docs/examples/multi-uv.c | 4 +++- docs/examples/multithread.c | 2 ++ docs/examples/sessioninfo.c | 2 ++ docs/examples/threaded-ssl.c | 3 ++- docs/examples/usercertinmem.c | 2 ++ 11 files changed, 61 insertions(+), 17 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index d78789b8a1a5..d01fb4a0b9dc 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -109,10 +109,10 @@ jobs: configure: CC=clang LDFLAGS=-Wl,-rpath,/home/runner/mbedtls/lib --with-mbedtls=/home/runner/mbedtls --enable-debug --with-fish-functions-dir --with-zsh-functions-dir - name: 'mbedtls' - install_packages: libnghttp2-dev + install_packages: libnghttp2-dev libuv1-dev install_steps: mbedtls PKG_CONFIG_PATH: /home/runner/mbedtls/lib/pkgconfig # Requires v3.6.0 - generate: -DCURL_USE_MBEDTLS=ON -DENABLE_DEBUG=ON + generate: -DCURL_USE_MBEDTLS=ON -DCURL_USE_LIBUV=ON -DENABLE_DEBUG=ON - name: 'mbedtls-pkg MultiSSL !pc' install_packages: libnghttp2-dev libmbedtls-dev diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index c32b71439c13..b4bbc8ea792c 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -276,7 +276,7 @@ jobs: configure: --enable-debug --with-openssl=/opt/homebrew/opt/openssl tflags: --test-event # cmake - - name: 'OpenSSL gsasl rtmp AppleIDN SecTrust' + - name: 'OpenSSL gsasl rtmp AppleIDN SecTrust +examples' install: libnghttp3 libngtcp2 gsasl rtmpdump generate: -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DCURL_USE_GSASL=ON -DUSE_LIBRTMP=ON -DUSE_APPLE_IDN=ON -DUSE_NGTCP2=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DUSE_APPLE_SECTRUST=ON - name: 'MultiSSL AppleIDN clang-tidy +examples' @@ -314,7 +314,7 @@ jobs: install: brotli mbedtls zstd install_steps: codeset-test generate: -DCURL_USE_MBEDTLS=ON -DCURL_DISABLE_LDAP=ON -DCURL_DEFAULT_SSL_BACKEND=mbedtls -DCURL_USE_OPENSSL=ON -DUSE_APPLE_IDN=ON - - name: 'GnuTLS !ldap krb5' + - name: 'GnuTLS !ldap krb5 +examples' install: gnutls nettle krb5 generate: -DENABLE_DEBUG=ON -DCURL_USE_GNUTLS=ON -DCURL_USE_OPENSSL=OFF -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/krb5 -DCURL_DISABLE_LDAP=ON -DUSE_SSLS_EXPORT=ON - name: 'aws-lc' diff --git a/docs/examples/CMakeLists.txt b/docs/examples/CMakeLists.txt index d86494c8708b..c86e8439fda7 100644 --- a/docs/examples/CMakeLists.txt +++ b/docs/examples/CMakeLists.txt @@ -24,14 +24,22 @@ add_custom_target(curl-examples) -# Get check_PROGRAMS variable +# Get check_PROGRAMS, COMPLICATED_MAY_BUILD, COMPLICATED_EXAMPLES variables curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") +set(_with_deps "") set(_all_src "") set(_all_canary "") set(_all "all") -foreach(_target IN LISTS check_PROGRAMS _all) # keep '_all' last +foreach(_target IN LISTS COMPLICATED_MAY_BUILD check_PROGRAMS _all) # keep 'COMPLICATED_MAY_BUILD' first, and '_all' last + # Strip .c suffix from COMPLICATED_MAY_BUILD items + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET _target STEM _target) + else() + get_filename_component(_target "${_target}" NAME_WE) + endif() + set(_more_libs "") set(_target_name "curl-example-${_target}") if(_target STREQUAL "all") if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) @@ -50,16 +58,36 @@ foreach(_target IN LISTS check_PROGRAMS _all) # keep '_all' last else() add_library(${_target_name} STATIC EXCLUDE_FROM_ALL ${_all_src}) endif() + if(_with_deps) + set(_more_libs ${CURL_LIBS}) # If any examples required dependencies, link them + endif() add_custom_target(curl-examples-build) # Special target to compile all tests quickly and build a single test to probe linkage add_dependencies(curl-examples-build ${_target_name} ${_all_canary}) # Include a full build of a single test else() + # Check if the example requires a build option. Then check if that build option is enabled. + # If it is, link all dependencies to the example. + set(_requires_regex "/\\* Requires: ([A-Z0-9_]+) \\*/") + file(STRINGS "${_target}.c" _req REGEX "${_requires_regex}") + string(REGEX REPLACE "${_requires_regex}" "\\1" _req "${_req}") + if(_req) + if(${${_req}}) + string(APPEND _with_deps " ${_target}:${_req}") + set(_more_libs ${CURL_LIBS}) + else() + continue() # Option required, but not found + endif() + endif() set(_all_canary ${_target_name}) # Save the last test for the curl-examples-build target list(APPEND _all_src "${_target}.c") add_executable(${_target_name} EXCLUDE_FROM_ALL "${_target}.c") add_dependencies(curl-examples ${_target_name}) endif() - target_link_libraries(${_target_name} ${LIB_SELECTED} ${CURL_NETWORK_AND_TIME_LIBS}) + target_link_libraries(${_target_name} ${LIB_SELECTED} ${CURL_NETWORK_AND_TIME_LIBS} ${_more_libs}) target_compile_definitions(${_target_name} PRIVATE "CURL_NO_OLDIES" "$<$:WIN32_LEAN_AND_MEAN>" "$<$:_CRT_SECURE_NO_DEPRECATE>") set_target_properties(${_target_name} PROPERTIES OUTPUT_NAME "${_target}" PROJECT_LABEL "Example ${_target}" UNITY_BUILD OFF) endforeach() + +if(_with_deps) + message(STATUS "Enabled examples with dependencies:${_with_deps}") +endif() diff --git a/docs/examples/Makefile.am b/docs/examples/Makefile.am index 89ebcc9840f6..0885b925c417 100644 --- a/docs/examples/Makefile.am +++ b/docs/examples/Makefile.am @@ -24,7 +24,8 @@ AUTOMAKE_OPTIONS = foreign nostdinc -EXTRA_DIST = CMakeLists.txt .checksrc README.md Makefile.example $(COMPLICATED_EXAMPLES) +EXTRA_DIST = CMakeLists.txt .checksrc README.md Makefile.example \ + $(COMPLICATED_MAY_BUILD) $(COMPLICATED_EXAMPLES) # Specify our include paths here, and do it relative to $(top_srcdir) and # $(top_builddir), to ensure that these paths which belong to the library @@ -53,7 +54,7 @@ LDADD = $(top_builddir)/lib/libcurl.la # This might hold -Werror CFLAGS += @CURL_CFLAG_EXTRAS@ -# Get check_PROGRAMS variable +# Get check_PROGRAMS, COMPLICATED_MAY_BUILD, COMPLICATED_EXAMPLES variables include Makefile.inc all: $(check_PROGRAMS) diff --git a/docs/examples/Makefile.inc b/docs/examples/Makefile.inc index bb6e42971b76..3bb68f25aa1f 100644 --- a/docs/examples/Makefile.inc +++ b/docs/examples/Makefile.inc @@ -140,10 +140,19 @@ check_PROGRAMS = \ websocket-cb \ websocket-updown +# These examples require external dependencies that may be available during +# the build. +COMPLICATED_MAY_BUILD = \ + cacertinmem.c \ + multi-uv.c \ + multithread.c \ + sessioninfo.c \ + threaded-ssl.c \ + usercertinmem.c + # These examples require external dependencies that may not be commonly # available on POSIX systems, so do not bother attempting to compile them here. COMPLICATED_EXAMPLES = \ - cacertinmem.c \ crawler.c \ ephiperfifo.c \ evhiperfifo.c \ @@ -152,11 +161,6 @@ COMPLICATED_EXAMPLES = \ htmltidy.c \ htmltitle.cpp \ multi-event.c \ - multi-uv.c \ - multithread.c \ - sessioninfo.c \ smooth-gtk-thread.c \ - threaded-ssl.c \ - usercertinmem.c \ version-check.pl \ xmlstream.c diff --git a/docs/examples/cacertinmem.c b/docs/examples/cacertinmem.c index 6a2649b29b79..e552ce5d69cf 100644 --- a/docs/examples/cacertinmem.c +++ b/docs/examples/cacertinmem.c @@ -26,6 +26,8 @@ * */ +/* Requires: USE_OPENSSL */ + #include #include #include diff --git a/docs/examples/multi-uv.c b/docs/examples/multi-uv.c index 07774c93eb90..8cebcd5e2677 100644 --- a/docs/examples/multi-uv.c +++ b/docs/examples/multi-uv.c @@ -21,11 +21,11 @@ * SPDX-License-Identifier: curl * ***************************************************************************/ - /* * multi_socket API using libuv * */ + /* Use the socket_action interface to download multiple files in parallel, powered by libuv. @@ -34,6 +34,8 @@ See https://docs.libuv.org/en/v1.x/index.html libuv API documentation */ +/* Requires: USE_LIBUV */ + #include #include #include diff --git a/docs/examples/multithread.c b/docs/examples/multithread.c index 4cdb74fbe444..b98977c443db 100644 --- a/docs/examples/multithread.c +++ b/docs/examples/multithread.c @@ -26,6 +26,8 @@ * */ +/* Requires: HAVE_PTHREAD_H */ + #include #include #include diff --git a/docs/examples/sessioninfo.c b/docs/examples/sessioninfo.c index 5fbc1cc4df7a..b9b3a3c46296 100644 --- a/docs/examples/sessioninfo.c +++ b/docs/examples/sessioninfo.c @@ -29,6 +29,8 @@ /* Note that this example currently requires curl to be linked against GnuTLS (and this program must also be linked against -lgnutls). */ +/* Requires: USE_GNUTLS */ + #ifndef CURL_DISABLE_DEPRECATION #define CURL_DISABLE_DEPRECATION #endif diff --git a/docs/examples/threaded-ssl.c b/docs/examples/threaded-ssl.c index 6590e8b202b9..3868899e4fca 100644 --- a/docs/examples/threaded-ssl.c +++ b/docs/examples/threaded-ssl.c @@ -36,7 +36,8 @@ * https://github.com/curl/curl/blob/curl-7_88_1/docs/examples/threaded-ssl.c */ -#define USE_OPENSSL /* or USE_GNUTLS accordingly */ +/* Requires: HAVE_PTHREAD_H */ +/* Also requires TLS support to run */ #include #include diff --git a/docs/examples/usercertinmem.c b/docs/examples/usercertinmem.c index 899895592e04..2a3c2b000649 100644 --- a/docs/examples/usercertinmem.c +++ b/docs/examples/usercertinmem.c @@ -31,6 +31,8 @@ * must be used in real circumstances when a secure connection is required. */ +/* Requires: USE_OPENSSL */ + #ifndef OPENSSL_SUPPRESS_DEPRECATED #define OPENSSL_SUPPRESS_DEPRECATED #endif From 9f52458e7d14a7185b39a8d1046e4935caeb0a54 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 7 Oct 2025 12:47:19 +0200 Subject: [PATCH 337/465] notify: use 'notify' in public header and docs Closes #18915 --- docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md | 8 +++--- docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md | 20 +++++++------- include/curl/typecheck-gcc.h | 28 ++++++++++---------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md b/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md index deb4b5b95c50..ad57cbea1414 100644 --- a/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md +++ b/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md @@ -46,10 +46,10 @@ struct priv { void *ours; }; -static void ntfy_cb(CURLM *multi, unsigned int notification, - CURL *easy, void *ntfyp) +static void notify_cb(CURLM *multi, unsigned int notification, + CURL *easy, void *notifyp) { - struct priv *p = ntfyp; + struct priv *p = notifyp; printf("my ptr: %p\n", p->ours); /* ... */ } @@ -59,7 +59,7 @@ int main(void) struct priv setup; CURLM *multi = curl_multi_init(); /* ... use socket callback and custom pointer */ - curl_multi_setopt(multi, CURLMOPT_NOTIFYFUNCTION, ntfy_cb); + curl_multi_setopt(multi, CURLMOPT_NOTIFYFUNCTION, notify_cb); curl_multi_setopt(multi, CURLMOPT_NOTIFYDATA, &setup); curl_multi_notify_enable(multi, CURLMNOTIFY_INFO_READ); } diff --git a/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md index 4091b1ae6841..0e10aa918787 100644 --- a/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md +++ b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md @@ -23,12 +23,12 @@ CURLMOPT_NOTIFYFUNCTION - callback receiving notifications ~~~c #include -void ntfy_callback(CURLM *multi, /* multi handle */ - unsigned int notification, /* notification type */ - CURL *easy, /* easy handle */ - void *ntfyp); /* private ntfy pointer */ +void notify_callback(CURLM *multi, /* multi handle */ + unsigned int notification, /* notification type */ + CURL *easy, /* easy handle */ + void *notifyp); /* private notify pointer */ -CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_NOTIFYFUNCTION, ntfy_callback); +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_NOTIFYFUNCTION, notify_callback); ~~~ # DESCRIPTION @@ -89,7 +89,7 @@ an internal handle when DoH or other features are used. *easy* identifies the transfer involved. This may be one of the application's own easy handle or an internal handle. -**ntfyp** is set with CURLMOPT_NOTIFYDATA(3). +**notifyp** is set with CURLMOPT_NOTIFYDATA(3). # DEFAULT @@ -104,10 +104,10 @@ struct priv { void *ours; }; -static void ntfy_cb(CURLM *multi, unsigned int notification, - CURL *easy, void *ntfyp) +static void notify_cb(CURLM *multi, unsigned int notification, + CURL *easy, void *notifyp) { - struct priv *p = ntfyp; + struct priv *p = notifyp; printf("my ptr: %p\n", p->ours); /* ... */ } @@ -117,7 +117,7 @@ int main(void) struct priv setup; CURLM *multi = curl_multi_init(); /* ... use socket callback and custom pointer */ - curl_multi_setopt(multi, CURLMOPT_NOTIFYFUNCTION, ntfy_cb); + curl_multi_setopt(multi, CURLMOPT_NOTIFYFUNCTION, notify_cb); curl_multi_setopt(multi, CURLMOPT_NOTIFYDATA, &setup); curl_multi_notify_enable(multi, CURLMNOTIFY_INFO_READ); } diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index de2cfb715a67..063cea57e6f2 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -208,9 +208,9 @@ if(curlcheck_charpp_option(option)) \ if(!curlcheck_ptrptr(value, char)) \ Wcurl_multi_setopt_err_charpp(); \ - if((option) == CURLMOPT_NOTIFYFUNCTION) \ - if(!curlcheck_multintfy_cb(value)) \ - Wcurl_multi_setopt_err_ntfycb(); \ + if((option) == CURLMOPT_NOTIFYFUNCTION) \ + if(!curlcheck_multinotify_cb(value)) \ + Wcurl_multi_setopt_err_notifycb(); \ if((option) == CURLMOPT_PUSHFUNCTION) \ if(!curlcheck_multipush_cb(value)) \ Wcurl_multi_setopt_err_pushcb(); \ @@ -227,7 +227,7 @@ /* evaluates to true if the option takes a data argument to pass to a callback */ #define curlcheck_multicb_data_option(option) \ - ((option) == CURLMOPT_NOTIFYDATA || \ + ((option) == CURLMOPT_NOTIFYDATA || \ (option) == CURLMOPT_PUSHDATA || \ (option) == CURLMOPT_SOCKETDATA || \ (option) == CURLMOPT_TIMERDATA || \ @@ -250,13 +250,13 @@ curlcheck_cb_compatible((expr), curl_socket_callback)) /* evaluates to true if expr is of type curl_push_callback */ -#define curlcheck_multipush_cb(expr) \ - (curlcheck_NULL(expr) || \ +#define curlcheck_multipush_cb(expr) \ + (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_push_callback)) /* evaluates to true if expr is of type curl_push_callback */ -#define curlcheck_multintfy_cb(expr) \ - (curlcheck_NULL(expr) || \ +#define curlcheck_multinotify_cb(expr) \ + (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_notify_callback)) /* @@ -284,7 +284,7 @@ CURLWARNING(Wcurl_multi_setopt_err_charpp, "curl_multi_setopt expects a 'char **' argument") CURLWARNING(Wcurl_multi_setopt_err_pushcb, "curl_multi_setopt expects a curl_push_callback argument") -CURLWARNING(Wcurl_multi_setopt_err_ntfycb, +CURLWARNING(Wcurl_multi_setopt_err_notifycb, "curl_multi_setopt expects a curl_notify_callback argument") CURLWARNING(Wcurl_multi_setopt_err_socketcb, "curl_multi_setopt expects a curl_socket_callback argument") @@ -392,16 +392,16 @@ CURLWARNING(Wcurl_easy_getinfo_err_curl_off_t, /* groups of curl_easy_setops options that take the same type of argument */ /* evaluates to true if option takes a long argument */ -#define curlcheck_long_option(option) \ +#define curlcheck_long_option(option) \ (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) #define curlcheck_off_t_option(option) \ (((option) > CURLOPTTYPE_OFF_T) && ((option) < CURLOPTTYPE_BLOB)) /* option takes a CURL * argument */ -#define curlcheck_curl_option(option) \ - ((option) == CURLOPT_STREAM_DEPENDS || \ - (option) == CURLOPT_STREAM_DEPENDS_E || \ +#define curlcheck_curl_option(option) \ + ((option) == CURLOPT_STREAM_DEPENDS || \ + (option) == CURLOPT_STREAM_DEPENDS_E || \ 0) /* evaluates to true if option takes a char* argument */ @@ -684,7 +684,7 @@ CURLWARNING(Wcurl_easy_getinfo_err_curl_off_t, (curlcheck_ptr((expr), void) || \ curlcheck_ptr((expr), FILE)) #else /* be less strict */ -#define curlcheck_cb_data(expr) \ +#define curlcheck_cb_data(expr) \ curlcheck_any_ptr(expr) #endif From 1103ccb73e316ee830c9dbfe95218974a32418a3 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 7 Oct 2025 20:30:06 +0200 Subject: [PATCH 338/465] examples/sessioninfo: cast printf string mask length to int Found via `-Wformat-signedness`: ``` docs/examples/sessioninfo.c: In function 'wrfu': docs/examples/sessioninfo.c:75:53: error: field precision specifier '.*' expects argument of type 'int', but argument 4 has type 'unsigned int' [-Werror=format=] fprintf(stderr, "Certificate #%u: %.*s", i, dn.size, dn.data); ^ ``` Ref: https://github.com/curl/curl/actions/runs/18320729052/job/52172864438?pr=18343#step:13:30 Ref: https://github.com/curl/curl/actions/runs/18320729095/job/52172886899?pr=18343#step:19:27 Also: - drop unnecessary parenthesis. - scope variables. Ref: #18343 Closes #18918 --- docs/examples/sessioninfo.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/examples/sessioninfo.c b/docs/examples/sessioninfo.c index b9b3a3c46296..ed5f0e9e292d 100644 --- a/docs/examples/sessioninfo.c +++ b/docs/examples/sessioninfo.c @@ -46,8 +46,6 @@ static CURL *curl; static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) { const struct curl_tlssessioninfo *info; - unsigned int cert_list_size; - const gnutls_datum_t *chainp; CURLcode res; (void)stream; @@ -56,11 +54,14 @@ static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) res = curl_easy_getinfo(curl, CURLINFO_TLS_SESSION, &info); if(!res) { + unsigned int cert_list_size; + const gnutls_datum_t *chainp; + switch(info->backend) { case CURLSSLBACKEND_GNUTLS: /* info->internals is now the gnutls_session_t */ chainp = gnutls_certificate_get_peers(info->internals, &cert_list_size); - if((chainp) && (cert_list_size)) { + if(chainp && cert_list_size) { unsigned int i; for(i = 0; i < cert_list_size; i++) { @@ -72,7 +73,8 @@ static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) gnutls_x509_crt_import(cert, &chainp[i], GNUTLS_X509_FMT_DER)) { if(GNUTLS_E_SUCCESS == gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &dn)) { - fprintf(stderr, "Certificate #%u: %.*s", i, dn.size, dn.data); + fprintf(stderr, "Certificate #%u: %.*s", i, + (int)dn.size, dn.data); gnutls_free(dn.data); } From 4bfd7a961521e1fd6aab7610e931d82a342781a8 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Tue, 7 Oct 2025 10:31:18 +0800 Subject: [PATCH 339/465] openssl: skip session resumption when verifystatus is set Resumed TLS sessions skip OCSP stapled-response verification. Force a full handshake so verifystatus() runs. Closes #18902 --- lib/vtls/openssl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 039eb51c9ad4..fb5cc1836230 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3727,6 +3727,7 @@ ossl_init_session_and_alpns(struct ossl_ctx *octx, Curl_ossl_init_session_reuse_cb *sess_reuse_cb) { struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + struct ssl_primary_config *conn_cfg = Curl_ssl_cf_get_primary_config(cf); struct alpn_spec alpns; char error_buffer[256]; CURLcode result; @@ -3734,7 +3735,7 @@ ossl_init_session_and_alpns(struct ossl_ctx *octx, Curl_alpn_copy(&alpns, alpns_requested); octx->reused_session = FALSE; - if(ssl_config->primary.cache_session) { + if(ssl_config->primary.cache_session && !conn_cfg->verifystatus) { struct Curl_ssl_session *scs = NULL; result = Curl_ssl_scache_take(cf, data, peer->scache_key, &scs); From 4e77388a0bb3ff06e8f6c17995aaf943a019462f Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Tue, 7 Oct 2025 13:59:09 +0800 Subject: [PATCH 340/465] h3/nghttp3: return NGHTTP3_ERR_CALLBACK_FAILURE from recv_header Closes #18904 --- lib/vquic/curl_ngtcp2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index b48d1af555ac..0254f594efcf 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -1142,7 +1142,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid, result = Curl_http_decode_status(&stream->status_code, (const char *)h3val.base, h3val.len); if(result) - return -1; + return NGHTTP3_ERR_CALLBACK_FAILURE; curlx_dyn_reset(&ctx->scratch); result = curlx_dyn_addn(&ctx->scratch, STRCONST("HTTP/3 ")); if(!result) @@ -1156,7 +1156,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid, CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] status: %s", stream_id, curlx_dyn_ptr(&ctx->scratch)); if(result) { - return -1; + return NGHTTP3_ERR_CALLBACK_FAILURE; } } else { From 38ab421f60f79f8dfd85f24a03c358a7a8431018 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Tue, 7 Oct 2025 13:59:29 +0800 Subject: [PATCH 341/465] h3/ngtcp2: close just-opened QUIC stream when submit_request fails Closes #18904 --- lib/vquic/curl_ngtcp2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 0254f594efcf..68f346af780a 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -1607,6 +1607,7 @@ static CURLcode h3_stream_open(struct Curl_cfilter *cf, "%d (%s)", stream->id, rc, nghttp3_strerror(rc)); break; } + cf_ngtcp2_stream_close(cf, data, stream); result = CURLE_SEND_ERROR; goto out; } From ab761794c1e6d124cd7c6dd2b337d7c433c1774e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 03:09:23 +0200 Subject: [PATCH 342/465] tests/server: drop pointless memory allocation overrides The code was overriding system memory allocation functions to a local jump table (declared in `curl_setup.h`). And setup that jump table to call the original system allocation functions. Also tested fine with cegcc/WinCE. The `_strdup` fallback was possibly required for an MSVC WinCE toolchain. Closes #18922 --- tests/server/Makefile.inc | 2 +- tests/server/memptr.c | 47 --------------------------------------- 2 files changed, 1 insertion(+), 48 deletions(-) delete mode 100644 tests/server/memptr.c diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index bbdacc1a17b9..c335e885b255 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -30,7 +30,7 @@ FIRST_C = first.c FIRST_H = first.h # Common files used by test programs -UTILS_C = memptr.c getpart.c util.c +UTILS_C = getpart.c util.c UTILS_H = CURLX_C = \ diff --git a/tests/server/memptr.c b/tests/server/memptr.c deleted file mode 100644 index 247bbf13ab81..000000000000 --- a/tests/server/memptr.c +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * 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 "curl_memory.h" - -#ifdef UNDER_CE -#define system_strdup _strdup -#else -#define system_strdup strdup -#endif - -#if defined(_MSC_VER) && defined(_DLL) -# pragma warning(push) -# pragma warning(disable:4232) /* MSVC extension, dllimport identity */ -#endif - -curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc; -curl_free_callback Curl_cfree = (curl_free_callback)free; -curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; -curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; -curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; - -#if defined(_MSC_VER) && defined(_DLL) -# pragma warning(pop) -#endif From 82fd9edb0e0313f206b23f90a000164b52412072 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 11:15:13 +0200 Subject: [PATCH 343/465] INSTALL-CMAKE.md: document useful build targets Closes #18927 --- docs/INSTALL-CMAKE.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index 4c7875252198..071c89888296 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -499,6 +499,26 @@ the feature detection is performed. Note: These variables are internal and subject to change. +## Useful build targets + +- `testdeps`: Build test dependencies (servers, tools, test certificates). + Individual targets: `curlinfo`, `libtests`, `servers`, `tunits`, `units` + Test certificates: `build-certs`, `clean-certs` +- `tests`: Run tests (`runtests.pl`). Customize via the `TFLAGS` environment variable, e.g. `TFLAGS=1621`. + Other flavors: `test-am`, `test-ci`, `test-event`, `test-full`, `test-nonflaky`, `test-quiet`, `test-torture` +- `curl-pytest`: Run tests (pytest). + Other flavor: `curl-test-ci` +- `curl-examples`: Build examples + Individual targets: `curl-example-`, + where is the .c filename without extension. +- `curl-examples-build`: Build examples quickly but without the ability to run them (for build tests) +- `curl-man`: Build man pages (built by default unless disabled) +- `curl_uninstall`: Uninstall curl +- `curl-completion-fish`: Build shell completions for fish (built by default if enabled) +- `curl-completion-zsh`: Build shell completions for zsh (built by default if enabled) +- `curl-ca-bundle`: Build the CA bundle via `scripts/mk-ca-bundle.pl` +- `curl-ca-firefox`: Build the CA bundle via `scritps/firefox-db2pem.sh` + # Migrating from Visual Studio IDE Project Files We recommend using CMake to build curl with MSVC. From 0b54ce6ffc395148f2c43ce4664ecd9678f822bd Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 13:37:29 +0200 Subject: [PATCH 344/465] INSTALL-CMAKE.md: fix typo in prev Not caught in original PR. Fixing it in CI separately. Follow-up 82fd9edb0e0313f206b23f90a000164b52412072 #18927 --- docs/INSTALL-CMAKE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index 071c89888296..a0430bbfa406 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -517,7 +517,7 @@ Note: These variables are internal and subject to change. - `curl-completion-fish`: Build shell completions for fish (built by default if enabled) - `curl-completion-zsh`: Build shell completions for zsh (built by default if enabled) - `curl-ca-bundle`: Build the CA bundle via `scripts/mk-ca-bundle.pl` -- `curl-ca-firefox`: Build the CA bundle via `scritps/firefox-db2pem.sh` +- `curl-ca-firefox`: Build the CA bundle via `scripts/firefox-db2pem.sh` # Migrating from Visual Studio IDE Project Files From 3800a26582af8b355e96cf80135ba7642e816ed6 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 13:41:50 +0200 Subject: [PATCH 345/465] GHA/checksrc: also run on .md file changes To avoid missing e.g. codespell issue when updating Markdown files only, as in 82fd9edb0e0313f206b23f90a000164b52412072 #18927 Follow-up to 0b54ce6ffc395148f2c43ce4664ecd9678f822bd Closes #18935 --- .github/workflows/checksrc.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index 4ea1961412d0..a0337904f2c7 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -12,7 +12,6 @@ name: 'Source' - master - '*/ci' paths-ignore: - - '**/*.md' - '.circleci/**' - 'appveyor.*' - 'Dockerfile' @@ -22,7 +21,6 @@ name: 'Source' branches: - master paths-ignore: - - '**/*.md' - '.circleci/**' - 'appveyor.*' - 'Dockerfile' From 6a31e3137a1352aec528d768dee8d5a1c509f451 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 14:36:22 +0200 Subject: [PATCH 346/465] GHA/dependabot: find more pip deps, tweak commit prefix Before this patch the Dependabot updater was only picking up `tests/requirements.txt`: https://github.com/curl/curl/network/updates/26616523/jobs Also prefix commit messages with `GHA:`. Bug: https://github.com/curl/curl/pull/18761#issuecomment-3381147189 Follow-up to b04137c1c6ed164594279c7d04b5e051634453ea #18761 Closes #18939 --- .github/dependabot.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a21592ee3e48..858b99e8e851 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,8 +8,15 @@ updates: directory: '/' schedule: interval: 'monthly' + commit-message: + prefix: 'GHA:' - package-ecosystem: 'pip' - directory: '/' + directories: + - '/.github/scripts' + - '/tests' + - '/tests/http' schedule: interval: 'monthly' + commit-message: + prefix: 'GHA:' From c951fe7e6daadf545016900267ca990d6476786e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 14:50:58 +0200 Subject: [PATCH 347/465] GHA/dependabot: tweak dir list to avoid a dupe, rename .txt file to avoid the bot It correctly picked all pips, but also picked `tests/http/requirements.txt` twice and also `.github/scripts/codespell-ignore.txt`. Try avoid these issues with this patch. Follow-up to 6a31e3137a1352aec528d768dee8d5a1c509f451 #18939 Closes #18946 --- .github/dependabot.yml | 1 - .../scripts/{codespell-ignore.txt => codespell-ignore.words} | 0 .github/scripts/codespell.sh | 2 +- .github/scripts/typos.toml | 2 +- 4 files changed, 2 insertions(+), 3 deletions(-) rename .github/scripts/{codespell-ignore.txt => codespell-ignore.words} (100%) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 858b99e8e851..bd5661bea41a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,7 +15,6 @@ updates: directories: - '/.github/scripts' - '/tests' - - '/tests/http' schedule: interval: 'monthly' commit-message: diff --git a/.github/scripts/codespell-ignore.txt b/.github/scripts/codespell-ignore.words similarity index 100% rename from .github/scripts/codespell-ignore.txt rename to .github/scripts/codespell-ignore.words diff --git a/.github/scripts/codespell.sh b/.github/scripts/codespell.sh index b373a7d210cc..6825b38c7eaf 100755 --- a/.github/scripts/codespell.sh +++ b/.github/scripts/codespell.sh @@ -15,5 +15,5 @@ codespell \ --skip 'packages/*' \ --skip 'scripts/wcurl' \ --ignore-regex '.*spellchecker:disable-line' \ - --ignore-words '.github/scripts/codespell-ignore.txt' \ + --ignore-words '.github/scripts/codespell-ignore.words' \ $(git ls-files) diff --git a/.github/scripts/typos.toml b/.github/scripts/typos.toml index a84017cf5303..2be01d59f6a6 100644 --- a/.github/scripts/typos.toml +++ b/.github/scripts/typos.toml @@ -21,7 +21,7 @@ extend-ignore-re = [ [files] extend-exclude = [ - ".github/scripts/codespell-ignore.txt", + ".github/scripts/codespell-ignore.words", ".github/scripts/spellcheck.words", "docs/THANKS", "packages/*", From 29093f0ee832bbd65314f681429429e1840c6575 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 12:46:51 +0000 Subject: [PATCH 348/465] GHA: bump dependencies - cryptography from 44.0.1 to 46.0.2 in tests/http - ruff from 0.13.2 to 0.14.0 in .github/scripts - reuse from 6.0.0 to 6.1.2 in .github/scripts - github/codeql-action from 3.30.5 to 4.30.7 Closes #18941 Closes #18942 Closes #18943 Closes #18945 Closes #18947 --- .github/scripts/requirements.txt | 4 ++-- .github/workflows/codeql.yml | 8 ++++---- tests/http/requirements.txt | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index c20a74767376..4533b2cfd7d9 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,5 +5,5 @@ cmakelang==0.6.13 codespell==2.4.1 pytype==2024.10.11 -reuse==6.0.0 -ruff==0.13.2 +reuse==6.1.2 +ruff==0.14.0 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index da12e575abc9..cc882a51a376 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -48,13 +48,13 @@ jobs: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/init@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 with: languages: actions, python queries: security-extended - name: 'perform analysis' - uses: github/codeql-action/analyze@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/analyze@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 c: name: 'C' @@ -84,7 +84,7 @@ jobs: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/init@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 with: languages: cpp build-mode: manual @@ -130,4 +130,4 @@ jobs: fi - name: 'perform analysis' - uses: github/codeql-action/analyze@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5 + uses: github/codeql-action/analyze@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 diff --git a/tests/http/requirements.txt b/tests/http/requirements.txt index 6a98723ac208..3b81a2ca13b0 100644 --- a/tests/http/requirements.txt +++ b/tests/http/requirements.txt @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: curl -cryptography==44.0.1 +cryptography==46.0.2 filelock==3.19.1 psutil==7.1.0 pytest==8.4.2 From bbce304c0bd4405cb2f5e484bded366764b1306e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 13:33:19 +0200 Subject: [PATCH 349/465] GHA/linux-old: dump logs on configure failure As done in other jobs, but here tailored to old cmake. The logs generated by ancient CMake aren't super useful though. Cherry-picked from #18932 Closes #18948 --- .github/workflows/linux-old.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index 5cb292cafcd5..c1415a981a73 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -89,6 +89,10 @@ jobs: VERBOSE=1 make install src/curl --disable --version + - name: 'cmake build-only configure log' + if: ${{ !cancelled() }} + run: cat bld-1/CMakeFiles/CMake*.log 2>/dev/null || true + - name: 'cmake build-only curl_config.h' run: | echo '::group::raw'; cat bld-1/lib/curl_config.h || true; echo '::endgroup::' @@ -104,6 +108,10 @@ jobs: -DCURL_USE_GNUTLS=ON -DENABLE_ARES=ON -DCURL_USE_GSSAPI=ON -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=OFF -DUSE_LIBRTMP=ON \ -DCURL_LIBCURL_VERSIONED_SYMBOLS=ON + - name: 'cmake configure log' + if: ${{ !cancelled() }} + run: cat bld-cares/CMakeFiles/CMake*.log 2>/dev/null || true + - name: 'cmake curl_config.h' run: | echo '::group::raw'; cat bld-cares/lib/curl_config.h || true; echo '::endgroup::' @@ -137,6 +145,10 @@ jobs: --with-gnutls --enable-ares --without-libssh2 --with-zstd --with-gssapi --with-librtmp \ --prefix="$PWD"/../curl-install-am + - name: 'autotools configure log' + if: ${{ !cancelled() }} + run: cat bld-am/config.log 2>/dev/null || true + - name: 'autotools curl_config.h' run: | echo '::group::raw'; cat bld-am/lib/curl_config.h || true; echo '::endgroup::' From 1f112242323848d0ebfc88ae97b139d18e7987f6 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 18:49:51 +0200 Subject: [PATCH 350/465] cmake/FindGSS: fix `pkg-config` fallback logic for CMake <3.16 The documented `__VERSION` variables are empty in all tested versions since 3.7.2 to 4.1.2. Stop using it as a fallback for <3.16 versions, and replace with the undocumented, but working, `FindPkgConfig` internal variable `_pkg_check_modules_pkg_name`. It contains the module name which was found. In practice it caused that with CMake <3.16 + `pkg-config`, curl always detected the Heimdal flavor of GSS. Also: Delete a fallback version detection method, which was already marked with a question mark in comments, and used the same, always empty, CMake variables. Ref: https://cmake.org/cmake/help/v4.1/module/FindPkgConfig.html Bug: https://github.com/curl/curl/pull/18932#issuecomment-3381807070 Closes #18950 --- CMake/FindGSS.cmake | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index 78a9194cd604..aa640c3342ad 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -277,25 +277,17 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr endif() endif() else() - # _gss_MODULE_NAME set since CMake 3.16 - if(_gss_MODULE_NAME STREQUAL _gnu_modname OR _gss_${_gnu_modname}_VERSION) + # _gss_MODULE_NAME set since CMake 3.16. + # _pkg_check_modules_pkg_name is undocumented and used as a fallback for CMake <3.16 versions. + if(_gss_MODULE_NAME STREQUAL _gnu_modname OR _pkg_check_modules_pkg_name STREQUAL _gnu_modname) set(GSS_FLAVOUR "GNU") set(GSS_PC_REQUIRES "gss") - if(NOT _gss_version) # for old CMake versions? - set(_gss_version ${_gss_${_gnu_modname}_VERSION}) - endif() - elseif(_gss_MODULE_NAME STREQUAL _mit_modname OR _gss_${_mit_modname}_VERSION) + elseif(_gss_MODULE_NAME STREQUAL _mit_modname OR _pkg_check_modules_pkg_name STREQUAL _mit_modname) set(GSS_FLAVOUR "MIT") set(GSS_PC_REQUIRES "mit-krb5-gssapi") - if(NOT _gss_version) # for old CMake versions? - set(_gss_version ${_gss_${_mit_modname}_VERSION}) - endif() else() set(GSS_FLAVOUR "Heimdal") set(GSS_PC_REQUIRES "heimdal-gssapi") - if(NOT _gss_version) # for old CMake versions? - set(_gss_version ${_gss_${_heimdal_modname}_VERSION}) - endif() endif() message(STATUS "Found GSS/${GSS_FLAVOUR} (via pkg-config): ${_gss_INCLUDE_DIRS} (found version \"${_gss_version}\")") endif() From ca789e09b53420dbc24ababec1ab44c88618f6d6 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 8 Oct 2025 14:44:23 +0200 Subject: [PATCH 351/465] wolfssl: no double get_error() detail Code was calling wolfSSL_get_error() on code that it had already retrieved with the same function. Remove that. Reported-by: Joshua Rogers Closes #18940 --- lib/vtls/wolfssl.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 6186ce985be7..d4a0e066fa03 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -1632,11 +1632,10 @@ static CURLcode wssl_send_earlydata(struct Curl_cfilter *cf, break; default: { char error_buffer[256]; - int detail = wolfSSL_get_error(wssl->ssl, err); CURL_TRC_CF(data, cf, "SSL send early data, error: '%s'(%d)", wssl_strerror((unsigned long)err, error_buffer, sizeof(error_buffer)), - detail); + err); result = CURLE_SEND_ERROR; break; } @@ -1878,7 +1877,6 @@ static CURLcode wssl_shutdown(struct Curl_cfilter *cf, char error_buffer[256]; int nread = -1, err; size_t i; - int detail; DEBUGASSERT(wctx); if(!wctx->ssl || cf->shutdown) { @@ -1959,11 +1957,10 @@ static CURLcode wssl_shutdown(struct Curl_cfilter *cf, connssl->io_need = CURL_SSL_IO_NEED_SEND; break; default: - detail = wolfSSL_get_error(wctx->ssl, err); CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s'(%d)", wssl_strerror((unsigned long)err, error_buffer, sizeof(error_buffer)), - detail); + err); result = CURLE_RECV_ERROR; break; } From 0f02744c41fa4da0f25091dcce5c1e9e0c2220b5 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 8 Oct 2025 11:56:09 +0200 Subject: [PATCH 352/465] apple sectrust: check correct result on old OS versions On ancient Apple OS versions where SecTrustEvaluateWithError() is not available, the deprected SecTrustEvaluate() is used. In that code branch, the code checked the wong variable for the verified result. Closes #18929 --- lib/vtls/apple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vtls/apple.c b/lib/vtls/apple.c index b565c8f031e1..c96ebe037bc6 100644 --- a/lib/vtls/apple.c +++ b/lib/vtls/apple.c @@ -267,8 +267,8 @@ CURLcode Curl_vtls_apple_verify(struct Curl_cfilter *cf, if(status != noErr) { failf(data, "Apple SecTrust verification failed: error %i", (int)status); } - else if((status == kSecTrustResultUnspecified) || - (status == kSecTrustResultProceed)) { + else if((sec_result == kSecTrustResultUnspecified) || + (sec_result == kSecTrustResultProceed)) { /* "unspecified" means system-trusted with no explicit user setting */ result = CURLE_OK; } From 008078fc38991dcb5cfbf4b850f9acbf832dc618 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 8 Oct 2025 08:33:55 +0200 Subject: [PATCH 353/465] http: make Content-Length parser more WHATWG Return error if there is something after the number other than whitespace and newline. Allow comma separated numbers and repeated headers as long as the new value is the same as was set before. Add test 767 to 771 to verify. Reported-by: Ignat Loskutov Fixes #18921 Closes #18925 --- lib/http.c | 61 +++++++++++++++++++++++++++--------------- tests/data/Makefile.am | 2 +- tests/data/test767 | 58 +++++++++++++++++++++++++++++++++++++++ tests/data/test768 | 57 +++++++++++++++++++++++++++++++++++++++ tests/data/test769 | 53 ++++++++++++++++++++++++++++++++++++ tests/data/test770 | 58 +++++++++++++++++++++++++++++++++++++++ tests/data/test771 | 57 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 324 insertions(+), 22 deletions(-) create mode 100644 tests/data/test767 create mode 100644 tests/data/test768 create mode 100644 tests/data/test769 create mode 100644 tests/data/test770 create mode 100644 tests/data/test771 diff --git a/lib/http.c b/lib/http.c index aea19d5167f5..6b1538a737e9 100644 --- a/lib/http.c +++ b/lib/http.c @@ -519,6 +519,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data, /* We decided to abort the ongoing transfer */ streamclose(conn, "Mid-auth HTTP and much data left to send"); data->req.size = 0; /* do not download any more than 0 bytes */ + data->req.http_bodyless = TRUE; } return CURLE_OK; } @@ -3118,32 +3119,50 @@ static CURLcode http_header_c(struct Curl_easy *data, struct SingleRequest *k = &data->req; const char *v; - /* Check for Content-Length: header lines to get size */ + /* Check for Content-Length: header lines to get size. Browsers insist we + should accept multiple Content-Length headers and that a comma separated + list also is fine and then we should accept them all as long as they are + the same value. Different values trigger error. + */ v = (!k->http_bodyless && !data->set.ignorecl) ? HD_VAL(hd, hdlen, "Content-Length:") : NULL; if(v) { - curl_off_t contentlength; - int offt = curlx_str_numblanks(&v, &contentlength); + do { + curl_off_t contentlength; + int offt = curlx_str_numblanks(&v, &contentlength); + + if(offt == STRE_OVERFLOW) { + /* out of range */ + if(data->set.max_filesize) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; + } + streamclose(conn, "overflow content-length"); + infof(data, "Overflow Content-Length: value"); + return CURLE_OK; + } + else { + if((offt == STRE_OK) && + ((k->size == -1) || /* not set to something before */ + (k->size == contentlength))) { /* or the same value */ - if(offt == STRE_OK) { - k->size = contentlength; - k->maxdownload = k->size; - } - else if(offt == STRE_OVERFLOW) { - /* out of range */ - if(data->set.max_filesize) { - failf(data, "Maximum file size exceeded"); - return CURLE_FILESIZE_EXCEEDED; + k->size = contentlength; + curlx_str_passblanks(&v); + + /* on a comma, loop and get the next instead */ + if(!curlx_str_single(&v, ',')) + continue; + + if(!curlx_str_newline(&v)) { + k->maxdownload = k->size; + return CURLE_OK; + } + } + /* negative, different value or just rubbish - bad HTTP */ + failf(data, "Invalid Content-Length: value"); + return CURLE_WEIRD_SERVER_REPLY; } - streamclose(conn, "overflow content-length"); - infof(data, "Overflow Content-Length: value"); - } - else { - /* negative or just rubbish - bad HTTP */ - failf(data, "Invalid Content-Length: value"); - return CURLE_WEIRD_SERVER_REPLY; - } - return CURLE_OK; + } while(1); } v = (!k->http_bodyless && data->set.str[STRING_ENCODING]) ? HD_VAL(hd, hdlen, "Content-Encoding:") : NULL; diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 0d2d47c99ab5..11d9fb7cff35 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -109,7 +109,7 @@ 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 test758 test759 test760 test761 test762 \ -test763 test764 test765 test766 \ +test763 test764 test765 test766 test767 test768 test769 test770 test771 \ \ test780 test781 test782 test783 test784 test785 test786 test787 test788 \ test789 test790 test791 test792 test793 test794 test796 test797 \ diff --git a/tests/data/test767 b/tests/data/test767 new file mode 100644 index 000000000000..0927be4f1b3f --- /dev/null +++ b/tests/data/test767 @@ -0,0 +1,58 @@ + + + +HTTP +HTTP GET + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 6 +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + +# +# Client-side + + +http + + +HTTP with two Content-Length response header fields same size + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + +Allocations: 135 +Maximum allocated: 136000 + + + diff --git a/tests/data/test768 b/tests/data/test768 new file mode 100644 index 000000000000..ced4353c30f4 --- /dev/null +++ b/tests/data/test768 @@ -0,0 +1,57 @@ + + + +HTTP +HTTP GET + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 6badness +Content-Length: 44 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + +# +# Client-side + + +http + + +HTTP with letters after the number in Content-Length + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + +8 + + + diff --git a/tests/data/test769 b/tests/data/test769 new file mode 100644 index 000000000000..773d741e3fee --- /dev/null +++ b/tests/data/test769 @@ -0,0 +1,53 @@ + + + +HTTP +HTTP GET + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + +# +# Client-side + + +http + + +HTTP with space after Content-Length number + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + + diff --git a/tests/data/test770 b/tests/data/test770 new file mode 100644 index 000000000000..98e3850c4c43 --- /dev/null +++ b/tests/data/test770 @@ -0,0 +1,58 @@ + + + +HTTP +HTTP GET + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 6,06,6 +Content-Length: 6, 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + +# +# Client-side + + +http + + +HTTP with Content-Length headers using comma separated list + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + +Allocations: 135 +Maximum allocated: 136000 + + + diff --git a/tests/data/test771 b/tests/data/test771 new file mode 100644 index 000000000000..b57c87c88bfc --- /dev/null +++ b/tests/data/test771 @@ -0,0 +1,57 @@ + + + +HTTP +HTTP GET + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 44 +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + +# +# Client-side + + +http + + +HTTP with two Content-Length headers using different sizes + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + +8 + + + From e4645c86b5d0692c6fc4aa413eeeefe601da0aed Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 8 Oct 2025 07:58:16 +0200 Subject: [PATCH 354/465] CURLOPT_COOKIEFILE.md: clarify when the cookies are loaded Closes #18924 --- docs/libcurl/opts/CURLOPT_COOKIEFILE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/libcurl/opts/CURLOPT_COOKIEFILE.md b/docs/libcurl/opts/CURLOPT_COOKIEFILE.md index 676d72855260..a4baf8febf46 100644 --- a/docs/libcurl/opts/CURLOPT_COOKIEFILE.md +++ b/docs/libcurl/opts/CURLOPT_COOKIEFILE.md @@ -55,6 +55,9 @@ If you use this option multiple times, you add more files to read cookies from. Setting this option to NULL disables the cookie engine and clears the list of files to read cookies from. +The cookies are loaded from the specified file(s) when the transfer starts, +not when this option is set. + # SECURITY CONCERNS This document previously mentioned how specifying a non-existing file can also From d58b6009df5eb6e946423b33ce3dc10fa3f5a37f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 8 Oct 2025 23:35:37 +0200 Subject: [PATCH 355/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 62 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 846340aee1da..d80ceae5fc26 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -3,14 +3,15 @@ curl and libcurl 8.17.0 Public curl releases: 271 Command line options: 273 curl_easy_setopt() options: 308 - Public functions in libcurl: 98 - Contributors: 3514 + Public functions in libcurl: 100 + Contributors: 3515 This release includes the following changes: o build: drop the winbuild build system [81] o krb5: drop support for Kerberos FTP [43] o libssh2: up the minimum requirement to 1.9.0 [85] + o multi: add notifications API [250] o progress: expand to use 6 characters per size [234] o ssl: support Apple SecTrust configurations [240] o tool_getparam: add --knownhosts [204] @@ -47,10 +48,13 @@ This release includes the following bugfixes: o checksrc: fix possible endless loops/errors in the banned function logic [220] o checksrc: fix to handle `)` predecing a banned function [229] o checksrc: reduce directory-specific exceptions [228] + o cmake/FindGSS: fix `pkg-config` fallback logic for CMake <3.16 [189] o cmake: add `CURL_CODE_COVERAGE` option [78] + o cmake: build the "all" examples source list dynamically [245] o cmake: clang detection tidy-ups [116] o cmake: drop exclamation in comment looking like a name [160] o cmake: fix building docs when the base directory contains `.3` [18] + o cmake: support building some complicated examples, build them in CI [235] o cmake: use modern alternatives for `get_filename_component()` [102] o cmake: use more `COMPILER_OPTIONS`, `LINK_OPTIONS` / `LINK_FLAGS` [152] o cmdline-docs: extended, clarified, refreshed [28] @@ -63,6 +67,7 @@ This release includes the following bugfixes: o curl_osslq: error out properly if BIO_ADDR_rawmake() fails [184] o curl_slist_append.md: clarify that a NULL pointer is not acceptable [72] o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] + o CURLOPT_COOKIEFILE.md: clarify when the cookies are loaded [159] o CURLOPT_HEADER/WRITEFUNCTION.md: drop '* size' since size is always 1 [63] o CURLOPT_MAXLIFETIME_CONN: make default 24 hours [10] o CURLOPT_SSL_VERIFYHOST.md: add see-also to two other VERIFYHOST options [32] @@ -75,7 +80,11 @@ This release includes the following bugfixes: o docs/libcurl: use lowercase must [5] o docs: fix/tidy code fences [87] o easy_getinfo: check magic, Curl_close safety [3] + o examples/sessioninfo: cast printf string mask length to int [232] + o examples/synctime: make the sscanf not overflow the local buffer [252] + o examples/usercertinmem: avoid stripping const [247] o examples: drop unused `curl/mprintf.h` includes [224] + o examples: fix build issues in 'complicated' examples [243] o examples: fix two build issues surfaced with WinCE [223] o examples: fix two issues found by CodeQL [35] o examples: fix two more cases of `stat()` TOCTOU [147] @@ -89,7 +98,9 @@ This release includes the following bugfixes: o gtls: avoid potential use of uninitialized variable in trace output [83] o hostip: remove leftover INT_MAX check in Curl_dnscache_prune [88] o http: handle user-defined connection headers [165] + o http: make Content-Length parser more WHATWG [183] o httpsrr: free old pointers when storing new [57] + o INSTALL-CMAKE.md: document useful build targets [215] o INTERNALS: drop Winsock 2.2 from the dependency list [162] o INTERNALS: specify minimum version for Heimdal: 7.1.0 [158] o ip-happy: do not set unnecessary timeout [95] @@ -129,8 +140,13 @@ This release includes the following bugfixes: o mdlinkcheck: reject URLs containing quotes [174] o multi.h: add CURLMINFO_LASTENTRY [51] o multi_ev: remove unnecessary data check that confuses analysers [167] + o nghttp3: return NGHTTP3_ERR_CALLBACK_FAILURE from recv_header [227] o ngtcp2: check error code on connect failure [13] + o ngtcp2: close just-opened QUIC stream when submit_request fails [222] + o ngtcp2: compare idle timeout in ms to avoid overflow [248] o ngtcp2: fix early return [131] + o ngtcp2: fix handling of blocked stream data [236] + o ngtcp2: fix returns when TLS verify failed [251] o noproxy: fix the IPV6 network mask pattern match [166] o openldap: avoid indexing the result at -1 for blank responses [44] o openldap: check ber_sockbuf_add_io() return code [163] @@ -144,7 +160,9 @@ This release includes the following bugfixes: o openssl: fix build for v1.0.2 [225] o openssl: make the asn1_object_dump name null terminated [56] o openssl: set io_need always [99] + o openssl: skip session resumption when verifystatus is set [230] o OS400: fix a use-after-free/double-free case [142] + o osslq: set idle timeout to 0 [237] o pingpong: remove two old leftover debug infof() calls o pytest: skip specific tests for no-verbose builds [171] o quic: fix min TLS version handling [14] @@ -165,6 +183,7 @@ This release includes the following bugfixes: o smb: adjust buffer size checks [45] o smtp: check EHLO responses case insensitively [50] o socks: handle error in verbose trace gracefully [94] + o socks: handle premature close [246] o socks: make Curl_blockread_all return CURLcode [67] o socks: rewwork, cleaning up socks state handling [135] o socks_gssapi: make the gss_context a local variable [144] @@ -187,6 +206,7 @@ This release includes the following bugfixes: o telnet: return error on crazy TTYPE or XDISPLOC lengths [123] o telnet: send failure logged but not returned [175] o telnet: use pointer[0] for "unknown" option instead of pointer[i] [217] + o tests/server: drop pointless memory allocation overrides [219] o tests/server: drop unsafe `open()` override in signal handler (Windows) [151] o tftp: check and act on tftp_set_timeouts() returning error [38] o tftp: default timeout per block is now 15 seconds [156] @@ -220,6 +240,7 @@ This release includes the following bugfixes: o unit1664: drop casts, expand masks to full values [221] o url: make Curl_init_userdefined return void [213] o urldata: FILE is not a list-only protocol [9] + o vquic: fix idle-timeout checks (ms<-->ns), 64-bit log & honor 0=no-timeout [249] o vquic: handling of io improvements [239] o vtls: alpn setting, check proto parameter [134] o vtls_int.h: clarify data_pending [124] @@ -230,6 +251,7 @@ This release includes the following bugfixes: o windows: use native error code types more [206] o wolfssl: check BIO read parameters [133] o wolfssl: fix error check in shutdown [105] + o wolfssl: no double get_error() detail [188] o ws: clarify an error message [125] o ws: reject curl_ws_recv called with NULL buffer with a buflen [118] @@ -259,13 +281,13 @@ advice from friends like these: BobodevMm on github, Christian Schmitz, Dan Fandrich, Daniel Stenberg, Daniel Terhorst-North, dependabot[bot], divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, Evgeny Grin (Karlson2k), - fds242 on github, Howard Chu, Javier Blazquez, Jicea, jmaggard10 on github, - Johannes Schindelin, Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, - kuchara on github, Marcel Raad, Michael Osipov, MichaÅ‚ Petryka, - Mohamed Daahir, Nir Azkiel, Patrick Monnerat, Pocs Norbert, Ray Satiro, - renovate[bot], rinsuki on github, Samuel Dionne-Riel, Samuel Henrique, - Stanislav Fort, Stefan Eissing, Viktor Szakats - (39 contributors) + fds242 on github, Howard Chu, Ignat Loskutov, Javier Blazquez, Jicea, + jmaggard10 on github, Johannes Schindelin, Joseph Birr-Pixton, Joshua Rogers, + kapsiR on github, kuchara on github, Marcel Raad, Michael Osipov, + MichaÅ‚ Petryka, Mohamed Daahir, Nir Azkiel, Patrick Monnerat, Pocs Norbert, + Ray Satiro, renovate[bot], rinsuki on github, Samuel Dionne-Riel, + Samuel Henrique, Stanislav Fort, Stefan Eissing, Viktor Szakats + (40 contributors) References to bug reports and discussions on issues: @@ -427,6 +449,7 @@ References to bug reports and discussions on issues: [156] = https://curl.se/bug/?i=18893 [157] = https://curl.se/bug/?i=18806 [158] = https://curl.se/bug/?i=18809 + [159] = https://curl.se/bug/?i=18924 [160] = https://curl.se/bug/?i=18810 [161] = https://curl.se/bug/?i=18749 [162] = https://curl.se/bug/?i=18808 @@ -450,9 +473,12 @@ References to bug reports and discussions on issues: [180] = https://curl.se/bug/?i=18886 [181] = https://curl.se/bug/?i=18884 [182] = https://curl.se/bug/?i=18754 + [183] = https://curl.se/bug/?i=18921 [184] = https://curl.se/bug/?i=18878 [185] = https://curl.se/bug/?i=18875 [186] = https://curl.se/bug/?i=18874 + [188] = https://curl.se/bug/?i=18940 + [189] = https://curl.se/bug/?i=18932 [191] = https://curl.se/bug/?i=18888 [192] = https://curl.se/bug/?i=18873 [193] = https://curl.se/bug/?i=18871 @@ -473,19 +499,37 @@ References to bug reports and discussions on issues: [212] = https://curl.se/bug/?i=18858 [213] = https://curl.se/bug/?i=18855 [214] = https://curl.se/bug/?i=18857 + [215] = https://curl.se/bug/?i=18927 [216] = https://curl.se/bug/?i=18852 [217] = https://curl.se/bug/?i=18851 [218] = https://curl.se/bug/?i=18850 + [219] = https://curl.se/bug/?i=18922 [220] = https://curl.se/bug/?i=18845 [221] = https://curl.se/bug/?i=18838 + [222] = https://curl.se/bug/?i=18904 [223] = https://curl.se/bug/?i=18843 [224] = https://curl.se/bug/?i=18842 [225] = https://curl.se/bug/?i=18841 [226] = https://curl.se/bug/?i=18839 + [227] = https://curl.se/bug/?i=18904 [228] = https://curl.se/bug/?i=18823 [229] = https://curl.se/bug/?i=18836 + [230] = https://curl.se/bug/?i=18902 [231] = https://curl.se/bug/?i=18835 + [232] = https://curl.se/bug/?i=18918 [234] = https://curl.se/bug/?i=18828 + [235] = https://curl.se/bug/?i=18909 + [236] = https://curl.se/bug/?i=18905 + [237] = https://curl.se/bug/?i=18907 [238] = https://curl.se/bug/?i=18829 [239] = https://curl.se/bug/?i=18812 [240] = https://curl.se/bug/?i=18703 + [243] = https://curl.se/bug/?i=18914 + [245] = https://curl.se/bug/?i=18911 + [246] = https://curl.se/bug/?i=18883 + [247] = https://curl.se/bug/?i=18908 + [248] = https://curl.se/bug/?i=18903 + [249] = https://curl.se/bug/?i=18903 + [250] = https://curl.se/bug/?i=18432 + [251] = https://curl.se/bug/?i=18881 + [252] = https://curl.se/bug/?i=18890 From 7c021fd14af3a4558bab8cb256abac77ac6148de Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 21:40:07 +0200 Subject: [PATCH 356/465] cmake: minor Heimdal flavour detection fix Do not detect Heimdal if a single `H` character appears in the vendor string, require the full name: `Heimdal`. Cherry-picked from #18932 Closes #18951 --- CMake/FindGSS.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index aa640c3342ad..398e38aa987c 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -164,7 +164,7 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr if(_gss_configure_failed) set(GSS_FLAVOUR "Heimdal") # most probably, should not really matter else() - if(_gss_vendor MATCHES "H|heimdal") + if(_gss_vendor MATCHES "Heimdal|heimdal") set(GSS_FLAVOUR "Heimdal") else() set(GSS_FLAVOUR "MIT") From 9fe8ba5c275002da7deb26f3d549fdda8944cf82 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 19:07:03 +0200 Subject: [PATCH 357/465] GHA/linux-old: sync terminology with other jobs [ci skip] Cherry-picked from #18932 --- .github/workflows/linux-old.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index c1415a981a73..6c5b18c2cfcf 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -100,7 +100,7 @@ jobs: # when this job can get a libssh version 0.9.0 or later, this should get # that enabled again - - name: 'cmake generate (out-of-tree, c-ares, zstd, gssapi)' + - name: 'cmake configure (out-of-tree, c-ares, zstd, gssapi)' run: | mkdir bld-cares cd bld-cares @@ -137,7 +137,7 @@ jobs: - name: 'autoreconf' run: autoreconf -if - - name: 'configure (out-of-tree, c-ares, zstd, gssapi)' + - name: 'autotools configure (out-of-tree, c-ares, zstd, gssapi)' run: | mkdir bld-am cd bld-am From cd7b45a3bbec0b43e87a9483a0fc8a82abaae956 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 9 Oct 2025 01:34:37 +0200 Subject: [PATCH 358/465] cmake/FindGSS: whitespace/formatting Sync format more with the rest of the Find modules. Cherry-picked from #18932 Closes #18957 --- CMake/FindGSS.cmake | 80 ++++++++++----------------------------------- 1 file changed, 17 insertions(+), 63 deletions(-) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index 398e38aa987c..18c84556c09d 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -47,10 +47,7 @@ include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckTypeSize) -set(_gss_root_hints - "${GSS_ROOT_DIR}" - "$ENV{GSS_ROOT_DIR}" -) +set(_gss_root_hints "${GSS_ROOT_DIR}" "$ENV{GSS_ROOT_DIR}") set(_gss_CFLAGS "") set(_gss_LIBRARY_DIRS "") @@ -69,37 +66,22 @@ if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}") endif() if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional approach. - find_file(_gss_configure_script - NAMES - "krb5-config" - HINTS - ${_gss_root_hints} - PATH_SUFFIXES - "bin" - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - ) - + find_file(_gss_configure_script NAMES "krb5-config" PATH_SUFFIXES "bin" HINTS ${_gss_root_hints} + NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH) # If not found in user-supplied directories, maybe system knows better - find_file(_gss_configure_script - NAMES - "krb5-config" - PATH_SUFFIXES - "bin" - ) + find_file(_gss_configure_script NAMES "krb5-config" PATH_SUFFIXES "bin") if(_gss_configure_script) set(_gss_INCLUDE_DIRS "") set(_gss_LIBRARIES "") - execute_process( - COMMAND ${_gss_configure_script} "--cflags" "gssapi" + execute_process(COMMAND ${_gss_configure_script} "--cflags" "gssapi" OUTPUT_VARIABLE _gss_cflags_raw RESULT_VARIABLE _gss_configure_failed - OUTPUT_STRIP_TRAILING_WHITESPACE - ) + OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "FindGSS krb5-config --cflags: ${_gss_cflags_raw}") + if(NOT _gss_configure_failed) # 0 means success # Should also work in an odd case when multiple directories are given. string(STRIP "${_gss_cflags_raw}" _gss_cflags_raw) @@ -116,12 +98,10 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr endforeach() endif() - execute_process( - COMMAND ${_gss_configure_script} "--libs" "gssapi" + execute_process(COMMAND ${_gss_configure_script} "--libs" "gssapi" OUTPUT_VARIABLE _gss_lib_flags RESULT_VARIABLE _gss_configure_failed - OUTPUT_STRIP_TRAILING_WHITESPACE - ) + OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "FindGSS krb5-config --libs: ${_gss_lib_flags}") if(NOT _gss_configure_failed) # 0 means success @@ -141,24 +121,20 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr endforeach() endif() - execute_process( - COMMAND ${_gss_configure_script} "--version" + execute_process(COMMAND ${_gss_configure_script} "--version" OUTPUT_VARIABLE _gss_version RESULT_VARIABLE _gss_configure_failed - OUTPUT_STRIP_TRAILING_WHITESPACE - ) + OUTPUT_STRIP_TRAILING_WHITESPACE) # Older versions may not have the "--version" parameter. In this case we just do not care. if(_gss_configure_failed) set(_gss_version 0) endif() - execute_process( - COMMAND ${_gss_configure_script} "--vendor" + execute_process(COMMAND ${_gss_configure_script} "--vendor" OUTPUT_VARIABLE _gss_vendor RESULT_VARIABLE _gss_configure_failed - OUTPUT_STRIP_TRAILING_WHITESPACE - ) + OUTPUT_STRIP_TRAILING_WHITESPACE) # Older versions may not have the "--vendor" parameter. In this case we just do not care. if(_gss_configure_failed) @@ -173,13 +149,7 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr else() # Either there is no config script or we are on a platform that does not provide one (Windows?) - find_path(_gss_INCLUDE_DIRS NAMES "gssapi/gssapi.h" - HINTS - ${_gss_root_hints} - PATH_SUFFIXES - "include" - "inc" - ) + find_path(_gss_INCLUDE_DIRS NAMES "gssapi/gssapi.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include" "inc") if(_gss_INCLUDE_DIRS) # We have found something cmake_push_check_state() @@ -201,23 +171,12 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr cmake_pop_check_state() else() # I am not convinced if this is the right way but this is what autotools do at the moment - find_path(_gss_INCLUDE_DIRS NAMES "gssapi.h" - HINTS - ${_gss_root_hints} - PATH_SUFFIXES - "include" - "inc" - ) + find_path(_gss_INCLUDE_DIRS NAMES "gssapi.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include" "inc") if(_gss_INCLUDE_DIRS) set(GSS_FLAVOUR "Heimdal") else() - find_path(_gss_INCLUDE_DIRS NAMES "gss.h" - HINTS - ${_gss_root_hints} - PATH_SUFFIXES - "include" - ) + find_path(_gss_INCLUDE_DIRS NAMES "gss.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include") if(_gss_INCLUDE_DIRS) set(GSS_FLAVOUR "GNU") @@ -268,12 +227,7 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr endif() endif() - find_library(_gss_LIBRARIES NAMES ${_gss_libname} - HINTS - ${_gss_libdir_hints} - PATH_SUFFIXES - ${_gss_libdir_suffixes} - ) + find_library(_gss_LIBRARIES NAMES ${_gss_libname} HINTS ${_gss_libdir_hints} PATH_SUFFIXES ${_gss_libdir_suffixes}) endif() endif() else() From 8be9a26451d466571864a608bc48cc77746ff00d Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 8 Oct 2025 12:03:18 +0200 Subject: [PATCH 359/465] build: drop Heimdal support, update docs, replace with MIT Kerberos in CI The kerberos5 library Heimdal is one of three GSS libraries curl support. It has a memory leak triggered by the new test in #18917 and the project seems mostly abandoned. Drop support and steer users to the MIT krb5 or GNU GSS libraries. Co-authored-by: Daniel Stenberg Ref: #18928 Closes #18928 Closes #18932 --- .github/workflows/codeql.yml | 2 +- .github/workflows/linux-old.yml | 2 +- .github/workflows/linux.yml | 19 +++----- .github/workflows/macos.yml | 10 ++-- .github/workflows/non-native.yml | 6 +-- CMake/FindGSS.cmake | 80 ++++++++------------------------ CMakeLists.txt | 38 +++++++-------- RELEASE-NOTES | 2 - configure.ac | 17 ++----- docs/INSTALL-CMAKE.md | 2 +- docs/INTERNALS.md | 1 - docs/KNOWN_BUGS | 15 ------ docs/TODO | 4 +- 13 files changed, 62 insertions(+), 136 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index cc882a51a376..58eaa35be5ba 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -76,7 +76,7 @@ jobs: sudo apt-get -o Dpkg::Use-Pty=0 update sudo rm -f /var/lib/man-db/auto-update sudo apt-get -o Dpkg::Use-Pty=0 install libpsl-dev libbrotli-dev libidn2-dev libssh2-1-dev libssh-dev \ - libnghttp2-dev libldap-dev heimdal-dev librtmp-dev libgnutls28-dev libwolfssl-dev + libnghttp2-dev libldap-dev libkrb5-dev librtmp-dev libgnutls28-dev libwolfssl-dev HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install c-ares gsasl libnghttp3 libngtcp2 mbedtls rustls-ffi - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index 6c5b18c2cfcf..fde23de811c2 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -68,7 +68,7 @@ jobs: dpkg -i freexian-archive-keyring_2022.06.08_all.deb echo 'deb http://deb.freexian.com/extended-lts stretch-lts main contrib non-free' | tee /etc/apt/sources.list.d/extended-lts.list apt-get -o Dpkg::Use-Pty=0 update - apt-get -o Dpkg::Use-Pty=0 install -y --no-install-suggests --no-install-recommends cmake make automake autoconf libtool gcc pkg-config libpsl-dev libzstd-dev zlib1g-dev libgnutls28-dev libc-ares-dev heimdal-dev libldap2-dev librtmp-dev stunnel4 groff + apt-get -o Dpkg::Use-Pty=0 install -y --no-install-suggests --no-install-recommends cmake make automake autoconf libtool gcc pkg-config libpsl-dev libzstd-dev zlib1g-dev libgnutls28-dev libc-ares-dev libkrb5-dev libldap2-dev librtmp-dev stunnel4 groff # GitHub's actions/checkout needs newer glibc and libstdc++. The latter also depends on # gcc-8-base, but it doesn't actually seem used in our situation and isn't available in # the main repo, so force the install. diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index d01fb4a0b9dc..da49ae67b5eb 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -69,13 +69,13 @@ jobs: fail-fast: false matrix: build: - - name: 'libressl heimdal' - install_packages: libidn2-dev libnghttp2-dev libldap-dev heimdal-dev + - name: 'libressl krb5' + install_packages: libidn2-dev libnghttp2-dev libldap-dev libkrb5-dev install_steps: libressl pytest codeset-test configure: LDFLAGS=-Wl,-rpath,/home/runner/libressl/lib --with-openssl=/home/runner/libressl --with-gssapi --enable-debug - - name: 'libressl heimdal valgrind' - install_packages: libnghttp2-dev libldap-dev heimdal-dev valgrind + - name: 'libressl krb5 valgrind' + install_packages: libnghttp2-dev libldap-dev libkrb5-dev valgrind install_steps: libressl generate: -DOPENSSL_ROOT_DIR=/home/runner/libressl -DCURL_USE_GSSAPI=ON -DENABLE_DEBUG=ON -DCURL_LIBCURL_VERSIONED_SYMBOLS=ON @@ -365,7 +365,7 @@ jobs: run: | apk add --no-cache build-base autoconf automake libtool perl openssl-dev \ libssh2-dev zlib-dev brotli-dev zstd-dev libidn2-dev openldap-dev \ - heimdal-dev libpsl-dev c-ares-dev \ + krb5-dev libpsl-dev c-ares-dev \ py3-impacket py3-asn1 py3-six py3-pycryptodomex \ perl-time-hires openssh stunnel sudo git openssl @@ -671,13 +671,8 @@ jobs: TEST_TARGET: ${{ matrix.build.torture && 'test-torture' || 'test-ci' }} TFLAGS: '${{ matrix.build.tflags }}' run: | - if [ "${TEST_TARGET}" = 'test-ci' ]; then - if [[ "${MATRIX_INSTALL_PACKAGES}" = *'valgrind'* ]]; then - TFLAGS+=' -j6' - if [[ "${MATRIX_INSTALL_PACKAGES}" = *'heimdal-dev'* ]]; then - TFLAGS+=' ~2056 ~2057 ~2077 ~2078' # memory leaks from Curl_auth_decode_spnego_message() -> gss_import_name() - fi - fi + if [ "${TEST_TARGET}" = 'test-ci' ] && [[ "${MATRIX_INSTALL_PACKAGES}" = *'valgrind'* ]]; then + TFLAGS+=' -j6' fi [ -f ~/venv/bin/activate ] && source ~/venv/bin/activate if [[ "${MATRIX_INSTALL_STEPS}" = *'codeset-test'* ]]; then diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index b4bbc8ea792c..7e85cb71e18b 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -294,17 +294,17 @@ jobs: - name: 'HTTP/3 clang-tidy' compiler: clang - install: llvm brotli zstd libnghttp3 libngtcp2 openldap heimdal + install: llvm brotli zstd libnghttp3 libngtcp2 openldap krb5 install_steps: clang-tidy skipall generate: >- -DCURL_USE_OPENSSL=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl -DUSE_NGTCP2=ON -DLDAP_INCLUDE_DIR=/opt/homebrew/opt/openldap/include -DLDAP_LIBRARY=/opt/homebrew/opt/openldap/lib/libldap.dylib -DLDAP_LBER_LIBRARY=/opt/homebrew/opt/openldap/lib/liblber.dylib - -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/heimdal + -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/krb5 -DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy - - name: 'LibreSSL openldap heimdal c-ares +examples' - install: libressl heimdal openldap - generate: -DENABLE_DEBUG=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/libressl -DENABLE_ARES=ON -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/heimdal -DLDAP_INCLUDE_DIR=/opt/homebrew/opt/openldap/include -DLDAP_LIBRARY=/opt/homebrew/opt/openldap/lib/libldap.dylib -DLDAP_LBER_LIBRARY=/opt/homebrew/opt/openldap/lib/liblber.dylib + - name: 'LibreSSL openldap krb5 c-ares +examples' + install: libressl krb5 openldap + generate: -DENABLE_DEBUG=ON -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/libressl -DENABLE_ARES=ON -DCURL_USE_GSSAPI=ON -DGSS_ROOT_DIR=/opt/homebrew/opt/krb5 -DLDAP_INCLUDE_DIR=/opt/homebrew/opt/openldap/include -DLDAP_LIBRARY=/opt/homebrew/opt/openldap/lib/libldap.dylib -DLDAP_LBER_LIBRARY=/opt/homebrew/opt/openldap/lib/liblber.dylib - name: 'wolfSSL !ldap brotli zstd' install: brotli wolfssl zstd install_steps: pytest diff --git a/.github/workflows/non-native.yml b/.github/workflows/non-native.yml index f0368a9240d1..8dccb9e39964 100644 --- a/.github/workflows/non-native.yml +++ b/.github/workflows/non-native.yml @@ -61,7 +61,7 @@ jobs: architecture: ${{ matrix.arch }} run: | # https://pkgsrc.se/ - time sudo pkgin -y install cmake ninja-build pkg-config perl brotli heimdal openldap-client libssh2 libidn2 libpsl nghttp2 py311-impacket + time sudo pkgin -y install cmake ninja-build pkg-config perl brotli mit-krb5 openldap-client libssh2 libidn2 libpsl nghttp2 py311-impacket time cmake -B bld -G Ninja \ -DCMAKE_INSTALL_PREFIX="$HOME"/curl-install \ -DCMAKE_UNITY_BUILD=ON \ @@ -164,10 +164,10 @@ jobs: # https://ports.freebsd.org/ if [ "${MATRIX_BUILD}" = 'cmake' ]; then time sudo pkg install -y cmake-core ninja perl5 \ - pkgconf brotli openldap26-client libidn2 libnghttp2 stunnel py311-impacket + pkgconf brotli krb5-devel openldap26-client libidn2 libnghttp2 stunnel py311-impacket else time sudo pkg install -y autoconf automake libtool \ - pkgconf brotli openldap26-client libidn2 libnghttp2 stunnel py311-impacket + pkgconf brotli krb5-devel openldap26-client libidn2 libnghttp2 stunnel py311-impacket export MAKEFLAGS=-j3 fi diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index 18c84556c09d..21d756c2bcc6 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -29,8 +29,8 @@ # # Result variables: # -# - `GSS_FOUND`: System has the Heimdal library. -# - `GSS_FLAVOUR`: "GNU", "MIT" or "Heimdal" if anything found. +# - `GSS_FOUND`: System has a GSS library. +# - `GSS_FLAVOUR`: "GNU" or "MIT" if anything found. # - `GSS_INCLUDE_DIRS`: The GSS include directories. # - `GSS_LIBRARIES`: The GSS library names. # - `GSS_LIBRARY_DIRS`: The GSS library directories. @@ -41,7 +41,6 @@ set(_gnu_modname "gss") set(_mit_modname "mit-krb5-gssapi") -set(_heimdal_modname "heimdal-gssapi") include(CheckIncludeFile) include(CheckIncludeFiles) @@ -56,7 +55,7 @@ set(_gss_LIBRARY_DIRS "") if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}") if(CURL_USE_PKGCONFIG) find_package(PkgConfig QUIET) - pkg_search_module(_gss ${_gnu_modname} ${_mit_modname} ${_heimdal_modname}) + pkg_search_module(_gss ${_gnu_modname} ${_mit_modname}) list(APPEND _gss_root_hints "${_gss_PREFIX}") set(_gss_version "${_gss_VERSION}") endif() @@ -137,14 +136,8 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr OUTPUT_STRIP_TRAILING_WHITESPACE) # Older versions may not have the "--vendor" parameter. In this case we just do not care. - if(_gss_configure_failed) - set(GSS_FLAVOUR "Heimdal") # most probably, should not really matter - else() - if(_gss_vendor MATCHES "Heimdal|heimdal") - set(GSS_FLAVOUR "Heimdal") - else() - set(GSS_FLAVOUR "MIT") - endif() + if(NOT _gss_configure_failed AND NOT _gss_vendor MATCHES "Heimdal|heimdal") + set(GSS_FLAVOUR "MIT") # assume a default, should not really matter endif() else() # Either there is no config script or we are on a platform that does not provide one (Windows?) @@ -155,33 +148,19 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr cmake_push_check_state() list(APPEND CMAKE_REQUIRED_INCLUDES "${_gss_INCLUDE_DIRS}") check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers) + cmake_pop_check_state() if(_gss_have_mit_headers) set(GSS_FLAVOUR "MIT") - else() - # Prevent compiling the header - just check if we can include it - list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D__ROKEN_H__") - check_include_file("roken.h" _gss_have_roken_h) - - check_include_file("heimdal/roken.h" _gss_have_heimdal_roken_h) - if(_gss_have_roken_h OR _gss_have_heimdal_roken_h) - set(GSS_FLAVOUR "Heimdal") - endif() endif() - cmake_pop_check_state() else() # I am not convinced if this is the right way but this is what autotools do at the moment find_path(_gss_INCLUDE_DIRS NAMES "gssapi.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include" "inc") + find_path(_gss_INCLUDE_DIRS NAMES "gss.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include") if(_gss_INCLUDE_DIRS) - set(GSS_FLAVOUR "Heimdal") - else() - find_path(_gss_INCLUDE_DIRS NAMES "gss.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include") - - if(_gss_INCLUDE_DIRS) - set(GSS_FLAVOUR "GNU") - set(GSS_PC_REQUIRES "gss") - endif() + set(GSS_FLAVOUR "GNU") + set(GSS_PC_REQUIRES "gss") endif() endif() @@ -201,35 +180,32 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr list(APPEND _gss_libdir_suffixes "lib/AMD64") if(GSS_FLAVOUR STREQUAL "GNU") set(_gss_libname "gss") - elseif(GSS_FLAVOUR STREQUAL "MIT") + else() # MIT set(_gss_libname "gssapi64") - else() - set(_gss_libname "libgssapi") endif() else() list(APPEND _gss_libdir_suffixes "lib/i386") if(GSS_FLAVOUR STREQUAL "GNU") set(_gss_libname "gss") - elseif(GSS_FLAVOUR STREQUAL "MIT") + else() # MIT set(_gss_libname "gssapi32") - else() - set(_gss_libname "libgssapi") endif() endif() else() list(APPEND _gss_libdir_suffixes "lib;lib64") # those suffixes are not checked for HINTS if(GSS_FLAVOUR STREQUAL "GNU") set(_gss_libname "gss") - elseif(GSS_FLAVOUR STREQUAL "MIT") + else() # MIT set(_gss_libname "gssapi_krb5") - else() - set(_gss_libname "gssapi") endif() endif() find_library(_gss_LIBRARIES NAMES ${_gss_libname} HINTS ${_gss_libdir_hints} PATH_SUFFIXES ${_gss_libdir_suffixes}) endif() endif() + if(NOT GSS_FLAVOUR) + message(FATAL_ERROR "GNU or MIT GSS is required") + endif() else() # _gss_MODULE_NAME set since CMake 3.16. # _pkg_check_modules_pkg_name is undocumented and used as a fallback for CMake <3.16 versions. @@ -240,8 +216,7 @@ else() set(GSS_FLAVOUR "MIT") set(GSS_PC_REQUIRES "mit-krb5-gssapi") else() - set(GSS_FLAVOUR "Heimdal") - set(GSS_PC_REQUIRES "heimdal-gssapi") + message(FATAL_ERROR "GNU or MIT GSS is required") endif() message(STATUS "Found GSS/${GSS_FLAVOUR} (via pkg-config): ${_gss_INCLUDE_DIRS} (found version \"${_gss_version}\")") endif() @@ -254,25 +229,8 @@ set(GSS_LIBRARY_DIRS ${_gss_LIBRARY_DIRS}) set(GSS_CFLAGS ${_gss_CFLAGS}) set(GSS_VERSION ${_gss_version}) -if(GSS_FLAVOUR) - if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal") - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(_heimdal_manifest_file "Heimdal.Application.amd64.manifest") - else() - set(_heimdal_manifest_file "Heimdal.Application.x86.manifest") - endif() - - if(EXISTS "${GSS_INCLUDE_DIRS}/${_heimdal_manifest_file}") - file(STRINGS "${GSS_INCLUDE_DIRS}/${_heimdal_manifest_file}" _heimdal_version_str - REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$") - - string(REGEX MATCH "[0-9]\\.[^\"]+" GSS_VERSION "${_heimdal_version_str}") - endif() - - if(NOT GSS_VERSION) - set(GSS_VERSION "Heimdal Unknown") - endif() - elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT") +if(NOT GSS_VERSION) + if(GSS_FLAVOUR STREQUAL "MIT") if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24) cmake_host_system_information(RESULT _mit_version QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/MIT/Kerberos/SDK/CurrentVersion" VALUE "VersionString") @@ -285,7 +243,7 @@ if(GSS_FLAVOUR) else() set(GSS_VERSION "MIT Unknown") endif() - elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "GNU") + else() # GNU if(GSS_INCLUDE_DIRS AND EXISTS "${GSS_INCLUDE_DIRS}/gss.h") set(_version_regex "#[\t ]*define[\t ]+GSS_VERSION[\t ]+\"([^\"]*)\"") file(STRINGS "${GSS_INCLUDE_DIRS}/gss.h" _version_str REGEX "${_version_regex}") diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b5ed10f8061..f711dff04a24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1442,36 +1442,36 @@ if(CURL_USE_GSSAPI) if(GSS_FLAVOUR STREQUAL "GNU") set(HAVE_GSSGNU 1) - else() + else() # MIT cmake_push_check_state() list(APPEND CMAKE_REQUIRED_INCLUDES "${GSS_INCLUDE_DIRS}") set(_include_list "") + check_include_file("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) if(HAVE_GSSAPI_GSSAPI_H) list(APPEND _include_list "gssapi/gssapi.h") endif() - check_include_files("${_include_list};gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) - if(GSS_FLAVOUR STREQUAL "MIT") - check_include_files("${_include_list};gssapi/gssapi_krb5.h" _have_gssapi_gssapi_krb5_h) - if(HAVE_GSSAPI_GSSAPI_GENERIC_H) - list(APPEND _include_list "gssapi/gssapi_generic.h") - endif() - if(_have_gssapi_gssapi_krb5_h) - list(APPEND _include_list "gssapi/gssapi_krb5.h") - endif() + check_include_files("${_include_list};gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) + check_include_files("${_include_list};gssapi/gssapi_krb5.h" _have_gssapi_gssapi_krb5_h) + if(HAVE_GSSAPI_GSSAPI_GENERIC_H) + list(APPEND _include_list "gssapi/gssapi_generic.h") + endif() + if(_have_gssapi_gssapi_krb5_h) + list(APPEND _include_list "gssapi/gssapi_krb5.h") + endif() - if(NOT DEFINED HAVE_GSS_C_NT_HOSTBASED_SERVICE) - string(APPEND CMAKE_REQUIRED_FLAGS " ${GSS_CFLAGS}") - list(APPEND CMAKE_REQUIRED_LIBRARIES "${GSS_LIBRARIES}") - curl_required_libpaths("${GSS_LIBRARY_DIRS}") - check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" "${_include_list}" HAVE_GSS_C_NT_HOSTBASED_SERVICE) - endif() - if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE) - set(HAVE_OLD_GSSMIT ON) - endif() + if(NOT DEFINED HAVE_GSS_C_NT_HOSTBASED_SERVICE) + string(APPEND CMAKE_REQUIRED_FLAGS " ${GSS_CFLAGS}") + list(APPEND CMAKE_REQUIRED_LIBRARIES "${GSS_LIBRARIES}") + curl_required_libpaths("${GSS_LIBRARY_DIRS}") + check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" "${_include_list}" HAVE_GSS_C_NT_HOSTBASED_SERVICE) + endif() + if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE) + set(HAVE_OLD_GSSMIT ON) endif() + unset(_include_list) cmake_pop_check_state() endif() diff --git a/RELEASE-NOTES b/RELEASE-NOTES index d80ceae5fc26..47c7dd52556d 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -102,7 +102,6 @@ This release includes the following bugfixes: o httpsrr: free old pointers when storing new [57] o INSTALL-CMAKE.md: document useful build targets [215] o INTERNALS: drop Winsock 2.2 from the dependency list [162] - o INTERNALS: specify minimum version for Heimdal: 7.1.0 [158] o ip-happy: do not set unnecessary timeout [95] o ip-happy: prevent event-based stall on retry [155] o krb5: return appropriate error on send failures [22] @@ -448,7 +447,6 @@ References to bug reports and discussions on issues: [155] = https://curl.se/bug/?i=18815 [156] = https://curl.se/bug/?i=18893 [157] = https://curl.se/bug/?i=18806 - [158] = https://curl.se/bug/?i=18809 [159] = https://curl.se/bug/?i=18924 [160] = https://curl.se/bug/?i=18810 [161] = https://curl.se/bug/?i=18749 diff --git a/configure.ac b/configure.ac index c90606f50780..c76be65e9667 100644 --- a/configure.ac +++ b/configure.ac @@ -1840,7 +1840,7 @@ if test x"$want_gss" = xyes; then gnu_gss=yes ], [ - dnl not found, check Heimdal or MIT + dnl not found, check for MIT AC_CHECK_HEADERS([gssapi/gssapi.h], [], [not_mit=1]) AC_CHECK_HEADERS( [gssapi/gssapi_generic.h gssapi/gssapi_krb5.h], @@ -1853,15 +1853,8 @@ if test x"$want_gss" = xyes; then #endif ]) if test "x$not_mit" = "x1"; then - dnl MIT not found, check for Heimdal - AC_CHECK_HEADER(gssapi.h, - [], - [ - dnl no header found, disabling GSS - want_gss=no - AC_MSG_WARN(disabling GSS-API support since no header files were found) - ] - ) + dnl MIT not found + AC_MSG_ERROR([MIT or GNU GSS library required, but not found]) else dnl MIT found dnl check if we have a really old MIT Kerberos version (<= 1.2) @@ -1894,7 +1887,7 @@ fi if test x"$want_gss" = xyes; then AC_DEFINE(HAVE_GSSAPI, 1, [if you have GSS-API libraries]) HAVE_GSSAPI=1 - curl_gss_msg="enabled (MIT Kerberos/Heimdal)" + curl_gss_msg="enabled (MIT Kerberos)" link_pkgconfig='' if test -n "$gnu_gss"; then @@ -1961,8 +1954,6 @@ if test x"$want_gss" = xyes; then if test -n "$link_pkgconfig"; then if test -n "$gnu_gss"; then LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE gss" - elif test "x$not_mit" = "x1"; then - LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE heimdal-gssapi" else LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE mit-krb5-gssapi" fi diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index a0430bbfa406..46215747e7d8 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -474,7 +474,7 @@ the parent project, ideally in the "extra" find package redirect file: Available variables: - `HAVE_GNUTLS_SRP`: `gnutls_srp_verifier` present in GnuTLS. -- `HAVE_GSS_C_NT_HOSTBASED_SERVICE`: `GSS_C_NT_HOSTBASED_SERVICE` present in GSS/Heimdal/Kerberos. +- `HAVE_GSS_C_NT_HOSTBASED_SERVICE`: `GSS_C_NT_HOSTBASED_SERVICE` present in GSS/Kerberos. - `HAVE_LDAP_INIT_FD`: `ldap_init_fd` present in LDAP library. - `HAVE_LDAP_URL_PARSE`: `ldap_url_parse` present in LDAP library. - `HAVE_OPENSSL_SRP`: `SSL_CTX_set_srp_username` present in OpenSSL (or fork). diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index 84b939f4dcb4..3ad1b3e8c2a4 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -36,7 +36,6 @@ versions of libs and build tools. - wolfSSL 3.4.6 - OpenLDAP 2.0 - MIT Kerberos 1.2.4 - - Heimdal 7.1.0 - nghttp2 1.15.0 ## Build tools diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 5b7df42bdab9..c9beb2836194 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -38,7 +38,6 @@ problems may have been fixed or changed somewhat since this was written. 5.2 curl-config --libs contains private details 5.3 LDFLAGS passed too late making libs linked incorrectly 5.6 Cygwin: make install installs curl-config.1 twice - 5.11 configure --with-gssapi with Heimdal is ignored on macOS 5.12 flaky CI builds 5.13 long paths are not fully supported on Windows 5.15 Unicode on Windows @@ -49,7 +48,6 @@ problems may have been fixed or changed somewhat since this was written. 6.5 NTLM does not support password with Unicode 'SECTION SIGN' character 6.6 libcurl can fail to try alternatives with --proxy-any 6.7 Do not clear digest for single realm - 6.8 Heimdal memory leaks 6.9 SHA-256 digest not supported in Windows SSPI builds 6.10 curl never completes Negotiate over HTTP 6.11 Negotiate on Windows fails @@ -238,12 +236,6 @@ problems may have been fixed or changed somewhat since this was written. https://github.com/curl/curl/issues/8839 -5.11 configure --with-gssapi with Heimdal is ignored on macOS - - ... unless you also pass --with-gssapi-libs - - https://github.com/curl/curl/issues/3841 - 5.12 flaky CI builds We run many CI builds for each commit and PR on github, and especially a @@ -342,13 +334,6 @@ problems may have been fixed or changed somewhat since this was written. https://github.com/curl/curl/issues/3267 -6.8 Heimdal memory leaks - - Running test 2077 and 2078 with curl built to do GSS with Heimdal causes - valgrind errors (memory leak). - - https://github.com/curl/curl/issues/14446 - 6.9 SHA-256 digest not supported in Windows SSPI builds Windows builds of curl that have SSPI enabled use the native Windows API calls diff --git a/docs/TODO b/docs/TODO index 4db3f5f4ed21..65d735d1be8c 100644 --- a/docs/TODO +++ b/docs/TODO @@ -496,8 +496,8 @@ 4.6 GSSAPI via Windows SSPI In addition to currently supporting the SASL GSSAPI mechanism (Kerberos V5) - via third-party GSS-API libraries, such as Heimdal or MIT Kerberos, also add - support for GSSAPI authentication via Windows SSPI. + via third-party GSS-API libraries, such as MIT Kerberos, also add support + for GSSAPI authentication via Windows SSPI. 4.7 STAT for LIST without data connection From cc7b12347b06378cf5558636e15d3c19a48d836a Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 8 Oct 2025 13:30:12 +0200 Subject: [PATCH 360/465] quiche: handle tls fail correctly quiche receive may report a TLS failure after a verified handshake. That needs to lead to a transfer receive error. Reported-by: Joshua Rogers Closes #18934 --- lib/vquic/curl_quiche.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index f5fd20fccbf1..1ae159bd4cd6 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -666,9 +666,11 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, X509_verify_cert_error_string(verify_ok)); return CURLE_PEER_FAILED_VERIFICATION; } + failf(r->data, "ingress, quiche reports TLS fail"); + return CURLE_RECV_ERROR; } else { - failf(r->data, "quiche_conn_recv() == %zd", nread); + failf(r->data, "quiche reports error %zd on receive", nread); return CURLE_RECV_ERROR; } } From 0b4a7045000e00cc7c8f657861bf0e717bb08ce0 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 8 Oct 2025 13:44:32 +0200 Subject: [PATCH 361/465] vquic: sending non-gso packets fix for EAGAIN The function returned OK on EAGAIN and not the correct code. Reported-by: Joshua Rogers Closes #18936 --- lib/vquic/vquic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index f722c7e127a2..30917b835af0 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -254,7 +254,7 @@ static CURLcode send_packet_no_gso(struct Curl_cfilter *cf, CURL_TRC_CF(data, cf, "vquic_%s(len=%zu, gso=%zu, calls=%zu)" " -> %d, sent=%zu", VQUIC_SEND_METHOD, pktlen, gsolen, calls, result, *psent); - return CURLE_OK; + return result; } static CURLcode vquic_send_packets(struct Curl_cfilter *cf, From c0a279a8e91a279f6942775073d21d0e93041af6 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 8 Oct 2025 14:06:55 +0200 Subject: [PATCH 362/465] socks: deny server basic-auth if not configured When the server proposes BASIC authentication and curl does not have that configured, fail right away. Reported-by: Joshua Rogers Closes #18937 --- lib/socks.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/socks.c b/lib/socks.c index e7e545442a9a..a0e1e6c04254 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -681,8 +681,12 @@ static CURLproxycode socks5_check_resp0(struct socks_state *sx, return CURLPX_GSSAPI_PERMSG; case 2: /* regular name + password authentication */ - sxstate(sx, cf, data, SOCKS5_ST_AUTH_INIT); - return CURLPX_OK; + if(data->set.socks5auth & CURLAUTH_BASIC) { + sxstate(sx, cf, data, SOCKS5_ST_AUTH_INIT); + return CURLPX_OK; + } + failf(data, "BASIC authentication proposed but not enabled."); + return CURLPX_NO_AUTH; case 255: failf(data, "No authentication method was acceptable."); return CURLPX_NO_AUTH; From 391e3fbeeccb7311562f60fbd9db964bc5bf3ec7 Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Thu, 9 Oct 2025 06:03:08 +0800 Subject: [PATCH 363/465] libssh/sftp: fix resume corruption by avoiding O_APPEND with rresume Opening the remote file with O_APPEND while attempting to resume causes all writes to be forced to EOF on servers/implementations where O_APPEND semantics override a prior seek(). As a result, sftp_seek64() is ignored and the resumed data is appended, duplicating/corrupting the file. Fix by: - Using O_WRONLY (without O_APPEND) when resume_from > 0. - Skipping the seek entirely if remote_append mode is requested. Closes #18952 --- lib/vssh/libssh.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 78d7986a9ecd..579eaeaa0ded 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1154,12 +1154,18 @@ static int myssh_in_UPLOAD_INIT(struct Curl_easy *data, } } - if(data->set.remote_append) - /* Try to open for append, but create if nonexisting */ - flags = O_WRONLY|O_CREAT|O_APPEND; - else if(data->state.resume_from > 0) - /* If we have restart position then open for append */ - flags = O_WRONLY|O_APPEND; + if(data->set.remote_append) { + /* True append mode: create if nonexisting */ + flags = O_WRONLY | O_CREAT | O_APPEND; + } + else if(data->state.resume_from > 0) { + /* + * Resume MUST NOT use O_APPEND. Many SFTP servers/impls force all + * writes to EOF when O_APPEND is set, ignoring a prior seek(). + * Open write-only and seek to the resume offset instead. + */ + flags = O_WRONLY; + } else /* Clear file before writing (normal behavior) */ flags = O_WRONLY|O_CREAT|O_TRUNC; @@ -1189,8 +1195,8 @@ static int myssh_in_UPLOAD_INIT(struct Curl_easy *data, } /* If we have a restart point then we need to seek to the correct - position. */ - if(data->state.resume_from > 0) { + position. Skip if in explicit remote append mode. */ + if(data->state.resume_from > 0 && !data->set.remote_append) { int seekerr = CURL_SEEKFUNC_OK; /* Let's read off the proper amount of bytes from the input. */ if(data->set.seek_func) { From dae19dd94a77dfc4568989cd84159b9502484b8b Mon Sep 17 00:00:00 2001 From: Joshua Rogers Date: Thu, 9 Oct 2025 06:06:40 +0800 Subject: [PATCH 364/465] libssh2/sftp: fix resume corruption by avoiding O_APPEND with rresume Opening the remote file with O_APPEND while attempting to resume causes all writes to be forced to EOF on servers/implementations where O_APPEND semantics override a prior seek(). As a result, sftp_seek64() is ignored and the resumed data is appended, duplicating/corrupting the file. Fix by: - Using O_WRONLY (without O_APPEND) when resume_from > 0. - Skipping the seek entirely if remote_append mode is requested. Closes #18952 --- lib/vssh/libssh2.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index c73ecec94960..65ccd29923e5 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1027,15 +1027,21 @@ sftp_upload_init(struct Curl_easy *data, } } - if(data->set.remote_append) - /* Try to open for append, but create if nonexisting */ - flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND; - else if(data->state.resume_from > 0) - /* If we have restart position then open for append */ - flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND; - else + if(data->set.remote_append) { + /* True append mode: create if nonexisting */ + flags = LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_APPEND; + } + else if(data->state.resume_from > 0) { + /* + * Resume MUST NOT use APPEND; some servers force writes to EOF when + * APPEND is set, ignoring a prior seek(). + */ + flags = LIBSSH2_FXF_WRITE; + } + else { /* Clear file before writing (normal behavior) */ - flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC; + flags = LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC; + } sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session, sshp->path, @@ -1093,8 +1099,8 @@ sftp_upload_init(struct Curl_easy *data, } /* If we have a restart point then we need to seek to the correct - position. */ - if(data->state.resume_from > 0) { + Skip if in explicit remote append mode. */ + if(data->state.resume_from > 0 && !data->set.remote_append) { int seekerr = CURL_SEEKFUNC_OK; /* Let's read off the proper amount of bytes from the input. */ if(data->set.seek_func) { From 93e91e965e80b94b559293b93d4fb3360b8281a3 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 8 Oct 2025 12:22:22 +0200 Subject: [PATCH 365/465] http2: check push header names by length first Reported-by: Joshua Rogers Closes #18930 --- lib/http2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/http2.c b/lib/http2.c index c33c633cf632..ff53fc4b947d 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -1590,7 +1590,8 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { char *h; - if(!strcmp(HTTP_PSEUDO_AUTHORITY, (const char *)name)) { + if((namelen == (sizeof(HTTP_PSEUDO_AUTHORITY)-1)) && + !strncmp(HTTP_PSEUDO_AUTHORITY, (const char *)name, namelen)) { /* pseudo headers are lower case */ int rc = 0; char *check = curl_maprintf("%s:%d", cf->conn->host.name, From 44a79d4f7afe52ca613516cf9dd5d83ac7d5c2c0 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 8 Oct 2025 12:28:14 +0200 Subject: [PATCH 366/465] http2: cleanup pushed newhandle on fail When nghttp2_session_set_stream_user_data() fails, clean up the new handle. Reported-by: Joshua Rogers Closes #18931 --- lib/http2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/http2.c b/lib/http2.c index ff53fc4b947d..43f4e9106caf 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -1030,6 +1030,7 @@ static int push_promise(struct Curl_cfilter *cf, infof(data, "failed to set user_data for stream %u", newstream->id); DEBUGASSERT(0); + discard_newhandle(cf, newhandle); rv = CURL_PUSH_DENY; goto fail; } From f609b5738931d4fa9ef75e9f48a9d3a21dea1ffb Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 8 Oct 2025 13:06:48 +0200 Subject: [PATCH 367/465] http2: ingress handling edge cases Fix some edge cases around the `data_max_bytes` handling when processing ingress. Reported-by: Joshua Rogers Closes #18933 --- lib/http2.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/http2.c b/lib/http2.c index 43f4e9106caf..4e2d59ff5187 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -623,9 +623,8 @@ static int should_close_session(struct cf_h2_ctx *ctx) * This function returns 0 if it succeeds, or -1 and error code will * be assigned to *err. */ -static int h2_process_pending_input(struct Curl_cfilter *cf, - struct Curl_easy *data, - CURLcode *err) +static CURLcode h2_process_pending_input(struct Curl_cfilter *cf, + struct Curl_easy *data) { struct cf_h2_ctx *ctx = cf->ctx; const unsigned char *buf; @@ -633,12 +632,10 @@ static int h2_process_pending_input(struct Curl_cfilter *cf, ssize_t rv; while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) { - rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen); if(rv < 0) { failf(data, "nghttp2 recv error %zd: %s", rv, nghttp2_strerror((int)rv)); - *err = CURLE_HTTP2; - return -1; + return CURLE_HTTP2; } Curl_bufq_skip(&ctx->inbufq, (size_t)rv); if(Curl_bufq_is_empty(&ctx->inbufq)) { @@ -658,7 +655,7 @@ static int h2_process_pending_input(struct Curl_cfilter *cf, connclose(cf->conn, "http/2: No new requests allowed"); } - return 0; + return CURLE_OK; } /* @@ -690,7 +687,8 @@ static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data, if(!result) { CURL_TRC_CF(data, cf, "%zu bytes stray data read before trying " "h2 connection", nread); - if(h2_process_pending_input(cf, data, &result) < 0) + result = h2_process_pending_input(cf, data); + if(result) /* immediate error, considered dead */ alive = FALSE; else { @@ -2045,10 +2043,14 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, if(!Curl_bufq_is_empty(&ctx->inbufq)) { CURL_TRC_CF(data, cf, "Process %zu bytes in connection buffer", Curl_bufq_len(&ctx->inbufq)); - if(h2_process_pending_input(cf, data, &result) < 0) + result = h2_process_pending_input(cf, data); + if(result) return result; } + if(!data_max_bytes) + data_max_bytes = H2_CHUNK_SIZE; + /* Receive data from the "lower" filters, e.g. network until * it is time to stop due to connection close or us not processing * all network input */ @@ -2063,6 +2065,10 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, Curl_multi_mark_dirty(data); break; } + else if(!stream) { + DEBUGASSERT(0); + break; + } result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread); if(result) { @@ -2083,7 +2089,8 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, data_max_bytes = (data_max_bytes > nread) ? (data_max_bytes - nread) : 0; } - if(h2_process_pending_input(cf, data, &result)) + result = h2_process_pending_input(cf, data); + if(result) return result; CURL_TRC_CF(data, cf, "[0] progress ingress: inbufg=%zu", Curl_bufq_len(&ctx->inbufq)); @@ -2546,7 +2553,7 @@ static CURLcode cf_h2_connect(struct Curl_cfilter *cf, } if(!first_time) { - result = h2_progress_ingress(cf, data, H2_CHUNK_SIZE); + result = h2_progress_ingress(cf, data, 0); if(result) goto out; } From 1ce6dff01a7d38618273e6fe20b73c4bc661e6ed Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 7 Oct 2025 07:49:00 +0200 Subject: [PATCH 368/465] openssl: fix peer certificate leak in channel binding Reported-by: Stanislav Fort Bug: https://hackerone.com/reports/3373640 Closes #18917 --- lib/vtls/openssl.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index fb5cc1836230..bd0e315fd820 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -5628,6 +5628,7 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex, struct connectdata *conn = data->conn; struct Curl_cfilter *cf = conn->cfilter[sockindex]; struct ossl_ctx *octx = NULL; + CURLcode result = CURLE_OK; do { const struct Curl_cftype *cft = cf->cft; @@ -5649,15 +5650,15 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex, } cert = SSL_get1_peer_certificate(octx->ssl); - if(!cert) { + if(!cert) /* No server certificate, don't do channel binding */ return CURLE_OK; - } if(!OBJ_find_sigid_algs(X509_get_signature_nid(cert), &algo_nid, NULL)) { failf(data, "Unable to find digest NID for certificate signature algorithm"); - return CURLE_SSL_INVALIDCERTSTATUS; + result = CURLE_SSL_INVALIDCERTSTATUS; + goto error; } /* https://datatracker.ietf.org/doc/html/rfc5929#section-4.1 */ @@ -5670,23 +5671,28 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex, algo_name = OBJ_nid2sn(algo_nid); failf(data, "Could not find digest algorithm %s (NID %d)", algo_name ? algo_name : "(null)", algo_nid); - return CURLE_SSL_INVALIDCERTSTATUS; + result = CURLE_SSL_INVALIDCERTSTATUS; + goto error; } } if(!X509_digest(cert, algo_type, buf, &length)) { failf(data, "X509_digest() failed"); - return CURLE_SSL_INVALIDCERTSTATUS; + result = CURLE_SSL_INVALIDCERTSTATUS; + goto error; } /* Append "tls-server-end-point:" */ - if(curlx_dyn_addn(binding, prefix, sizeof(prefix) - 1) != CURLE_OK) - return CURLE_OUT_OF_MEMORY; + result = curlx_dyn_addn(binding, prefix, sizeof(prefix) - 1); + if(result) + goto error; + /* Append digest */ - if(curlx_dyn_addn(binding, buf, length)) - return CURLE_OUT_OF_MEMORY; + result = curlx_dyn_addn(binding, buf, length); - return CURLE_OK; +error: + X509_free(cert); + return result; #else /* No X509_get_signature_nid support */ (void)data; From 5d32c4fc7b559528a562a390c230f627fec94376 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 7 Oct 2025 09:22:05 +0200 Subject: [PATCH 369/465] test1582: verify the TLS channel binding cert memory leak fix --- tests/data/Makefile.am | 2 +- tests/data/test1582 | 54 ++++++++++++++++++++++++++++++++++ tests/libtest/Makefile.inc | 1 + tests/libtest/lib1582.c | 60 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 tests/data/test1582 create mode 100644 tests/libtest/lib1582.c diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 11d9fb7cff35..ce97740b9af0 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -209,7 +209,7 @@ 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 \ +test1580 test1581 test1582 \ \ test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \ test1598 test1599 test1600 test1601 test1602 test1603 test1604 test1605 \ diff --git a/tests/data/test1582 b/tests/data/test1582 new file mode 100644 index 000000000000..146863fd6994 --- /dev/null +++ b/tests/data/test1582 @@ -0,0 +1,54 @@ + + + +HTTPS +GSS-API + + + +# Server-side + + +HTTP/1.1 401 OK +Date: Tue, 09 Nov 2030 14:49:00 GMT +Server: test-server/fake +Content-Length: 7 +WWW-Authenticate: Negotiate + +nomnom + + + +# Client-side + + +SSL +GSS-API +OpenSSL + + +http +https + + +Negotiate over HTTPS with channel binding + + +lib%TESTNUMBER + + +https://%HOSTIP:%HTTPSPORT/ + + + + + +GET / HTTP/1.1 +Host: %HOSTIP:%HTTPSPORT +Accept: */* + + + + + + diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index cac833f26f7d..67ffabad0b3d 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -91,6 +91,7 @@ TESTS_C = \ lib1559.c lib1560.c lib1564.c lib1565.c \ lib1567.c lib1568.c lib1569.c lib1571.c \ lib1576.c \ + lib1582.c \ lib1591.c lib1592.c lib1593.c lib1594.c lib1597.c \ lib1598.c lib1599.c \ lib1662.c \ diff --git a/tests/libtest/lib1582.c b/tests/libtest/lib1582.c new file mode 100644 index 000000000000..0e209beee450 --- /dev/null +++ b/tests/libtest/lib1582.c @@ -0,0 +1,60 @@ +/*************************************************************************** + * _ _ ____ _ + * 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 "memdebug.h" + +static CURLcode test_lib1582(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_HEADER, 1L); + test_setopt(curl, CURLOPT_VERBOSE, 1L); + test_setopt(curl, CURLOPT_URL, URL); + test_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_NEGOTIATE); + test_setopt(curl, CURLOPT_USERPWD, ":"); + test_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + test_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + + res = curl_easy_perform(curl); + +test_cleanup: + curl_easy_cleanup(curl); + curl_global_cleanup(); + + return res; +} From 29d0a308b4537b315849a70b0010f4b0aea6dccb Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 09:50:20 +0200 Subject: [PATCH 370/465] setopt: allow CURLOPT_DNS_CACHE_TIMEOUT set to -1 It is documented as valid. Regression from commit b059f7deaf3 shipped in 8.16.0 Reported-by: Andrei Kurushin Fixes #18959 Closes #18960 --- lib/setopt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/setopt.c b/lib/setopt.c index 5558bded0a11..7097c7f7b015 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -879,7 +879,10 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, switch(option) { case CURLOPT_DNS_CACHE_TIMEOUT: - return setopt_set_timeout_sec(&s->dns_cache_timeout_ms, arg); + if(arg != -1) + return setopt_set_timeout_sec(&s->dns_cache_timeout_ms, arg); + s->dns_cache_timeout_ms = -1; + break; case CURLOPT_CA_CACHE_TIMEOUT: if(Curl_ssl_supports(data, SSLSUPP_CA_CACHE)) { From 7ab9018ea70b1ced6737a755ac96b9a00eef4073 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 10:15:41 +0200 Subject: [PATCH 371/465] mk-lib1521: verify the setopt options that accept -1 --- tests/libtest/mk-lib1521.pl | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/libtest/mk-lib1521.pl b/tests/libtest/mk-lib1521.pl index e0a7d157d883..95a600c3d02a 100755 --- a/tests/libtest/mk-lib1521.pl +++ b/tests/libtest/mk-lib1521.pl @@ -255,6 +255,12 @@ name, code, curl_easy_strerror(code), lineno); } +static void errneg(const char *name, CURLcode code, int lineno) +{ + curl_mprintf("%s set to -1 returned %d, \\"%s\\" on line %d\\n", + name, code, curl_easy_strerror(code), lineno); +} + static void errstring(const char *name, CURLcode code, int lineno) { /* allow this set of options to return CURLE_BAD_FUNCTION_ARGUMENT @@ -322,6 +328,23 @@ return 0; } +/* long options that should handle -1 */ +static bool bad_neg(int check) +{ + switch(check) { + case CURLOPT_DNS_CACHE_TIMEOUT: + case CURLOPT_INFILESIZE: + case CURLOPT_INFILESIZE_LARGE: + case CURLOPT_MAXREDIRS: + case CURLOPT_POSTFIELDSIZE: + case CURLOPT_POSTFIELDSIZE_LARGE: + case CURLOPT_RESUME_FROM: + case CURLOPT_RESUME_FROM_LARGE: + return TRUE; + } + return FALSE; +} + /* macro to check the first setopt of an option which then is allowed to get a non-existing function return code back */ #define present(x) ((x != CURLE_NOT_BUILT_IN) && (x != CURLE_UNKNOWN_OPTION)) @@ -456,6 +479,12 @@ MOO ; + my $negcheck = < Date: Thu, 9 Oct 2025 09:07:27 +0200 Subject: [PATCH 372/465] hostip: don't store negative resolves due unrelated errors Like for: - OOM - resolver_start() returns error - DoH has problems Fixes #18953 Fixes #18954 Reported-by: Joshua Rogers Closes #18958 --- lib/hostip.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/hostip.c b/lib/hostip.c index ceea1897322a..a6531c31711b 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -846,6 +846,7 @@ CURLcode Curl_resolv(struct Curl_easy *data, int respwait = 0; bool is_ipaddr; size_t hostname_len; + bool keep_negative = TRUE; /* cache a negative result */ #ifndef CURL_DISABLE_DOH data->conn->bits.doh = FALSE; /* default is not */ @@ -887,8 +888,10 @@ CURLcode Curl_resolv(struct Curl_easy *data, st = data->set.resolver_start(resolver, NULL, data->set.resolver_start_client); Curl_set_in_callback(data, FALSE); - if(st) + if(st) { + keep_negative = FALSE; goto error; + } } /* shortcut literal IP addresses, if we are not told to resolve them. */ @@ -947,10 +950,11 @@ CURLcode Curl_resolv(struct Curl_easy *data, else if(addr) { /* we got a response, create a dns entry, add to cache, return */ dns = Curl_dnscache_mk_entry(data, addr, hostname, 0, port, FALSE); - if(!dns) - goto error; - if(Curl_dnscache_add(data, dns)) + if(!dns || Curl_dnscache_add(data, dns)) { + /* this is OOM or similar, don't store such negative resolves */ + keep_negative = FALSE; goto error; + } show_resolve_info(data, dns); *entry = dns; return CURLE_OK; @@ -966,7 +970,8 @@ CURLcode Curl_resolv(struct Curl_easy *data, Curl_resolv_unlink(data, &dns); *entry = NULL; Curl_async_shutdown(data); - store_negative_resolve(data, hostname, port); + if(keep_negative) + store_negative_resolve(data, hostname, port); return CURLE_COULDNT_RESOLVE_HOST; } @@ -1550,7 +1555,8 @@ CURLcode Curl_resolv_check(struct Curl_easy *data, result = Curl_async_is_resolved(data, dns); if(*dns) show_resolve_info(data, *dns); - if(result) + if((result == CURLE_COULDNT_RESOLVE_HOST) || + (result == CURLE_COULDNT_RESOLVE_PROXY)) store_negative_resolve(data, data->state.async.hostname, data->state.async.port); return result; From 56c892af1f46c7b1c803304ee62e524340007ab2 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 9 Oct 2025 12:36:43 +0200 Subject: [PATCH 373/465] examples/sessioninfo: do not disable security Also make it return the curl result code. Follow-up to df70a68984308952dcacf33d11593cb22ad80464 #18909 Closes #18969 --- docs/examples/sessioninfo.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/examples/sessioninfo.c b/docs/examples/sessioninfo.c index ed5f0e9e292d..bbdcfe8d2319 100644 --- a/docs/examples/sessioninfo.c +++ b/docs/examples/sessioninfo.c @@ -96,25 +96,22 @@ static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) int main(void) { + CURLcode res = CURLE_OK; + curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/"); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, wrfu); - - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); - (void)curl_easy_perform(curl); + res = curl_easy_perform(curl); curl_easy_cleanup(curl); } curl_global_cleanup(); - return 0; + return (int)res; } From e78185625f149d89c56ef32af580f1d122c2f42b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 9 Oct 2025 12:51:08 +0200 Subject: [PATCH 374/465] examples: allow `vsnprintf` again Ref: https://github.com/curl/curl/pull/18668#issuecomment-3383422410 Follow-up to b12da22db1f11da51082977dc21a7edee7858911 #18866 Closes #18970 --- docs/examples/.checksrc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/examples/.checksrc b/docs/examples/.checksrc index 59899762bfde..c81d1597681d 100644 --- a/docs/examples/.checksrc +++ b/docs/examples/.checksrc @@ -10,6 +10,7 @@ allowfunc snprintf allowfunc socket allowfunc sscanf allowfunc strerror +allowfunc vsnprintf banfunc curl_maprintf banfunc curl_mfprintf banfunc curl_mprintf From 92ee9173685907ddf53eb57b61b5c4845ae00459 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 9 Oct 2025 12:54:17 +0200 Subject: [PATCH 375/465] examples: update `.gitignore` Follow-up to f6f62933e917b8b5c9a9394907ce4b69600214b4 #18264 Closes #18971 --- docs/examples/.gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/examples/.gitignore b/docs/examples/.gitignore index 4b78bd78dd05..6d14f24cd184 100644 --- a/docs/examples/.gitignore +++ b/docs/examples/.gitignore @@ -35,7 +35,6 @@ getreferrer ghiper headerapi hiperfifo -href_extractor hsts-preload htmltidy http-options From 801ebf1e1a1415a869b00107a464a4492a98eb77 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 9 Oct 2025 13:48:06 +0200 Subject: [PATCH 376/465] GHA: rename config files to match pyspelling To make it more obvious what needs to be looked at when pyspelling is reporting an issue. Follow-up to 95e50ad69473d8229b85478a3f2138b7e632fbe8 #18756 Closes #18974 --- .github/scripts/codespell.sh | 2 +- .github/scripts/{spellcheck.words => pyspelling.words} | 0 .github/scripts/{spellcheck.yaml => pyspelling.yaml} | 0 .github/scripts/spacecheck.pl | 2 +- .github/scripts/typos.toml | 2 +- .github/workflows/checkdocs.yml | 4 ++-- 6 files changed, 5 insertions(+), 5 deletions(-) rename .github/scripts/{spellcheck.words => pyspelling.words} (100%) rename .github/scripts/{spellcheck.yaml => pyspelling.yaml} (100%) diff --git a/.github/scripts/codespell.sh b/.github/scripts/codespell.sh index 6825b38c7eaf..bbbbef571968 100755 --- a/.github/scripts/codespell.sh +++ b/.github/scripts/codespell.sh @@ -9,7 +9,7 @@ cd "$(dirname "${0}")"/../.. # shellcheck disable=SC2046 codespell \ - --skip '.github/scripts/spellcheck.words' \ + --skip '.github/scripts/pyspelling.words' \ --skip '.github/scripts/typos.toml' \ --skip 'docs/THANKS' \ --skip 'packages/*' \ diff --git a/.github/scripts/spellcheck.words b/.github/scripts/pyspelling.words similarity index 100% rename from .github/scripts/spellcheck.words rename to .github/scripts/pyspelling.words diff --git a/.github/scripts/spellcheck.yaml b/.github/scripts/pyspelling.yaml similarity index 100% rename from .github/scripts/spellcheck.yaml rename to .github/scripts/pyspelling.yaml diff --git a/.github/scripts/spacecheck.pl b/.github/scripts/spacecheck.pl index 7caf52632761..fbd064db3ba2 100755 --- a/.github/scripts/spacecheck.pl +++ b/.github/scripts/spacecheck.pl @@ -53,7 +53,7 @@ my $non_ascii_allowed = join(', ', @non_ascii_allowed); my @non_ascii = ( - ".github/scripts/spellcheck.words", + ".github/scripts/pyspelling.words", ".mailmap", "RELEASE-NOTES", "docs/BINDINGS.md", diff --git a/.github/scripts/typos.toml b/.github/scripts/typos.toml index 2be01d59f6a6..28dcad73bec4 100644 --- a/.github/scripts/typos.toml +++ b/.github/scripts/typos.toml @@ -22,7 +22,7 @@ extend-ignore-re = [ [files] extend-exclude = [ ".github/scripts/codespell-ignore.words", - ".github/scripts/spellcheck.words", + ".github/scripts/pyspelling.words", "docs/THANKS", "packages/*", "projects/Windows/tmpl/curl.vcxproj", diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index ad0c41e37aac..91ed7452d19c 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -126,10 +126,10 @@ jobs: run: | source ~/venv/bin/activate # setup the custom wordlist - grep -v '^#' .github/scripts/spellcheck.words > wordlist.txt + grep -v '^#' .github/scripts/pyspelling.words > wordlist.txt aspell --version pyspelling --version - pyspelling --verbose --jobs 5 --config .github/scripts/spellcheck.yaml + pyspelling --verbose --jobs 5 --config .github/scripts/pyspelling.yaml badwords-synopsis: name: 'badwords, synopsis' From 83bed97ad85d2fb7a0be8079318e2ce003bb34a0 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 9 Oct 2025 09:55:38 +0200 Subject: [PATCH 377/465] rustls: pass the correct result to rustls_failf Reported-by: Joshua Rogers Closes #18961 --- lib/vtls/rustls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index a3ab49a101ea..ff2dea82b606 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -1103,7 +1103,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, connssl->peer.hostname, &rconn); if(rr != RUSTLS_RESULT_OK) { - rustls_failf(data, result, "rustls_client_connection_new"); + rustls_failf(data, rr, "rustls_client_connection_new"); return CURLE_COULDNT_CONNECT; } DEBUGASSERT(rconn); From 9e2c582d6c4d676d34c56406301886784021e263 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 9 Oct 2025 11:42:43 +0200 Subject: [PATCH 378/465] memdup0: handle edge case When length is already SIZE_MAX, fail without allocating. Reported-by: Joshua Rogers Closes #18966 --- lib/strdup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/strdup.c b/lib/strdup.c index 66fd7c60eb5f..3339e909ee79 100644 --- a/lib/strdup.c +++ b/lib/strdup.c @@ -111,7 +111,7 @@ void *Curl_memdup(const void *src, size_t length) ***************************************************************************/ void *Curl_memdup0(const char *src, size_t length) { - char *buf = malloc(length + 1); + char *buf = (length < SIZE_MAX) ? malloc(length + 1) : NULL; if(!buf) return NULL; if(length) { From d1d5855689a29ee0ebc3ee5abd34959cfc8530d4 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 9 Oct 2025 10:26:30 +0200 Subject: [PATCH 379/465] openssl: add comments regarding OCSP verification To allow future reviewers of "security" reports to more easily find out why code is this way. Closes #18962 --- lib/vtls/openssl.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index bd0e315fd820..533acdaf8db7 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2589,6 +2589,9 @@ static CURLcode verifystatus(struct Curl_cfilter *cf, for(i = 0; i < (int)sk_X509_num(ch); i++) { X509 *issuer = sk_X509_value(ch, (ossl_valsize_t)i); if(X509_check_issued(issuer, cert) == X509_V_OK) { + /* Note to analysis tools: using SHA1 here is fine. The `id` + * generated is used as a hash lookup key, not as a verifier + * of the OCSP data itself. This all according to RFC 5019. */ id = OCSP_cert_to_id(EVP_sha1(), cert, issuer); break; } @@ -2611,7 +2614,14 @@ static CURLcode verifystatus(struct Curl_cfilter *cf, goto end; } - /* Validate the corresponding single OCSP response */ + /* Validate the OCSP response issuing and update times. + * - `thisupd` is the time the OCSP response was issued + * - `nextupd` is the time the OCSP response should be updated + * (valid life time assigned by the OCSP responder) + * - 3rd param: how many seconds of clock skew we allow between + * our clock and the instance that issued the OCSP response + * - 4th param: how many seconds in the past `thisupd` may be, with + * -1 meaning there is no limit. */ if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) { failf(data, "OCSP response has expired"); result = CURLE_SSL_INVALIDCERTSTATUS; From e7247d86971c5ff559d87ccc55b5355d4224f59a Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Fri, 18 Oct 2024 14:12:31 -0400 Subject: [PATCH 380/465] tool_operate: keep failed partial download for retry auto-resume - Keep data from a failed download instead of discarding it on retry in some limited cases when we know it's ok (currently only HTTP 200/206). Prior to this change on failed transfer the tool truncated any outfile data written before retrying the transfer. This change adds an exception for HTTP downloads when the user requested auto-resume, because in that case we can keep the outfile data and resume from the new position. Reported-by: tkzv@users.noreply.github.com Fixes https://github.com/curl/curl/issues/18035 Closes https://github.com/curl/curl/pull/18665 --- src/tool_operate.c | 74 +++++++++++++++++++++++- tests/data/Makefile.am | 2 +- tests/data/test3035 | 127 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 tests/data/test3035 diff --git a/src/tool_operate.c b/src/tool_operate.c index ca0d2e77f593..1901ab3ac178 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -336,6 +336,32 @@ void single_transfer_cleanup(void) glob_cleanup(&state->inglob); } +/* Helper function for retrycheck. + * + * This function is a prerequisite check used to determine whether or not some + * already downloaded data (ie out->bytes written) can be safely resumed in a + * subsequent transfer. The conditions are somewhat pedantic to avoid any risk + * of data corruption. + * + * Specific HTTP limitations (scheme, method, response code, etc) are checked + * in retrycheck if this prerequisite check is met. + */ +static bool is_outfile_auto_resumable(struct OperationConfig *config, + struct per_transfer *per, + CURLcode result) +{ + struct OutStruct *outs = &per->outs; + return config->use_resume && config->resume_from_current && + config->resume_from >= 0 && outs->init == config->resume_from && + outs->bytes > 0 && outs->filename && outs->s_isreg && outs->fopened && + outs->stream && !ferror(outs->stream) && + !config->customrequest && !per->uploadfile && + (config->httpreq == TOOL_HTTPREQ_UNSPEC || + config->httpreq == TOOL_HTTPREQ_GET) && + /* CURLE_WRITE_ERROR could mean outs->bytes is not accurate */ + result != CURLE_WRITE_ERROR && result != CURLE_RANGE_ERROR; +} + static CURLcode retrycheck(struct OperationConfig *config, struct per_transfer *per, CURLcode result, @@ -353,7 +379,6 @@ static CURLcode retrycheck(struct OperationConfig *config, RETRY_FTP, RETRY_LAST /* not used */ } retry = RETRY_NO; - long response = 0; if((CURLE_OPERATION_TIMEDOUT == result) || (CURLE_COULDNT_RESOLVE_HOST == result) || (CURLE_COULDNT_RESOLVE_PROXY == result) || @@ -378,6 +403,7 @@ static CURLcode retrycheck(struct OperationConfig *config, scheme = proto_token(scheme); if(scheme == proto_http || scheme == proto_https) { /* This was HTTP(S) */ + long response = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); switch(response) { @@ -404,6 +430,7 @@ static CURLcode retrycheck(struct OperationConfig *config, } /* if CURLE_OK */ else if(result) { const char *scheme; + long response = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme); @@ -432,6 +459,7 @@ static CURLcode retrycheck(struct OperationConfig *config, ": HTTP error", ": FTP error" }; + bool truncate = TRUE; /* truncate output file */ if(RETRY_HTTP == retry) { curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after); @@ -482,7 +510,49 @@ static CURLcode retrycheck(struct OperationConfig *config, per->retry_remaining--; - if(outs->bytes && outs->filename && outs->stream) { + /* Skip truncation of outfile if auto-resume is enabled for download and + the partially received data is good. Only for HTTP GET requests in + limited circumstances. */ + if(is_outfile_auto_resumable(config, per, result)) { + long response = 0; + struct curl_header *header = NULL; + const char *method = NULL, *scheme = NULL; + + curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_METHOD, &method); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme); + scheme = proto_token(scheme); + + if((scheme == proto_http || scheme == proto_https) && + method && !strcmp(method, "GET") && + ((response == 206 && config->resume_from) || + (response == 200 && + !curl_easy_header(curl, "Accept-Ranges", 0, + CURLH_HEADER, -1, &header) && + !strcmp(header->value, "bytes")))) { + + notef("Keeping %" CURL_FORMAT_CURL_OFF_T " bytes", outs->bytes); + if(fflush(outs->stream)) { + errorf("Failed to flush output file stream"); + return CURLE_WRITE_ERROR; + } + if(outs->bytes >= CURL_OFF_T_MAX - outs->init) { + errorf("Exceeded maximum supported file size (" + "%" CURL_FORMAT_CURL_OFF_T " + " + "%" CURL_FORMAT_CURL_OFF_T ")", + outs->init, outs->bytes); + return CURLE_WRITE_ERROR; + } + truncate = FALSE; + outs->init += outs->bytes; + outs->bytes = 0; + config->resume_from = outs->init; + curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, + config->resume_from); + } + } + + if(truncate && outs->bytes && outs->filename && outs->stream) { #ifndef __MINGW32CE__ struct_stat fileinfo; diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index ce97740b9af0..99c287507f76 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -275,7 +275,7 @@ test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \ test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \ test3016 test3017 test3018 test3019 test3020 test3021 test3022 test3023 \ test3024 test3025 test3026 test3027 test3028 test3029 test3030 test3031 \ -test3032 test3033 test3034 \ +test3032 test3033 test3034 test3035 \ \ test3100 test3101 test3102 test3103 test3104 test3105 \ \ diff --git a/tests/data/test3035 b/tests/data/test3035 new file mode 100644 index 000000000000..19fefa23183f --- /dev/null +++ b/tests/data/test3035 @@ -0,0 +1,127 @@ + + + +HTTP +HTTP GET +Content-Range +Resume +retry + + + +# Server-side + + +# +# the first chunk +# + +HTTP/1.1 200 OK swsbounce swsclose +Accept-Ranges: bytes +Content-Type: text/html +Content-Length: 26 + +abcde + + +# +# the second chunk +# + +HTTP/1.1 206 Partial Content swsbounce swsclose +Content-Type: text/html +Content-Length: 21 +Content-Range: bytes 5-25/26 + +fghijk + + +# +# some nonsense that curl should ignore as unresumable +# + +HTTP/1.1 404 Not Found swsbounce +Content-Type: text/html +Content-Length: 5 + +body + + +# +# some more nonsense that curl should ignore as unresumable +# + +HTTP/1.1 200 OK swsbounce +Accept-Ranges: bytes +Content-Type: text/html +Content-Length: 30 + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + +# +# the third chunk +# + +HTTP/1.1 206 Partial Content swsbounce swsclose +Content-Type: text/html +Content-Length: 15 +Content-Range: bytes 11-25/26 + +lmnopqrstuvwxyz + + + +# Client-side + + +http + + +HTTP retry failed download with keep data and auto-resume + + +--continue-at - --retry 4 --retry-delay 1 --retry-all-errors -o %LOGDIR/outfile%TESTNUMBER http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Range: bytes=5- +User-Agent: curl/%VERSION +Accept: */* + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Range: bytes=11- +User-Agent: curl/%VERSION +Accept: */* + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Range: bytes=11- +User-Agent: curl/%VERSION +Accept: */* + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Range: bytes=11- +User-Agent: curl/%VERSION +Accept: */* + + + + +abcdefghijklmnopqrstuvwxyz + + + + From 0780de2625bf8bb3bcb0f88bbbc401b2750ec1bb Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Fri, 19 Sep 2025 22:12:05 -0400 Subject: [PATCH 381/465] examples: add an example for logging failed transfers - Add an example that demonstrates per-transfer verbose logging to memory. The transfer's log is written to disk only if the transfer fails. Closes https://github.com/curl/curl/pull/18668 --- docs/examples/.gitignore | 1 + docs/examples/Makefile.inc | 1 + docs/examples/log_failed_transfers.c | 335 +++++++++++++++++++++++++++ 3 files changed, 337 insertions(+) create mode 100644 docs/examples/log_failed_transfers.c diff --git a/docs/examples/.gitignore b/docs/examples/.gitignore index 6d14f24cd184..788eefe1ef17 100644 --- a/docs/examples/.gitignore +++ b/docs/examples/.gitignore @@ -68,6 +68,7 @@ interface ipv6 keepalive localport +log_failed_transfers maxconnects multi-app multi-debugcallback diff --git a/docs/examples/Makefile.inc b/docs/examples/Makefile.inc index 3bb68f25aa1f..29c4e3e997bd 100644 --- a/docs/examples/Makefile.inc +++ b/docs/examples/Makefile.inc @@ -84,6 +84,7 @@ check_PROGRAMS = \ ipv6 \ keepalive \ localport \ + log_failed_transfers \ maxconnects \ multi-app \ multi-debugcallback \ diff --git a/docs/examples/log_failed_transfers.c b/docs/examples/log_failed_transfers.c new file mode 100644 index 000000000000..1ec6350510ab --- /dev/null +++ b/docs/examples/log_failed_transfers.c @@ -0,0 +1,335 @@ +/*************************************************************************** + * _ _ ____ _ + * 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 + * + ***************************************************************************/ +/* + * Save failed transfer verbose log to disk + * + */ +/* + * + * This example demonstrates per-transfer verbose logging to memory. + * The transfer's log is written to disk only if the transfer fails. + * + */ + +#ifdef _WIN32 +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define unlink _unlink +#else +#include +#include +#endif + +struct mem { + /* 'buf' points to memory contents that is always zero terminated so that it + can be treated like a string if appropriate. 'recent' points to the most + recent data written to 'buf'. */ + char *buf, *recent; + /* 'len' and 'allocsize' are the length and allocated size of 'buf' */ + size_t len, allocsize; +}; + +struct transfer { + const char *url, *bodyfile, *logfile; + struct mem log; + FILE *bodyfp; + CURL *curl; +}; + +static void mem_reset(struct mem *mem) +{ + free(mem->buf); + mem->buf = NULL; + mem->recent = NULL; + mem->len = 0; + mem->allocsize = 0; +} + +/* expand free buffer space to needed size. return -1 or 'needed'. */ +static int mem_need(struct mem *mem, size_t needed) +{ + char *newbuf; + size_t newsize; + + if(needed > (unsigned)INT_MAX) + return -1; + + if(needed <= (mem->allocsize - mem->len)) + return (int)needed; + + /* min 4k makes reallocations much less frequent when lengths are small */ + newsize = needed < 4096 ? 4096 : needed; + + newsize += mem->len; + + if(newsize < mem->len || newsize > (unsigned)INT_MAX) + return -1; + + newbuf = realloc(mem->buf, newsize); + + if(!newbuf) + return -1; + + if(mem->recent && mem->buf != newbuf) + mem->recent = newbuf + (mem->recent - mem->buf); + + mem->buf = newbuf; + mem->allocsize = newsize; + + return (int)needed; +} + +static int mem_addn(struct mem *mem, const char *buf, size_t len) +{ + if(len + 1 < len || mem_need(mem, len + 1) < 0) + return -1; + mem->recent = mem->buf + mem->len; + memcpy(mem->recent, buf, len); + mem->len += len; + mem->buf[mem->len] = '\0'; + return (int)len; +} + +static int mem_add(struct mem *mem, const char *str) +{ + return mem_addn(mem, str, strlen(str)); +} + +#if defined(__GNUC__) || defined(__clang__) +__attribute__ ((format (printf, 2, 3))) +#endif +static int mem_addf(struct mem *mem, const char *format, ...) +{ + int i, x; + va_list va; + + /* we need about 100 chars or less to write 95% of lines */ + x = 128; + + /* first try: there's probably enough memory to write everything. + second try: there's definitely enough memory to write everything. */ + for(i = 0; i < 2; ++i) { + if(x < 0 || mem_need(mem, (size_t)x + 1) < 0) + break; + + va_start(va, format); + x = vsnprintf(mem->buf + mem->len, mem->allocsize - mem->len, format, va); + va_end(va); + + if(x >= 0 && (size_t)x < (mem->allocsize - mem->len)) { + mem->recent = mem->buf + mem->len; + mem->len += (size_t)x; + return x; + } + +#ifdef _WIN32 + /* Not all versions of Windows CRT vsnprintf are compliant with C99. Some + return -1 if buffer too small. Try _vscprintf to get the needed size. */ + if(!i && x < 0) { + va_start(va, format); + x = _vscprintf(format, va); + va_end(va); + } +#endif + } + + if(mem->buf) + mem->buf[mem->len] = '\0'; + return -1; +} + +static int mydebug(CURL *handle, curl_infotype type, + char *data, size_t size, void *userdata) +{ + struct transfer *t = (struct transfer *)userdata; + static const char s_infotype[CURLINFO_END][3] = { + "* ", "< ", "> ", "{ ", "} ", "{ ", "} " }; + + (void)handle; + + switch(type) { + case CURLINFO_TEXT: + case CURLINFO_HEADER_OUT: + case CURLINFO_HEADER_IN: + /* mem_addn is faster than passing large data as %s to mem_addf */ + mem_addn(&t->log, s_infotype[type], 2); + mem_addn(&t->log, data, size); + if(!size || data[size - 1] != '\n') + mem_add(&t->log, "\n"); + break; + default: + break; + } + + return 0; +} + +static size_t mywrite(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + struct transfer *t = (struct transfer *)userdata; + + return fwrite(ptr, size, nmemb, t->bodyfp); +} + +int main(void) +{ + unsigned i; + int total_failed = 0; + char errbuf[CURL_ERROR_SIZE] = { 0, }; + struct transfer transfer[2]; + + memset(transfer, 0, sizeof(transfer)); + + transfer[0].url = "https://httpbin.org/get"; + transfer[0].bodyfile = "200.txt"; + transfer[0].logfile = "200_transfer_log.txt"; + + transfer[1].url = "https://httpbin.org/status/400"; + transfer[1].bodyfile = "400.txt"; + transfer[1].logfile = "400_transfer_log.txt"; + + if(curl_global_init(CURL_GLOBAL_DEFAULT)) { + fprintf(stderr, "curl_global_init failed\n"); + return 1; + } + + /* You could enable global tracing for extra verbosity when verbosity is + enabled for a transfer. */ +#if 0 + curl_global_trace("all"); +#endif + + for(i = 0; i < sizeof(transfer)/sizeof(transfer[0]); ++i) { + int failed = 0; + struct transfer *t = &transfer[i]; + + t->curl = curl_easy_init(); + + if(!t->curl) { + fprintf(stderr, "curl_easy_init failed\n"); + curl_global_cleanup(); + return 1; + } + + curl_easy_setopt(t->curl, CURLOPT_URL, t->url); + + /* Enable following redirects */ + curl_easy_setopt(t->curl, CURLOPT_FOLLOWLOCATION, 1L); + + /* Enable verbose logging to memory */ + curl_easy_setopt(t->curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(t->curl, CURLOPT_DEBUGFUNCTION, mydebug); + curl_easy_setopt(t->curl, CURLOPT_DEBUGDATA, t); + + /* Enable writing the body to a file */ + curl_easy_setopt(t->curl, CURLOPT_WRITEFUNCTION, mywrite); + curl_easy_setopt(t->curl, CURLOPT_WRITEDATA, t); + + /* Enable immediate error on HTTP status codes >= 400 in most cases, + instead of downloading the body to a file */ + curl_easy_setopt(t->curl, CURLOPT_FAILONERROR, 1L); + + /* Enable detailed error messages */ + curl_easy_setopt(t->curl, CURLOPT_ERRORBUFFER, errbuf); + + mem_addf(&t->log, "Downloading %s to file %s\n", t->url, t->bodyfile); + printf("%s", t->log.recent); + + /* Create the body file */ + t->bodyfp = fopen(t->bodyfile, "wb"); + + if(t->bodyfp) { + /* Perform the transfer */ + CURLcode result = curl_easy_perform(t->curl); + + /* Save the body file */ + fclose(t->bodyfp); + t->bodyfp = NULL; + + if(result == CURLE_OK) { + /* You could retrieve more information about the transfer here via + curl_easy_getinfo and mark the transfer as failed if needed. */ + mem_addf(&t->log, "Transfer successful.\n"); + fprintf(stderr, "%s", t->log.recent); + failed = 0; + } + else { + mem_addf(&t->log, "Transfer failed: (%d) %s\n", result, + (errbuf[0] ? errbuf : curl_easy_strerror(result))); + fprintf(stderr, "%s", t->log.recent); + failed = 1; + } + } + else { + mem_addf(&t->log, "Failed to create body output file %s: %s\n", + t->bodyfile, strerror(errno)); + fprintf(stderr, "%s", t->log.recent); + failed = 1; + } + + if(failed) { + FILE *fp = fopen(t->logfile, "wb"); + + if(fp && t->log.len == fwrite(t->log.buf, 1, t->log.len, fp)) + fprintf(stderr, "Transfer log written to %s\n", t->logfile); + else { + fprintf(stderr, "Failed to write transfer log to %s: %s\n", + t->logfile, strerror(errno)); + } + + if(fp) + fclose(fp); + + /* Depending on how the transfer failed a body file may or may not have + been written, and you may or may not want it. */ + unlink(t->bodyfile); + + ++total_failed; + } + + mem_reset(&t->log); + + curl_easy_cleanup(t->curl); + + t->curl = NULL; + + printf("\n"); + } + + return total_failed ? 1 : 0; +} From 1e6d507de779d52c6a614a8d50b561ed337bbef4 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 13:18:05 +0200 Subject: [PATCH 382/465] schannel_verify: fix mem-leak in Curl_verify_host Reported-by: Stanislav Fort Closes #18972 --- lib/vtls/schannel_verify.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index e64a113ff2b6..d72790e9df57 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -611,8 +611,8 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, sspi_status = Curl_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, - SECPKG_ATTR_REMOTE_CERT_CONTEXT, - &pCertContextServer); + SECPKG_ATTR_REMOTE_CERT_CONTEXT, + &pCertContextServer); if((sspi_status != SEC_E_OK) || !pCertContextServer) { char buffer[WINAPI_ERROR_LEN]; @@ -667,13 +667,14 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, goto cleanup; } actual_len = cert_get_name_string(data, pCertContextServer, - (LPTSTR)cert_hostname_buff, len, alt_name_info, Win8_compat); + (LPTSTR)cert_hostname_buff, len, + alt_name_info, Win8_compat); /* Sanity check */ if(actual_len != len) { failf(data, - "schannel: CertGetNameString() returned certificate " - "name information of unexpected size"); + "schannel: CertGetNameString() returned certificate " + "name information of unexpected size"); goto cleanup; } @@ -684,7 +685,6 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, while(cert_hostname_buff_index < len && cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') && result == CURLE_PEER_FAILED_VERIFICATION) { - char *cert_hostname; /* Comparing the cert name and the connection hostname encoded as UTF-8 @@ -692,15 +692,14 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, * (or some equivalent) encoding */ cert_hostname = curlx_convert_tchar_to_UTF8( - &cert_hostname_buff[cert_hostname_buff_index]); + &cert_hostname_buff[cert_hostname_buff_index]); if(!cert_hostname) { result = CURLE_OUT_OF_MEMORY; } else { if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname), conn_hostname, hostlen)) { - infof(data, - "schannel: connection hostname (%s) validated " + infof(data, "schannel: connection hostname (%s) validated " "against certificate name (%s)", conn_hostname, cert_hostname); result = CURLE_OK; @@ -736,6 +735,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, } cleanup: + LocalFree(alt_name_info); Curl_safefree(cert_hostname_buff); if(pCertContextServer) From 2a2a2e5d107f1ad7fbb5e88dab03ed37c8177e76 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 16:35:39 +0200 Subject: [PATCH 383/465] vauth/digest: improve the digest parser Previously, if for example the nonce would end with "realm=" etc it would get the wrong piece, due to the naive parser. Reported-by: Joshua Rogers Closes #18975 --- lib/vauth/digest.c | 61 +++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c index 4196ae725c1d..0a0b3580ed09 100644 --- a/lib/vauth/digest.c +++ b/lib/vauth/digest.c @@ -193,26 +193,43 @@ static char *auth_digest_string_quoted(const char *source) /* Retrieves the value for a corresponding key from the challenge string * returns TRUE if the key could be found, FALSE if it does not exists */ -static bool auth_digest_get_key_value(const char *chlg, - const char *key, - char *value, - size_t max_val_len, - char end_char) +static bool auth_digest_get_key_value(const char *chlg, const char *key, + char *buf, size_t buflen) { - char *find_pos; - size_t i; - - find_pos = strstr(chlg, key); - if(!find_pos) - return FALSE; - - find_pos += strlen(key); - - for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i) - value[i] = *find_pos++; - value[i] = '\0'; + /* keyword=[value],keyword2=[value] + The values may or may not be quoted. + */ + + do { + struct Curl_str data; + struct Curl_str name; + if(!curlx_str_until(&chlg, &name, 64, '=') && + !curlx_str_single(&chlg, '=')) { + /* this is the key, get the value, possibly quoted */ + int rc = curlx_str_quotedword(&chlg, &data, 256); + if(rc == STRE_BEGQUOTE) + /* try unquoted until comma */ + rc = curlx_str_until(&chlg, &data, 256, ','); + if(rc) + return FALSE; /* weird */ + + if(curlx_str_cmp(&name, key)) { + /* if this is our key, return the value */ + if(curlx_strlen(&data) >= buflen) + /* doesn't fit */ + return FALSE; + memcpy(buf, curlx_str(&data), curlx_strlen(&data)); + buf[curlx_strlen(&data)] = 0; + return TRUE; + } + if(curlx_str_single(&chlg, ',')) + return FALSE; + } + else /* odd syntax */ + break; + } while(1); - return TRUE; + return FALSE; } static CURLcode auth_digest_get_qop_values(const char *options, int *value) @@ -268,21 +285,21 @@ static CURLcode auth_decode_digest_md5_message(const struct bufref *chlgref, return CURLE_BAD_CONTENT_ENCODING; /* Retrieve nonce string from the challenge */ - if(!auth_digest_get_key_value(chlg, "nonce=\"", nonce, nlen, '\"')) + if(!auth_digest_get_key_value(chlg, "nonce", nonce, nlen)) return CURLE_BAD_CONTENT_ENCODING; /* Retrieve realm string from the challenge */ - if(!auth_digest_get_key_value(chlg, "realm=\"", realm, rlen, '\"')) { + if(!auth_digest_get_key_value(chlg, "realm", realm, rlen)) { /* Challenge does not have a realm, set empty string [RFC2831] page 6 */ *realm = '\0'; } /* Retrieve algorithm string from the challenge */ - if(!auth_digest_get_key_value(chlg, "algorithm=", alg, alen, ',')) + if(!auth_digest_get_key_value(chlg, "algorithm", alg, alen)) return CURLE_BAD_CONTENT_ENCODING; /* Retrieve qop-options string from the challenge */ - if(!auth_digest_get_key_value(chlg, "qop=\"", qop, qlen, '\"')) + if(!auth_digest_get_key_value(chlg, "qop", qop, qlen)) return CURLE_BAD_CONTENT_ENCODING; return CURLE_OK; From 2c6505e0ef9c0368e9acbef5662eb15e43328b65 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 16:51:55 +0200 Subject: [PATCH 384/465] krb5_gssapi: fix memory leak on error path If a non-compliant amount of bytes is received, the function would return error without free. Reported-by: Joshua Rogers Closes #18976 --- lib/vauth/krb5_gssapi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/vauth/krb5_gssapi.c b/lib/vauth/krb5_gssapi.c index 70144e5514ad..a414d0a35961 100644 --- a/lib/vauth/krb5_gssapi.c +++ b/lib/vauth/krb5_gssapi.c @@ -225,6 +225,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ if(output_token.length != 4) { infof(data, "GSSAPI handshake failure (invalid security data)"); + gss_release_buffer(&unused_status, &output_token); return CURLE_BAD_CONTENT_ENCODING; } From 435da1f849ad9a5e91b8e348d6830b0c546ac15a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 17:17:31 +0200 Subject: [PATCH 385/465] Curl_resolv: fix comment. 'entry' argument is not optional Reported-by: Joshua Rogers Closes #18979 --- lib/hostip.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/hostip.c b/lib/hostip.c index a6531c31711b..41db274c5d4e 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -819,9 +819,9 @@ static CURLcode store_negative_resolve(struct Curl_easy *data, /* * Curl_resolv() is the main name resolve function within libcurl. It resolves - * a name and returns a pointer to the entry in the 'entry' argument (if one - * is provided). This function might return immediately if we are using asynch - * resolves. See the return codes. + * a name and returns a pointer to the entry in the 'entry' argument. This + * function might return immediately if we are using asynch resolves. See the + * return codes. * * The cache entry we return will get its 'inuse' counter increased when this * function is used. You MUST call Curl_resolv_unlink() later (when you are From 71585f9894cf97ed6719487cb03aa97d2f94b7cd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 17:23:56 +0200 Subject: [PATCH 386/465] asyn-ares: use the duped hostname pointer for all calls In one c-ares call the passed in pointer was used and not the new duplicated one. This is probably fine but might as well use the new pointer as all the other calls do, which will survive longer. Reported-by: Joshua Rogers Closes #18980 --- lib/asyn-ares.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 236697695eda..dcbed0129c73 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -793,7 +793,7 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data, /* The stack seems to be IPv6-enabled */ /* areschannel is already setup in the Curl_open() function */ CURL_TRC_DNS(data, "asyn-ares: fire off query for A"); - ares_gethostbyname(ares->channel, hostname, PF_INET, + ares_gethostbyname(ares->channel, data->state.async.hostname, PF_INET, async_ares_hostbyname_cb, data); CURL_TRC_DNS(data, "asyn-ares: fire off query for AAAA"); ares->num_pending = 2; From eb3a4314fee5e27dc815a6ef3df632718f6ea823 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 22:10:32 +0200 Subject: [PATCH 387/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 69 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 47c7dd52556d..44ef5ddfc1e5 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -8,6 +8,7 @@ curl and libcurl 8.17.0 This release includes the following changes: + o build: drop Heimdal support [267] o build: drop the winbuild build system [81] o krb5: drop support for Kerberos FTP [43] o libssh2: up the minimum requirement to 1.9.0 [85] @@ -22,6 +23,7 @@ This release includes the following changes: This release includes the following bugfixes: o ares: fix leak in tracing [91] + o asyn-ares: use the duped hostname pointer for all calls [158] o asyn-thrdd resolver: clear timeout when done [97] o asyn-thrdd: drop pthread_cancel [30] o autotools: add support for libgsasl auto-detection via pkg-config [112] @@ -49,11 +51,13 @@ This release includes the following bugfixes: o checksrc: fix to handle `)` predecing a banned function [229] o checksrc: reduce directory-specific exceptions [228] o cmake/FindGSS: fix `pkg-config` fallback logic for CMake <3.16 [189] + o cmake/FindGSS: whitespace/formatting [268] o cmake: add `CURL_CODE_COVERAGE` option [78] o cmake: build the "all" examples source list dynamically [245] o cmake: clang detection tidy-ups [116] o cmake: drop exclamation in comment looking like a name [160] o cmake: fix building docs when the base directory contains `.3` [18] + o cmake: minor Heimdal flavour detection fix [269] o cmake: support building some complicated examples, build them in CI [235] o cmake: use modern alternatives for `get_filename_component()` [102] o cmake: use more `COMPILER_OPTIONS`, `LINK_OPTIONS` / `LINK_FLAGS` [152] @@ -65,6 +69,7 @@ This release includes the following bugfixes: o curl_easy_getinfo: error code on NULL arg [2] o curl_mem_undef.h: limit to `CURLDEBUG` for non-memalloc overrides [19] o curl_osslq: error out properly if BIO_ADDR_rawmake() fails [184] + o Curl_resolv: fix comment. 'entry' argument is not optional [187] o curl_slist_append.md: clarify that a NULL pointer is not acceptable [72] o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] o CURLOPT_COOKIEFILE.md: clarify when the cookies are loaded [159] @@ -81,6 +86,7 @@ This release includes the following bugfixes: o docs: fix/tidy code fences [87] o easy_getinfo: check magic, Curl_close safety [3] o examples/sessioninfo: cast printf string mask length to int [232] + o examples/sessioninfo: do not disable security [255] o examples/synctime: make the sscanf not overflow the local buffer [252] o examples/usercertinmem: avoid stripping const [247] o examples: drop unused `curl/mprintf.h` includes [224] @@ -96,7 +102,11 @@ This release includes the following bugfixes: o ftp: improve fragile check for first digit > 3 [194] o ftp: remove misleading comments [193] o gtls: avoid potential use of uninitialized variable in trace output [83] + o hostip: don't store negative resolves due unrelated errors [256] o hostip: remove leftover INT_MAX check in Curl_dnscache_prune [88] + o http2: check push header names by length first [261] + o http2: cleanup pushed newhandle on fail [260] + o http2: ingress handling edge cases [259] o http: handle user-defined connection headers [165] o http: make Content-Length parser more WHATWG [183] o httpsrr: free old pointers when storing new [57] @@ -105,6 +115,7 @@ This release includes the following bugfixes: o ip-happy: do not set unnecessary timeout [95] o ip-happy: prevent event-based stall on retry [155] o krb5: return appropriate error on send failures [22] + o krb5_gssapi: fix memory leak on error path [190] o krb5_sspi: the chlg argument is NOT optional [200] o ldap: do not base64 encode zero length string [42] o ldap: tidy-up types, fix error code confusion [191] @@ -114,6 +125,8 @@ This release includes the following bugfixes: o lib: upgrade/multiplex handling [136] o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] + o libssh/sftp: fix resume corruption by avoiding O_APPEND with rresume [263] + o libssh2/sftp: fix resume corruption by avoiding O_APPEND with rresume [262] o libssh2/sftp_realpath: change state consistently [185] o libssh2: bail out on chgrp and chown number parsing errors [202] o libssh2: clarify that sshp->path is always at least one byte [201] @@ -137,6 +150,7 @@ This release includes the following bugfixes: o mbedtls: check result of setting ALPN [127] o mbedtls: handle WANT_WRITE from mbedtls_ssl_read() [145] o mdlinkcheck: reject URLs containing quotes [174] + o memdup0: handle edge case [241] o multi.h: add CURLMINFO_LASTENTRY [51] o multi_ev: remove unnecessary data check that confuses analysers [167] o nghttp3: return NGHTTP3_ERR_CALLBACK_FAILURE from recv_header [227] @@ -157,6 +171,7 @@ This release includes the following bugfixes: o openssl: clear retry flag on x509 error [130] o openssl: fail the transfer if ossl_certchain() fails [23] o openssl: fix build for v1.0.2 [225] + o openssl: fix peer certificate leak in channel binding [258] o openssl: make the asn1_object_dump name null terminated [56] o openssl: set io_need always [99] o openssl: skip session resumption when verifystatus is set [230] @@ -168,19 +183,24 @@ This release includes the following bugfixes: o quic: ignore EMSGSIZE on receive [4] o quiche: fix possible leaks on teardown [205] o quiche: fix verbose message when ip quadruple cannot be obtained. [128] + o quiche: handle tls fail correctly [266] o quiche: when ingress processing fails, return that error code [103] o runtests: tag tests that require curl verbose strings [172] o rustls: fix clang-tidy warning [107] o rustls: fix comment describing cr_recv() [117] + o rustls: pass the correct result to rustls_failf [242] o rustls: typecast variable for safer trace output [69] o rustls: use %zu for size_t in failf() format string [121] o sasl: clear canceled mechanism instead of toggling it [41] o schannel: assign result before using it [62] + o schannel_verify: fix mem-leak in Curl_verify_host [208] o schannel_verify: use more human friendly error messages [96] o setopt: accept *_SSL_VERIFYHOST set to 2L [31] + o setopt: allow CURLOPT_DNS_CACHE_TIMEOUT set to -1 [257] o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] o smb: adjust buffer size checks [45] o smtp: check EHLO responses case insensitively [50] + o socks: deny server basic-auth if not configured [264] o socks: handle error in verbose trace gracefully [94] o socks: handle premature close [246] o socks: make Curl_blockread_all return CURLcode [67] @@ -231,6 +251,7 @@ This release includes the following bugfixes: o tool_getparam: always disable "lib-ids" for tracing [169] o tool_getparam: warn if provided header looks malformed [179] o tool_operate: improve wording in retry message [37] + o tool_operate: keep failed partial download for retry auto-resume [210] o tool_operate: keep the progress meter for --out-null [33] o tool_progress: handle possible integer overflows [164] o tool_progress: make max5data() use an algorithm [170] @@ -239,8 +260,10 @@ This release includes the following bugfixes: o unit1664: drop casts, expand masks to full values [221] o url: make Curl_init_userdefined return void [213] o urldata: FILE is not a list-only protocol [9] + o vauth/digest: improve the digest parser [203] o vquic: fix idle-timeout checks (ms<-->ns), 64-bit log & honor 0=no-timeout [249] o vquic: handling of io improvements [239] + o vquic: sending non-gso packets fix for EAGAIN [265] o vtls: alpn setting, check proto parameter [134] o vtls_int.h: clarify data_pending [124] o vtls_scache: fix race condition [157] @@ -276,17 +299,18 @@ Planned upcoming removals include: This release would not have looked like this without help, code, reports and advice from friends like these: - Adam Light, Alice Lee Poetics, Andrew Kirillov, Andrew Olsen, - BobodevMm on github, Christian Schmitz, Dan Fandrich, Daniel Stenberg, - Daniel Terhorst-North, dependabot[bot], divinity76 on github, - Emilio Pozuelo Monfort, Ethan Everett, Evgeny Grin (Karlson2k), - fds242 on github, Howard Chu, Ignat Loskutov, Javier Blazquez, Jicea, - jmaggard10 on github, Johannes Schindelin, Joseph Birr-Pixton, Joshua Rogers, - kapsiR on github, kuchara on github, Marcel Raad, Michael Osipov, - MichaÅ‚ Petryka, Mohamed Daahir, Nir Azkiel, Patrick Monnerat, Pocs Norbert, - Ray Satiro, renovate[bot], rinsuki on github, Samuel Dionne-Riel, - Samuel Henrique, Stanislav Fort, Stefan Eissing, Viktor Szakats - (40 contributors) + Adam Light, Alice Lee Poetics, Andrei Kurushin, Andrew Kirillov, + Andrew Olsen, BobodevMm on github, Christian Schmitz, Dan Fandrich, + Daniel Stenberg, Daniel Terhorst-North, dependabot[bot], + divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, + Evgeny Grin (Karlson2k), fds242 on github, Howard Chu, Ignat Loskutov, + Javier Blazquez, Jicea, jmaggard10 on github, Johannes Schindelin, + Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, kuchara on github, + Marcel Raad, Michael Osipov, MichaÅ‚ Petryka, Mohamed Daahir, Nir Azkiel, + Patrick Monnerat, Pocs Norbert, Ray Satiro, renovate[bot], rinsuki on github, + Samuel Dionne-Riel, Samuel Henrique, Stanislav Fort, Stefan Eissing, + tkzv on github, Viktor Szakats + (42 contributors) References to bug reports and discussions on issues: @@ -447,6 +471,7 @@ References to bug reports and discussions on issues: [155] = https://curl.se/bug/?i=18815 [156] = https://curl.se/bug/?i=18893 [157] = https://curl.se/bug/?i=18806 + [158] = https://curl.se/bug/?i=18980 [159] = https://curl.se/bug/?i=18924 [160] = https://curl.se/bug/?i=18810 [161] = https://curl.se/bug/?i=18749 @@ -475,8 +500,10 @@ References to bug reports and discussions on issues: [184] = https://curl.se/bug/?i=18878 [185] = https://curl.se/bug/?i=18875 [186] = https://curl.se/bug/?i=18874 + [187] = https://curl.se/bug/?i=18979 [188] = https://curl.se/bug/?i=18940 [189] = https://curl.se/bug/?i=18932 + [190] = https://curl.se/bug/?i=18976 [191] = https://curl.se/bug/?i=18888 [192] = https://curl.se/bug/?i=18873 [193] = https://curl.se/bug/?i=18871 @@ -489,10 +516,13 @@ References to bug reports and discussions on issues: [200] = https://curl.se/bug/?i=18865 [201] = https://curl.se/bug/?i=18864 [202] = https://curl.se/bug/?i=18863 + [203] = https://curl.se/bug/?i=18975 [204] = https://curl.se/bug/?i=18859 [205] = https://curl.se/bug/?i=18880 [206] = https://curl.se/bug/?i=18868 [207] = https://curl.se/bug/?i=18872 + [208] = https://curl.se/bug/?i=18972 + [210] = https://curl.se/bug/?i=18035 [211] = https://curl.se/bug/?i=18860 [212] = https://curl.se/bug/?i=18858 [213] = https://curl.se/bug/?i=18855 @@ -522,6 +552,8 @@ References to bug reports and discussions on issues: [238] = https://curl.se/bug/?i=18829 [239] = https://curl.se/bug/?i=18812 [240] = https://curl.se/bug/?i=18703 + [241] = https://curl.se/bug/?i=18966 + [242] = https://curl.se/bug/?i=18961 [243] = https://curl.se/bug/?i=18914 [245] = https://curl.se/bug/?i=18911 [246] = https://curl.se/bug/?i=18883 @@ -531,3 +563,18 @@ References to bug reports and discussions on issues: [250] = https://curl.se/bug/?i=18432 [251] = https://curl.se/bug/?i=18881 [252] = https://curl.se/bug/?i=18890 + [255] = https://curl.se/bug/?i=18969 + [256] = https://curl.se/bug/?i=18953 + [257] = https://curl.se/bug/?i=18959 + [258] = https://hackerone.com/reports/3373640 + [259] = https://curl.se/bug/?i=18933 + [260] = https://curl.se/bug/?i=18931 + [261] = https://curl.se/bug/?i=18930 + [262] = https://curl.se/bug/?i=18952 + [263] = https://curl.se/bug/?i=18952 + [264] = https://curl.se/bug/?i=18937 + [265] = https://curl.se/bug/?i=18936 + [266] = https://curl.se/bug/?i=18934 + [267] = https://curl.se/bug/?i=18928 + [268] = https://curl.se/bug/?i=18957 + [269] = https://curl.se/bug/?i=18951 From 6c0338115ae5f2cde96a9268f54e63fa725d0d7a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 22:32:09 +0200 Subject: [PATCH 388/465] ftp: simplify the 150/126 size scanner The file size is weirdly returned in a 150 or 126 response as "XXX bytes" mentioned somewhere in the response string. This is a rewrite of the size scanner to replace the strange strstr() + backwards search from before with a plain forward search until '[number] + " bytes"' is a match. Triggered by a report by Joshua Rogers about the previous parser. Closes #18984 --- lib/ftp.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/lib/ftp.c b/lib/ftp.c index c3b8aafbc5d5..adcad3dd7587 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -2496,30 +2496,19 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data, * those cases only confuses us. * * Example D above makes this parsing a little tricky */ - const char *bytes; - char *buf = curlx_dyn_ptr(&ftpc->pp.recvbuf); - bytes = strstr(buf, " bytes"); - if(bytes) { - long in = (long)(--bytes-buf); - /* this is a hint there is size information in there! ;-) */ - while(--in) { - /* scan for the left parenthesis and break there */ - if('(' == *bytes) - break; - /* skip only digits */ - if(!ISDIGIT(*bytes)) { - bytes = NULL; + size_t len = curlx_dyn_len(&ftpc->pp.recvbuf); + if(len >= 7) { /* "1 bytes" is 7 characters */ + size_t i; + for(i = 0; i < len - 7; i++) { + curl_off_t what; + char *buf = curlx_dyn_ptr(&ftpc->pp.recvbuf); + const char *c = &buf[i]; + if(!curlx_str_number(&c, &what, CURL_OFF_T_MAX) && + !curlx_str_single(&c, ' ') && + !strncmp(c, "bytes", 5)) { + size = what; break; } - /* one more estep backwards */ - bytes--; - } - /* if we have nothing but digits: */ - if(bytes) { - ++bytes; - /* get the number! */ - if(curlx_str_number(&bytes, &size, CURL_OFF_T_MAX)) - size = 1; } } } From d35bdfa8f28d646166592f607b8100b6c60be0f0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 22:50:01 +0200 Subject: [PATCH 389/465] openldap: fix memory-leak in error path The 'ber' pointer could escape a free if an early error occurred. Reported-by: Joshua Rogers Closes #18985 --- lib/openldap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/openldap.c b/lib/openldap.c index 72cfdc7039a8..92364e3e77c9 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -1216,7 +1216,6 @@ static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf, break; } - ber_free(ber, 0); if(!result) result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0); @@ -1225,6 +1224,7 @@ static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf, break; } + ber_free(ber, 0); ldap_msgfree(msg); return result; } From be5a5c10d49bfe35e7e2ccf63ae700abad786379 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 22:57:29 +0200 Subject: [PATCH 390/465] openldap: fix memory-leak on oldap_do's exit path On SSL sockbuf setup failure in `oldap_do`, the 'lud' data would not be freed and instead leak. Reported-by: Joshua Rogers Closes #18986 --- lib/openldap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/openldap.c b/lib/openldap.c index 92364e3e77c9..b84268dae7c0 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -988,8 +988,10 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done) Sockbuf *sb; /* re-install the libcurl SSL handlers into the sockbuf. */ if((ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb) != LDAP_OPT_SUCCESS) || - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data)) + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data)) { + ldap_free_urldesc(lud); return CURLE_FAILED_INIT; + } } #endif From 0d560d00faaa6fa3ff3918d82c8fbd551452d17e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 9 Oct 2025 17:15:02 +0200 Subject: [PATCH 391/465] kerberos: drop logic for MIT Kerberos <1.2.3 (pre-2002) versions curl requires 1.2.4 or newer. Also: - vms: stop defining `gss_nt_service_name`. Added in f9cf3de70b3a494f627eda6cccf6607616eaf449, symbol not used in curl code since 355bf01c828af16c47ab52bccb9ade769f8bf158. Closes #18978 --- CMakeLists.txt | 28 +-------------------- configure.ac | 23 ----------------- docs/INSTALL-CMAKE.md | 1 - lib/curl_config.h.cmake | 3 --- lib/curl_gssapi.h | 6 ----- packages/vms/generate_config_vms_h_curl.com | 5 ---- 6 files changed, 1 insertion(+), 65 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f711dff04a24..d1c8fa32c5c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1445,34 +1445,8 @@ if(CURL_USE_GSSAPI) else() # MIT cmake_push_check_state() list(APPEND CMAKE_REQUIRED_INCLUDES "${GSS_INCLUDE_DIRS}") - - set(_include_list "") - check_include_file("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) - if(HAVE_GSSAPI_GSSAPI_H) - list(APPEND _include_list "gssapi/gssapi.h") - endif() - - check_include_files("${_include_list};gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) - check_include_files("${_include_list};gssapi/gssapi_krb5.h" _have_gssapi_gssapi_krb5_h) - if(HAVE_GSSAPI_GSSAPI_GENERIC_H) - list(APPEND _include_list "gssapi/gssapi_generic.h") - endif() - if(_have_gssapi_gssapi_krb5_h) - list(APPEND _include_list "gssapi/gssapi_krb5.h") - endif() - - if(NOT DEFINED HAVE_GSS_C_NT_HOSTBASED_SERVICE) - string(APPEND CMAKE_REQUIRED_FLAGS " ${GSS_CFLAGS}") - list(APPEND CMAKE_REQUIRED_LIBRARIES "${GSS_LIBRARIES}") - curl_required_libpaths("${GSS_LIBRARY_DIRS}") - check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" "${_include_list}" HAVE_GSS_C_NT_HOSTBASED_SERVICE) - endif() - if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE) - set(HAVE_OLD_GSSMIT ON) - endif() - - unset(_include_list) + check_include_file("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) cmake_pop_check_state() endif() else() diff --git a/configure.ac b/configure.ac index c76be65e9667..c8843b5b46ca 100644 --- a/configure.ac +++ b/configure.ac @@ -1855,29 +1855,6 @@ if test x"$want_gss" = xyes; then if test "x$not_mit" = "x1"; then dnl MIT not found AC_MSG_ERROR([MIT or GNU GSS library required, but not found]) - else - dnl MIT found - dnl check if we have a really old MIT Kerberos version (<= 1.2) - AC_MSG_CHECKING([if GSS-API headers declare GSS_C_NT_HOSTBASED_SERVICE]) - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([[ - #include - #include - #include - ]],[[ - gss_import_name( - (OM_uint32 *)0, - (gss_buffer_t)0, - GSS_C_NT_HOSTBASED_SERVICE, - (gss_name_t *)0); - ]]) - ],[ - AC_MSG_RESULT([yes]) - ],[ - AC_MSG_RESULT([no]) - AC_DEFINE(HAVE_OLD_GSSMIT, 1, - [if you have an old MIT Kerberos version, lacking GSS_C_NT_HOSTBASED_SERVICE]) - ]) fi ] ) diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index 46215747e7d8..e5c6b0d375e6 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -474,7 +474,6 @@ the parent project, ideally in the "extra" find package redirect file: Available variables: - `HAVE_GNUTLS_SRP`: `gnutls_srp_verifier` present in GnuTLS. -- `HAVE_GSS_C_NT_HOSTBASED_SERVICE`: `GSS_C_NT_HOSTBASED_SERVICE` present in GSS/Kerberos. - `HAVE_LDAP_INIT_FD`: `ldap_init_fd` present in LDAP library. - `HAVE_LDAP_URL_PARSE`: `ldap_url_parse` present in LDAP library. - `HAVE_OPENSSL_SRP`: `SSL_CTX_set_srp_username` present in OpenSSL (or fork). diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 521a439eef3e..9f37bbb6e26f 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -421,9 +421,6 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NET_IF_H 1 -/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */ -#cmakedefine HAVE_OLD_GSSMIT 1 - /* Define to 1 if you have the `pipe' function. */ #cmakedefine HAVE_PIPE 1 diff --git a/lib/curl_gssapi.h b/lib/curl_gssapi.h index 2659f23460dc..6df7e059d325 100644 --- a/lib/curl_gssapi.h +++ b/lib/curl_gssapi.h @@ -51,12 +51,6 @@ OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min, void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, OM_uint32 major, OM_uint32 minor); -/* Provide some definitions missing in old headers */ -#ifdef HAVE_OLD_GSSMIT -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#define NCOMPAT 1 -#endif - /* Define our privacy and integrity protection values */ #define GSSAUTH_P_NONE 1 #define GSSAUTH_P_INTEGRITY 2 diff --git a/packages/vms/generate_config_vms_h_curl.com b/packages/vms/generate_config_vms_h_curl.com index 271ac608694b..d7bc8bfc8f3b 100644 --- a/packages/vms/generate_config_vms_h_curl.com +++ b/packages/vms/generate_config_vms_h_curl.com @@ -337,11 +337,6 @@ $write cvh "#ifdef USE_UNIX_SOCKETS" $write cvh "#undef USE_UNIX_SOCKETS" $write cvh "#endif" $! -$write cvh "#ifndef HAVE_OLD_GSSMIT" -$write cvh "#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE" -$write cvh "#endif" -$! -$! $! Note: $! The CURL_EXTERN_SYMBOL is used for platforms that need the compiler $! to know about universal symbols. VMS does not need this support so From 69efbcaa03b99b927806af43752bcd5d667a676d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 23:03:18 +0200 Subject: [PATCH 392/465] ldap: avoid null ptr deref on failure ldap_get_dn() can return NULL on error Reported-by: Joshua Rogers Closes #18988 --- lib/ldap.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/lib/ldap.c b/lib/ldap.c index be65ea2055c2..2314bbf58512 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -535,7 +535,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) /* Get the DN and write it to the client */ { char *name; - size_t name_len; + size_t name_len = 0; #ifdef USE_WIN32_LDAP TCHAR *dn = ldap_get_dn(server, entryIterator); name = curlx_convert_tchar_to_UTF8(dn); @@ -549,32 +549,20 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #else char *dn = name = ldap_get_dn(server, entryIterator); #endif - name_len = strlen(name); - - result = Curl_client_write(data, CLIENTWRITE_BODY, "DN: ", 4); - if(result) { - FREE_ON_WINLDAP(name); - ldap_memfree(dn); - goto quit; - } - - result = Curl_client_write(data, CLIENTWRITE_BODY, name, name_len); - if(result) { - FREE_ON_WINLDAP(name); - ldap_memfree(dn); - goto quit; + if(!name) + result = CURLE_FAILED_INIT; + else { + name_len = strlen(name); + result = Curl_client_write(data, CLIENTWRITE_BODY, "DN: ", 4); } - - result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1); - if(result) { - FREE_ON_WINLDAP(name); - ldap_memfree(dn); - - goto quit; - } - + if(!result) + result = Curl_client_write(data, CLIENTWRITE_BODY, name, name_len); + if(!result) + result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1); FREE_ON_WINLDAP(name); ldap_memfree(dn); + if(result) + goto quit; } /* Get the attributes and write them to the client */ From c049c37acd074a61bbd07eebe25fdf32af575a2a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Oct 2025 23:21:37 +0200 Subject: [PATCH 393/465] libssh: make atime and mtime cap the timestamp instead of wrap The libssh API uses a 32 bit type for datestamp, so instead of just force-typecast it, make sure it gets capped at UINT_MAX if the value is larger. Reported-by: Joshua Rogers Closes #18989 --- lib/vssh/libssh.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 579eaeaa0ded..544e682b771e 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1864,6 +1864,9 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, sshc->actualcode = CURLE_QUOTE_ERROR; return SSH_NO_ERROR; } + if(date > UINT_MAX) + /* because the liubssh API can't deal with a larger value */ + date = UINT_MAX; if(!strncmp(cmd, "atime", 5)) sshc->quote_attrs->atime = (uint32_t)date; else /* mtime */ From e5950b2d372ac4f15f6b348227f462d4c3c4d37a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 10 Oct 2025 02:49:46 +0200 Subject: [PATCH 394/465] kerberos: stop including `gssapi/gssapi_generic.h` It's a legacy MIT Kerberos header that's no longer used by curl since: 355bf01c828af16c47ab52bccb9ade769f8bf158 (2015-01-09) There were still mentions of it after this patch, when using versions <1.2.3, but those versions aren't supported since: 99185417952da30c8ddd82ab962fb58da96260b2 (2008-06-12) This header remains in use by autotools and cmake to detect MIT Kerberos (vs. Heimdal, which doesn't have it.) Ref: https://github.com/curl/curl/pull/18978#issuecomment-3387414995 Closes #18990 --- .github/scripts/cmp-config.pl | 1 + CMakeLists.txt | 1 - lib/curl_config.h.cmake | 3 --- lib/urldata.h | 3 --- lib/vauth/vauth.h | 3 --- 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/scripts/cmp-config.pl b/.github/scripts/cmp-config.pl index 5fb8c0abdcaf..4284fcaee70b 100755 --- a/.github/scripts/cmp-config.pl +++ b/.github/scripts/cmp-config.pl @@ -45,6 +45,7 @@ '#define HAVE_BROTLI 1' => 1, '#define HAVE_BROTLI_DECODE_H 1' => 1, '#define HAVE_DLFCN_H 1' => 1, + '#define HAVE_GSSAPI_GSSAPI_GENERIC_H 1' => 1, '#define HAVE_GSSAPI_GSSAPI_KRB5_H 1' => 1, '#define HAVE_INTTYPES_H 1' => 1, '#define HAVE_LDAP_H 1' => 1, diff --git a/CMakeLists.txt b/CMakeLists.txt index d1c8fa32c5c8..387dd57dc27d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1446,7 +1446,6 @@ if(CURL_USE_GSSAPI) cmake_push_check_state() list(APPEND CMAKE_REQUIRED_INCLUDES "${GSS_INCLUDE_DIRS}") check_include_file("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) - check_include_file("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H) cmake_pop_check_state() endif() else() diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 9f37bbb6e26f..3f0bcf22ee62 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -315,9 +315,6 @@ /* if you have the gssapi libraries */ #cmakedefine HAVE_GSSAPI 1 -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_GSSAPI_GSSAPI_GENERIC_H 1 - /* Define to 1 if you have the header file. */ #cmakedefine HAVE_GSSAPI_GSSAPI_H 1 diff --git a/lib/urldata.h b/lib/urldata.h index d924b911941d..cdf028853eab 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -195,9 +195,6 @@ typedef CURLcode (Curl_recv)(struct Curl_easy *data, /* transfer */ # else # include # endif -# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H -# include -# endif #endif #ifdef USE_LIBSSH2 diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h index 57fd27a6a7f3..26e5adc6281f 100644 --- a/lib/vauth/vauth.h +++ b/lib/vauth/vauth.h @@ -241,9 +241,6 @@ CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, # else # include # endif -# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H -# include -# endif #endif /* meta key for storing KRB5 meta at connection */ From 9442dd480e9fe4ded646287b5116be27a0cb4efd Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 10 Oct 2025 14:37:41 +0200 Subject: [PATCH 395/465] GHA/linux: test GNU GSS with autotools, cmake, valgrind and scan-build The cmake build is running runtests with valgrind. The autotools one is running scan-build. Also: - ignore two memleaks with GNU GSS detected by valgrind. - add comment on support status of `GSS_C_DELEG_POLICY_FLAG`. Closes #19008 --- .github/workflows/linux.yml | 10 +++++++--- lib/curl_gssapi.c | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index da49ae67b5eb..e0e256fbb3ab 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -93,8 +93,8 @@ jobs: install_steps: wolfssl-opensslextra configure: LDFLAGS=-Wl,-rpath,/home/runner/wolfssl-opensslextra/lib --with-wolfssl=/home/runner/wolfssl-opensslextra --enable-ech --enable-debug - - name: 'mbedtls valgrind' - install_packages: libnghttp2-dev libidn2-dev libldap-dev valgrind + - name: 'mbedtls gss valgrind' + install_packages: libnghttp2-dev libidn2-dev libldap-dev libgss-dev valgrind install_steps: mbedtls generate: >- -DCURL_USE_MBEDTLS=ON -DENABLE_DEBUG=ON @@ -102,6 +102,7 @@ jobs: -DMBEDTLS_LIBRARY=/home/runner/mbedtls/lib/libmbedtls.a -DMBEDX509_LIBRARY=/home/runner/mbedtls/lib/libmbedx509.a -DMBEDCRYPTO_LIBRARY=/home/runner/mbedtls/lib/libmbedcrypto.a + -DCURL_USE_GSSAPI=ON - name: 'mbedtls clang' install_packages: libnghttp2-dev libldap-dev clang @@ -223,7 +224,7 @@ jobs: --enable-ech --with-gssapi --enable-ssls-export - name: 'scan-build' - install_packages: clang-tools clang libssl-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev libkrb5-dev librtmp-dev libgnutls28-dev + install_packages: clang-tools clang libssl-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev libgss-dev librtmp-dev libgnutls28-dev install_steps: skipall mbedtls rustls wolfssl-opensslextra install_steps_brew: gsasl CC: clang @@ -673,6 +674,9 @@ jobs: run: | if [ "${TEST_TARGET}" = 'test-ci' ] && [[ "${MATRIX_INSTALL_PACKAGES}" = *'valgrind'* ]]; then TFLAGS+=' -j6' + if [[ "${MATRIX_INSTALL_PACKAGES}" = *'libgss-dev'* ]]; then + TFLAGS+=' ~2077 ~2078' # memory leaks from Curl_auth_decode_spnego_message() -> gss_init_sec_context() + fi fi [ -f ~/venv/bin/activate ] && source ~/venv/bin/activate if [[ "${MATRIX_INSTALL_STEPS}" = *'codeset-test'* ]]; then diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c index 87f644a9084f..42ccaa3e2962 100644 --- a/lib/curl_gssapi.c +++ b/lib/curl_gssapi.c @@ -313,7 +313,7 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, req_flags |= GSS_C_MUTUAL_FLAG; if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) { -#ifdef GSS_C_DELEG_POLICY_FLAG +#ifdef GSS_C_DELEG_POLICY_FLAG /* MIT Kerberos 1.8+, missing from GNU GSS */ req_flags |= GSS_C_DELEG_POLICY_FLAG; #else infof(data, "WARNING: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not " From fc9b215fde7f359a5a323f906f26b87d35ac654e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 9 Oct 2025 13:34:56 +0200 Subject: [PATCH 396/465] CI.md: refresh Closes #18973 --- .github/scripts/pyspelling.words | 3 ++ docs/tests/CI.md | 78 ++++++++++++++------------------ 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/.github/scripts/pyspelling.words b/.github/scripts/pyspelling.words index 73e68f48840e..a5c28091301f 100644 --- a/.github/scripts/pyspelling.words +++ b/.github/scripts/pyspelling.words @@ -97,6 +97,7 @@ changeset CharConv charset charsets +checkdocs checksrc checksums chgrp @@ -293,6 +294,7 @@ getinfo GETing getpwuid ggcov +GHA Ghedini giga Gisle @@ -931,6 +933,7 @@ VC vcpkg vexxhost Viktor +virtualized Virtuozzo VLAN VM diff --git a/docs/tests/CI.md b/docs/tests/CI.md index 40c87ba14e16..1730f1d18943 100644 --- a/docs/tests/CI.md +++ b/docs/tests/CI.md @@ -11,19 +11,16 @@ large number of test suites. Every pull request is verified for each of the following: - - ... it still builds, warning-free, on Linux and macOS, with both - clang and gcc - - ... it still builds fine on Windows with several MSVC versions - - ... it still builds with cmake on Linux, with gcc and clang - - ... it follows rudimentary code style rules - - ... the test suite still runs 100% fine - - ... the release tarball (the "dist") still works - - ... it builds fine in-tree as well as out-of-tree - - ... code coverage does not shrink drastically - - ... different TLS backends still compile and pass tests + - it still builds, warning-free, on Linux, macOS, Windows, BSDs, with both + clang and gcc, autotools and cmake, out-of-tree and in-tree. + - it still builds fine on Windows with all supported MSVC versions + - it follows rudimentary code style rules + - the test suite still runs 100% fine + - the release tarball (the "dist") still works + - different TLS backends and options still compile and pass tests If the pull-request fails one of these tests, it shows up as a red X and you -are expected to fix the problem. If you do not understand when the issue is or +are expected to fix the problem. If you do not understand what the issue is or have other problems to fix the complaint, just ask and other project members can likely help out. @@ -31,59 +28,58 @@ Consider the following table while looking at pull request failures: | CI platform as shown in PR | State | What to look at next | | ----------------------------------- | ------ | -------------------------- | - | CI / CodeQL | stable | quality check results | - | CI / fuzzing | stable | fuzzing results | - | CI / macos ... | stable | all errors and failures | - | Code scanning results / CodeQL | stable | quality check results | - | FreeBSD FreeBSD: ... | stable | all errors and failures | - | LGTM analysis: Python | stable | new findings | - | LGTM analysis: C/C++ | stable | new findings | - | buildbot/curl_Schannel_ ... | stable | all errors and failures | - | AppVeyor | flaky | all errors and failures | + | Linux / macOS / Windows / ... | stable | all errors and failures | + | Fuzzer | stable | fuzzing results | + | Code analyzers | stable | new findings | + | checkdocs / checksrc / dist / ... | stable | all errors and failures | + | AppVeyor | stable | all errors and failures | + | buildbot/curl_Schannel ... | stable | all errors and failures | | curl.curl (linux ...) | stable | all errors and failures | - | curl.curl (windows ...) | flaky | repetitive errors/failures | - | CodeQL | stable | new findings | -Sometimes the tests fail due to a dependency service temporarily being offline -or otherwise unavailable, for example package downloads. In this case you can -just try to update your pull requests to rerun the tests later as described -below. +Sometimes the tests fail or run slowly due to a dependency service temporarily +having issues, for example package downloads, or virtualized (non-native) +environments. Sometimes a flaky failed test may occur in any jobs. + +Windows jobs have a number of flaky issues, most often, these: +- test run hanging and timing out after 20 minutes. +- test run aborting with 2304 (hex 0900) or 3840 (hex 0F00). +- test run crashing with fork errors. +- steps past the test run exiting with -1073741502 (hex C0000142). + +In these cases you can just try to update your pull requests to rerun the tests +later as described below. + +A detailed overview of test runs and results can be found on +[Test Clutch](https://testclutch.curl.se/). ## CI servers Here are the different CI environments that are currently in use, and how they are configured: -### GitHub Actions +### GitHub Actions (GHA) GitHub Actions runs the following tests: -- macOS tests with a variety of different compilation options +- Tests with a variety of different compilation options, OSes, CPUs. - Fuzz tests ([see the curl-fuzzer repo for more info](https://github.com/curl/curl-fuzzer)). -- CodeQL static analysis +- Static analysis and sanitizers: clang-tidy, scan-build, address sanitizer, + memory sanitizer, thread sanitizer, CodeQL, valgrind, torture tests. These are each configured in different files in `.github/workflows`. -### Azure - -Not used anymore. - -### AppVeyor +### AppVeyor CI AppVeyor runs a variety of different Windows builds, with different compilation options. -As of November 2021 `@bagder`, `@mback2k`, `@jay`, `@vszakats`, `@dfandrich` +As of October 2025 `@bagder`, `@mback2k`, `@jay`, `@vszakats`, `@dfandrich` and `@danielgustafsson` have administrator access to the AppVeyor CI environment. Additional admins/group members can be added on request. The tests are configured in `appveyor.yml`. -### Zuul - -Not used anymore. - ### Circle CI Circle CI runs a basic Linux test suite on Ubuntu for both x86 and ARM @@ -94,7 +90,3 @@ website](https://app.circleci.com/pipelines/github/curl/curl). `@bagder` has access to edit the "Project Settings" on that page. Additional admins/group members can be added on request. - -### Cirrus CI - -Not used anymore. From 0855f3070931c57c27180c48f7ada0336be977fc Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 10 Oct 2025 03:09:16 +0200 Subject: [PATCH 397/465] kerberos: bump minimum to 1.3 (2003-07-08), drop legacy logic Previous minimum was: 1.2.4 (2002-02-28) - assume `gssapi/gssapi.h` header for MIT Kerberos. Drop logic detecting this header, and drop alternate logic including a bare "gssapi.h". Bare `gssapi.h` is Heimdal-specific. MIT Kerberos added support for it for Heimdal compatibility on 2006-11-09, redirecting to `gssapi/gssapi.h`. MIT Kerberos supported the latter header in the 1990s already. Ref: 40e1a016f92903c731f07325bc1f9c6416ae1ac3 (2008-03-06) Ref: https://github.com/krb5/krb5/commit/d11935200186040132e05e2beaaba20a770ee3ef (2006-11-09) - configure.ac: stop using `HAVE_GSSAPI_GSSAPI_H`. Added in 2010 to support "ancient distros such as RHEL-3" where `gssapi/gssapi_krb5.h` did not include `gssapi/gssapi.h`. MIT Kerberos includes it since commit: https://github.com/krb5/krb5/commit/d9e959edfa8da7cab3bde96c9c4ca39beaf8db69 (2003-03-06) Released in 1.3 (2003-07-08). Bump minimum required version to avoid this issue. Reverts cca192e58f9ed7c4b33c1c991f69ff830c58b38f (2010-04-16) Ref: https://web.mit.edu/kerberos/dist/historic.html Ref: https://sources.debian.org/src/krb5/ Closes #18992 --- .github/scripts/cmp-config.pl | 1 + CMakeLists.txt | 5 ----- configure.ac | 11 ++--------- docs/INTERNALS.md | 2 +- lib/curl_config.h.cmake | 3 --- lib/urldata.h | 4 +--- lib/vauth/vauth.h | 4 +--- 7 files changed, 6 insertions(+), 24 deletions(-) diff --git a/.github/scripts/cmp-config.pl b/.github/scripts/cmp-config.pl index 4284fcaee70b..3ad0570e2839 100755 --- a/.github/scripts/cmp-config.pl +++ b/.github/scripts/cmp-config.pl @@ -46,6 +46,7 @@ '#define HAVE_BROTLI_DECODE_H 1' => 1, '#define HAVE_DLFCN_H 1' => 1, '#define HAVE_GSSAPI_GSSAPI_GENERIC_H 1' => 1, + '#define HAVE_GSSAPI_GSSAPI_H 1' => 1, '#define HAVE_GSSAPI_GSSAPI_KRB5_H 1' => 1, '#define HAVE_INTTYPES_H 1' => 1, '#define HAVE_LDAP_H 1' => 1, diff --git a/CMakeLists.txt b/CMakeLists.txt index 387dd57dc27d..b48b0452842d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1442,11 +1442,6 @@ if(CURL_USE_GSSAPI) if(GSS_FLAVOUR STREQUAL "GNU") set(HAVE_GSSGNU 1) - else() # MIT - cmake_push_check_state() - list(APPEND CMAKE_REQUIRED_INCLUDES "${GSS_INCLUDE_DIRS}") - check_include_file("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H) - cmake_pop_check_state() endif() else() message(WARNING "GSSAPI has been requested, but no supporting libraries found. Skipping.") diff --git a/configure.ac b/configure.ac index c8843b5b46ca..0880552cfbac 100644 --- a/configure.ac +++ b/configure.ac @@ -1841,17 +1841,10 @@ if test x"$want_gss" = xyes; then ], [ dnl not found, check for MIT - AC_CHECK_HEADERS([gssapi/gssapi.h], [], [not_mit=1]) AC_CHECK_HEADERS( - [gssapi/gssapi_generic.h gssapi/gssapi_krb5.h], + [gssapi/gssapi.h gssapi/gssapi_generic.h gssapi/gssapi_krb5.h], [], - [not_mit=1], - [ - AC_INCLUDES_DEFAULT - #ifdef HAVE_GSSAPI_GSSAPI_H - #include - #endif - ]) + [not_mit=1]) if test "x$not_mit" = "x1"; then dnl MIT not found AC_MSG_ERROR([MIT or GNU GSS library required, but not found]) diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index 3ad1b3e8c2a4..b6b00e924a73 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -35,7 +35,7 @@ versions of libs and build tools. - libidn2 2.0.0 - wolfSSL 3.4.6 - OpenLDAP 2.0 - - MIT Kerberos 1.2.4 + - MIT Kerberos 1.3 - nghttp2 1.15.0 ## Build tools diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 3f0bcf22ee62..be6fe4176e26 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -315,9 +315,6 @@ /* if you have the gssapi libraries */ #cmakedefine HAVE_GSSAPI 1 -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_GSSAPI_GSSAPI_H 1 - /* if you have the GNU gssapi libraries */ #cmakedefine HAVE_GSSGNU 1 diff --git a/lib/urldata.h b/lib/urldata.h index cdf028853eab..b6b8f6f8fe3d 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -190,10 +190,8 @@ typedef CURLcode (Curl_recv)(struct Curl_easy *data, /* transfer */ #ifdef HAVE_GSSAPI # ifdef HAVE_GSSGNU # include -# elif defined HAVE_GSSAPI_GSSAPI_H -# include # else -# include +# include # endif #endif diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h index 26e5adc6281f..9a33ca0c2317 100644 --- a/lib/vauth/vauth.h +++ b/lib/vauth/vauth.h @@ -236,10 +236,8 @@ CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, #ifdef HAVE_GSSAPI # ifdef HAVE_GSSGNU # include -# elif defined HAVE_GSSAPI_GSSAPI_H -# include # else -# include +# include # endif #endif From 05aa61fb3d7f026aeedbdf23b0f267a159317b54 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 10 Oct 2025 06:37:45 +0200 Subject: [PATCH 398/465] cmake/FindGSS: drop wrong header check for GNU GSS GNU GSS offers `gss.h`; do not check for `gssapi.h`. `gssapi.h` was originally published by Heimdal, and later MIT Kerberos also added it for Heimdal compatibility. Closes #18993 --- CMake/FindGSS.cmake | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index 21d756c2bcc6..6bb5dac1b2c9 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -154,9 +154,7 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr set(GSS_FLAVOUR "MIT") endif() else() - # I am not convinced if this is the right way but this is what autotools do at the moment - find_path(_gss_INCLUDE_DIRS NAMES "gssapi.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include" "inc") - find_path(_gss_INCLUDE_DIRS NAMES "gss.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include") + find_path(_gss_INCLUDE_DIRS NAMES "gss.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include") if(_gss_INCLUDE_DIRS) set(GSS_FLAVOUR "GNU") From aeacf9a3e8efb6d93d33fe7cf7350e37c985a619 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 10 Oct 2025 06:43:41 +0200 Subject: [PATCH 399/465] cmake/FindGSS: dedupe pkg-config module strings Closes #18994 --- CMake/FindGSS.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index 6bb5dac1b2c9..36ad9ed57260 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -158,7 +158,7 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr if(_gss_INCLUDE_DIRS) set(GSS_FLAVOUR "GNU") - set(GSS_PC_REQUIRES "gss") + set(GSS_PC_REQUIRES ${_gnu_modname}) endif() endif() @@ -209,10 +209,10 @@ else() # _pkg_check_modules_pkg_name is undocumented and used as a fallback for CMake <3.16 versions. if(_gss_MODULE_NAME STREQUAL _gnu_modname OR _pkg_check_modules_pkg_name STREQUAL _gnu_modname) set(GSS_FLAVOUR "GNU") - set(GSS_PC_REQUIRES "gss") + set(GSS_PC_REQUIRES ${_gnu_modname}) elseif(_gss_MODULE_NAME STREQUAL _mit_modname OR _pkg_check_modules_pkg_name STREQUAL _mit_modname) set(GSS_FLAVOUR "MIT") - set(GSS_PC_REQUIRES "mit-krb5-gssapi") + set(GSS_PC_REQUIRES ${_mit_modname}) else() message(FATAL_ERROR "GNU or MIT GSS is required") endif() From 7fecc009eacf2bd4815b4dd7b9ec082bca7a1bcc Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 8 Oct 2025 14:29:54 +0200 Subject: [PATCH 400/465] socks: advance iobuf instead of reset During the SOCKS connect phase, the `iobuf` is used to receive repsonses from the server. If the server sends more bytes than expected, the code discarded them silently. Fix this by advancing the iobuf only with the length consumed. Reported-by: Joshua Rogers Closes #18938 --- lib/socks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/socks.c b/lib/socks.c index a0e1e6c04254..10fca7b44c99 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -432,7 +432,7 @@ static CURLproxycode socks4_check_resp(struct socks_state *sx, switch(resp[1]) { case 90: CURL_TRC_CF(data, cf, "SOCKS4%s request granted.", sx->socks4a ? "a" : ""); - Curl_bufq_reset(&sx->iobuf); + Curl_bufq_skip(&sx->iobuf, 8); return CURLPX_OK; case 91: failf(data, @@ -664,7 +664,7 @@ static CURLproxycode socks5_check_resp0(struct socks_state *sx, } auth_mode = resp[1]; - Curl_bufq_reset(&sx->iobuf); + Curl_bufq_skip(&sx->iobuf, 2); switch(auth_mode) { case 0: @@ -765,7 +765,7 @@ static CURLproxycode socks5_check_auth_resp(struct socks_state *sx, /* ignore the first (VER) byte */ auth_status = resp[1]; - Curl_bufq_reset(&sx->iobuf); + Curl_bufq_skip(&sx->iobuf, 2); if(auth_status) { failf(data, "User was rejected by the SOCKS5 server (%d %d).", From 4cc476b37fc9f9f402e107f8ff85c60bad8c19ab Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 9 Oct 2025 10:41:02 +0200 Subject: [PATCH 401/465] gnutls: check conversion of peer cert chain Check the result when converting the peer certificate chain into gnutls internal x590 data structure for errors. Reported-by: Joshua Rogers Closes #18964 --- lib/vtls/gtls.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 43edbd57ad2b..1c0a6fb2d610 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -1701,12 +1701,24 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf, infof(data, " SSL certificate verification SKIPPED"); /* initialize an X.509 certificate structure. */ - gnutls_x509_crt_init(&x509_cert); + if(gnutls_x509_crt_init(&x509_cert)) { + failf(data, "failed to init gnutls x509_crt"); + *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND; + result = CURLE_SSL_CONNECT_ERROR; + goto out; + } - if(chain.certs) + if(chain.certs) { /* convert the given DER or PEM encoded Certificate to the native gnutls_x509_crt_t format */ - gnutls_x509_crt_import(x509_cert, chain.certs, GNUTLS_X509_FMT_DER); + rc = gnutls_x509_crt_import(x509_cert, chain.certs, GNUTLS_X509_FMT_DER); + if(rc) { + failf(data, "error parsing server's certificate chain"); + *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND; + result = CURLE_SSL_CONNECT_ERROR; + goto out; + } + } /* Check for time-based validity */ certclock = gnutls_x509_crt_get_expiration_time(x509_cert); @@ -1773,10 +1785,15 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf, if(config->issuercert) { gnutls_datum_t issuerp; - gnutls_x509_crt_init(&x509_issuer); + if(gnutls_x509_crt_init(&x509_issuer)) { + failf(data, "failed to init gnutls x509_crt for issuer"); + result = CURLE_SSL_ISSUER_ERROR; + goto out; + } issuerp = load_file(config->issuercert); - gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); - rc = (int)gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); + rc = gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); + if(!rc) + rc = (int)gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); unload_file(issuerp); if(rc <= 0) { failf(data, "server certificate issuer check failed (IssuerCert: %s)", From a4d3c4e84720c3f2cb94fef1a4e680bb4b3e91a2 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 9 Oct 2025 11:23:42 +0200 Subject: [PATCH 402/465] ws: fix some edge cases Fix edge cases around handling of pending send frames and encoding frames with size_t/curl_off_t possible flowy things. Reported-by: Joshua Rogers Closes #18965 --- lib/ws.c | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/lib/ws.c b/lib/ws.c index d3379c650237..6c8f07e1776e 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -647,6 +647,22 @@ static CURLcode ws_enc_add_cntrl(struct Curl_easy *data, return CURLE_OK; } +static curl_off_t ws_payload_remain(curl_off_t payload_total, + curl_off_t payload_offset, + size_t payload_buffered) +{ + curl_off_t remain = payload_total - payload_offset; + if((payload_total < 0) || (payload_offset < 0) || (remain < 0)) + return -1; +#if SIZEOF_OFF_T <= SIZEOF_SIZE_T + if((curl_off_t)payload_buffered < 0) + return -1; +#endif + if(remain < (curl_off_t)payload_buffered) + return -1; + return remain - (curl_off_t)payload_buffered; +} + static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen, int frame_age, int frame_flags, curl_off_t payload_offset, @@ -658,11 +674,16 @@ static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen, struct Curl_easy *data = ctx->data; struct websocket *ws = ctx->ws; bool auto_pong = !data->set.ws_no_auto_pong; - curl_off_t remain = (payload_len - (payload_offset + buflen)); + curl_off_t remain; CURLcode result; (void)frame_age; *pnwritten = 0; + remain = ws_payload_remain(payload_len, payload_offset, buflen); + if(remain < 0) { + DEBUGASSERT(0); /* parameter mismatch */ + return CURLE_BAD_FUNCTION_ARGUMENT; + } if(auto_pong && (frame_flags & CURLWS_PING) && !remain) { /* auto-respond to PINGs, only works for single-frame payloads atm */ @@ -981,12 +1002,18 @@ static CURLcode ws_enc_add_pending(struct Curl_easy *data, result); goto out; } - /* our buffer should always be able to take in a control frame */ - DEBUGASSERT(n == ws->pending.payload_len); + if(n != ws->pending.payload_len) { + DEBUGASSERT(0); /* buffer should always be able to take all */ + CURL_TRC_WS(data, "ws_enc_cntrl(), error added only %zu/%zu payload,", + n, ws->pending.payload_len); + result = CURLE_SEND_ERROR; + goto out; + } + /* the frame should be complete now */ DEBUGASSERT(!ws->enc.payload_remain); + memset(&ws->pending, 0, sizeof(ws->pending)); out: - memset(&ws->pending, 0, sizeof(ws->pending)); return result; } @@ -1445,10 +1472,16 @@ static CURLcode ws_client_collect(const unsigned char *buf, size_t buflen, struct ws_collect *ctx = userp; struct Curl_easy *data = ctx->data; bool auto_pong = !data->set.ws_no_auto_pong; - curl_off_t remain = (payload_len - (payload_offset + buflen)); + curl_off_t remain; CURLcode result = CURLE_OK; *pnwritten = 0; + remain = ws_payload_remain(payload_len, payload_offset, buflen); + if(remain < 0) { + DEBUGASSERT(0); /* parameter mismatch */ + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!ctx->bufidx) { /* first write */ ctx->frame_age = frame_age; From 9d7b532404181568de1611084bd9f446cd4a4d26 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 9 Oct 2025 12:19:49 +0200 Subject: [PATCH 403/465] cf-socket: set FD_CLOEXEC on all sockets opened Removed TODO item Reported-by: Joshua Rogers Closes #18968 --- docs/TODO | 9 --------- lib/cf-socket.c | 24 ++++++++++++++++++++---- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/docs/TODO b/docs/TODO index 65d735d1be8c..6c3ba904e721 100644 --- a/docs/TODO +++ b/docs/TODO @@ -34,7 +34,6 @@ 1.20 SRV and URI DNS records 1.22 CURLINFO_PAUSE_STATE 1.25 Expose tried IP addresses that failed - 1.28 FD_CLOEXEC 1.30 config file parsing 1.31 erase secrets from heap/stack after use 1.32 add asynch getaddrinfo support @@ -349,14 +348,6 @@ https://github.com/curl/curl/issues/2126 -1.28 FD_CLOEXEC - - It sets the close-on-exec flag for the file descriptor, which causes the file - descriptor to be automatically (and atomically) closed when any of the - exec-family functions succeed. Should probably be set by default? - - https://github.com/curl/curl/issues/2252 - 1.30 config file parsing Consider providing an API, possibly in a separate companion library, for diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 0182de67e80a..758641e40dbe 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -371,6 +371,17 @@ static CURLcode socket_open(struct Curl_easy *data, /* no socket, no connection */ return CURLE_COULDNT_CONNECT; +#ifdef HAVE_FCNTL + if(fcntl(*sockfd, F_SETFD, FD_CLOEXEC) < 0) { + char errbuf[STRERROR_LEN]; + failf(data, "fcntl set CLOEXEC: %s", + curlx_strerror(SOCKERRNO, errbuf, sizeof(errbuf))); + close(*sockfd); + *sockfd = CURL_SOCKET_BAD; + return CURLE_COULDNT_CONNECT; + } +#endif + #if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) if(data->conn->scope_id && (addr->family == AF_INET6)) { struct sockaddr_in6 * const sa6 = (void *)&addr->curl_sa_addr; @@ -2122,11 +2133,16 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, curlx_strerror(SOCKERRNO, errbuf, sizeof(errbuf))); return CURLE_FTP_ACCEPT_FAILED; } - - infof(data, "Connection accepted from server"); -#ifndef HAVE_ACCEPT4 - (void)curlx_nonblock(s_accepted, TRUE); /* enable non-blocking */ +#if !defined(HAVE_ACCEPT4) && defined(HAVE_FCNTL) + if((fcntl(s_accepted, F_SETFD, FD_CLOEXEC) < 0) || + (curlx_nonblock(s_accepted, TRUE) < 0)) { + failf(data, "fcntl set CLOEXEC/NONBLOCK: %s", + curlx_strerror(SOCKERRNO, errbuf, sizeof(errbuf))); + return CURLE_FTP_ACCEPT_FAILED; + } #endif + infof(data, "Connection accepted from server"); + /* Replace any filter on SECONDARY with one listening on this socket */ ctx->listening = FALSE; ctx->accepted = TRUE; From bf41be6292cf712315815c722aab2653a0ec827f Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 10 Oct 2025 09:48:52 +0200 Subject: [PATCH 404/465] conn: fix hostname move on connection reuse When reusing a connection, the `host` and `conn_to_host` hostname structs are moved from the template connection onto the existing one. There was a NULLing of a tempplate member missing in `conn_to_host` which could then lead to a double free. Make this struct move into a static function, doing the correct thing for both `struct hostname` in a connection. Reported-by: Joshua Rogers Closes #18995 --- lib/url.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/url.c b/lib/url.c index 6a433b09efd1..6d69fc11bf88 100644 --- a/lib/url.c +++ b/lib/url.c @@ -3286,6 +3286,14 @@ static CURLcode resolve_server(struct Curl_easy *data, return CURLE_OK; } +static void url_move_hostname(struct hostname *dest, struct hostname *src) +{ + Curl_safefree(dest->rawalloc); + Curl_free_idnconverted_hostname(dest); + *dest = *src; + memset(src, 0, sizeof(*src)); +} + /* * Cleanup the connection `temp`, just allocated for `data`, before using the * previously `existing` one for `data`. All relevant info is copied over @@ -3340,15 +3348,9 @@ static void reuse_conn(struct Curl_easy *data, * used the original hostname in SNI to negotiate? Do we send * requests for another host through the different SNI? */ - Curl_free_idnconverted_hostname(&existing->host); - Curl_free_idnconverted_hostname(&existing->conn_to_host); - Curl_safefree(existing->host.rawalloc); - Curl_safefree(existing->conn_to_host.rawalloc); - existing->host = temp->host; - temp->host.rawalloc = NULL; - temp->host.encalloc = NULL; - existing->conn_to_host = temp->conn_to_host; - temp->conn_to_host.rawalloc = NULL; + url_move_hostname(&existing->host, &temp->host); + url_move_hostname(&existing->conn_to_host, &temp->conn_to_host); + existing->conn_to_port = temp->conn_to_port; existing->remote_port = temp->remote_port; free(existing->hostname_resolve); From 03448f477a0cfa3868dfd15a7b9278dcecf944a2 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 10 Oct 2025 10:15:38 +0200 Subject: [PATCH 405/465] thread: errno on thread creation When thread creation fails, the code uses `errno` to remember the cause. But pthread_create() never sets errno and gives the error as return value. Fix that by setting the return value into errno on failure. Windows: I think the ifdef was the wrong way around. Also set a generic Windows Error code on CE systems. Reported-by: Joshua Rogers Closes #18998 --- lib/curl_threads.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/curl_threads.c b/lib/curl_threads.c index a585d26d3fac..352e002a3ddd 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -60,14 +60,18 @@ curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T { curl_thread_t t = malloc(sizeof(pthread_t)); struct Curl_actual_call *ac = malloc(sizeof(struct Curl_actual_call)); + int rc; if(!(ac && t)) goto err; ac->func = func; ac->arg = arg; - if(pthread_create(t, NULL, curl_thread_create_thunk, ac) != 0) + rc = pthread_create(t, NULL, curl_thread_create_thunk, ac); + if(rc) { + CURL_SETERRNO(rc); goto err; + } return t; @@ -103,13 +107,15 @@ curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T { curl_thread_t t = CreateThread(NULL, 0, func, arg, 0, NULL); if(!t) { -#ifdef UNDER_CE +#ifndef UNDER_CE DWORD gle = GetLastError(); /* !checksrc! disable ERRNOVAR 1 */ int err = (gle == ERROR_ACCESS_DENIED || gle == ERROR_NOT_ENOUGH_MEMORY) ? EACCES : EINVAL; CURL_SETERRNO(err); +#else + CURL_SETERRNO(31); /* Windows ERROR_GEN_FAILURE */ #endif return curl_thread_t_null; } From 05fbe85e628ca697e7f3c59bd677024e3cec125c Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 10 Oct 2025 10:40:55 +0200 Subject: [PATCH 406/465] c-ares: when resolving failed, persist error Repeated calls to `Curl_async_is_resolved()` after a failure returned OK and not the error that was the result of the resolve fail. Reported-by: Joshua Rogers Closes #18999 --- lib/asyn-ares.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index dcbed0129c73..d39db23a7bdb 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -302,11 +302,13 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, if(data->state.async.done) { *dns = data->state.async.dns; - return CURLE_OK; + return ares->result; } - if(Curl_ares_perform(ares->channel, 0) < 0) - return CURLE_UNRECOVERABLE_POLL; + if(Curl_ares_perform(ares->channel, 0) < 0) { + result = CURLE_UNRECOVERABLE_POLL; + goto out; + } #ifndef HAVE_CARES_GETADDRINFO /* Now that we have checked for any last minute results above, see if there @@ -371,6 +373,9 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, result, *dns ? "" : "not "); async_ares_cleanup(data); } + +out: + ares->result = result; return result; } From 67c75b67125d09029288dd490050471c46c50ece Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Fri, 10 Oct 2025 15:55:50 +0200 Subject: [PATCH 407/465] os400: document threads handling in code. This is to clarify threads unavaibility check and handling for security bug busters unaware of OS400 specificities. Fixes #18967 Closes #19009 --- packages/OS400/os400sys.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/OS400/os400sys.c b/packages/OS400/os400sys.c index bc227a0e69fc..40eca6edc290 100644 --- a/packages/OS400/os400sys.c +++ b/packages/OS400/os400sys.c @@ -158,6 +158,11 @@ get_buffer(struct buffer_t *buf, long size) } +/* + * Get buffer address for the given local key. + * This is always called though `Curl_thread_buffer' and when threads are + * NOT made available by the os, so no mutex lock/unlock occurs. + */ static char * buffer_unthreaded(localkey_t key, long size) { @@ -165,6 +170,12 @@ buffer_unthreaded(localkey_t key, long size) } +/* + * Get buffer address for the given local key, taking care of + * concurrent threads. + * This is always called though `Curl_thread_buffer' and when threads are + * made available by the os. + */ static char * buffer_threaded(localkey_t key, long size) { @@ -208,16 +219,21 @@ buffer_undef(localkey_t key, long size) /* Determine if we can use pthread-specific data. */ if(Curl_thread_buffer == buffer_undef) { /* If unchanged during lock. */ - if(!pthread_key_create(&thdkey, thdbufdestroy)) + /* OS400 interactive jobs do not support threads: check here. */ + if(!pthread_key_create(&thdkey, thdbufdestroy)) { + /* Threads are supported: use the thread-aware buffer procedure. */ Curl_thread_buffer = buffer_threaded; + } else { + /* No multi-threading available: allocate storage for single-thread + * buffer headers. */ locbufs = calloc((size_t) LK_LAST, sizeof(*locbufs)); if(!locbufs) { - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); /* For symetry: will probably fail. */ return (char *) NULL; } else - Curl_thread_buffer = buffer_unthreaded; + Curl_thread_buffer = buffer_unthreaded; /* Use unthreaded version. */ } atexit(terminate); From 6e9246aeb321b3cbbe07a323dec39e6392a4cb71 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 10 Oct 2025 22:57:10 +0200 Subject: [PATCH 408/465] cmake/FindGSS: simplify/de-dupe lib setup - lib name is always `gss` with GNU GSS. - move lib name assigments to the detection blocks. Closes #19012 --- CMake/FindGSS.cmake | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index 36ad9ed57260..db36cf2100bc 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -145,6 +145,8 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr find_path(_gss_INCLUDE_DIRS NAMES "gssapi/gssapi.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include" "inc") if(_gss_INCLUDE_DIRS) # We have found something + set(_gss_libdir_suffixes "") + cmake_push_check_state() list(APPEND CMAKE_REQUIRED_INCLUDES "${_gss_INCLUDE_DIRS}") check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers) @@ -152,6 +154,18 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr if(_gss_have_mit_headers) set(GSS_FLAVOUR "MIT") + if(WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND _gss_libdir_suffixes "lib/AMD64") + set(_gss_libname "gssapi64") + else() + list(APPEND _gss_libdir_suffixes "lib/i386") + set(_gss_libname "gssapi32") + endif() + else() + list(APPEND _gss_libdir_suffixes "lib" "lib64") # those suffixes are not checked for HINTS + set(_gss_libname "gssapi_krb5") + endif() endif() else() find_path(_gss_INCLUDE_DIRS NAMES "gss.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include") @@ -159,12 +173,12 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr if(_gss_INCLUDE_DIRS) set(GSS_FLAVOUR "GNU") set(GSS_PC_REQUIRES ${_gnu_modname}) + set(_gss_libname "gss") endif() endif() - # If we have headers, check if we can link libraries + # If we have headers, look up libraries if(GSS_FLAVOUR) - set(_gss_libdir_suffixes "") set(_gss_libdir_hints ${_gss_root_hints}) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) cmake_path(GET _gss_INCLUDE_DIRS PARENT_PATH _gss_calculated_potential_root) @@ -173,31 +187,6 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr endif() list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root}) - if(WIN32) - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - list(APPEND _gss_libdir_suffixes "lib/AMD64") - if(GSS_FLAVOUR STREQUAL "GNU") - set(_gss_libname "gss") - else() # MIT - set(_gss_libname "gssapi64") - endif() - else() - list(APPEND _gss_libdir_suffixes "lib/i386") - if(GSS_FLAVOUR STREQUAL "GNU") - set(_gss_libname "gss") - else() # MIT - set(_gss_libname "gssapi32") - endif() - endif() - else() - list(APPEND _gss_libdir_suffixes "lib;lib64") # those suffixes are not checked for HINTS - if(GSS_FLAVOUR STREQUAL "GNU") - set(_gss_libname "gss") - else() # MIT - set(_gss_libname "gssapi_krb5") - endif() - endif() - find_library(_gss_LIBRARIES NAMES ${_gss_libname} HINTS ${_gss_libdir_hints} PATH_SUFFIXES ${_gss_libdir_suffixes}) endif() endif() From f04e7a7eface29607981f81662d9dff429372134 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 10 Oct 2025 23:11:14 +0200 Subject: [PATCH 409/465] cmake: pre-fill three more type sizes on Windows Use `CMAKE_SIZEOF_VOID_P` to fill the size of three types that differ on 32 and 64-bit Windows: `curl_socket_t`, `size_t`, and on mingw-w64: `ssize_t`. `time_t` remains the only type needing detection at configuration time, with MSVC or mingw-w64. Ref: https://cmake.org/cmake/help/v4.1/variable/CMAKE_SIZEOF_VOID_P.html Closes #19013 --- CMake/win32-cache.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMake/win32-cache.cmake b/CMake/win32-cache.cmake index 058c35dd8d51..8cb9b58b3937 100644 --- a/CMake/win32-cache.cmake +++ b/CMake/win32-cache.cmake @@ -191,7 +191,8 @@ if(MINGW OR MSVC) curl_prefill_type_size("LONG_LONG" 8) curl_prefill_type_size("__INT64" 8) curl_prefill_type_size("CURL_OFF_T" 8) - # CURL_SOCKET_T, SIZE_T: 8 for _WIN64, 4 otherwise + curl_prefill_type_size("CURL_SOCKET_T" ${CMAKE_SIZEOF_VOID_P}) + curl_prefill_type_size("SIZE_T" ${CMAKE_SIZEOF_VOID_P}) # TIME_T: 8 for _WIN64 or UCRT or MSVC and not Windows CE, 4 otherwise # Also 4 for non-UCRT 32-bit when _USE_32BIT_TIME_T is set. # mingw-w64 sets _USE_32BIT_TIME_T unless __MINGW_USE_VC2005_COMPAT is explicit defined. @@ -200,7 +201,7 @@ if(MINGW OR MSVC) set(HAVE_FILE_OFFSET_BITS 0) curl_prefill_type_size("OFF_T" 4) else() - # SSIZE_T: 8 for _WIN64, 4 otherwise + curl_prefill_type_size("SSIZE_T" ${CMAKE_SIZEOF_VOID_P}) set(HAVE_FILE_OFFSET_BITS 1) # mingw-w64 v3+ curl_prefill_type_size("OFF_T" 8) # mingw-w64 v3+ endif() From 16f0d4ae3ad0a113dde0488b5119ec7ad03cf7d7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 11 Oct 2025 00:11:16 +0200 Subject: [PATCH 410/465] curl_threads: delete WinCE fallback branch Both WinCE and Windows use `CreateThread()` now, so the use of `GetLastError()` works for both. Follow-up to 03448f477a0cfa3868dfd15a7b9278dcecf944a2 #18998 Follow-up to 1c49f2f26d0f200bb9de61f795f06a1bc56845e9 #18451 Follow-up to af0216251b94e751baa47146ac9609db70793b8e #1589 Closes #19015 --- lib/curl_threads.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/curl_threads.c b/lib/curl_threads.c index 352e002a3ddd..68bfddddcbcd 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -107,16 +107,12 @@ curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T { curl_thread_t t = CreateThread(NULL, 0, func, arg, 0, NULL); if(!t) { -#ifndef UNDER_CE DWORD gle = GetLastError(); /* !checksrc! disable ERRNOVAR 1 */ int err = (gle == ERROR_ACCESS_DENIED || gle == ERROR_NOT_ENOUGH_MEMORY) ? EACCES : EINVAL; CURL_SETERRNO(err); -#else - CURL_SETERRNO(31); /* Windows ERROR_GEN_FAILURE */ -#endif return curl_thread_t_null; } return t; From b419f1fd8779277e7bf8c97f58708cf466c3ffe0 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 11 Oct 2025 00:27:36 +0200 Subject: [PATCH 411/465] examples/log_failed_transfers: make it build for WinCE - include `windows.h` after `winsock2.h` via `curl/curl.h`. - avoid `errno` for WinCE. - avoid `_vscprintf` for WinCE. Ref: 4535532ed36d2129b107ab357262072f82c2b34a #18843 Follow-up to 0780de2625bf8bb3bcb0f88bbbc401b2750ec1bb #18668 Closes #19016 --- docs/examples/log_failed_transfers.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/examples/log_failed_transfers.c b/docs/examples/log_failed_transfers.c index 1ec6350510ab..66e193167712 100644 --- a/docs/examples/log_failed_transfers.c +++ b/docs/examples/log_failed_transfers.c @@ -32,14 +32,9 @@ * */ -#ifdef _WIN32 -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif -#include -#endif - +#ifndef UNDER_CE #include +#endif #include #include #include @@ -47,6 +42,10 @@ #include #ifdef _WIN32 +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#include #define strcasecmp _stricmp #define strncasecmp _strnicmp #define unlink _unlink @@ -157,7 +156,7 @@ static int mem_addf(struct mem *mem, const char *format, ...) return x; } -#ifdef _WIN32 +#if defined(_WIN32) && !defined(UNDER_CE) /* Not all versions of Windows CRT vsnprintf are compliant with C99. Some return -1 if buffer too small. Try _vscprintf to get the needed size. */ if(!i && x < 0) { @@ -296,9 +295,11 @@ int main(void) } } else { +#ifndef UNDER_CE mem_addf(&t->log, "Failed to create body output file %s: %s\n", t->bodyfile, strerror(errno)); fprintf(stderr, "%s", t->log.recent); +#endif failed = 1; } @@ -307,10 +308,12 @@ int main(void) if(fp && t->log.len == fwrite(t->log.buf, 1, t->log.len, fp)) fprintf(stderr, "Transfer log written to %s\n", t->logfile); +#ifndef UNDER_CE else { fprintf(stderr, "Failed to write transfer log to %s: %s\n", t->logfile, strerror(errno)); } +#endif if(fp) fclose(fp); From 66753bc1203167c2a07737963149e83d93e3788c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 11 Oct 2025 15:44:10 +0200 Subject: [PATCH 412/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 44ef5ddfc1e5..4d5ce575ce14 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -38,10 +38,12 @@ This release includes the following bugfixes: o build: avoid overriding system symbols for fopen functions [150] o build: avoid overriding system symbols for socket functions [68] o build: show llvm/clang in platform flags and `buildinfo.txt` [126] + o c-ares: when resolving failed, persist error [270] o cf-h2-proxy: break loop on edge case [140] o cf-ip-happy: mention unix domain path, not port number [161] o cf-socket: always check Curl_cf_socket_peek() return code [198] o cf-socket: check params and remove accept procondition [197] + o cf-socket: set FD_CLOEXEC on all sockets opened [273] o cf-socket: tweak a memcpy() to read better [177] o cf-socket: use the right byte order for ports in bindlocal [61] o cfilter: unlink and discard [46] @@ -50,7 +52,11 @@ This release includes the following bugfixes: o checksrc: fix possible endless loops/errors in the banned function logic [220] o checksrc: fix to handle `)` predecing a banned function [229] o checksrc: reduce directory-specific exceptions [228] + o CI.md: refresh [280] + o cmake/FindGSS: dedupe pkg-config module strings [277] + o cmake/FindGSS: drop wrong header check for GNU GSS [278] o cmake/FindGSS: fix `pkg-config` fallback logic for CMake <3.16 [189] + o cmake/FindGSS: simplify/de-dupe lib setup [253] o cmake/FindGSS: whitespace/formatting [268] o cmake: add `CURL_CODE_COVERAGE` option [78] o cmake: build the "all" examples source list dynamically [245] @@ -58,12 +64,14 @@ This release includes the following bugfixes: o cmake: drop exclamation in comment looking like a name [160] o cmake: fix building docs when the base directory contains `.3` [18] o cmake: minor Heimdal flavour detection fix [269] + o cmake: pre-fill three more type sizes on Windows [244] o cmake: support building some complicated examples, build them in CI [235] o cmake: use modern alternatives for `get_filename_component()` [102] o cmake: use more `COMPILER_OPTIONS`, `LINK_OPTIONS` / `LINK_FLAGS` [152] o cmdline-docs: extended, clarified, refreshed [28] o cmdline-opts/_PROGRESS.md: explain the suffixes [154] o configure: add "-mt" for pthread support on HP-UX [52] + o conn: fix hostname move on connection reuse [272] o cookie: avoid saving a cookie file if no transfer was done [11] o cpool: make bundle->dest an array; fix UB [218] o curl_easy_getinfo: error code on NULL arg [2] @@ -71,6 +79,7 @@ This release includes the following bugfixes: o curl_osslq: error out properly if BIO_ADDR_rawmake() fails [184] o Curl_resolv: fix comment. 'entry' argument is not optional [187] o curl_slist_append.md: clarify that a NULL pointer is not acceptable [72] + o curl_threads: delete WinCE fallback branch [233] o CURLINFO_FTP_ENTRY_PATH.md: this is for SFTP as well [8] o CURLOPT_COOKIEFILE.md: clarify when the cookies are loaded [159] o CURLOPT_HEADER/WRITEFUNCTION.md: drop '* size' since size is always 1 [63] @@ -101,6 +110,8 @@ This release includes the following bugfixes: o ftp: fix the 213 scanner memchr buffer limit argument [196] o ftp: improve fragile check for first digit > 3 [194] o ftp: remove misleading comments [193] + o ftp: simplify the 150/126 size scanner [288] + o gnutls: check conversion of peer cert chain [275] o gtls: avoid potential use of uninitialized variable in trace output [83] o hostip: don't store negative resolves due unrelated errors [256] o hostip: remove leftover INT_MAX check in Curl_dnscache_prune [88] @@ -114,9 +125,13 @@ This release includes the following bugfixes: o INTERNALS: drop Winsock 2.2 from the dependency list [162] o ip-happy: do not set unnecessary timeout [95] o ip-happy: prevent event-based stall on retry [155] + o kerberos: bump minimum to 1.3 (2003-07-08), drop legacy logic [279] + o kerberos: drop logic for MIT Kerberos <1.2.3 (pre-2002) versions [285] + o kerberos: stop including `gssapi/gssapi_generic.h` [282] o krb5: return appropriate error on send failures [22] o krb5_gssapi: fix memory leak on error path [190] o krb5_sspi: the chlg argument is NOT optional [200] + o ldap: avoid null ptr deref on failure [284] o ldap: do not base64 encode zero length string [42] o ldap: tidy-up types, fix error code confusion [191] o lib: drop unused include and duplicate guards [226] @@ -139,6 +154,7 @@ This release includes the following bugfixes: o libssh: error on bad chgrp number [71] o libssh: error on bad chown number and store the value [64] o libssh: fix range parsing error handling mistake [120] + o libssh: make atime and mtime cap the timestamp instead of wrap [283] o libssh: react on errors from ssh_scp_read [24] o libssh: return out of memory correctly if aprintf fails [60] o Makefile.example: fix option order [231] @@ -164,6 +180,8 @@ This release includes the following bugfixes: o openldap: avoid indexing the result at -1 for blank responses [44] o openldap: check ber_sockbuf_add_io() return code [163] o openldap: check ldap_get_option() return codes [119] + o openldap: fix memory-leak in error path [287] + o openldap: fix memory-leak on oldap_do's exit path [286] o openssl-quic: check results better [132] o openssl-quic: handle error in SSL_get_stream_read_error_code [129] o openssl-quic: ignore unexpected streams opened by server [176] @@ -175,6 +193,7 @@ This release includes the following bugfixes: o openssl: make the asn1_object_dump name null terminated [56] o openssl: set io_need always [99] o openssl: skip session resumption when verifystatus is set [230] + o os400: document threads handling in code. [254] o OS400: fix a use-after-free/double-free case [142] o osslq: set idle timeout to 0 [237] o pingpong: remove two old leftover debug infof() calls @@ -200,6 +219,7 @@ This release includes the following bugfixes: o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] o smb: adjust buffer size checks [45] o smtp: check EHLO responses case insensitively [50] + o socks: advance iobuf instead of reset [276] o socks: deny server basic-auth if not configured [264] o socks: handle error in verbose trace gracefully [94] o socks: handle premature close [246] @@ -234,6 +254,7 @@ This release includes the following bugfixes: o tftp: propagate expired timer from tftp_state_timeout() [39] o tftp: return error if it hits an illegal state [138] o tftp: return error when sendto() fails [59] + o thread: errno on thread creation [271] o tidy-up: `fcntl.h` includes [98] o tidy-up: assortment of small fixes [115] o tidy-up: avoid using the reserved macro namespace [76] @@ -275,6 +296,7 @@ This release includes the following bugfixes: o wolfssl: fix error check in shutdown [105] o wolfssl: no double get_error() detail [188] o ws: clarify an error message [125] + o ws: fix some edge cases [274] o ws: reject curl_ws_recv called with NULL buffer with a buflen [118] This release includes the following known bugs: @@ -545,6 +567,7 @@ References to bug reports and discussions on issues: [230] = https://curl.se/bug/?i=18902 [231] = https://curl.se/bug/?i=18835 [232] = https://curl.se/bug/?i=18918 + [233] = https://curl.se/bug/?i=19015 [234] = https://curl.se/bug/?i=18828 [235] = https://curl.se/bug/?i=18909 [236] = https://curl.se/bug/?i=18905 @@ -555,6 +578,7 @@ References to bug reports and discussions on issues: [241] = https://curl.se/bug/?i=18966 [242] = https://curl.se/bug/?i=18961 [243] = https://curl.se/bug/?i=18914 + [244] = https://curl.se/bug/?i=19013 [245] = https://curl.se/bug/?i=18911 [246] = https://curl.se/bug/?i=18883 [247] = https://curl.se/bug/?i=18908 @@ -563,6 +587,8 @@ References to bug reports and discussions on issues: [250] = https://curl.se/bug/?i=18432 [251] = https://curl.se/bug/?i=18881 [252] = https://curl.se/bug/?i=18890 + [253] = https://curl.se/bug/?i=19012 + [254] = https://curl.se/bug/?i=18967 [255] = https://curl.se/bug/?i=18969 [256] = https://curl.se/bug/?i=18953 [257] = https://curl.se/bug/?i=18959 @@ -578,3 +604,21 @@ References to bug reports and discussions on issues: [267] = https://curl.se/bug/?i=18928 [268] = https://curl.se/bug/?i=18957 [269] = https://curl.se/bug/?i=18951 + [270] = https://curl.se/bug/?i=18999 + [271] = https://curl.se/bug/?i=18998 + [272] = https://curl.se/bug/?i=18995 + [273] = https://curl.se/bug/?i=18968 + [274] = https://curl.se/bug/?i=18965 + [275] = https://curl.se/bug/?i=18964 + [276] = https://curl.se/bug/?i=18938 + [277] = https://curl.se/bug/?i=18994 + [278] = https://curl.se/bug/?i=18993 + [279] = https://curl.se/bug/?i=18992 + [280] = https://curl.se/bug/?i=18973 + [282] = https://curl.se/bug/?i=18990 + [283] = https://curl.se/bug/?i=18989 + [284] = https://curl.se/bug/?i=18988 + [285] = https://curl.se/bug/?i=18978 + [286] = https://curl.se/bug/?i=18986 + [287] = https://curl.se/bug/?i=18985 + [288] = https://curl.se/bug/?i=18984 From 142d61a0ee71b2c58f8f03495fb43d83b478db64 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 10 Oct 2025 09:53:32 +0200 Subject: [PATCH 413/465] doswin: CloseHandle the thread on shutdown As this is in the tool shutdown the impact of it was nothing. Also, move two global variables to local. Follow-up to 9a2663322c330ff11275abafd612e9c Reported-by: Joshua Rogers Closes #18996 --- src/tool_doswin.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tool_doswin.c b/src/tool_doswin.c index 5cf58405b392..8e9e5f023d39 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -809,9 +809,6 @@ static DWORD WINAPI win_stdin_thread_func(void *thread_data) } /* The background thread that reads and buffers the true stdin. */ -static HANDLE stdin_thread = NULL; -static curl_socket_t socket_r = CURL_SOCKET_BAD; - curl_socket_t win32_stdin_read_thread(void) { int result; @@ -819,6 +816,8 @@ curl_socket_t win32_stdin_read_thread(void) int rc = 0, socksize = 0; struct win_thread_data *tdata = NULL; SOCKADDR_IN selfaddr; + static HANDLE stdin_thread = NULL; + static curl_socket_t socket_r = CURL_SOCKET_BAD; if(socket_r != CURL_SOCKET_BAD) { assert(stdin_thread != NULL); @@ -930,6 +929,7 @@ curl_socket_t win32_stdin_read_thread(void) if(stdin_thread) { TerminateThread(stdin_thread, 1); + CloseHandle(stdin_thread); stdin_thread = NULL; } From b3f9c837d3906c8f8214e848139f544c777240ab Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 10 Oct 2025 23:54:15 +0200 Subject: [PATCH 414/465] asyn-ares: remove wrong comment about the callback argument Both the c-ares documentation and the c-ares source code contradict the previous comment (and mentions/contains no such restriction). Ref: #19001 Closes #19014 --- lib/asyn-ares.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index d39db23a7bdb..040100acec36 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -517,8 +517,6 @@ static void async_ares_hostbyname_cb(void *user_data, (void)timeouts; /* ignored */ if(ARES_EDESTRUCTION == status) - /* when this ares handle is getting destroyed, the 'arg' pointer may not - be valid so only defer it when we know the 'status' says its fine! */ return; if(ARES_SUCCESS == status) { From 1648f23ed367ecaaa66e4cc029dccf0733f52a9d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 11 Oct 2025 22:54:54 +0200 Subject: [PATCH 415/465] socksd: remove --bindonly mention, there is no such option Reported-by: Joshua Rogers Closes #19026 --- tests/server/socksd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/server/socksd.c b/tests/server/socksd.c index f16b1d79ed2e..1f2460ec2908 100644 --- a/tests/server/socksd.c +++ b/tests/server/socksd.c @@ -851,7 +851,6 @@ static int test_socksd(int argc, char *argv[]) " --ipv4\n" " --ipv6\n" " --unix-socket [file]\n" - " --bindonly\n" " --port [port]\n"); return 0; } From d03a6b79b45921dead4d7848696bd1f1910d5970 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 11 Oct 2025 23:34:45 +0200 Subject: [PATCH 416/465] lib1514: fix return code mixup Reported-by: Joshua Rogers Closes #19027 --- tests/libtest/lib1514.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/libtest/lib1514.c b/tests/libtest/lib1514.c index 265f47af08d3..fc7e33e3d3b3 100644 --- a/tests/libtest/lib1514.c +++ b/tests/libtest/lib1514.c @@ -55,7 +55,6 @@ static size_t t1514_read_cb(char *ptr, size_t size, size_t nmemb, void *userp) static CURLcode test_lib1514(const char *URL) { CURL *curl; - CURLcode result = CURLE_OK; CURLcode res = CURLE_OK; static char testdata[] = "dummy"; @@ -77,12 +76,12 @@ static CURLcode test_lib1514(const char *URL) easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); } - result = curl_easy_perform(curl); + res = curl_easy_perform(curl); test_cleanup: curl_easy_cleanup(curl); curl_global_cleanup(); - return result; + return res; } From 44429da2e12ec660d000d3e3394900f03d4c3761 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 10 Oct 2025 11:28:29 +0200 Subject: [PATCH 417/465] smb: transfer debugassert to real check That also works for non-debug builds. Reported-by: Joshua Rogers Cloes #19003 --- lib/smb.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/smb.c b/lib/smb.c index f7d06eb4900e..2aa8e96644a9 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -545,7 +545,7 @@ static CURLcode smb_recv_message(struct Curl_easy *data, char *buf = smbc->recv_buf; size_t bytes_read; size_t nbt_size; - size_t msg_size; + size_t msg_size = sizeof(struct smb_header); size_t len = MAX_MESSAGE_SIZE - smbc->got; CURLcode result; @@ -565,10 +565,19 @@ static CURLcode smb_recv_message(struct Curl_easy *data, nbt_size = Curl_read16_be((const unsigned char *) (buf + sizeof(unsigned short))) + sizeof(unsigned int); + if(nbt_size > MAX_MESSAGE_SIZE) { + failf(data, "too large NetBIOS frame size %zu", nbt_size); + return CURLE_RECV_ERROR; + } + else if(nbt_size < msg_size) { + /* Each SMB message must be at least this large, e.g. 32 bytes */ + failf(data, "too small NetBIOS frame size %zu", nbt_size); + return CURLE_RECV_ERROR; + } + if(smbc->got < nbt_size) return CURLE_OK; - msg_size = sizeof(struct smb_header); if(nbt_size >= msg_size + 1) { /* Add the word count */ msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short); @@ -577,7 +586,7 @@ static CURLcode smb_recv_message(struct Curl_easy *data, msg_size += sizeof(unsigned short) + Curl_read16_le((const unsigned char *)&buf[msg_size]); if(nbt_size < msg_size) - return CURLE_READ_ERROR; + return CURLE_RECV_ERROR; } } @@ -661,7 +670,10 @@ static CURLcode smb_send_message(struct Curl_easy *data, { smb_format_message(smbc, req, (struct smb_header *)smbc->send_buf, cmd, msg_len); - DEBUGASSERT((sizeof(struct smb_header) + msg_len) <= MAX_MESSAGE_SIZE); + if((sizeof(struct smb_header) + msg_len) > MAX_MESSAGE_SIZE) { + DEBUGASSERT(0); + return CURLE_SEND_ERROR; + } memcpy(smbc->send_buf + sizeof(struct smb_header), msg, msg_len); return smb_send(data, smbc, sizeof(struct smb_header) + msg_len, 0); From dd7762c309d8e1f6c633825747be7ab812699940 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 10 Oct 2025 12:00:29 +0200 Subject: [PATCH 418/465] libssh2: use sockindex consistently Although the protocol should only run on index 0, there was a mix of looked up sockindex and using constant 0 in tls send/recv. Reported-by: Joshua Rogers Closes #19004 --- lib/vssh/libssh2.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 65ccd29923e5..a92e7508d519 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -3207,12 +3207,12 @@ static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer, size_t length, int flags, void **abstract) { struct Curl_easy *data = (struct Curl_easy *)*abstract; + int sockindex = Curl_conn_sockindex(data, sock); size_t nread; CURLcode result; struct connectdata *conn = data->conn; - Curl_recv *backup = conn->recv[0]; + Curl_recv *backup = conn->recv[sockindex]; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - int socknum = Curl_conn_sockindex(data, sock); (void)flags; if(!sshc) @@ -3220,9 +3220,9 @@ static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer, /* swap in the TLS reader function for this call only, and then swap back the SSH one again */ - conn->recv[0] = sshc->tls_recv; - result = Curl_conn_recv(data, socknum, buffer, length, &nread); - conn->recv[0] = backup; + conn->recv[sockindex] = sshc->tls_recv; + result = Curl_conn_recv(data, sockindex, buffer, length, &nread); + conn->recv[sockindex] = backup; if(result == CURLE_AGAIN) return -EAGAIN; /* magic return code for libssh2 */ else if(result) @@ -3235,12 +3235,12 @@ static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer, size_t length, int flags, void **abstract) { struct Curl_easy *data = (struct Curl_easy *)*abstract; + int sockindex = Curl_conn_sockindex(data, sock); size_t nwrite; CURLcode result; struct connectdata *conn = data->conn; - Curl_send *backup = conn->send[0]; + Curl_send *backup = conn->send[sockindex]; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - int socknum = Curl_conn_sockindex(data, sock); (void)flags; if(!sshc) @@ -3248,9 +3248,9 @@ static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer, /* swap in the TLS writer function for this call only, and then swap back the SSH one again */ - conn->send[0] = sshc->tls_send; - result = Curl_conn_send(data, socknum, buffer, length, FALSE, &nwrite); - conn->send[0] = backup; + conn->send[sockindex] = sshc->tls_send; + result = Curl_conn_send(data, sockindex, buffer, length, FALSE, &nwrite); + conn->send[sockindex] = backup; if(result == CURLE_AGAIN) return -EAGAIN; /* magic return code for libssh2 */ else if(result) From 6e35eb4879ec2ee97f43da295f52c6841beeafae Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Fri, 10 Oct 2025 14:33:36 +0200 Subject: [PATCH 419/465] lib: SSL connection reuse Protocol handlers not flagging PROTOPT_SSL that allow reuse of existing SSL connections now need to carry the flag PROTOPT_SSL_REUSE. Add PROTOPT_SSL_REUSE to imap, ldap, pop3, smtp and ftp. Add tests the http: urls do not reuse https: connections and vice versa. Reported-by: Sakthi SK Fixes #19006 Closes #19007 --- lib/ftp.c | 2 +- lib/imap.c | 3 ++- lib/ldap.c | 2 +- lib/openldap.c | 2 +- lib/pop3.c | 2 +- lib/smtp.c | 2 +- lib/url.c | 9 +++++---- lib/urldata.h | 3 +++ tests/http/test_01_basic.py | 20 ++++++++++++++++++++ 9 files changed, 35 insertions(+), 10 deletions(-) diff --git a/lib/ftp.c b/lib/ftp.c index adcad3dd7587..f633d213058a 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -271,7 +271,7 @@ const struct Curl_handler Curl_handler_ftp = { CURLPROTO_FTP, /* family */ PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP | - PROTOPT_WILDCARD /* flags */ + PROTOPT_WILDCARD | PROTOPT_SSL_REUSE /* flags */ }; diff --git a/lib/imap.c b/lib/imap.c index 69e4e0c2c608..47757d3f2978 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -209,7 +209,8 @@ const struct Curl_handler Curl_handler_imap = { CURLPROTO_IMAP, /* protocol */ CURLPROTO_IMAP, /* family */ PROTOPT_CLOSEACTION| /* flags */ - PROTOPT_URLOPTIONS + PROTOPT_URLOPTIONS| + PROTOPT_SSL_REUSE }; #ifdef USE_SSL diff --git a/lib/ldap.c b/lib/ldap.c index 2314bbf58512..0b475d07bbc4 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -199,7 +199,7 @@ const struct Curl_handler Curl_handler_ldap = { PORT_LDAP, /* defport */ CURLPROTO_LDAP, /* protocol */ CURLPROTO_LDAP, /* family */ - PROTOPT_NONE /* flags */ + PROTOPT_SSL_REUSE /* flags */ }; #ifdef HAVE_LDAP_SSL diff --git a/lib/openldap.c b/lib/openldap.c index b84268dae7c0..fb771161d61d 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -139,7 +139,7 @@ const struct Curl_handler Curl_handler_ldap = { PORT_LDAP, /* defport */ CURLPROTO_LDAP, /* protocol */ CURLPROTO_LDAP, /* family */ - PROTOPT_NONE /* flags */ + PROTOPT_SSL_REUSE /* flags */ }; #ifdef USE_SSL diff --git a/lib/pop3.c b/lib/pop3.c index ce9f81e3d5aa..dbcc2d198df2 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -200,7 +200,7 @@ const struct Curl_handler Curl_handler_pop3 = { CURLPROTO_POP3, /* protocol */ CURLPROTO_POP3, /* family */ PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ - PROTOPT_URLOPTIONS + PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE }; #ifdef USE_SSL diff --git a/lib/smtp.c b/lib/smtp.c index 8daf0ad89de3..76ed4f280afd 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -205,7 +205,7 @@ const struct Curl_handler Curl_handler_smtp = { CURLPROTO_SMTP, /* protocol */ CURLPROTO_SMTP, /* family */ PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ - PROTOPT_URLOPTIONS + PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE }; #ifdef USE_SSL diff --git a/lib/url.c b/lib/url.c index 6d69fc11bf88..f0fe7d3d4135 100644 --- a/lib/url.c +++ b/lib/url.c @@ -932,15 +932,16 @@ static bool url_match_multiplex_limits(struct connectdata *conn, static bool url_match_ssl_use(struct connectdata *conn, struct url_conn_match *m) { - if(m->needle->handler->flags&PROTOPT_SSL) { + if(m->needle->handler->flags & PROTOPT_SSL) { /* We are looking for SSL, if `conn` does not do it, not a match. */ if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) return FALSE; } else if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) { - /* We are not *requiring* SSL, however `conn` has it. If the - * protocol *family* is not the same, not a match. */ - if(get_protocol_family(conn->handler) != m->needle->handler->protocol) + /* If the protocol does not allow reuse of SSL connections OR + is of another protocol family, not a match. */ + if(!(m->needle->handler->flags & PROTOPT_SSL_REUSE) || + (get_protocol_family(conn->handler) != m->needle->handler->protocol)) return FALSE; } return TRUE; diff --git a/lib/urldata.h b/lib/urldata.h index b6b8f6f8fe3d..30bbbae416e4 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -578,6 +578,9 @@ struct Curl_handler { #define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ASCII) in username and password */ #define PROTOPT_NOTCPPROXY (1<<14) /* this protocol cannot proxy over TCP */ +#define PROTOPT_SSL_REUSE (1<<15) /* this protocol may reuse an existing + SSL connection in the same family + without having PROTOPT_SSL. */ #define CONNCHECK_NONE 0 /* No checks */ #define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */ diff --git a/tests/http/test_01_basic.py b/tests/http/test_01_basic.py index 4ac4e8e6e1e8..692bb3d7b266 100644 --- a/tests/http/test_01_basic.py +++ b/tests/http/test_01_basic.py @@ -273,3 +273,23 @@ def test_01_17_TE(self, env: Env, httpd, te_in, te_out): assert r.responses[0]['header']['request-te'] == te_out, f'{r.responses[0]}' else: assert 'request-te' not in r.responses[0]['header'], f'{r.responses[0]}' + + # check that an existing https: connection is not reused for http: + def test_01_18_tls_reuse(self, env: Env, httpd): + proto = 'h2' + curl = CurlClient(env=env) + url1 = f'https://{env.authority_for(env.domain1, proto)}/data.json' + url2 = f'http://{env.authority_for(env.domain1, proto)}/data.json' + r = curl.http_download(urls=[url1, url2], alpn_proto=proto, with_stats=True) + assert len(r.stats) == 2 + assert r.total_connects == 2, f'{r.dump_logs()}' + + # check that an existing http: connection is not reused for https: + def test_01_19_plain_reuse(self, env: Env, httpd): + proto = 'h2' + curl = CurlClient(env=env) + url1 = f'http://{env.domain1}:{env.http_port}/data.json' + url2 = f'https://{env.domain1}:{env.http_port}/data.json' + r = curl.http_download(urls=[url1, url2], alpn_proto=proto, with_stats=True) + assert len(r.stats) == 2 + assert r.total_connects == 2, f'{r.dump_logs()}' From 2b49d17cbacc6e919786c16019f3e330dc0f7605 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 11 Oct 2025 22:44:30 +0200 Subject: [PATCH 420/465] docs: expand on quoting rules for file names in SFTP quote Reported-by: Harry Sintonen Closes #19025 --- docs/cmdline-opts/quote.md | 9 ++++++--- docs/libcurl/opts/CURLOPT_QUOTE.md | 12 ++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/cmdline-opts/quote.md b/docs/cmdline-opts/quote.md index 04a47424a0ba..a5563010c6a5 100644 --- a/docs/cmdline-opts/quote.md +++ b/docs/cmdline-opts/quote.md @@ -37,9 +37,12 @@ You must send syntactically correct FTP commands as RFC 959 defines to FTP servers, or one of the commands listed below to SFTP servers. SFTP is a binary protocol. Unlike for FTP, curl interprets SFTP quote commands -itself before sending them to the server. Filenames may be quoted shell-style -to embed spaces or special characters. Following is the list of all supported -SFTP quote commands: +itself before sending them to the server. Filenames must be provided within +double quotes to embed spaces, backslashes, quotes or double quotes. Within +double quotes the following escape sequences are available for that purpose: +\\, \", and \'. + +Following is the list of all supported SFTP quote commands: ## atime date file The atime command sets the last access time of the file named by the file diff --git a/docs/libcurl/opts/CURLOPT_QUOTE.md b/docs/libcurl/opts/CURLOPT_QUOTE.md index 5e00f45137ef..11b6997c6811 100644 --- a/docs/libcurl/opts/CURLOPT_QUOTE.md +++ b/docs/libcurl/opts/CURLOPT_QUOTE.md @@ -52,11 +52,15 @@ libcurl does not inspect, parse or "understand" the commands passed to the server using this option. If you change connection state, working directory or similar using quote commands, libcurl does not know about it. -The path arguments for FTP or SFTP can use single or double quotes to -distinguish a space from being the parameter separator or being a part of the -path. e.g. rename with sftp using a quote command like this: +The path arguments for FTP or SFTP should use double quotes to distinguish a +space from being the parameter separator or being a part of the path. For +example, rename with sftp using a quote command like this: - "rename 'test/_upload.txt' 'test/Hello World.txt'" + rename "test/_upload.txt" "test/Hello World.txt" + +For SFTP, filenames must be provided within double quotes to embed spaces, +backslashes, quotes or double quotes. Within double quotes the following +escape sequences are available for that purpose: \\, \", and \'. # SFTP commands From 578706addec3d41cb5db64160d23795a95ca11d9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 12 Oct 2025 11:05:46 +0200 Subject: [PATCH 421/465] libssh/libssh2: reject quote command lines with too much data If there is lingering letters left on the right side after the paths have been parsed, they are syntactically incorrect so returning error is the safe thing to do. Reported-by: Harry Sintonen Closes #19030 --- lib/vssh/libssh.c | 26 ++++++++++++++++++++++++++ lib/vssh/libssh2.c | 24 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 544e682b771e..69666c53884f 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1557,6 +1557,18 @@ static int myssh_in_SFTP_POSTQUOTE_INIT(struct Curl_easy *data, return SSH_NO_ERROR; } +static int return_quote_error(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + failf(data, "Suspicious data after the command line"); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return SSH_NO_ERROR; +} + static int myssh_in_SFTP_QUOTE(struct Curl_easy *data, struct ssh_conn *sshc, struct SSHPROTO *sshp) @@ -1665,6 +1677,8 @@ static int myssh_in_SFTP_QUOTE(struct Curl_easy *data, sshc->actualcode = result; return SSH_NO_ERROR; } + if(*cp) + return return_quote_error(data, sshc); sshc->quote_attrs = NULL; myssh_to(data, sshc, SSH_SFTP_QUOTE_STAT); return SSH_NO_ERROR; @@ -1686,10 +1700,14 @@ static int myssh_in_SFTP_QUOTE(struct Curl_easy *data, sshc->actualcode = result; return SSH_NO_ERROR; } + if(*cp) + return return_quote_error(data, sshc); myssh_to(data, sshc, SSH_SFTP_QUOTE_SYMLINK); return SSH_NO_ERROR; } else if(!strncmp(cmd, "mkdir ", 6)) { + if(*cp) + return return_quote_error(data, sshc); /* create dir */ myssh_to(data, sshc, SSH_SFTP_QUOTE_MKDIR); return SSH_NO_ERROR; @@ -1710,20 +1728,28 @@ static int myssh_in_SFTP_QUOTE(struct Curl_easy *data, sshc->actualcode = result; return SSH_NO_ERROR; } + if(*cp) + return return_quote_error(data, sshc); myssh_to(data, sshc, SSH_SFTP_QUOTE_RENAME); return SSH_NO_ERROR; } else if(!strncmp(cmd, "rmdir ", 6)) { /* delete dir */ + if(*cp) + return return_quote_error(data, sshc); myssh_to(data, sshc, SSH_SFTP_QUOTE_RMDIR); return SSH_NO_ERROR; } else if(!strncmp(cmd, "rm ", 3)) { + if(*cp) + return return_quote_error(data, sshc); myssh_to(data, sshc, SSH_SFTP_QUOTE_UNLINK); return SSH_NO_ERROR; } #ifdef HAS_STATVFS_SUPPORT else if(!strncmp(cmd, "statvfs ", 8)) { + if(*cp) + return return_quote_error(data, sshc); myssh_to(data, sshc, SSH_SFTP_QUOTE_STATVFS); return SSH_NO_ERROR; } diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index a92e7508d519..ad416aba8e00 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -843,6 +843,15 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data, return result; } +static CURLcode return_quote_error(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + failf(data, "Suspicious data after the command line"); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + return CURLE_QUOTE_ERROR; +} + static CURLcode sftp_quote(struct Curl_easy *data, struct ssh_conn *sshc, struct SSHPROTO *sshp) @@ -930,6 +939,9 @@ static CURLcode sftp_quote(struct Curl_easy *data, Curl_safefree(sshc->quote_path1); return result; } + if(*cp) + return_quote_error(data, sshc); + memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); myssh_state(data, sshc, SSH_SFTP_QUOTE_STAT); return result; @@ -946,10 +958,14 @@ static CURLcode sftp_quote(struct Curl_easy *data, Curl_safefree(sshc->quote_path1); return result; } + if(*cp) + return_quote_error(data, sshc); myssh_state(data, sshc, SSH_SFTP_QUOTE_SYMLINK); return result; } else if(!strncmp(cmd, "mkdir ", 6)) { + if(*cp) + return_quote_error(data, sshc); /* create dir */ myssh_state(data, sshc, SSH_SFTP_QUOTE_MKDIR); return result; @@ -965,19 +981,27 @@ static CURLcode sftp_quote(struct Curl_easy *data, Curl_safefree(sshc->quote_path1); return result; } + if(*cp) + return_quote_error(data, sshc); myssh_state(data, sshc, SSH_SFTP_QUOTE_RENAME); return result; } else if(!strncmp(cmd, "rmdir ", 6)) { + if(*cp) + return_quote_error(data, sshc); /* delete dir */ myssh_state(data, sshc, SSH_SFTP_QUOTE_RMDIR); return result; } else if(!strncmp(cmd, "rm ", 3)) { + if(*cp) + return_quote_error(data, sshc); myssh_state(data, sshc, SSH_SFTP_QUOTE_UNLINK); return result; } else if(!strncmp(cmd, "statvfs ", 8)) { + if(*cp) + return_quote_error(data, sshc); myssh_state(data, sshc, SSH_SFTP_QUOTE_STATVFS); return result; } From 1e90a63a49e9cbfea8ff52055576df1189b47a7d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 12 Oct 2025 11:15:08 +0200 Subject: [PATCH 422/465] sws: pass in socket reference to allow function to close it The function service_connection() now passes in a reference to the socket instead of by value since the sub function http_connect() might close it and set *infdp = CURL_SOCKET_BAD. This would previously not be detected when service_connection() returned and potentially cause a double close of the socket. Reported-by: Joshua Rogers Closes #19031 --- tests/server/sws.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/server/sws.c b/tests/server/sws.c index 1fbbb3c2478d..caa5605534e4 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -1898,7 +1898,7 @@ static curl_socket_t accept_connection(curl_socket_t sock) /* returns 1 if the connection should be serviced again immediately, 0 if there is no data waiting, or < 0 if it should be closed */ -static int service_connection(curl_socket_t msgsock, +static int service_connection(curl_socket_t *msgsock, struct sws_httprequest *req, curl_socket_t listensock, const char *connecthost, @@ -1908,7 +1908,7 @@ static int service_connection(curl_socket_t msgsock, return -1; while(!req->done_processing) { - int rc = sws_get_request(msgsock, req); + int rc = sws_get_request(*msgsock, req); if(rc <= 0) { /* Nothing further to read now, possibly because the socket was closed */ return rc; @@ -1928,7 +1928,7 @@ static int service_connection(curl_socket_t msgsock, } } - sws_send_doc(msgsock, req); + sws_send_doc(*msgsock, req); if(got_exit_signal) return -1; @@ -1948,7 +1948,7 @@ static int service_connection(curl_socket_t msgsock, return 1; } else { - http_connect(&msgsock, listensock, connecthost, req->connect_port, + http_connect(msgsock, listensock, connecthost, req->connect_port, keepalive_secs); return -1; } @@ -2391,7 +2391,7 @@ static int test_sws(int argc, char *argv[]) /* Service this connection until it has nothing available */ do { - rc = service_connection(all_sockets[socket_idx], req, sock, + rc = service_connection(&all_sockets[socket_idx], req, sock, connecthost, keepalive_secs); if(got_exit_signal) goto sws_cleanup; From 1feeda422e4bf247d9181a06e5642ca5cc3bdfb2 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 12 Oct 2025 11:24:07 +0200 Subject: [PATCH 423/465] examples/synctime: fix null termination assumptions bonus: dont parse argv[0] for options Reported-by: Joshua Rogers Closes #19032 --- docs/examples/synctime.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c index 591761fe1c2c..071037a44806 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -117,7 +117,6 @@ static SYSTEMTIME LOCALTime; #define HTTP_COMMAND_HEAD 0 #define HTTP_COMMAND_GET 1 - static size_t SyncTime_CURL_WriteOutput(void *ptr, size_t size, size_t nmemb, void *stream) { @@ -125,6 +124,7 @@ static size_t SyncTime_CURL_WriteOutput(void *ptr, size_t size, size_t nmemb, return nmemb * size; } +/* Remember: do not assume headers are passed on null terminated! */ static size_t SyncTime_CURL_WriteHeader(void *ptr, size_t size, size_t nmemb, void *stream) { @@ -135,18 +135,22 @@ static size_t SyncTime_CURL_WriteHeader(void *ptr, size_t size, size_t nmemb, if(ShowAllHeader == 1) fprintf(stderr, "%.*s", (int)nmemb, (char *)ptr); - if(strncmp((char *)ptr, "Date:", 5) == 0) { + if((nmemb >= 5) && !strncmp((char *)ptr, "Date:", 5)) { if(ShowAllHeader == 0) fprintf(stderr, "HTTP Server. %.*s", (int)nmemb, (char *)ptr); if(AutoSyncTime == 1) { - int RetVal; + int RetVal = 0; + char *field = ptr; *TmpStr1 = 0; *TmpStr2 = 0; - RetVal = sscanf((char *)ptr, "Date: %25s %hu %25s %hu %hu:%hu:%hu", - TmpStr1, &SYSTime.wDay, TmpStr2, &SYSTime.wYear, - &SYSTime.wHour, &SYSTime.wMinute, - &SYSTime.wSecond); + if(nmemb && (field[nmemb] == '\n')) { + field[nmemb] = 0; /* null terminated */ + RetVal = sscanf(field, "Date: %25s %hu %25s %hu %hu:%hu:%hu", + TmpStr1, &SYSTime.wDay, TmpStr2, &SYSTime.wYear, + &SYSTime.wHour, &SYSTime.wMinute, + &SYSTime.wSecond); + } if(RetVal == 7) { int i; @@ -165,7 +169,7 @@ static size_t SyncTime_CURL_WriteHeader(void *ptr, size_t size, size_t nmemb, } } - if(strncmp((char *)ptr, "X-Cache: HIT", 12) == 0) { + if((nmemb >= 12) && !strncmp((char *)ptr, "X-Cache: HIT", 12)) { fprintf(stderr, "ERROR: HTTP Server data is cached." " Server Date is no longer valid.\n"); AutoSyncTime = 0; @@ -251,7 +255,7 @@ int main(int argc, char *argv[]) conf_init(conf); if(argc > 1) { - int OptionIndex = 0; + int OptionIndex = 1; while(OptionIndex < argc) { if(strncmp(argv[OptionIndex], "--server=", 9) == 0) snprintf(conf->timeserver, MAX_STRING, "%s", &argv[OptionIndex][9]); From e90b2aaa7e9dce64c3d7416b17a7c2feb7208db3 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 12 Oct 2025 11:38:39 +0200 Subject: [PATCH 424/465] tftp: error requests for blank filenames Reported-by: Joshua Rogers Closes #19033 --- lib/tftp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/tftp.c b/lib/tftp.c index 8279f29e650e..0a9b8a8e870b 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -460,6 +460,10 @@ static CURLcode tftp_send_first(struct tftp_conn *state, /* As RFC3617 describes the separator slash is not actually part of the filename so we skip the always-present first letter of the path string. */ + if(!state->data->state.up.path[1]) { + failf(data, "Missing filename"); + return CURLE_TFTP_ILLEGAL; + } result = Curl_urldecode(&state->data->state.up.path[1], 0, &filename, NULL, REJECT_ZERO); if(result) From cde85412d03a52ed801b1e936f43ac033af65cf0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 13 Oct 2025 08:27:01 +0200 Subject: [PATCH 425/465] KNOWN_BUGS: We do not support auth-int for Digest using PUT or POST Closes #19038 --- docs/KNOWN_BUGS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index c9beb2836194..d4e4423094ef 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -43,6 +43,7 @@ problems may have been fixed or changed somewhat since this was written. 5.15 Unicode on Windows 6. Authentication + 6.1 Digest auth-int for PUT/POST 6.2 MIT Kerberos for Windows build 6.3 NTLM in system context uses wrong name 6.5 NTLM does not support password with Unicode 'SECTION SIGN' character @@ -301,6 +302,10 @@ problems may have been fixed or changed somewhat since this was written. 6. Authentication +6.1 Digest auth-int for PUT/POST + + We do not support auth-int for Digest using PUT or POST + 6.2 MIT Kerberos for Windows build libcurl fails to build with MIT Kerberos for Windows (KfW) due to KfW's From 56450ce26fa6ec05d1a1d63ee07efb9a204b656e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 12 Oct 2025 23:48:14 +0200 Subject: [PATCH 426/465] tool_msgs: make errorf() show if --show-error Assisted-by: Mitchell Blank Jr Ref: #19029 Closes #19035 --- src/tool_msgs.c | 79 +++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/src/tool_msgs.c b/src/tool_msgs.c index f83cdc76c1b8..896788745c7c 100644 --- a/src/tool_msgs.c +++ b/src/tool_msgs.c @@ -43,45 +43,43 @@ static void voutf(const char *prefix, va_list ap) { size_t width = (get_terminal_columns() - strlen(prefix)); + size_t len; + char *ptr; + char *print_buffer; DEBUGASSERT(!strchr(fmt, '\n')); - if(!global->silent) { - size_t len; - char *ptr; - char *print_buffer; - - print_buffer = curl_mvaprintf(fmt, ap); - if(!print_buffer) - return; - len = strlen(print_buffer); - ptr = print_buffer; - while(len > 0) { - fputs(prefix, tool_stderr); + print_buffer = curl_mvaprintf(fmt, ap); + if(!print_buffer) + return; + len = strlen(print_buffer); - if(len > width) { - size_t cut = width-1; + ptr = print_buffer; + while(len > 0) { + fputs(prefix, tool_stderr); - while(!ISBLANK(ptr[cut]) && cut) { - cut--; - } - if(cut == 0) - /* not a single cutting position was found, just cut it at the - max text width then! */ - cut = width-1; + if(len > width) { + size_t cut = width-1; - (void)fwrite(ptr, cut + 1, 1, tool_stderr); - fputs("\n", tool_stderr); - ptr += cut + 1; /* skip the space too */ - len -= cut + 1; - } - else { - fputs(ptr, tool_stderr); - fputs("\n", tool_stderr); - len = 0; + while(!ISBLANK(ptr[cut]) && cut) { + cut--; } + if(cut == 0) + /* not a single cutting position was found, just cut it at the + max text width then! */ + cut = width-1; + + (void)fwrite(ptr, cut + 1, 1, tool_stderr); + fputs("\n", tool_stderr); + ptr += cut + 1; /* skip the space too */ + len -= cut + 1; + } + else { + fputs(ptr, tool_stderr); + fputs("\n", tool_stderr); + len = 0; } - curl_free(print_buffer); } + curl_free(print_buffer); } /* @@ -90,11 +88,12 @@ static void voutf(const char *prefix, */ void notef(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - if(global->tracetype) + if(global->tracetype) { + va_list ap; + va_start(ap, fmt); voutf(NOTE_PREFIX, fmt, ap); - va_end(ap); + va_end(ap); + } } /* @@ -103,10 +102,12 @@ void notef(const char *fmt, ...) */ void warnf(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - voutf(WARN_PREFIX, fmt, ap); - va_end(ap); + if(!global->silent) { + va_list ap; + va_start(ap, fmt); + voutf(WARN_PREFIX, fmt, ap); + va_end(ap); + } } /* From 27375ca36489475796a0e533bea6b040b0712da0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 12 Oct 2025 15:58:43 +0200 Subject: [PATCH 427/465] tool_getparam: make --fail and --fail-with-body override each other This allows users to put one of them in their .curlrc and still easily use the other one at will in command lines. The --no-* versions disable both of them. Reported-by: Mitchell Blank Jr Fixes #19029 Closes #19034 --- src/config2setopts.c | 2 +- src/tool_cfgable.h | 7 +++++-- src/tool_getparam.c | 24 +++++++++--------------- src/tool_operate.c | 5 ++--- tests/data/test360 | 26 +++++++++++++++++++++----- 5 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/config2setopts.c b/src/config2setopts.c index 0a519ed04865..c367959ccb3e 100644 --- a/src/config2setopts.c +++ b/src/config2setopts.c @@ -851,7 +851,7 @@ CURLcode config2setopts(struct OperationConfig *config, if(result) return result; - my_setopt_long(curl, CURLOPT_FAILONERROR, config->failonerror); + my_setopt_long(curl, CURLOPT_FAILONERROR, config->fail == FAIL_WO_BODY); my_setopt_str(curl, CURLOPT_REQUEST_TARGET, config->request_target); my_setopt_long(curl, CURLOPT_UPLOAD, !!per->uploadfile); my_setopt_long(curl, CURLOPT_DIRLISTONLY, config->dirlistonly); diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 3c67695124e7..630f23fd9654 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -58,6 +58,10 @@ struct State { curl_off_t urlidx; /* index for globbed URLs */ }; +#define FAIL_NONE 0 +#define FAIL_WITH_BODY 1 +#define FAIL_WO_BODY 2 + struct OperationConfig { struct dynbuf postdata; char *useragent; @@ -223,6 +227,7 @@ struct OperationConfig { unsigned short porttouse; unsigned char ssl_version; /* 0 - 4, 0 being default */ unsigned char ssl_version_max; /* 0 - 4, 0 being default */ + unsigned char fail; /* NONE, with body, without body */ BIT(remote_name_all); /* --remote-name-all */ BIT(remote_time); BIT(cookiesession); /* new session? */ @@ -241,8 +246,6 @@ struct OperationConfig { BIT(ftp_append); /* APPE on ftp */ BIT(use_ascii); /* select ASCII or text transfer */ BIT(autoreferer); /* automatically set referer */ - BIT(failonerror); /* fail on (HTTP) errors */ - BIT(failwithbody); /* fail on (HTTP) errors but still store body */ BIT(show_headers); /* show headers to data output */ BIT(no_body); /* do not get the body */ BIT(dirlistonly); /* only get the FTP dir list */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c index b533f41aa7df..0cff5b558d9b 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -2037,14 +2037,6 @@ static ParameterError opt_bool(struct OperationConfig *config, case C_MAIL_RCPT_ALLOWFAILS: /* --mail-rcpt-allowfails */ config->mail_rcpt_allowfails = toggle; break; - case C_FAIL_WITH_BODY: /* --fail-with-body */ - config->failwithbody = toggle; - if(config->failonerror && config->failwithbody) { - errorf("You must select either --fail or " - "--fail-with-body, not both."); - return PARAM_BAD_USE; - } - break; case C_REMOVE_ON_ERROR: /* --remove-on-error */ if(config->use_resume && toggle) { errorf("--continue-at is mutually exclusive with --remove-on-error"); @@ -2052,13 +2044,15 @@ static ParameterError opt_bool(struct OperationConfig *config, } config->rm_partial = toggle; break; - case C_FAIL: /* --fail */ - config->failonerror = toggle; - if(config->failonerror && config->failwithbody) { - errorf("You must select either --fail or " - "--fail-with-body, not both."); - return PARAM_BAD_USE; - } + case C_FAIL: /* --fail without body */ + if(toggle && (config->fail == FAIL_WITH_BODY)) + warnf("--fail deselects --fail-with-body here"); + config->fail = toggle ? FAIL_WO_BODY : FAIL_NONE; + break; + case C_FAIL_WITH_BODY: /* --fail-with-body */ + if(toggle && (config->fail == FAIL_WO_BODY)) + warnf("--fail-with-body deselects --fail here"); + config->fail = toggle ? FAIL_WITH_BODY : FAIL_NONE; break; case C_GLOBOFF: /* --globoff */ config->globoff = toggle; diff --git a/src/tool_operate.c b/src/tool_operate.c index 1901ab3ac178..397b2159e198 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -393,8 +393,7 @@ static CURLcode retrycheck(struct OperationConfig *config, retry = RETRY_CONNREFUSED; } else if((CURLE_OK == result) || - ((config->failonerror || config->failwithbody) && - (CURLE_HTTP_RETURNED_ERROR == result))) { + (config->fail && (CURLE_HTTP_RETURNED_ERROR == result))) { /* If it returned OK. _or_ failonerror was enabled and it returned due to such an error, check for HTTP transient errors to retry on. */ @@ -659,7 +658,7 @@ static CURLcode post_per_transfer(struct per_transfer *per, if(result == CURLE_PEER_FAILED_VERIFICATION) fputs(CURL_CA_CERT_ERRORMSG, tool_stderr); } - else if(config->failwithbody) { + else if(config->fail == FAIL_WITH_BODY) { /* if HTTP response >= 400, return error */ long code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); diff --git a/tests/data/test360 b/tests/data/test360 index b7d570d7b6c4..f98d03a036cc 100644 --- a/tests/data/test360 +++ b/tests/data/test360 @@ -6,7 +6,23 @@ -# Client-side + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- + + + http @@ -15,14 +31,14 @@ http Error on both --fail-with-body and --fail -http://%HOSTIP:%HTTPPORT/%TESTNUMBER --fail-with-body --fail +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --fail-with-body --fail --no-progress-meter # Verify data after the test has been "shot" - -2 - + +Warning: --fail deselects --fail-with-body here + From 67c4256f7e4f00d8e85b9a7da0b6004bfe5669e1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 13 Oct 2025 08:41:38 +0200 Subject: [PATCH 428/465] pop3: function could get the ->transfer field wrong In pop3_perform(), pop3->transfer was derived from the old data->req.no_body. Then, pop3_perform_command() re-computed data->req.no_body. Now we instead call pop3_perform_command() first. Reported-by: Joshua Rogers Closes #19039 --- lib/pop3.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/pop3.c b/lib/pop3.c index dbcc2d198df2..a0fd881a791f 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1377,18 +1377,17 @@ static CURLcode pop3_perform(struct Curl_easy *data, bool *connected, DEBUGF(infof(data, "DO phase starts")); - if(data->req.no_body) { + /* Start the first command in the DO phase, may alter data->req.no_body */ + result = pop3_perform_command(data); + if(result) + return result; + + if(data->req.no_body) /* Requested no body means no transfer */ pop3->transfer = PPTRANSFER_INFO; - } *dophase_done = FALSE; /* not done yet */ - /* Start the first command in the DO phase */ - result = pop3_perform_command(data); - if(result) - return result; - /* Run the state-machine */ result = pop3_multi_statemach(data, dophase_done); *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); From e003c0b25934bd8875ce34df2e4141fe518356ae Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 13 Oct 2025 09:24:57 +0200 Subject: [PATCH 429/465] socks_sspi: remove the enforced mode clearing Reported-by: Joshua Rogers Closes #19040 --- lib/socks_sspi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 69b000421944..54049e8c9928 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -325,8 +325,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, infof(data, "SOCKS5 server supports GSS-API %s data protection.", (gss_enc == 0) ? "no" : ((gss_enc == 1) ? "integrity":"confidentiality") ); - /* force to no data protection, avoid encryption/decryption for now */ - gss_enc = 0; + /* * Sending the encryption type in clear seems wrong. It should be * protected with gss_seal()/gss_wrap(). See RFC1961 extract below From dee72fe31e3c07433b0f7c103bc416a65f572e03 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 13 Oct 2025 09:36:08 +0200 Subject: [PATCH 430/465] libssh2: fix EAGAIN return in ssh_state_auth_agent Reported-by: Joshua Rogers Closes #19042 --- lib/vssh/libssh2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index ad416aba8e00..dfdb8526d610 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1850,8 +1850,9 @@ static CURLcode ssh_state_auth_agent(struct Curl_easy *data, if(rc != LIBSSH2_ERROR_EAGAIN) { /* tried and failed? go to next identity */ sshc->sshagent_prev_identity = sshc->sshagent_identity; + return CURLE_OK; } - return CURLE_OK; + return CURLE_AGAIN; } } From 5e74b2df345c702359926b78fa8c32a08689058e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Sat, 11 Oct 2025 10:48:23 +0200 Subject: [PATCH 431/465] REUSE: move copyright headers to `.checksrc` To make it simpler to move them around, create and delete them without syncing with `REUSE.toml`. Also: - checksrc: allow empty lines in `.checksrc`. - comment on why curl printfs are disallowed in examples. Closes #19024 --- REUSE.toml | 5 ----- docs/examples/.checksrc | 6 ++++++ scripts/.checksrc | 4 ++++ scripts/checksrc.pl | 4 ++++ src/.checksrc | 4 ++++ tests/server/.checksrc | 4 ++++ 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/REUSE.toml b/REUSE.toml index d3b98edb4879..40531913af3b 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -39,11 +39,6 @@ path = [ "tests/certs/**", "tests/data/test**", "tests/valgrind.supp", - # checksrc control files - "docs/examples/.checksrc", - "scripts/.checksrc", - "src/.checksrc", - "tests/server/.checksrc", ] SPDX-FileCopyrightText = "Daniel Stenberg, , et al." SPDX-License-Identifier = "curl" diff --git a/docs/examples/.checksrc b/docs/examples/.checksrc index c81d1597681d..e35dccc7261d 100644 --- a/docs/examples/.checksrc +++ b/docs/examples/.checksrc @@ -1,3 +1,7 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + allowfunc fclose allowfunc fdopen allowfunc fopen @@ -11,6 +15,8 @@ allowfunc socket allowfunc sscanf allowfunc strerror allowfunc vsnprintf + +# Use of curl printf functions is discouraged banfunc curl_maprintf banfunc curl_mfprintf banfunc curl_mprintf diff --git a/scripts/.checksrc b/scripts/.checksrc index 84d62d2b750c..03e98fee8925 100644 --- a/scripts/.checksrc +++ b/scripts/.checksrc @@ -1 +1,5 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + allowfunc printf diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index 5a8c80ebfe5b..c424924e4572 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -202,6 +202,10 @@ sub readlocalfile { if(/^\s*(#.*)/) { next; } + # Skip empty lines + elsif($_ eq '') { + next; + } elsif(/^enable ([A-Z]+)$/) { if(!defined($warnings_extended{$1})) { print STDERR "invalid warning specified in .checksrc: \"$1\"\n"; diff --git a/src/.checksrc b/src/.checksrc index 946367c4999f..bc97c06028da 100644 --- a/src/.checksrc +++ b/src/.checksrc @@ -1 +1,5 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + enable STDERR diff --git a/tests/server/.checksrc b/tests/server/.checksrc index d4be12473ac4..a4e094e1c913 100644 --- a/tests/server/.checksrc +++ b/tests/server/.checksrc @@ -1,3 +1,7 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + allowfunc accept allowfunc fclose allowfunc fopen From 6d0fcdf2ed9942ad92665c2b96ab431c8829b53d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 13 Oct 2025 09:45:28 +0200 Subject: [PATCH 432/465] libssh: catch a resume point larger than the size As it would otherwise trigger broken math Reported-by: Joshua Rogers Closes #19044 --- lib/vssh/libssh.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 69666c53884f..6bb32643af2d 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1239,6 +1239,10 @@ static int myssh_in_UPLOAD_INIT(struct Curl_easy *data, /* now, decrease the size of the read */ if(data->state.infilesize > 0) { + if(data->state.resume_from > data->state.infilesize) { + failf(data, "Resume point beyond size"); + return myssh_to_ERROR(data, sshc, CURLE_BAD_FUNCTION_ARGUMENT); + } data->state.infilesize -= data->state.resume_from; data->req.size = data->state.infilesize; Curl_pgrsSetUploadSize(data, data->state.infilesize); From f1828b54047dba804d04e4c0ebd402c6e9a11533 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 13 Oct 2025 09:40:38 +0200 Subject: [PATCH 433/465] libssh2: avoid risking using an uninitialized local struct field Reported-by: Joshua Rogers Closes #19043 --- lib/vssh/libssh2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index dfdb8526d610..ee468bb35958 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1428,6 +1428,7 @@ sftp_download_stat(struct Curl_easy *data, data->req.size = -1; data->req.maxdownload = -1; Curl_pgrsSetDownloadSize(data, -1); + attrs.filesize = 0; /* might be uninitialized but will be read below */ } else { curl_off_t size = attrs.filesize; From 6deea19eb4396e68b42b2b7d3b32aaba8f30b03b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 13 Oct 2025 16:03:46 +0200 Subject: [PATCH 434/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 53 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 4d5ce575ce14..986a21bea742 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,7 +4,7 @@ curl and libcurl 8.17.0 Command line options: 273 curl_easy_setopt() options: 308 Public functions in libcurl: 100 - Contributors: 3515 + Contributors: 3517 This release includes the following changes: @@ -23,6 +23,7 @@ This release includes the following changes: This release includes the following bugfixes: o ares: fix leak in tracing [91] + o asyn-ares: remove wrong comment about the callback argument [306] o asyn-ares: use the duped hostname pointer for all calls [158] o asyn-thrdd resolver: clear timeout when done [97] o asyn-thrdd: drop pthread_cancel [30] @@ -92,10 +93,13 @@ This release includes the following bugfixes: o docs/libcurl: clarify some timeout option behavior [15] o docs/libcurl: remove ancient version references [7] o docs/libcurl: use lowercase must [5] + o docs: expand on quoting rules for file names in SFTP quote [300] o docs: fix/tidy code fences [87] + o doswin: CloseHandle the thread on shutdown [307] o easy_getinfo: check magic, Curl_close safety [3] o examples/sessioninfo: cast printf string mask length to int [232] o examples/sessioninfo: do not disable security [255] + o examples/synctime: fix null termination assumptions [297] o examples/synctime: make the sscanf not overflow the local buffer [252] o examples/usercertinmem: avoid stripping const [247] o examples: drop unused `curl/mprintf.h` includes [224] @@ -134,21 +138,28 @@ This release includes the following bugfixes: o ldap: avoid null ptr deref on failure [284] o ldap: do not base64 encode zero length string [42] o ldap: tidy-up types, fix error code confusion [191] + o lib1514: fix return code mixup [304] o lib: drop unused include and duplicate guards [226] o lib: fix build error and compiler warnings with verbose strings disabled [173] o lib: remove personal names from comments [168] + o lib: SSL connection reuse [301] o lib: upgrade/multiplex handling [136] o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] + o libssh/libssh2: reject quote command lines with too much data [299] o libssh/sftp: fix resume corruption by avoiding O_APPEND with rresume [263] o libssh2/sftp: fix resume corruption by avoiding O_APPEND with rresume [262] o libssh2/sftp_realpath: change state consistently [185] + o libssh2: avoid risking using an uninitialized local struct field [209] o libssh2: bail out on chgrp and chown number parsing errors [202] o libssh2: clarify that sshp->path is always at least one byte [201] o libssh2: drop two redundant null-terminations [26] o libssh2: error check and null-terminate in ssh_state_sftp_readdir_link() [34] + o libssh2: fix EAGAIN return in ssh_state_auth_agent [290] o libssh2: fix return code for EAGAIN [186] + o libssh2: use sockindex consistently [302] o libssh: acknowledge SSH_AGAIN in the SFTP state machine [89] + o libssh: catch a resume point larger than the size [281] o libssh: clarify myssh_block2waitfor [92] o libssh: drop two unused assignments [104] o libssh: error on bad chgrp number [71] @@ -197,6 +208,7 @@ This release includes the following bugfixes: o OS400: fix a use-after-free/double-free case [142] o osslq: set idle timeout to 0 [237] o pingpong: remove two old leftover debug infof() calls + o pop3: function could get the ->transfer field wrong [292] o pytest: skip specific tests for no-verbose builds [171] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] @@ -218,6 +230,7 @@ This release includes the following bugfixes: o setopt: allow CURLOPT_DNS_CACHE_TIMEOUT set to -1 [257] o setopt: make CURLOPT_MAXREDIRS accept -1 (again) [1] o smb: adjust buffer size checks [45] + o smb: transfer debugassert to real check [303] o smtp: check EHLO responses case insensitively [50] o socks: advance iobuf instead of reset [276] o socks: deny server basic-auth if not configured [264] @@ -231,10 +244,13 @@ This release includes the following bugfixes: o socks_gssapi: remove the forced "no protection" [143] o socks_sspi: bail out on too long fields [137] o socks_sspi: fix memory cleanup calls [40] + o socks_sspi: remove the enforced mode clearing [291] o socks_sspi: restore non-blocking socket on error paths [48] + o socksd: remove --bindonly mention, there is no such option [305] o ssl-sessions.md: mark option experimental [12] o strerror: drop workaround for SalfordC win32 header bug [214] o sws: fix checking `sscanf()` return value [17] + o sws: pass in socket reference to allow function to close it [298] o tcp-nodelay.md: expand the documentation [153] o telnet: ignore empty suboptions [86] o telnet: make bad_option() consider NULL a bad option too [192] @@ -249,6 +265,7 @@ This release includes the following bugfixes: o tests/server: drop unsafe `open()` override in signal handler (Windows) [151] o tftp: check and act on tftp_set_timeouts() returning error [38] o tftp: default timeout per block is now 15 seconds [156] + o tftp: error requests for blank filenames [296] o tftp: handle tftp_multi_statemach() return code [65] o tftp: pin the first used address [110] o tftp: propagate expired timer from tftp_state_timeout() [39] @@ -270,7 +287,9 @@ This release includes the following bugfixes: o tool_filetime: replace cast with the fitting printf mask (Windows) [212] o tool_getparam/set_rate: skip the multiplication on overflow [84] o tool_getparam: always disable "lib-ids" for tracing [169] + o tool_getparam: make --fail and --fail-with-body override each other [293] o tool_getparam: warn if provided header looks malformed [179] + o tool_msgs: make errorf() show if --show-error [294] o tool_operate: improve wording in retry message [37] o tool_operate: keep failed partial download for retry auto-resume [210] o tool_operate: keep the progress meter for --out-null [33] @@ -325,14 +344,15 @@ advice from friends like these: Andrew Olsen, BobodevMm on github, Christian Schmitz, Dan Fandrich, Daniel Stenberg, Daniel Terhorst-North, dependabot[bot], divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, - Evgeny Grin (Karlson2k), fds242 on github, Howard Chu, Ignat Loskutov, - Javier Blazquez, Jicea, jmaggard10 on github, Johannes Schindelin, - Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, kuchara on github, - Marcel Raad, Michael Osipov, Michał Petryka, Mohamed Daahir, Nir Azkiel, - Patrick Monnerat, Pocs Norbert, Ray Satiro, renovate[bot], rinsuki on github, + Evgeny Grin (Karlson2k), fds242 on github, Harry Sintonen, Howard Chu, + Ignat Loskutov, Javier Blazquez, Jicea, jmaggard10 on github, + Johannes Schindelin, Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, + kuchara on github, Marcel Raad, Michael Osipov, Michał Petryka, + Mitchell Blank Jr, Mohamed Daahir, Nir Azkiel, Patrick Monnerat, + Pocs Norbert, Ray Satiro, renovate[bot], rinsuki on github, Sakthi SK, Samuel Dionne-Riel, Samuel Henrique, Stanislav Fort, Stefan Eissing, tkzv on github, Viktor Szakats - (42 contributors) + (45 contributors) References to bug reports and discussions on issues: @@ -544,6 +564,7 @@ References to bug reports and discussions on issues: [206] = https://curl.se/bug/?i=18868 [207] = https://curl.se/bug/?i=18872 [208] = https://curl.se/bug/?i=18972 + [209] = https://curl.se/bug/?i=19043 [210] = https://curl.se/bug/?i=18035 [211] = https://curl.se/bug/?i=18860 [212] = https://curl.se/bug/?i=18858 @@ -615,6 +636,7 @@ References to bug reports and discussions on issues: [278] = https://curl.se/bug/?i=18993 [279] = https://curl.se/bug/?i=18992 [280] = https://curl.se/bug/?i=18973 + [281] = https://curl.se/bug/?i=19044 [282] = https://curl.se/bug/?i=18990 [283] = https://curl.se/bug/?i=18989 [284] = https://curl.se/bug/?i=18988 @@ -622,3 +644,20 @@ References to bug reports and discussions on issues: [286] = https://curl.se/bug/?i=18986 [287] = https://curl.se/bug/?i=18985 [288] = https://curl.se/bug/?i=18984 + [290] = https://curl.se/bug/?i=19042 + [291] = https://curl.se/bug/?i=19040 + [292] = https://curl.se/bug/?i=19039 + [293] = https://curl.se/bug/?i=19029 + [294] = https://curl.se/bug/?i=19035 + [296] = https://curl.se/bug/?i=19033 + [297] = https://curl.se/bug/?i=19032 + [298] = https://curl.se/bug/?i=19031 + [299] = https://curl.se/bug/?i=19030 + [300] = https://curl.se/bug/?i=19025 + [301] = https://curl.se/bug/?i=19006 + [302] = https://curl.se/bug/?i=19004 + [303] = https://curl.se/bug/?i=19003 + [304] = https://curl.se/bug/?i=19027 + [305] = https://curl.se/bug/?i=19026 + [306] = https://curl.se/bug/?i=19014 + [307] = https://curl.se/bug/?i=18996 From 497b3f022e9031eaa134697a5f5542b9d5ea3611 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 13 Oct 2025 13:44:23 +0200 Subject: [PATCH 435/465] checksrc: allow disabling warnings on FIXME/TODO comments Follow-up to 71ace9f3c16a434385fc27b3e8bffb52deb6ccd1 Closes #19048 --- scripts/checksrc.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/checksrc.pl b/scripts/checksrc.pl index c424924e4572..7059d6857500 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -134,6 +134,7 @@ 'EQUALSNULL' => 'if/while comparison with == NULL', 'ERRNOVAR' => 'use of bare errno define', 'EXCLAMATIONSPACE' => 'Whitespace after exclamation mark in expression', + 'FIXME' => 'FIXME or TODO comment', 'FOPENMODE' => 'fopen needs a macro for the mode string', 'INCLUDEDUP', => 'same file is included again', 'INDENTATION' => 'wrong start column for code', From 5cf0a6789da260518ed025d41d7dd6a7069fbfcd Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 13 Oct 2025 16:08:42 +0200 Subject: [PATCH 436/465] examples: call `curl_global_cleanup()` where missing Reported-by: Joshua Rogers (for `sepheaders.c`) Closes #19051 --- docs/examples/multi-uv.c | 2 ++ docs/examples/persistent.c | 2 ++ docs/examples/postit2-formadd.c | 3 +++ docs/examples/postit2.c | 3 +++ docs/examples/sepheaders.c | 2 ++ docs/examples/smooth-gtk-thread.c | 2 ++ docs/examples/synctime.c | 3 +++ docs/examples/threaded-ssl.c | 2 ++ 8 files changed, 19 insertions(+) diff --git a/docs/examples/multi-uv.c b/docs/examples/multi-uv.c index 8cebcd5e2677..cc27668d5706 100644 --- a/docs/examples/multi-uv.c +++ b/docs/examples/multi-uv.c @@ -252,5 +252,7 @@ int main(int argc, char **argv) uv_run(uv.loop, UV_RUN_DEFAULT); curl_multi_cleanup(uv.multi); + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/persistent.c b/docs/examples/persistent.c index be5e8c33e667..ffcf343fbf92 100644 --- a/docs/examples/persistent.c +++ b/docs/examples/persistent.c @@ -66,5 +66,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/postit2-formadd.c b/docs/examples/postit2-formadd.c index 0d9034612a56..88fb92475032 100644 --- a/docs/examples/postit2-formadd.c +++ b/docs/examples/postit2-formadd.c @@ -115,5 +115,8 @@ int main(int argc, char *argv[]) /* free slist */ curl_slist_free_all(headerlist); } + + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/postit2.c b/docs/examples/postit2.c index 0f12cd478669..d16d3fccf64e 100644 --- a/docs/examples/postit2.c +++ b/docs/examples/postit2.c @@ -100,5 +100,8 @@ int main(int argc, char *argv[]) /* free slist */ curl_slist_free_all(headerlist); } + + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/sepheaders.c b/docs/examples/sepheaders.c index 31a320124168..8f48033a0d71 100644 --- a/docs/examples/sepheaders.c +++ b/docs/examples/sepheaders.c @@ -91,5 +91,7 @@ int main(void) /* cleanup curl stuff */ curl_easy_cleanup(curl_handle); + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/smooth-gtk-thread.c b/docs/examples/smooth-gtk-thread.c index 49a412d95843..dc79276ba8a4 100644 --- a/docs/examples/smooth-gtk-thread.c +++ b/docs/examples/smooth-gtk-thread.c @@ -214,5 +214,7 @@ int main(int argc, char **argv) gdk_threads_leave(); printf("gdk_threads_leave\n"); + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c index 071037a44806..d5f5a5bfde1a 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -360,6 +360,9 @@ int main(int argc, char *argv[]) conf_init(conf); curl_easy_cleanup(curl); } + + curl_global_cleanup(); + return RetValue; } #endif /* CURL_WINDOWS_UWP */ diff --git a/docs/examples/threaded-ssl.c b/docs/examples/threaded-ssl.c index 3868899e4fca..98377ee84040 100644 --- a/docs/examples/threaded-ssl.c +++ b/docs/examples/threaded-ssl.c @@ -97,5 +97,7 @@ int main(int argc, char **argv) fprintf(stderr, "Thread %d terminated\n", i); } + curl_global_cleanup(); + return 0; } From 3049c8e0a0c31174a482dbfa46586aaed6ed9c3f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 13 Oct 2025 16:18:40 +0200 Subject: [PATCH 437/465] examples: return `curl_easy_perform()` results Where missing. Or explicitly `(void)` it where we ignore it on purpose. Reported-by: Joshua Rogers (for `sepheaders.c`) Closes #19052 --- docs/examples/multithread.c | 2 +- docs/examples/sepheaders.c | 5 +++-- docs/examples/smooth-gtk-thread.c | 2 +- docs/examples/threaded-ssl.c | 2 +- docs/examples/url2file.c | 6 ++++-- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/examples/multithread.c b/docs/examples/multithread.c index b98977c443db..a47758062f5d 100644 --- a/docs/examples/multithread.c +++ b/docs/examples/multithread.c @@ -57,7 +57,7 @@ static void *pull_one_url(void *pindex) curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, urls[i]); - curl_easy_perform(curl); /* ignores error */ + (void)curl_easy_perform(curl); /* ignores error */ curl_easy_cleanup(curl); return NULL; diff --git a/docs/examples/sepheaders.c b/docs/examples/sepheaders.c index 8f48033a0d71..097183f82169 100644 --- a/docs/examples/sepheaders.c +++ b/docs/examples/sepheaders.c @@ -38,6 +38,7 @@ static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) int main(void) { + CURLcode res; CURL *curl_handle; static const char *headerfilename = "head.out"; FILE *headerfile; @@ -80,7 +81,7 @@ int main(void) curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, bodyfile); /* get it! */ - curl_easy_perform(curl_handle); + res = curl_easy_perform(curl_handle); /* close the header file */ fclose(headerfile); @@ -93,5 +94,5 @@ int main(void) curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/smooth-gtk-thread.c b/docs/examples/smooth-gtk-thread.c index dc79276ba8a4..3b615cb344c3 100644 --- a/docs/examples/smooth-gtk-thread.c +++ b/docs/examples/smooth-gtk-thread.c @@ -80,7 +80,7 @@ static void run_one(gchar *http, int j) /* Write to the file */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file); - curl_easy_perform(curl); + (void)curl_easy_perform(curl); fclose(outfile); curl_easy_cleanup(curl); diff --git a/docs/examples/threaded-ssl.c b/docs/examples/threaded-ssl.c index 98377ee84040..fb60b7f16050 100644 --- a/docs/examples/threaded-ssl.c +++ b/docs/examples/threaded-ssl.c @@ -64,7 +64,7 @@ static void *pull_one_url(void *pindex) might be downloading stuff from an impostor */ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_perform(curl); /* ignores error */ + (void)curl_easy_perform(curl); /* ignores error */ curl_easy_cleanup(curl); return NULL; diff --git a/docs/examples/url2file.c b/docs/examples/url2file.c index 9ed7da5a84a6..c55d2a77c792 100644 --- a/docs/examples/url2file.c +++ b/docs/examples/url2file.c @@ -38,6 +38,8 @@ static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) int main(int argc, char *argv[]) { + CURLcode res = CURLE_OK; + CURL *curl_handle; static const char *pagefilename = "page.out"; FILE *pagefile; @@ -72,7 +74,7 @@ int main(int argc, char *argv[]) curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile); /* get it! */ - curl_easy_perform(curl_handle); + res = curl_easy_perform(curl_handle); /* close the header file */ fclose(pagefile); @@ -83,5 +85,5 @@ int main(int argc, char *argv[]) curl_global_cleanup(); - return 0; + return (int)res; } From 4c7507daf913c2e7f3ff96b1ff92e467a3d2ece5 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 13 Oct 2025 16:30:18 +0200 Subject: [PATCH 438/465] examples: improve global init, error checks and returning errors - add `curl_global_init()` and `curl_global_cleanup()` where missing. - check the result of `curl_global_init()` where missing. - return the last curl error from `main()`. - drop Win32-specific socket initialization in favor of `curl_global_init()`. - rename some outliers to `res` for curl result code. - fix cleanup in some error cases. Inspired by Joshua's report on examples. Closes #19053 --- docs/examples/10-at-a-time.c | 5 +- docs/examples/address-scope.c | 10 +- docs/examples/altsvc.c | 8 +- docs/examples/anyauthput.c | 8 +- docs/examples/block_ip.c | 5 +- docs/examples/cacertinmem.c | 26 ++--- docs/examples/certinfo.c | 6 +- docs/examples/chkspeed.c | 4 +- docs/examples/connect-to.c | 11 ++- docs/examples/cookie_interface.c | 5 +- docs/examples/crawler.c | 6 +- docs/examples/debug.c | 7 +- docs/examples/default-scheme.c | 7 +- docs/examples/ephiperfifo.c | 13 ++- docs/examples/evhiperfifo.c | 6 ++ docs/examples/externalsocket.c | 16 +--- docs/examples/fileupload.c | 10 +- docs/examples/ftp-delete.c | 7 +- docs/examples/ftp-wildcard.c | 113 ++++++++++------------ docs/examples/ftpget.c | 6 +- docs/examples/ftpgetinfo.c | 6 +- docs/examples/ftpgetresp.c | 11 ++- docs/examples/ftpsget.c | 6 +- docs/examples/ftpupload.c | 8 +- docs/examples/ftpuploadfrommem.c | 2 +- docs/examples/ftpuploadresume.c | 5 +- docs/examples/getinfo.c | 8 +- docs/examples/getinmemory.c | 8 +- docs/examples/getredirect.c | 7 +- docs/examples/getreferrer.c | 7 +- docs/examples/ghiper.c | 9 +- docs/examples/headerapi.c | 6 +- docs/examples/hiperfifo.c | 10 +- docs/examples/hsts-preload.c | 8 +- docs/examples/htmltidy.c | 87 +++++++++-------- docs/examples/htmltitle.cpp | 13 ++- docs/examples/http-options.c | 6 +- docs/examples/http-post.c | 6 +- docs/examples/http2-download.c | 10 +- docs/examples/http2-pushinmemory.c | 7 +- docs/examples/http2-serverpush.c | 8 +- docs/examples/http2-upload.c | 11 ++- docs/examples/http3-present.c | 4 +- docs/examples/http3.c | 6 +- docs/examples/httpcustomheader.c | 8 +- docs/examples/httpput-postfields.c | 6 +- docs/examples/httpput.c | 8 +- docs/examples/https.c | 7 +- docs/examples/imap-append.c | 7 +- docs/examples/imap-authzid.c | 7 +- docs/examples/imap-copy.c | 7 +- docs/examples/imap-create.c | 7 +- docs/examples/imap-delete.c | 7 +- docs/examples/imap-examine.c | 7 +- docs/examples/imap-fetch.c | 7 +- docs/examples/imap-list.c | 7 +- docs/examples/imap-lsub.c | 7 +- docs/examples/imap-multi.c | 58 +++++------ docs/examples/imap-noop.c | 7 +- docs/examples/imap-search.c | 7 +- docs/examples/imap-ssl.c | 7 +- docs/examples/imap-store.c | 7 +- docs/examples/imap-tls.c | 7 +- docs/examples/interface.c | 7 +- docs/examples/ipv6.c | 7 +- docs/examples/keepalive.c | 7 +- docs/examples/localport.c | 7 +- docs/examples/log_failed_transfers.c | 8 +- docs/examples/maxconnects.c | 8 +- docs/examples/multi-app.c | 5 + docs/examples/multi-debugcallback.c | 6 ++ docs/examples/multi-double.c | 6 ++ docs/examples/multi-event.c | 7 +- docs/examples/multi-formadd.c | 5 + docs/examples/multi-legacy.c | 6 ++ docs/examples/multi-post.c | 5 + docs/examples/multi-single.c | 4 +- docs/examples/multi-uv.c | 6 +- docs/examples/multithread.c | 5 +- docs/examples/netrc.c | 7 +- docs/examples/persistent.c | 7 +- docs/examples/pop3-authzid.c | 7 +- docs/examples/pop3-dele.c | 7 +- docs/examples/pop3-list.c | 7 +- docs/examples/pop3-multi.c | 58 +++++------ docs/examples/pop3-noop.c | 7 +- docs/examples/pop3-retr.c | 7 +- docs/examples/pop3-ssl.c | 7 +- docs/examples/pop3-stat.c | 7 +- docs/examples/pop3-tls.c | 7 +- docs/examples/pop3-top.c | 7 +- docs/examples/pop3-uidl.c | 7 +- docs/examples/post-callback.c | 2 +- docs/examples/postinmemory.c | 5 +- docs/examples/postit2-formadd.c | 4 +- docs/examples/postit2.c | 4 +- docs/examples/progressfunc.c | 6 +- docs/examples/protofeats.c | 4 +- docs/examples/range.c | 7 +- docs/examples/resolve.c | 6 +- docs/examples/rtsp-options.c | 6 +- docs/examples/sendrecv.c | 6 +- docs/examples/sepheaders.c | 93 +++++++++--------- docs/examples/sessioninfo.c | 6 +- docs/examples/sftpget.c | 7 +- docs/examples/sftpuploadresume.c | 5 +- docs/examples/shared-connection-cache.c | 9 +- docs/examples/simple.c | 6 +- docs/examples/simplepost.c | 10 +- docs/examples/simplessl.c | 6 +- docs/examples/smooth-gtk-thread.c | 4 +- docs/examples/smtp-authzid.c | 7 +- docs/examples/smtp-expn.c | 7 +- docs/examples/smtp-mail.c | 7 +- docs/examples/smtp-mime.c | 7 +- docs/examples/smtp-multi.c | 122 ++++++++++++------------ docs/examples/smtp-ssl.c | 7 +- docs/examples/smtp-tls.c | 7 +- docs/examples/smtp-vrfy.c | 9 +- docs/examples/synctime.c | 6 +- docs/examples/threaded-ssl.c | 5 +- docs/examples/unixsocket.c | 8 +- docs/examples/url2file.c | 9 +- docs/examples/urlapi.c | 8 +- docs/examples/usercertinmem.c | 15 +-- docs/examples/websocket-cb.c | 8 +- docs/examples/websocket-updown.c | 55 ++++++----- docs/examples/websocket.c | 45 +++++---- docs/examples/xmlstream.c | 7 +- 129 files changed, 1002 insertions(+), 497 deletions(-) diff --git a/docs/examples/10-at-a-time.c b/docs/examples/10-at-a-time.c index 38a0f24ac62f..48e0030040c5 100644 --- a/docs/examples/10-at-a-time.c +++ b/docs/examples/10-at-a-time.c @@ -109,7 +109,10 @@ int main(void) int msgs_left = -1; int left = 0; - curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + cm = curl_multi_init(); /* Limit the amount of simultaneous connections curl should allow: */ diff --git a/docs/examples/address-scope.c b/docs/examples/address-scope.c index 43e9cf898627..82607e2df50e 100644 --- a/docs/examples/address-scope.c +++ b/docs/examples/address-scope.c @@ -37,7 +37,10 @@ int main(void) #if !defined(_WIN32) && !defined(MSDOS) && !defined(__AMIGA__) /* Windows/MS-DOS users need to find how to use if_nametoindex() */ CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -57,6 +60,9 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } -#endif + curl_global_cleanup(); + return (int)res; +#else return 0; +#endif } diff --git a/docs/examples/altsvc.c b/docs/examples/altsvc.c index 8a1ae8ed3b40..4021c90002e9 100644 --- a/docs/examples/altsvc.c +++ b/docs/examples/altsvc.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -54,5 +57,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/anyauthput.c b/docs/examples/anyauthput.c index 505d16b217b2..81bb1fb9071d 100644 --- a/docs/examples/anyauthput.c +++ b/docs/examples/anyauthput.c @@ -111,7 +111,11 @@ int main(int argc, char **argv) #endif /* In Windows, this inits the Winsock stuff */ - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) { + fclose(fp); + return (int)res; + } /* get a curl handle */ curl = curl_easy_init(); @@ -161,5 +165,5 @@ int main(int argc, char **argv) fclose(fp); /* close the local file */ curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/block_ip.c b/docs/examples/block_ip.c index 181cd8270db7..b99fab58c389 100644 --- a/docs/examples/block_ip.c +++ b/docs/examples/block_ip.c @@ -301,9 +301,10 @@ int main(void) if(!filter) return 1; - if(curl_global_init(CURL_GLOBAL_DEFAULT)) { + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) { free(filter); - return 1; + return (int)res; } curl = curl_easy_init(); diff --git a/docs/examples/cacertinmem.c b/docs/examples/cacertinmem.c index e552ce5d69cf..d72dc490018a 100644 --- a/docs/examples/cacertinmem.c +++ b/docs/examples/cacertinmem.c @@ -56,8 +56,6 @@ static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer) { - CURLcode rv = CURLE_ABORTED_BY_CALLBACK; - /** This example uses two (fake) certificates **/ /* replace the XXX with the actual CA certificates */ static const char mypem[] = @@ -89,14 +87,14 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer) (void)pointer; if(!cts || !cbio) { - return rv; + return CURLE_ABORTED_BY_CALLBACK; } inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL); if(!inf) { BIO_free(cbio); - return rv; + return CURLE_ABORTED_BY_CALLBACK; } for(i = 0; i < sk_X509_INFO_num(inf); i++) { @@ -112,16 +110,18 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer) sk_X509_INFO_pop_free(inf, X509_INFO_free); BIO_free(cbio); - rv = CURLE_OK; - return rv; + return CURLE_OK; } int main(void) { CURL *ch; - CURLcode rv; + CURLcode res; + + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; - curl_global_init(CURL_GLOBAL_ALL); ch = curl_easy_init(); curl_easy_setopt(ch, CURLOPT_VERBOSE, 0L); curl_easy_setopt(ch, CURLOPT_HEADER, 0L); @@ -145,8 +145,8 @@ int main(void) /* first try: retrieve page without ca certificates -> should fail * unless libcurl was built --with-ca-fallback enabled at build-time */ - rv = curl_easy_perform(ch); - if(rv == CURLE_OK) + res = curl_easy_perform(ch); + if(res == CURLE_OK) printf("*** transfer succeeded ***\n"); else printf("*** transfer failed ***\n"); @@ -166,13 +166,13 @@ int main(void) * "modifications" to the SSL CONTEXT just before link init */ curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); - rv = curl_easy_perform(ch); - if(rv == CURLE_OK) + res = curl_easy_perform(ch); + if(res == CURLE_OK) printf("*** transfer succeeded ***\n"); else printf("*** transfer failed ***\n"); curl_easy_cleanup(ch); curl_global_cleanup(); - return (int)rv; + return (int)res; } diff --git a/docs/examples/certinfo.c b/docs/examples/certinfo.c index 795be6c3d19d..0443aa42f46c 100644 --- a/docs/examples/certinfo.c +++ b/docs/examples/certinfo.c @@ -41,7 +41,9 @@ int main(void) CURL *curl; CURLcode res; - curl_global_init(CURL_GLOBAL_DEFAULT); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -83,5 +85,5 @@ int main(void) curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/chkspeed.c b/docs/examples/chkspeed.c index 32bd92005d5b..d4b2abbab819 100644 --- a/docs/examples/chkspeed.c +++ b/docs/examples/chkspeed.c @@ -156,7 +156,9 @@ int main(int argc, char *argv[]) } /* init libcurl */ - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; /* init the curl session */ curl_handle = curl_easy_init(); diff --git a/docs/examples/connect-to.c b/docs/examples/connect-to.c index ad1e30464964..253c531c420d 100644 --- a/docs/examples/connect-to.c +++ b/docs/examples/connect-to.c @@ -30,8 +30,12 @@ int main(void) { + struct curl_slist *host; CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; /* Each single string should be written using the format @@ -41,8 +45,7 @@ int main(void) */ /* instead of curl.se:443, it resolves and uses example.com:443 but in other aspects work as if it still is curl.se */ - struct curl_slist *host = curl_slist_append(NULL, - "curl.se:443:example.com:443"); + host = curl_slist_append(NULL, "curl.se:443:example.com:443"); curl = curl_easy_init(); if(curl) { @@ -66,5 +69,7 @@ int main(void) curl_slist_free_all(host); + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/cookie_interface.c b/docs/examples/cookie_interface.c index cb68977121c1..cebbd3cdcff0 100644 --- a/docs/examples/cookie_interface.c +++ b/docs/examples/cookie_interface.c @@ -72,7 +72,10 @@ main(void) CURL *curl; CURLcode res; - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { char nline[512]; diff --git a/docs/examples/crawler.c b/docs/examples/crawler.c index 6b737652d40e..a7ca5fa2fe40 100644 --- a/docs/examples/crawler.c +++ b/docs/examples/crawler.c @@ -182,10 +182,14 @@ int main(void) int pending; int complete; int still_running; + CURLcode res; + + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; signal(SIGINT, sighandler); LIBXML_TEST_VERSION - curl_global_init(CURL_GLOBAL_DEFAULT); multi_handle = curl_multi_init(); curl_multi_setopt(multi_handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, max_con); curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 6L); diff --git a/docs/examples/debug.c b/docs/examples/debug.c index 5303c833f5ea..85fdea95d329 100644 --- a/docs/examples/debug.c +++ b/docs/examples/debug.c @@ -128,6 +128,10 @@ int main(void) CURLcode res; struct data config; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + config.trace_ascii = 1; /* enable ASCII tracing */ curl = curl_easy_init(); @@ -151,5 +155,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/default-scheme.c b/docs/examples/default-scheme.c index 13e1e08fcb3e..b4ea5fa3bfb4 100644 --- a/docs/examples/default-scheme.c +++ b/docs/examples/default-scheme.c @@ -33,6 +33,10 @@ int main(void) CURL *curl; CURLcode res; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "example.com"); @@ -53,5 +57,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/ephiperfifo.c b/docs/examples/ephiperfifo.c index 3fddb2b7431f..c22a3601010e 100644 --- a/docs/examples/ephiperfifo.c +++ b/docs/examples/ephiperfifo.c @@ -449,6 +449,7 @@ void sigint_handler(int signo) int main(int argc, char **argv) { + CURLcode res; struct GlobalInfo g; struct itimerspec its; struct epoll_event ev; @@ -456,6 +457,10 @@ int main(int argc, char **argv) (void)argc; (void)argv; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + g_should_exit_ = 0; signal(SIGINT, sigint_handler); @@ -463,12 +468,14 @@ int main(int argc, char **argv) g.epfd = epoll_create1(EPOLL_CLOEXEC); if(g.epfd == -1) { perror("epoll_create1 failed"); + curl_global_cleanup(); return 1; } g.tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); if(g.tfd == -1) { perror("timerfd_create failed"); + curl_global_cleanup(); return 1; } @@ -481,8 +488,10 @@ int main(int argc, char **argv) ev.data.fd = g.tfd; epoll_ctl(g.epfd, EPOLL_CTL_ADD, g.tfd, &ev); - if(init_fifo(&g)) + if(init_fifo(&g)) { + curl_global_cleanup(); return 1; + } g.multi = curl_multi_init(); /* setup the generic multi interface options we want */ @@ -508,6 +517,7 @@ int main(int argc, char **argv) } else { perror("epoll_wait"); + curl_global_cleanup(); return 1; } } @@ -530,5 +540,6 @@ int main(int argc, char **argv) curl_multi_cleanup(g.multi); clean_fifo(&g); + curl_global_cleanup(); return 0; } diff --git a/docs/examples/evhiperfifo.c b/docs/examples/evhiperfifo.c index 364a0f42fefa..79dfd3452178 100644 --- a/docs/examples/evhiperfifo.c +++ b/docs/examples/evhiperfifo.c @@ -415,10 +415,15 @@ static int init_fifo(struct GlobalInfo *g) int main(int argc, char **argv) { + CURLcode res; struct GlobalInfo g; (void)argc; (void)argv; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + memset(&g, 0, sizeof(g)); g.loop = ev_default_loop(0); @@ -439,5 +444,6 @@ int main(int argc, char **argv) ev_loop(g.loop, 0); curl_multi_cleanup(g.multi); + curl_global_cleanup(); return 0; } diff --git a/docs/examples/externalsocket.c b/docs/examples/externalsocket.c index 84c9ba4eb226..99e719b74574 100644 --- a/docs/examples/externalsocket.c +++ b/docs/examples/externalsocket.c @@ -103,14 +103,9 @@ int main(void) struct sockaddr_in servaddr; /* socket address structure */ curl_socket_t sockfd; -#ifdef _WIN32 - WSADATA wsaData; - int initwsa = WSAStartup(MAKEWORD(2, 2), &wsaData); - if(initwsa) { - printf("WSAStartup failed: %d\n", initwsa); - return 1; - } -#endif + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -175,8 +170,7 @@ int main(void) } } -#ifdef _WIN32 - WSACleanup(); -#endif + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/fileupload.c b/docs/examples/fileupload.c index 29c3c3c3c138..f827c68390a7 100644 --- a/docs/examples/fileupload.c +++ b/docs/examples/fileupload.c @@ -46,9 +46,15 @@ int main(void) curl_off_t speed_upload, total_time; FILE *fd; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + fd = fopen("debugit", "rb"); /* open file to upload */ - if(!fd) + if(!fd) { + curl_global_cleanup(); return 1; /* cannot continue */ + } /* to get the file size */ #ifdef UNDER_CE @@ -58,6 +64,7 @@ int main(void) if(fstat(fileno(fd), &file_info) != 0) { #endif fclose(fd); + curl_global_cleanup(); return 1; /* cannot continue */ } @@ -100,5 +107,6 @@ int main(void) curl_easy_cleanup(curl); } fclose(fd); + curl_global_cleanup(); return 0; } diff --git a/docs/examples/ftp-delete.c b/docs/examples/ftp-delete.c index b879da48d3ef..f5c553ff68ef 100644 --- a/docs/examples/ftp-delete.c +++ b/docs/examples/ftp-delete.c @@ -37,14 +37,15 @@ static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream) return size * nmemb; } - int main(void) { CURL *curl; CURLcode res; struct curl_slist *headerlist = NULL; - curl_global_init(CURL_GLOBAL_DEFAULT); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -80,5 +81,5 @@ int main(void) curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/ftp-wildcard.c b/docs/examples/ftp-wildcard.c index ddc6e4aae4c6..0861f2f0487e 100644 --- a/docs/examples/ftp-wildcard.c +++ b/docs/examples/ftp-wildcard.c @@ -32,67 +32,6 @@ struct callback_data { FILE *output; }; -static long file_is_coming(struct curl_fileinfo *finfo, - void *data, - int remains); - -static long file_is_downloaded(void *data); - -static size_t write_it(char *buff, size_t size, size_t nmemb, - void *cb_data); - -int main(int argc, char **argv) -{ - /* curl easy handle */ - CURL *handle; - - /* help data */ - struct callback_data data = { 0 }; - - /* global initialization */ - CURLcode rc = curl_global_init(CURL_GLOBAL_ALL); - if(rc) - return (int)rc; - - /* initialization of easy handle */ - handle = curl_easy_init(); - if(!handle) { - curl_global_cleanup(); - return CURLE_OUT_OF_MEMORY; - } - - /* turn on wildcard matching */ - curl_easy_setopt(handle, CURLOPT_WILDCARDMATCH, 1L); - - /* callback is called before download of concrete file started */ - curl_easy_setopt(handle, CURLOPT_CHUNK_BGN_FUNCTION, file_is_coming); - - /* callback is called after data from the file have been transferred */ - curl_easy_setopt(handle, CURLOPT_CHUNK_END_FUNCTION, file_is_downloaded); - - /* this callback writes contents into files */ - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_it); - - /* put transfer data into callbacks */ - curl_easy_setopt(handle, CURLOPT_CHUNK_DATA, &data); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data); - - /* curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); */ - - /* set a URL containing wildcard pattern (only in the last part) */ - if(argc == 2) - curl_easy_setopt(handle, CURLOPT_URL, argv[1]); - else - curl_easy_setopt(handle, CURLOPT_URL, "ftp://example.com/test/*"); - - /* and start transfer! */ - rc = curl_easy_perform(handle); - - curl_easy_cleanup(handle); - curl_global_cleanup(); - return (int)rc; -} - static long file_is_coming(struct curl_fileinfo *finfo, void *input, int remains) { @@ -151,3 +90,55 @@ static size_t write_it(char *buff, size_t size, size_t nmemb, written = fwrite(buff, size, nmemb, stdout); return written; } + +int main(int argc, char **argv) +{ + /* curl easy handle */ + CURL *handle; + + /* help data */ + struct callback_data data = { 0 }; + + /* global initialization */ + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + + /* initialization of easy handle */ + handle = curl_easy_init(); + if(!handle) { + curl_global_cleanup(); + return CURLE_OUT_OF_MEMORY; + } + + /* turn on wildcard matching */ + curl_easy_setopt(handle, CURLOPT_WILDCARDMATCH, 1L); + + /* callback is called before download of concrete file started */ + curl_easy_setopt(handle, CURLOPT_CHUNK_BGN_FUNCTION, file_is_coming); + + /* callback is called after data from the file have been transferred */ + curl_easy_setopt(handle, CURLOPT_CHUNK_END_FUNCTION, file_is_downloaded); + + /* this callback writes contents into files */ + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_it); + + /* put transfer data into callbacks */ + curl_easy_setopt(handle, CURLOPT_CHUNK_DATA, &data); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data); + + /* curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); */ + + /* set a URL containing wildcard pattern (only in the last part) */ + if(argc == 2) + curl_easy_setopt(handle, CURLOPT_URL, argv[1]); + else + curl_easy_setopt(handle, CURLOPT_URL, "ftp://example.com/test/*"); + + /* and start transfer! */ + res = curl_easy_perform(handle); + + curl_easy_cleanup(handle); + curl_global_cleanup(); + return (int)res; +} diff --git a/docs/examples/ftpget.c b/docs/examples/ftpget.c index 95369c1c02bd..f4ba1e52aa24 100644 --- a/docs/examples/ftpget.c +++ b/docs/examples/ftpget.c @@ -57,7 +57,9 @@ int main(void) NULL }; - curl_global_init(CURL_GLOBAL_DEFAULT); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -90,5 +92,5 @@ int main(void) curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/ftpgetinfo.c b/docs/examples/ftpgetinfo.c index 485b26bddc72..549d3003a8a3 100644 --- a/docs/examples/ftpgetinfo.c +++ b/docs/examples/ftpgetinfo.c @@ -49,7 +49,9 @@ int main(void) curl_off_t filesize = 0; const char *filename = strrchr(ftpurl, '/') + 1; - curl_global_init(CURL_GLOBAL_DEFAULT); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -89,5 +91,5 @@ int main(void) curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/ftpgetresp.c b/docs/examples/ftpgetresp.c index 7b40f77c9483..7b6a6e3d2dae 100644 --- a/docs/examples/ftpgetresp.c +++ b/docs/examples/ftpgetresp.c @@ -47,15 +47,22 @@ int main(void) FILE *ftpfile; FILE *respfile; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + /* local filename to store the file as */ ftpfile = fopen(FTPBODY, "wb"); /* b is binary, needed on Windows */ - if(!ftpfile) + if(!ftpfile) { + curl_global_cleanup(); return 1; + } /* local filename to store the FTP server's response lines in */ respfile = fopen(FTPHEADERS, "wb"); /* b is binary, needed on Windows */ if(!respfile) { fclose(ftpfile); + curl_global_cleanup(); return 1; } @@ -81,5 +88,5 @@ int main(void) fclose(ftpfile); /* close the local file */ fclose(respfile); /* close the response file */ - return 0; + return (int)res; } diff --git a/docs/examples/ftpsget.c b/docs/examples/ftpsget.c index dfe80b9f8bc9..c2aee89c8487 100644 --- a/docs/examples/ftpsget.c +++ b/docs/examples/ftpsget.c @@ -59,7 +59,9 @@ int main(void) NULL }; - curl_global_init(CURL_GLOBAL_DEFAULT); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -97,5 +99,5 @@ int main(void) curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/ftpupload.c b/docs/examples/ftpupload.c index 4f3b679226eb..7588a829532f 100644 --- a/docs/examples/ftpupload.c +++ b/docs/examples/ftpupload.c @@ -109,7 +109,11 @@ int main(void) printf("Local file size: %lu bytes.\n", (unsigned long)fsize); /* In Windows, this inits the Winsock stuff */ - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) { + fclose(hd_src); + return (int)res; + } /* get a curl handle */ curl = curl_easy_init(); @@ -155,5 +159,5 @@ int main(void) fclose(hd_src); /* close the local file */ curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/ftpuploadfrommem.c b/docs/examples/ftpuploadfrommem.c index 3748d68a05b9..70242376ae17 100644 --- a/docs/examples/ftpuploadfrommem.c +++ b/docs/examples/ftpuploadfrommem.c @@ -122,5 +122,5 @@ int main(void) curl_easy_cleanup(curl); } curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/ftpuploadresume.c b/docs/examples/ftpuploadresume.c index 67495aec6870..544b746873ce 100644 --- a/docs/examples/ftpuploadresume.c +++ b/docs/examples/ftpuploadresume.c @@ -154,7 +154,10 @@ int main(void) { CURL *curlhandle = NULL; - curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curlhandle = curl_easy_init(); upload(curlhandle, "ftp://user:pass@example.com/path/file", "C:\\file", diff --git a/docs/examples/getinfo.c b/docs/examples/getinfo.c index 9c178c2c8ce3..d6257afa791c 100644 --- a/docs/examples/getinfo.c +++ b/docs/examples/getinfo.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -50,5 +53,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/getinmemory.c b/docs/examples/getinmemory.c index 173247d91520..589047097b54 100644 --- a/docs/examples/getinmemory.c +++ b/docs/examples/getinmemory.c @@ -66,11 +66,13 @@ int main(void) struct MemoryStruct chunk; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + chunk.memory = malloc(1); /* grown as needed by the realloc above */ chunk.size = 0; /* no data at this point */ - curl_global_init(CURL_GLOBAL_ALL); - /* init the curl session */ curl_handle = curl_easy_init(); @@ -114,5 +116,5 @@ int main(void) /* we are done with libcurl, so clean it up */ curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/getredirect.c b/docs/examples/getredirect.c index 91c778d3c1b8..908cd5f850f8 100644 --- a/docs/examples/getredirect.c +++ b/docs/examples/getredirect.c @@ -35,6 +35,10 @@ int main(void) char *location; long response_code; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); @@ -68,5 +72,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/getreferrer.c b/docs/examples/getreferrer.c index c46f7825a0aa..ae42f4605fce 100644 --- a/docs/examples/getreferrer.c +++ b/docs/examples/getreferrer.c @@ -32,10 +32,12 @@ int main(void) { CURL *curl; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { - CURLcode res; - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); curl_easy_setopt(curl, CURLOPT_REFERER, "https://example.org/referrer"); @@ -55,5 +57,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } + curl_global_cleanup(); return 0; } diff --git a/docs/examples/ghiper.c b/docs/examples/ghiper.c index 7d8449cdf0a9..50308fd47c38 100644 --- a/docs/examples/ghiper.c +++ b/docs/examples/ghiper.c @@ -421,9 +421,15 @@ int main(void) int fd; GIOChannel* ch; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + fd = init_fifo(); - if(fd == CURL_SOCKET_BAD) + if(fd == CURL_SOCKET_BAD) { + curl_global_cleanup(); return 1; + } ch = g_io_channel_unix_new(fd); g_io_add_watch(ch, G_IO_IN, fifo_cb, g); gmain = g_main_loop_new(NULL, FALSE); @@ -438,5 +444,6 @@ int main(void) g_main_loop_run(gmain); curl_multi_cleanup(g->multi); + curl_global_cleanup(); return 0; } diff --git a/docs/examples/headerapi.c b/docs/examples/headerapi.c index ede0c5cbdaed..428374bac667 100644 --- a/docs/examples/headerapi.c +++ b/docs/examples/headerapi.c @@ -40,9 +40,12 @@ int main(void) { CURL *curl; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { - CURLcode res; struct curl_header *header; curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); /* example.com is redirected, so we tell libcurl to follow redirection */ @@ -77,5 +80,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } + curl_global_cleanup(); return 0; } diff --git a/docs/examples/hiperfifo.c b/docs/examples/hiperfifo.c index 1af1eb0c72c3..cc22e70abbe4 100644 --- a/docs/examples/hiperfifo.c +++ b/docs/examples/hiperfifo.c @@ -414,14 +414,21 @@ static void clean_fifo(struct GlobalInfo *g) int main(int argc, char **argv) { + CURLcode res; struct GlobalInfo g; (void)argc; (void)argv; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + memset(&g, 0, sizeof(g)); g.evbase = event_base_new(); - if(init_fifo(&g)) + if(init_fifo(&g)) { + curl_global_cleanup(); return 1; + } g.multi = curl_multi_init(); evtimer_assign(&g.timer_event, g.evbase, timer_cb, &g); @@ -443,5 +450,6 @@ int main(int argc, char **argv) event_del(&g.timer_event); event_base_free(g.evbase); curl_multi_cleanup(g.multi); + curl_global_cleanup(); return 0; } diff --git a/docs/examples/hsts-preload.c b/docs/examples/hsts-preload.c index ba9fe87a9441..303b17f52500 100644 --- a/docs/examples/hsts-preload.c +++ b/docs/examples/hsts-preload.c @@ -80,7 +80,10 @@ static CURLSTScode hstswrite(CURL *easy, struct curl_hstsentry *e, int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -114,5 +117,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/htmltidy.c b/docs/examples/htmltidy.c index 498bb85bdc8a..952132fbc497 100644 --- a/docs/examples/htmltidy.c +++ b/docs/examples/htmltidy.c @@ -76,55 +76,58 @@ void dumpNode(TidyDoc doc, TidyNode tnod, int indent) int main(int argc, char **argv) { - if(argc == 2) { - CURL *curl; - char curl_errbuf[CURL_ERROR_SIZE]; - TidyDoc tdoc; - TidyBuffer docbuf = {0}; - TidyBuffer tidy_errbuf = {0}; - int err; + CURL *curl; + char curl_errbuf[CURL_ERROR_SIZE]; + TidyDoc tdoc; + TidyBuffer docbuf = {0}; + TidyBuffer tidy_errbuf = {0}; + CURLcode res; - curl = curl_easy_init(); - curl_easy_setopt(curl, CURLOPT_URL, argv[1]); - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); + if(argc != 2) { + printf("usage: %s \n", argv[0]); + return 1; + } + + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + + curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); - tdoc = tidyCreate(); - tidyOptSetBool(tdoc, TidyForceOutput, yes); /* try harder */ - tidyOptSetInt(tdoc, TidyWrapLen, 4096); - tidySetErrorBuffer(tdoc, &tidy_errbuf); - tidyBufInit(&docbuf); + tdoc = tidyCreate(); + tidyOptSetBool(tdoc, TidyForceOutput, yes); /* try harder */ + tidyOptSetInt(tdoc, TidyWrapLen, 4096); + tidySetErrorBuffer(tdoc, &tidy_errbuf); + tidyBufInit(&docbuf); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &docbuf); - err = curl_easy_perform(curl); - if(!err) { - err = tidyParseBuffer(tdoc, &docbuf); /* parse the input */ - if(err >= 0) { - err = tidyCleanAndRepair(tdoc); /* fix any problems */ - if(err >= 0) { - err = tidyRunDiagnostics(tdoc); /* load tidy error buffer */ - if(err >= 0) { - dumpNode(tdoc, tidyGetRoot(tdoc), 0); /* walk the tree */ - fprintf(stderr, "%s\n", tidy_errbuf.bp); /* show errors */ - } + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &docbuf); + res = curl_easy_perform(curl); + if(!res) { + res = tidyParseBuffer(tdoc, &docbuf); /* parse the input */ + if(res >= 0) { + res = tidyCleanAndRepair(tdoc); /* fix any problems */ + if(res >= 0) { + res = tidyRunDiagnostics(tdoc); /* load tidy error buffer */ + if(res >= 0) { + dumpNode(tdoc, tidyGetRoot(tdoc), 0); /* walk the tree */ + fprintf(stderr, "%s\n", tidy_errbuf.bp); /* show errors */ } } } - else - fprintf(stderr, "%s\n", curl_errbuf); - - /* clean-up */ - curl_easy_cleanup(curl); - tidyBufFree(&docbuf); - tidyBufFree(&tidy_errbuf); - tidyRelease(tdoc); - return err; - } else - printf("usage: %s \n", argv[0]); + fprintf(stderr, "%s\n", curl_errbuf); - return 0; + /* clean-up */ + curl_easy_cleanup(curl); + curl_global_cleanup(); + tidyBufFree(&docbuf); + tidyBufFree(&tidy_errbuf); + tidyRelease(tdoc); + return (int)res; } diff --git a/docs/examples/htmltitle.cpp b/docs/examples/htmltitle.cpp index 8d75f588fc1a..e4979ee859d3 100644 --- a/docs/examples/htmltitle.cpp +++ b/docs/examples/htmltitle.cpp @@ -263,7 +263,7 @@ static void parseHtml(const std::string &html, int main(int argc, char *argv[]) { CURL *conn = NULL; - CURLcode code; + CURLcode res; std::string title; // Ensure one argument is given @@ -273,21 +273,24 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - curl_global_init(CURL_GLOBAL_DEFAULT); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; // Initialize CURL connection if(!init(conn, argv[1])) { fprintf(stderr, "Connection initialization failed\n"); + curl_global_cleanup(); return EXIT_FAILURE; } // Retrieve content for the URL - code = curl_easy_perform(conn); + res = curl_easy_perform(conn); curl_easy_cleanup(conn); - if(code != CURLE_OK) { + if(res != CURLE_OK) { fprintf(stderr, "Failed to get '%s' [%s]\n", argv[1], errorBuffer); return EXIT_FAILURE; } @@ -298,5 +301,5 @@ int main(int argc, char *argv[]) // Display the extracted title printf("Title: %s\n", title.c_str()); - return EXIT_SUCCESS; + return (int)res; } diff --git a/docs/examples/http-options.c b/docs/examples/http-options.c index 586b55f12a51..9520670baeab 100644 --- a/docs/examples/http-options.c +++ b/docs/examples/http-options.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -55,5 +58,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } + curl_global_cleanup(); return 0; } diff --git a/docs/examples/http-post.c b/docs/examples/http-post.c index 901ee1e3f041..fb91822bb8ab 100644 --- a/docs/examples/http-post.c +++ b/docs/examples/http-post.c @@ -34,7 +34,9 @@ int main(void) CURLcode res; /* In Windows, this inits the Winsock stuff */ - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; /* get a curl handle */ curl = curl_easy_init(); @@ -57,5 +59,5 @@ int main(void) curl_easy_cleanup(curl); } curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/http2-download.c b/docs/examples/http2-download.c index a524cac27f32..634323466762 100644 --- a/docs/examples/http2-download.c +++ b/docs/examples/http2-download.c @@ -190,11 +190,13 @@ static int setup(struct transfer *t, int num) */ int main(int argc, char **argv) { + CURLcode res; struct transfer trans[NUM_HANDLES]; CURLM *multi_handle; int i; int still_running = 0; /* keep number of running handles */ int num_transfers; + if(argc > 1) { /* if given a number, do that many transfers */ num_transfers = atoi(argv[1]); @@ -204,12 +206,18 @@ int main(int argc, char **argv) else num_transfers = 3; /* suitable default */ + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + /* init a multi stack */ multi_handle = curl_multi_init(); for(i = 0; i < num_transfers; i++) { - if(setup(&trans[i], i)) + if(setup(&trans[i], i)) { + curl_global_cleanup(); return 1; + } /* add the individual transfer */ curl_multi_add_handle(multi_handle, trans[i].easy); diff --git a/docs/examples/http2-pushinmemory.c b/docs/examples/http2-pushinmemory.c index 873883ca504d..3e2b4af1c2a1 100644 --- a/docs/examples/http2-pushinmemory.c +++ b/docs/examples/http2-pushinmemory.c @@ -130,6 +130,10 @@ int main(void) int i; struct CURLMsg *m; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + /* init a multi stack */ multi = curl_multi_init(); @@ -155,7 +159,6 @@ int main(void) if(mcode) break; - /* * When doing server push, libcurl itself created and added one or more * easy handles but *we* need to clean them up when they are done. @@ -173,8 +176,8 @@ int main(void) } - curl_multi_cleanup(multi); + curl_global_cleanup(); /* 'pushindex' is now the number of received transfers */ for(i = 0; i < pushindex; i++) { diff --git a/docs/examples/http2-serverpush.c b/docs/examples/http2-serverpush.c index cea54e3af1a5..0d0e991776d9 100644 --- a/docs/examples/http2-serverpush.c +++ b/docs/examples/http2-serverpush.c @@ -212,6 +212,7 @@ static int server_push_callback(CURL *parent, */ int main(int argc, char *argv[]) { + CURLcode res; CURL *easy; CURLM *multi_handle; int transfers = 1; /* we start with one */ @@ -221,6 +222,10 @@ int main(int argc, char *argv[]) if(argc == 2) url = argv[1]; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + /* init a multi stack */ multi_handle = curl_multi_init(); @@ -229,6 +234,7 @@ int main(int argc, char *argv[]) /* set options */ if(setup(easy, url)) { fprintf(stderr, "failed\n"); + curl_global_cleanup(); return 1; } @@ -270,7 +276,7 @@ int main(int argc, char *argv[]) } while(transfers); /* as long as we have transfers going */ curl_multi_cleanup(multi_handle); - + curl_global_cleanup(); return 0; } diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index a22161d76dd2..9cc3c5652cbc 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -292,6 +292,7 @@ static int setup(struct input *i, int num, const char *upload) */ int main(int argc, char **argv) { + CURLcode res; struct input trans[NUM_HANDLES]; CURLM *multi_handle; int i; @@ -313,12 +314,18 @@ int main(int argc, char **argv) else num_transfers = 3; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + /* init a multi stack */ multi_handle = curl_multi_init(); for(i = 0; i < num_transfers; i++) { - if(setup(&trans[i], i, filename)) + if(setup(&trans[i], i, filename)) { + curl_global_cleanup(); return 1; + } /* add the individual transfer */ curl_multi_add_handle(multi_handle, trans[i].hnd); @@ -348,5 +355,7 @@ int main(int argc, char **argv) curl_easy_cleanup(trans[i].hnd); } + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/http3-present.c b/docs/examples/http3-present.c index 56ba0f572474..084f265c46a9 100644 --- a/docs/examples/http3-present.c +++ b/docs/examples/http3-present.c @@ -32,7 +32,9 @@ int main(void) { curl_version_info_data *ver; - curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; ver = curl_version_info(CURLVERSION_NOW); if(ver->features & CURL_VERSION_HTTP2) diff --git a/docs/examples/http3.c b/docs/examples/http3.c index 573ea20d2b48..323f6d7d17b6 100644 --- a/docs/examples/http3.c +++ b/docs/examples/http3.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -50,5 +53,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } + curl_global_cleanup(); return 0; } diff --git a/docs/examples/httpcustomheader.c b/docs/examples/httpcustomheader.c index a3881674c1bd..0657313ddf6c 100644 --- a/docs/examples/httpcustomheader.c +++ b/docs/examples/httpcustomheader.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -68,5 +71,6 @@ int main(void) /* free the custom headers */ curl_slist_free_all(chunk); } - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/httpput-postfields.c b/docs/examples/httpput-postfields.c index 5f410837b867..b855f454aec4 100644 --- a/docs/examples/httpput-postfields.c +++ b/docs/examples/httpput-postfields.c @@ -58,7 +58,9 @@ int main(int argc, char **argv) url = argv[1]; /* In Windows, this inits the Winsock stuff */ - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; /* get a curl handle */ curl = curl_easy_init(); @@ -100,5 +102,5 @@ int main(int argc, char **argv) } curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/httpput.c b/docs/examples/httpput.c index 1951cb232e8b..2aef62fc6713 100644 --- a/docs/examples/httpput.c +++ b/docs/examples/httpput.c @@ -101,7 +101,11 @@ int main(int argc, char **argv) } /* In Windows, this inits the Winsock stuff */ - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) { + fclose(hd_src); + return (int)res; + } /* get a curl handle */ curl = curl_easy_init(); @@ -137,5 +141,5 @@ int main(int argc, char **argv) fclose(hd_src); /* close the local file */ curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/https.c b/docs/examples/https.c index c1cba877df61..23729afcaa02 100644 --- a/docs/examples/https.c +++ b/docs/examples/https.c @@ -31,9 +31,10 @@ int main(void) { CURL *curl; - CURLcode res; - curl_global_init(CURL_GLOBAL_DEFAULT); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -79,5 +80,5 @@ int main(void) curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/imap-append.c b/docs/examples/imap-append.c index 1839deac1dd6..e8851ce97717 100644 --- a/docs/examples/imap-append.c +++ b/docs/examples/imap-append.c @@ -87,7 +87,10 @@ static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -126,5 +129,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-authzid.c b/docs/examples/imap-authzid.c index eb615c6f3d5c..b7c2e43f99d9 100644 --- a/docs/examples/imap-authzid.c +++ b/docs/examples/imap-authzid.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -69,5 +72,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-copy.c b/docs/examples/imap-copy.c index a221be0ca8de..8adb8b8c6d80 100644 --- a/docs/examples/imap-copy.c +++ b/docs/examples/imap-copy.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -69,5 +72,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-create.c b/docs/examples/imap-create.c index 6a9b565345a9..51fbe5f1420c 100644 --- a/docs/examples/imap-create.c +++ b/docs/examples/imap-create.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -65,5 +68,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-delete.c b/docs/examples/imap-delete.c index e43ab2e9824f..a7682f7664d3 100644 --- a/docs/examples/imap-delete.c +++ b/docs/examples/imap-delete.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -65,5 +68,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-examine.c b/docs/examples/imap-examine.c index 34217bfa42c1..a46d450d21ab 100644 --- a/docs/examples/imap-examine.c +++ b/docs/examples/imap-examine.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -65,5 +68,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-fetch.c b/docs/examples/imap-fetch.c index 416fe8809684..937d3e05b80e 100644 --- a/docs/examples/imap-fetch.c +++ b/docs/examples/imap-fetch.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -63,5 +66,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-list.c b/docs/examples/imap-list.c index 0253b543e6fa..2d882503d09e 100644 --- a/docs/examples/imap-list.c +++ b/docs/examples/imap-list.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -64,5 +67,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-lsub.c b/docs/examples/imap-lsub.c index cf45a5fc2da8..74472d42ec23 100644 --- a/docs/examples/imap-lsub.c +++ b/docs/examples/imap-lsub.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -66,5 +69,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-multi.c b/docs/examples/imap-multi.c index 42fa7381cd21..e2d5dd4e9cc6 100644 --- a/docs/examples/imap-multi.c +++ b/docs/examples/imap-multi.c @@ -39,44 +39,48 @@ int main(void) { CURL *curl; - CURLM *mcurl; - int still_running = 1; - curl_global_init(CURL_GLOBAL_DEFAULT); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); - if(!curl) - return 1; + if(curl) { + CURLM *mcurl; - mcurl = curl_multi_init(); - if(!mcurl) - return 2; + mcurl = curl_multi_init(); + if(mcurl) { + int still_running = 1; - /* Set username and password */ - curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); - curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); - /* This fetches message 1 from the user's inbox */ - curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com/INBOX/;UID=1"); + /* This fetches message 1 from the user's inbox */ + curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com/" + "INBOX/;UID=1"); - /* Tell the multi stack about our easy handle */ - curl_multi_add_handle(mcurl, curl); + /* Tell the multi stack about our easy handle */ + curl_multi_add_handle(mcurl, curl); - do { - CURLMcode mc = curl_multi_perform(mcurl, &still_running); + do { + CURLMcode mc = curl_multi_perform(mcurl, &still_running); - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(mcurl, NULL, 0, 1000, NULL); + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(mcurl, NULL, 0, 1000, NULL); - if(mc) - break; - } while(still_running); + if(mc) + break; + } while(still_running); + + /* Always cleanup */ + curl_multi_remove_handle(mcurl, curl); + curl_multi_cleanup(mcurl); + } + curl_easy_cleanup(curl); + } - /* Always cleanup */ - curl_multi_remove_handle(mcurl, curl); - curl_multi_cleanup(mcurl); - curl_easy_cleanup(curl); curl_global_cleanup(); return 0; diff --git a/docs/examples/imap-noop.c b/docs/examples/imap-noop.c index 9e5a3da2d527..1d8607590f6f 100644 --- a/docs/examples/imap-noop.c +++ b/docs/examples/imap-noop.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -65,5 +68,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-search.c b/docs/examples/imap-search.c index 141b06f649db..b4e1576b38c6 100644 --- a/docs/examples/imap-search.c +++ b/docs/examples/imap-search.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -69,5 +72,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-ssl.c b/docs/examples/imap-ssl.c index e632c30e86d8..59edd130e526 100644 --- a/docs/examples/imap-ssl.c +++ b/docs/examples/imap-ssl.c @@ -40,7 +40,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -90,5 +93,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-store.c b/docs/examples/imap-store.c index d04a6072cc4e..95d8f0747652 100644 --- a/docs/examples/imap-store.c +++ b/docs/examples/imap-store.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -80,5 +83,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/imap-tls.c b/docs/examples/imap-tls.c index 8fbc96bb55c3..9009174ccf01 100644 --- a/docs/examples/imap-tls.c +++ b/docs/examples/imap-tls.c @@ -40,7 +40,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -90,5 +93,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/interface.c b/docs/examples/interface.c index f1a2016ced5d..0698b6a8e2f2 100644 --- a/docs/examples/interface.c +++ b/docs/examples/interface.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -48,5 +51,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/ipv6.c b/docs/examples/ipv6.c index 1b698705d0cc..1a55d640494f 100644 --- a/docs/examples/ipv6.c +++ b/docs/examples/ipv6.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -44,5 +47,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/keepalive.c b/docs/examples/keepalive.c index e06d7ff37b7b..8d55c7133774 100644 --- a/docs/examples/keepalive.c +++ b/docs/examples/keepalive.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -54,5 +57,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/localport.c b/docs/examples/localport.c index 7e88ce48a7c4..2700457211dd 100644 --- a/docs/examples/localport.c +++ b/docs/examples/localport.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -49,5 +52,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/log_failed_transfers.c b/docs/examples/log_failed_transfers.c index 66e193167712..fe5f02f882c8 100644 --- a/docs/examples/log_failed_transfers.c +++ b/docs/examples/log_failed_transfers.c @@ -207,6 +207,7 @@ static size_t mywrite(char *ptr, size_t size, size_t nmemb, void *userdata) int main(void) { + CURLcode res; unsigned i; int total_failed = 0; char errbuf[CURL_ERROR_SIZE] = { 0, }; @@ -222,9 +223,10 @@ int main(void) transfer[1].bodyfile = "400.txt"; transfer[1].logfile = "400_transfer_log.txt"; - if(curl_global_init(CURL_GLOBAL_DEFAULT)) { + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) { fprintf(stderr, "curl_global_init failed\n"); - return 1; + return (int)res; } /* You could enable global tracing for extra verbosity when verbosity is @@ -334,5 +336,7 @@ int main(void) printf("\n"); } + curl_global_cleanup(); + return total_failed ? 1 : 0; } diff --git a/docs/examples/maxconnects.c b/docs/examples/maxconnects.c index 2e8e5b50a82c..e89f971cf41e 100644 --- a/docs/examples/maxconnects.c +++ b/docs/examples/maxconnects.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -62,5 +65,8 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } + + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/multi-app.c b/docs/examples/multi-app.c index 5bbf580f82ef..8deee683709c 100644 --- a/docs/examples/multi-app.c +++ b/docs/examples/multi-app.c @@ -52,6 +52,10 @@ int main(void) CURLMsg *msg; /* for picking up messages with the transfer status */ int msgs_left; /* how many messages are left */ + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + /* Allocate one curl handle per transfer */ for(i = 0; i < HANDLECOUNT; i++) handles[i] = curl_easy_init(); @@ -110,6 +114,7 @@ int main(void) } curl_multi_cleanup(multi_handle); + curl_global_cleanup(); return 0; } diff --git a/docs/examples/multi-debugcallback.c b/docs/examples/multi-debugcallback.c index 738732279dbd..a27c238a5791 100644 --- a/docs/examples/multi-debugcallback.c +++ b/docs/examples/multi-debugcallback.c @@ -127,6 +127,10 @@ int main(void) int still_running = 0; /* keep number of running handles */ + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + http_handle = curl_easy_init(); /* set the options (I left out a few, you get the point anyway) */ @@ -157,5 +161,7 @@ int main(void) curl_easy_cleanup(http_handle); + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/multi-double.c b/docs/examples/multi-double.c index 99bd736a9ce3..8c5c5d687ad3 100644 --- a/docs/examples/multi-double.c +++ b/docs/examples/multi-double.c @@ -42,6 +42,10 @@ int main(void) int still_running = 1; /* keep number of running handles */ + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + http_handle = curl_easy_init(); http_handle2 = curl_easy_init(); @@ -89,5 +93,7 @@ int main(void) curl_easy_cleanup(http_handle); curl_easy_cleanup(http_handle2); + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/multi-event.c b/docs/examples/multi-event.c index 23dff05ed2b4..62dc73b33fb6 100644 --- a/docs/examples/multi-event.c +++ b/docs/examples/multi-event.c @@ -219,12 +219,15 @@ static int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, int main(int argc, char **argv) { + CURLcode res; + if(argc <= 1) return 0; - if(curl_global_init(CURL_GLOBAL_ALL)) { + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) { fprintf(stderr, "Could not init curl\n"); - return 1; + return (int)res; } base = event_base_new(); diff --git a/docs/examples/multi-formadd.c b/docs/examples/multi-formadd.c index 58c7e641c4a1..84312ffd160a 100644 --- a/docs/examples/multi-formadd.c +++ b/docs/examples/multi-formadd.c @@ -48,6 +48,10 @@ int main(void) struct curl_slist *headerlist = NULL; static const char buf[] = "Expect:"; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + CURL_IGNORE_DEPRECATION( /* Fill in the file upload field. This makes libcurl load data from the given file name when curl_easy_perform() is called. */ @@ -116,5 +120,6 @@ int main(void) /* free slist */ curl_slist_free_all(headerlist); } + curl_global_cleanup(); return 0; } diff --git a/docs/examples/multi-legacy.c b/docs/examples/multi-legacy.c index b0c37ea8d54a..63c238f2475a 100644 --- a/docs/examples/multi-legacy.c +++ b/docs/examples/multi-legacy.c @@ -58,6 +58,10 @@ int main(void) CURLMsg *msg; /* for picking up messages with the transfer status */ int msgs_left; /* how many messages are left */ + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + /* Allocate one curl handle per transfer */ for(i = 0; i < HANDLECOUNT; i++) handles[i] = curl_easy_init(); @@ -187,5 +191,7 @@ int main(void) for(i = 0; i < HANDLECOUNT; i++) curl_easy_cleanup(handles[i]); + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/multi-post.c b/docs/examples/multi-post.c index 84af48f4bfb5..45416b85114b 100644 --- a/docs/examples/multi-post.c +++ b/docs/examples/multi-post.c @@ -43,6 +43,10 @@ int main(void) struct curl_slist *headerlist = NULL; static const char buf[] = "Expect:"; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); multi_handle = curl_multi_init(); @@ -100,5 +104,6 @@ int main(void) /* free slist */ curl_slist_free_all(headerlist); } + curl_global_cleanup(); return 0; } diff --git a/docs/examples/multi-single.c b/docs/examples/multi-single.c index 0ead96f4871f..3ba26e79db66 100644 --- a/docs/examples/multi-single.c +++ b/docs/examples/multi-single.c @@ -41,7 +41,9 @@ int main(void) CURLM *multi_handle; int still_running = 1; /* keep number of running handles */ - curl_global_init(CURL_GLOBAL_DEFAULT); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; http_handle = curl_easy_init(); diff --git a/docs/examples/multi-uv.c b/docs/examples/multi-uv.c index cc27668d5706..b4f5587c0fb1 100644 --- a/docs/examples/multi-uv.c +++ b/docs/examples/multi-uv.c @@ -226,13 +226,16 @@ static int cb_socket(CURL *easy, curl_socket_t s, int action, int main(int argc, char **argv) { + CURLcode res; struct datauv uv = { 0 }; int running_handles; if(argc <= 1) return 0; - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; uv.loop = uv_default_loop(); uv_timer_init(uv.loop, &uv.timeout); @@ -251,6 +254,7 @@ int main(int argc, char **argv) curl_multi_socket_action(uv.multi, CURL_SOCKET_TIMEOUT, 0, &running_handles); uv_run(uv.loop, UV_RUN_DEFAULT); curl_multi_cleanup(uv.multi); + curl_global_cleanup(); curl_global_cleanup(); diff --git a/docs/examples/multithread.c b/docs/examples/multithread.c index a47758062f5d..5818dfebee49 100644 --- a/docs/examples/multithread.c +++ b/docs/examples/multithread.c @@ -72,11 +72,14 @@ static void *pull_one_url(void *pindex) int main(void) { + CURLcode res; pthread_t tid[NUMT]; int i; /* Must initialize libcurl before any threads are started */ - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; for(i = 0; i < NUMT; i++) { int error = pthread_create(&tid[i], diff --git a/docs/examples/netrc.c b/docs/examples/netrc.c index 42e1b6341e50..148a7e422be9 100644 --- a/docs/examples/netrc.c +++ b/docs/examples/netrc.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -45,5 +48,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/persistent.c b/docs/examples/persistent.c index ffcf343fbf92..7cde055d69b8 100644 --- a/docs/examples/persistent.c +++ b/docs/examples/persistent.c @@ -32,9 +32,10 @@ int main(void) { CURL *curl; - CURLcode res; - curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -68,5 +69,5 @@ int main(void) curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/pop3-authzid.c b/docs/examples/pop3-authzid.c index 3281b322bb9c..8cfe80bca239 100644 --- a/docs/examples/pop3-authzid.c +++ b/docs/examples/pop3-authzid.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -68,5 +71,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/pop3-dele.c b/docs/examples/pop3-dele.c index fe3795c245ae..84592da4f9ff 100644 --- a/docs/examples/pop3-dele.c +++ b/docs/examples/pop3-dele.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -68,5 +71,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/pop3-list.c b/docs/examples/pop3-list.c index 2cd44e41cdb1..05ecc662331a 100644 --- a/docs/examples/pop3-list.c +++ b/docs/examples/pop3-list.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -62,5 +65,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/pop3-multi.c b/docs/examples/pop3-multi.c index 54eb7ecc3243..4d418a7d09a7 100644 --- a/docs/examples/pop3-multi.c +++ b/docs/examples/pop3-multi.c @@ -38,46 +38,50 @@ int main(void) { + CURLcode res; CURL *curl; - CURLM *mcurl; - int still_running = 1; - curl_global_init(CURL_GLOBAL_DEFAULT); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); - if(!curl) - return 1; + if(curl) { + CURLM *mcurl; - mcurl = curl_multi_init(); - if(!mcurl) - return 2; + mcurl = curl_multi_init(); + if(mcurl) { + int still_running = 1; - /* Set username and password */ - curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); - curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); + /* Set username and password */ + curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); + curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); - /* This retrieves message 1 from the user's mailbox */ - curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com/1"); + /* This retrieves message 1 from the user's mailbox */ + curl_easy_setopt(curl, CURLOPT_URL, "pop3://pop.example.com/1"); - /* Tell the multi stack about our easy handle */ - curl_multi_add_handle(mcurl, curl); + /* Tell the multi stack about our easy handle */ + curl_multi_add_handle(mcurl, curl); - do { - CURLMcode mc = curl_multi_perform(mcurl, &still_running); + do { + CURLMcode mc = curl_multi_perform(mcurl, &still_running); - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(mcurl, NULL, 0, 1000, NULL); + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(mcurl, NULL, 0, 1000, NULL); - if(mc) - break; + if(mc) + break; - } while(still_running); + } while(still_running); + + /* Always cleanup */ + curl_multi_remove_handle(mcurl, curl); + curl_multi_cleanup(mcurl); + } + curl_easy_cleanup(curl); + } - /* Always cleanup */ - curl_multi_remove_handle(mcurl, curl); - curl_multi_cleanup(mcurl); - curl_easy_cleanup(curl); curl_global_cleanup(); return 0; diff --git a/docs/examples/pop3-noop.c b/docs/examples/pop3-noop.c index 16181d2875ef..0ab6eb2d14c5 100644 --- a/docs/examples/pop3-noop.c +++ b/docs/examples/pop3-noop.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -68,5 +71,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/pop3-retr.c b/docs/examples/pop3-retr.c index 8e690f972f2b..c89c77e5d649 100644 --- a/docs/examples/pop3-retr.c +++ b/docs/examples/pop3-retr.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -62,5 +65,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/pop3-ssl.c b/docs/examples/pop3-ssl.c index 23dd959ea0af..63a9edca70d6 100644 --- a/docs/examples/pop3-ssl.c +++ b/docs/examples/pop3-ssl.c @@ -40,7 +40,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -89,5 +92,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/pop3-stat.c b/docs/examples/pop3-stat.c index 419859bfa6db..afaf79c9a4db 100644 --- a/docs/examples/pop3-stat.c +++ b/docs/examples/pop3-stat.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -68,5 +71,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/pop3-tls.c b/docs/examples/pop3-tls.c index b2f504c475d8..a4a7208986b4 100644 --- a/docs/examples/pop3-tls.c +++ b/docs/examples/pop3-tls.c @@ -40,7 +40,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -89,5 +92,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/pop3-top.c b/docs/examples/pop3-top.c index 7ceba881b295..7584503b0c2c 100644 --- a/docs/examples/pop3-top.c +++ b/docs/examples/pop3-top.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -65,5 +68,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/pop3-uidl.c b/docs/examples/pop3-uidl.c index 496e5b08d45e..aec10342311d 100644 --- a/docs/examples/pop3-uidl.c +++ b/docs/examples/pop3-uidl.c @@ -39,7 +39,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -65,5 +68,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/post-callback.c b/docs/examples/post-callback.c index fa0c575e6578..7c5a87e9acf7 100644 --- a/docs/examples/post-callback.c +++ b/docs/examples/post-callback.c @@ -79,7 +79,7 @@ int main(void) if(res != CURLE_OK) { fprintf(stderr, "curl_global_init() failed: %s\n", curl_easy_strerror(res)); - return 1; + return (int)res; } /* get a curl handle */ diff --git a/docs/examples/postinmemory.c b/docs/examples/postinmemory.c index cbdc77f75c72..2a8f2b6dd0c8 100644 --- a/docs/examples/postinmemory.c +++ b/docs/examples/postinmemory.c @@ -63,10 +63,13 @@ int main(void) struct MemoryStruct chunk; static const char *postthis = "Field=1&Field=2&Field=3"; + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + chunk.memory = malloc(1); /* grown as needed by realloc above */ chunk.size = 0; /* no data at this point */ - curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.org/"); diff --git a/docs/examples/postit2-formadd.c b/docs/examples/postit2-formadd.c index 88fb92475032..81f8bfd27c11 100644 --- a/docs/examples/postit2-formadd.c +++ b/docs/examples/postit2-formadd.c @@ -57,7 +57,9 @@ int main(int argc, char *argv[]) struct curl_slist *headerlist = NULL; static const char buf[] = "Expect:"; - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; CURL_IGNORE_DEPRECATION( /* Fill in the file upload field */ diff --git a/docs/examples/postit2.c b/docs/examples/postit2.c index d16d3fccf64e..c42ea812c118 100644 --- a/docs/examples/postit2.c +++ b/docs/examples/postit2.c @@ -53,7 +53,9 @@ int main(int argc, char *argv[]) struct curl_slist *headerlist = NULL; static const char buf[] = "Expect:"; - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { diff --git a/docs/examples/progressfunc.c b/docs/examples/progressfunc.c index e164f03ca5c5..012fd1e6aee1 100644 --- a/docs/examples/progressfunc.c +++ b/docs/examples/progressfunc.c @@ -70,9 +70,12 @@ static int xferinfo(void *p, int main(void) { CURL *curl; - CURLcode res = CURLE_OK; struct myprogress prog; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { prog.lastruntime = 0; @@ -93,5 +96,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } + curl_global_cleanup(); return (int)res; } diff --git a/docs/examples/protofeats.c b/docs/examples/protofeats.c index 3e762218ae24..fef4a3798d79 100644 --- a/docs/examples/protofeats.c +++ b/docs/examples/protofeats.c @@ -37,7 +37,9 @@ int main(void) curl_version_info_data *ver; const char *const *ptr; - curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; ver = curl_version_info(CURLVERSION_NOW); printf("Protocols:\n"); diff --git a/docs/examples/range.c b/docs/examples/range.c index c8229fca4d43..ec85ed878dc3 100644 --- a/docs/examples/range.c +++ b/docs/examples/range.c @@ -30,7 +30,10 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -41,5 +44,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/resolve.c b/docs/examples/resolve.c index 6514e93d8d3c..4ccc3ff1d815 100644 --- a/docs/examples/resolve.c +++ b/docs/examples/resolve.c @@ -32,7 +32,6 @@ int main(void) { CURL *curl; - CURLcode res = CURLE_OK; /* Each single name resolve string should be written using the format HOST:PORT:ADDRESS where HOST is the name libcurl tries to resolve, PORT @@ -42,6 +41,10 @@ int main(void) struct curl_slist *host = curl_slist_append(NULL, "example.com:443:127.0.0.1"); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_RESOLVE, host); @@ -53,6 +56,7 @@ int main(void) } curl_slist_free_all(host); + curl_global_cleanup(); return (int)res; } diff --git a/docs/examples/rtsp-options.c b/docs/examples/rtsp-options.c index d1ddbf01ff24..50d5e2f27ee0 100644 --- a/docs/examples/rtsp-options.c +++ b/docs/examples/rtsp-options.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -51,5 +54,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } + curl_global_cleanup(); return 0; } diff --git a/docs/examples/sendrecv.c b/docs/examples/sendrecv.c index 8cbb5b0722fc..71faeb4ad31e 100644 --- a/docs/examples/sendrecv.c +++ b/docs/examples/sendrecv.c @@ -83,6 +83,10 @@ int main(void) const char *request = "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"; size_t request_len = strlen(request); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + /* A general note of caution here: if you are using curl_easy_recv() or curl_easy_send() to implement HTTP or _any_ other protocol libcurl supports "natively", you are doing it wrong and you should stop. @@ -93,7 +97,6 @@ int main(void) curl = curl_easy_init(); if(curl) { - CURLcode res; curl_socket_t sockfd; size_t nsent_total = 0; @@ -175,5 +178,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } + curl_global_cleanup(); return 0; } diff --git a/docs/examples/sepheaders.c b/docs/examples/sepheaders.c index 097183f82169..cea07fd56698 100644 --- a/docs/examples/sepheaders.c +++ b/docs/examples/sepheaders.c @@ -38,60 +38,65 @@ static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) int main(void) { - CURLcode res; CURL *curl_handle; - static const char *headerfilename = "head.out"; - FILE *headerfile; - static const char *bodyfilename = "body.out"; - FILE *bodyfile; - curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; /* init the curl session */ curl_handle = curl_easy_init(); + if(curl_handle) { + static const char *headerfilename = "head.out"; + FILE *headerfile; + static const char *bodyfilename = "body.out"; + FILE *bodyfile; + + /* set URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, "https://example.com"); + + /* no progress meter please */ + curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); + + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); + + /* open the header file */ + headerfile = fopen(headerfilename, "wb"); + if(!headerfile) { + curl_easy_cleanup(curl_handle); + curl_global_cleanup(); + return -1; + } + + /* open the body file */ + bodyfile = fopen(bodyfilename, "wb"); + if(!bodyfile) { + curl_easy_cleanup(curl_handle); + fclose(headerfile); + curl_global_cleanup(); + return -1; + } + + /* we want the headers be written to this file handle */ + curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, headerfile); + + /* we want the body be written to this file handle instead of stdout */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, bodyfile); + + /* get it! */ + res = curl_easy_perform(curl_handle); + + /* close the header file */ + fclose(headerfile); - /* set URL to get */ - curl_easy_setopt(curl_handle, CURLOPT_URL, "https://example.com"); - - /* no progress meter please */ - curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); - - /* send all data to this function */ - curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); + /* close the body file */ + fclose(bodyfile); - /* open the header file */ - headerfile = fopen(headerfilename, "wb"); - if(!headerfile) { + /* cleanup curl stuff */ curl_easy_cleanup(curl_handle); - return -1; - } - - /* open the body file */ - bodyfile = fopen(bodyfilename, "wb"); - if(!bodyfile) { - curl_easy_cleanup(curl_handle); - fclose(headerfile); - return -1; } - /* we want the headers be written to this file handle */ - curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, headerfile); - - /* we want the body be written to this file handle instead of stdout */ - curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, bodyfile); - - /* get it! */ - res = curl_easy_perform(curl_handle); - - /* close the header file */ - fclose(headerfile); - - /* close the body file */ - fclose(bodyfile); - - /* cleanup curl stuff */ - curl_easy_cleanup(curl_handle); - curl_global_cleanup(); return (int)res; diff --git a/docs/examples/sessioninfo.c b/docs/examples/sessioninfo.c index bbdcfe8d2319..c7ea52ccc2e8 100644 --- a/docs/examples/sessioninfo.c +++ b/docs/examples/sessioninfo.c @@ -96,9 +96,9 @@ static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) int main(void) { - CURLcode res = CURLE_OK; - - curl_global_init(CURL_GLOBAL_DEFAULT); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { diff --git a/docs/examples/sftpget.c b/docs/examples/sftpget.c index 4d33939a40bf..36653c5b828c 100644 --- a/docs/examples/sftpget.c +++ b/docs/examples/sftpget.c @@ -62,13 +62,14 @@ static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, int main(void) { CURL *curl; - CURLcode res; struct FtpFile ftpfile = { "yourfile.bin", /* name to store the file as if successful */ NULL }; - curl_global_init(CURL_GLOBAL_DEFAULT); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -108,5 +109,5 @@ int main(void) curl_global_cleanup(); - return 0; + return (int)res; } diff --git a/docs/examples/sftpuploadresume.c b/docs/examples/sftpuploadresume.c index f1f7b0c275a3..4bb0f3e48ebb 100644 --- a/docs/examples/sftpuploadresume.c +++ b/docs/examples/sftpuploadresume.c @@ -125,7 +125,10 @@ int main(void) const char *filename = "filename"; CURL *curlhandle = NULL; - curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curlhandle = curl_easy_init(); if(!sftpResumeUpload(curlhandle, remote, filename)) { diff --git a/docs/examples/shared-connection-cache.c b/docs/examples/shared-connection-cache.c index dc6805a9f19e..a8549d776668 100644 --- a/docs/examples/shared-connection-cache.c +++ b/docs/examples/shared-connection-cache.c @@ -51,6 +51,10 @@ int main(void) CURLSH *share; int i; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + share = curl_share_init(); curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); @@ -63,8 +67,6 @@ int main(void) for(i = 0; i < 3; i++) { CURL *curl = curl_easy_init(); if(curl) { - CURLcode res; - curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/"); /* use the share object */ @@ -83,5 +85,6 @@ int main(void) } curl_share_cleanup(share); - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/simple.c b/docs/examples/simple.c index 53c8e4754f3d..29ed14313eda 100644 --- a/docs/examples/simple.c +++ b/docs/examples/simple.c @@ -31,7 +31,10 @@ int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -49,5 +52,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } + curl_global_cleanup(); return 0; } diff --git a/docs/examples/simplepost.c b/docs/examples/simplepost.c index 7ced982fe010..b1175ba924a4 100644 --- a/docs/examples/simplepost.c +++ b/docs/examples/simplepost.c @@ -31,10 +31,13 @@ int main(void) { + static const char *postthis = "moo mooo moo moo"; + CURL *curl; - CURLcode res; - static const char *postthis = "moo mooo moo moo"; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -54,5 +57,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/simplessl.c b/docs/examples/simplessl.c index 220dc62bcd1b..5da79a79a068 100644 --- a/docs/examples/simplessl.c +++ b/docs/examples/simplessl.c @@ -77,7 +77,11 @@ int main(void) if(!headerfile) return 1; - curl_global_init(CURL_GLOBAL_DEFAULT); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) { + fclose(headerfile); + return (int)res; + } curl = curl_easy_init(); if(curl) { diff --git a/docs/examples/smooth-gtk-thread.c b/docs/examples/smooth-gtk-thread.c index 3b615cb344c3..29d134db47b1 100644 --- a/docs/examples/smooth-gtk-thread.c +++ b/docs/examples/smooth-gtk-thread.c @@ -169,7 +169,9 @@ int main(int argc, char **argv) GtkWidget *top_window, *outside_frame, *inside_frame, *progress_bar; /* Must initialize libcurl before any threads are started */ - curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; /* Init thread */ g_thread_init(NULL); diff --git a/docs/examples/smtp-authzid.c b/docs/examples/smtp-authzid.c index daaeab16943c..addc17691e0f 100644 --- a/docs/examples/smtp-authzid.c +++ b/docs/examples/smtp-authzid.c @@ -95,10 +95,13 @@ static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) int main(void) { CURL *curl; - CURLcode res = CURLE_OK; struct curl_slist *recipients = NULL; struct upload_status upload_ctx = { 0 }; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { /* This is the URL for your mailserver. In this example we connect to the @@ -158,5 +161,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/smtp-expn.c b/docs/examples/smtp-expn.c index 202d1d089fa8..baec49be6906 100644 --- a/docs/examples/smtp-expn.c +++ b/docs/examples/smtp-expn.c @@ -42,9 +42,12 @@ int main(void) { CURL *curl; - CURLcode res; struct curl_slist *recipients = NULL; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { /* This is the URL for your mailserver */ @@ -77,5 +80,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/smtp-mail.c b/docs/examples/smtp-mail.c index 29918de7ff93..6583fc47099f 100644 --- a/docs/examples/smtp-mail.c +++ b/docs/examples/smtp-mail.c @@ -92,10 +92,13 @@ static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) int main(void) { CURL *curl; - CURLcode res = CURLE_OK; struct curl_slist *recipients = NULL; struct upload_status upload_ctx = { 0 }; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { /* This is the URL for your mailserver */ @@ -146,5 +149,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/smtp-mime.c b/docs/examples/smtp-mime.c index 7a2a9c618b03..d26021ef3407 100644 --- a/docs/examples/smtp-mime.c +++ b/docs/examples/smtp-mime.c @@ -71,7 +71,10 @@ static const char inline_html[] = int main(void) { CURL *curl; - CURLcode res = CURLE_OK; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -164,5 +167,7 @@ int main(void) curl_mime_free(mime); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/smtp-multi.c b/docs/examples/smtp-multi.c index 8837c57fd87f..f7619465ee17 100644 --- a/docs/examples/smtp-multi.c +++ b/docs/examples/smtp-multi.c @@ -85,68 +85,72 @@ static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) int main(void) { CURL *curl; - CURLM *mcurl; - int still_running = 1; - struct curl_slist *recipients = NULL; - struct upload_status upload_ctx = { 0 }; - curl_global_init(CURL_GLOBAL_DEFAULT); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); - if(!curl) - return 1; - - mcurl = curl_multi_init(); - if(!mcurl) - return 2; - - /* This is the URL for your mailserver */ - curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); - - /* Note that this option is not strictly required, omitting it results in - * libcurl sending the MAIL FROM command with empty sender data. All - * autoresponses should have an empty reverse-path, and should be directed - * to the address in the reverse-path which triggered them. Otherwise, they - * could cause an endless loop. See RFC 5321 Section 4.5.5 for more details. - */ - curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_MAIL); - - /* Add two recipients, in this particular case they correspond to the - * To: and Cc: addressees in the header, but they could be any kind of - * recipient. */ - recipients = curl_slist_append(recipients, TO_MAIL); - recipients = curl_slist_append(recipients, CC_MAIL); - curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); - - /* We are using a callback function to specify the payload (the headers and - * body of the message). You could just use the CURLOPT_READDATA option to - * specify a FILE pointer to read from. */ - curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); - curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); - curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); - - /* Tell the multi stack about our easy handle */ - curl_multi_add_handle(mcurl, curl); - - do { - CURLMcode mc = curl_multi_perform(mcurl, &still_running); - - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(mcurl, NULL, 0, 1000, NULL); - - if(mc) - break; - - } while(still_running); - - /* Free the list of recipients */ - curl_slist_free_all(recipients); - - /* Always cleanup */ - curl_multi_remove_handle(mcurl, curl); - curl_multi_cleanup(mcurl); - curl_easy_cleanup(curl); + if(curl) { + CURLM *mcurl; + + mcurl = curl_multi_init(); + if(mcurl) { + int still_running = 1; + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx = { 0 }; + + /* This is the URL for your mailserver */ + curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); + + /* Note that this option is not strictly required, omitting it results + * in libcurl sending the MAIL FROM command with empty sender data. All + * autoresponses should have an empty reverse-path, and should be + * directed to the address in the reverse-path which triggered them. + * Otherwise, they could cause an endless loop. See RFC 5321 Section + * 4.5.5 for more details. + */ + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_MAIL); + + /* Add two recipients, in this particular case they correspond to the + * To: and Cc: addressees in the header, but they could be any kind of + * recipient. */ + recipients = curl_slist_append(recipients, TO_MAIL); + recipients = curl_slist_append(recipients, CC_MAIL); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + /* We are using a callback function to specify the payload (the headers + * and body of the message). You could just use the CURLOPT_READDATA + * option to specify a FILE pointer to read from. */ + curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + /* Tell the multi stack about our easy handle */ + curl_multi_add_handle(mcurl, curl); + + do { + CURLMcode mc = curl_multi_perform(mcurl, &still_running); + + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(mcurl, NULL, 0, 1000, NULL); + + if(mc) + break; + + } while(still_running); + + /* Free the list of recipients */ + curl_slist_free_all(recipients); + + /* Always cleanup */ + curl_multi_remove_handle(mcurl, curl); + curl_multi_cleanup(mcurl); + } + curl_easy_cleanup(curl); + } + curl_global_cleanup(); return 0; diff --git a/docs/examples/smtp-ssl.c b/docs/examples/smtp-ssl.c index c88b4fe7cab0..f952441c9c6a 100644 --- a/docs/examples/smtp-ssl.c +++ b/docs/examples/smtp-ssl.c @@ -89,10 +89,13 @@ static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) int main(void) { CURL *curl; - CURLcode res = CURLE_OK; struct curl_slist *recipients = NULL; struct upload_status upload_ctx = { 0 }; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { /* Set username and password */ @@ -166,5 +169,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/smtp-tls.c b/docs/examples/smtp-tls.c index 34a00bd54835..3eaea9d879fc 100644 --- a/docs/examples/smtp-tls.c +++ b/docs/examples/smtp-tls.c @@ -89,10 +89,13 @@ static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) int main(void) { CURL *curl; - CURLcode res = CURLE_OK; struct curl_slist *recipients = NULL; struct upload_status upload_ctx = { 0 }; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { /* Set username and password */ @@ -169,5 +172,7 @@ int main(void) curl_easy_cleanup(curl); } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/smtp-vrfy.c b/docs/examples/smtp-vrfy.c index 0135efef2df0..76dd8069adfa 100644 --- a/docs/examples/smtp-vrfy.c +++ b/docs/examples/smtp-vrfy.c @@ -45,9 +45,12 @@ int main(void) { CURL *curl; - CURLcode res; struct curl_slist *recipients = NULL; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { /* This is the URL for your mailserver */ @@ -77,5 +80,7 @@ int main(void) curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + + return (int)res; } diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c index d5f5a5bfde1a..da2c7ea0f362 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -245,6 +245,7 @@ static int conf_init(struct conf *conf) int main(int argc, char *argv[]) { + CURLcode res; CURL *curl; struct conf conf[1]; int RetValue; @@ -285,7 +286,10 @@ int main(int argc, char *argv[]) snprintf(conf->timeserver, MAX_STRING, "%s", DefaultTimeServer[0]); /* Init CURL before usage */ - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + curl = curl_easy_init(); if(curl) { struct tm *lt; diff --git a/docs/examples/threaded-ssl.c b/docs/examples/threaded-ssl.c index fb60b7f16050..7f09a76fc187 100644 --- a/docs/examples/threaded-ssl.c +++ b/docs/examples/threaded-ssl.c @@ -72,13 +72,16 @@ static void *pull_one_url(void *pindex) int main(int argc, char **argv) { + CURLcode res; pthread_t tid[NUMT]; int i; (void)argc; (void)argv; /* Must initialize libcurl before any threads are started */ - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; for(i = 0; i < NUMT; i++) { int error = pthread_create(&tid[i], diff --git a/docs/examples/unixsocket.c b/docs/examples/unixsocket.c index 63acd4b6a2e0..738ffc2c972f 100644 --- a/docs/examples/unixsocket.c +++ b/docs/examples/unixsocket.c @@ -41,7 +41,10 @@ int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -63,5 +66,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/url2file.c b/docs/examples/url2file.c index c55d2a77c792..2e8e225fce90 100644 --- a/docs/examples/url2file.c +++ b/docs/examples/url2file.c @@ -38,8 +38,7 @@ static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) int main(int argc, char *argv[]) { - CURLcode res = CURLE_OK; - + CURLcode res; CURL *curl_handle; static const char *pagefilename = "page.out"; FILE *pagefile; @@ -49,7 +48,11 @@ int main(int argc, char *argv[]) return 1; } - curl_global_init(CURL_GLOBAL_ALL); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) { + fprintf(stderr, "Could not init curl\n"); + return (int)res; + } /* init the curl session */ curl_handle = curl_easy_init(); diff --git a/docs/examples/urlapi.c b/docs/examples/urlapi.c index 2ed78eb11fc6..8953146e4dad 100644 --- a/docs/examples/urlapi.c +++ b/docs/examples/urlapi.c @@ -35,11 +35,14 @@ int main(void) { CURL *curl; - CURLcode res; CURLU *urlp; CURLUcode uc; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + /* get a curl handle */ curl = curl_easy_init(); @@ -73,5 +76,6 @@ int main(void) cleanup: curl_url_cleanup(urlp); curl_easy_cleanup(curl); - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/usercertinmem.c b/docs/examples/usercertinmem.c index 2a3c2b000649..d95e2a1cddd1 100644 --- a/docs/examples/usercertinmem.c +++ b/docs/examples/usercertinmem.c @@ -157,7 +157,10 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer) int main(void) { CURL *ch; - CURLcode rv; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl_global_init(CURL_GLOBAL_ALL); ch = curl_easy_init(); @@ -180,8 +183,8 @@ int main(void) curl_easy_setopt(ch, CURLOPT_SSLKEYTYPE, "PEM"); /* first try: retrieve page without user certificate and key -> fails */ - rv = curl_easy_perform(ch); - if(rv == CURLE_OK) + res = curl_easy_perform(ch); + if(res == CURLE_OK) printf("*** transfer succeeded ***\n"); else printf("*** transfer failed ***\n"); @@ -191,13 +194,13 @@ int main(void) * "modifications" to the SSL CONTEXT just before link init */ curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); - rv = curl_easy_perform(ch); - if(rv == CURLE_OK) + res = curl_easy_perform(ch); + if(res == CURLE_OK) printf("*** transfer succeeded ***\n"); else printf("*** transfer failed ***\n"); curl_easy_cleanup(ch); curl_global_cleanup(); - return (int)rv; + return (int)res; } diff --git a/docs/examples/websocket-cb.c b/docs/examples/websocket-cb.c index 09d6c647dd19..aa81d89ab126 100644 --- a/docs/examples/websocket-cb.c +++ b/docs/examples/websocket-cb.c @@ -44,7 +44,10 @@ static size_t writecb(char *b, size_t size, size_t nitems, void *p) int main(void) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); if(curl) { @@ -64,5 +67,6 @@ int main(void) /* always cleanup */ curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/websocket-updown.c b/docs/examples/websocket-updown.c index 0257c6077ed6..f95c151cacd1 100644 --- a/docs/examples/websocket-updown.c +++ b/docs/examples/websocket-updown.c @@ -87,39 +87,42 @@ int main(int argc, const char *argv[]) { CURL *easy; struct read_ctx rctx; - CURLcode res; const char *payload = "Hello, friend!"; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + memset(&rctx, 0, sizeof(rctx)); easy = curl_easy_init(); - if(!easy) - return 1; - - if(argc == 2) - curl_easy_setopt(easy, CURLOPT_URL, argv[1]); - else - curl_easy_setopt(easy, CURLOPT_URL, "wss://example.com"); + if(easy) { + if(argc == 2) + curl_easy_setopt(easy, CURLOPT_URL, argv[1]); + else + curl_easy_setopt(easy, CURLOPT_URL, "wss://example.com"); - curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, writecb); - curl_easy_setopt(easy, CURLOPT_WRITEDATA, easy); - curl_easy_setopt(easy, CURLOPT_READFUNCTION, readcb); - /* tell curl that we want to send the payload */ - rctx.easy = easy; - rctx.blen = strlen(payload); - memcpy(rctx.buf, payload, rctx.blen); - curl_easy_setopt(easy, CURLOPT_READDATA, &rctx); - curl_easy_setopt(easy, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, writecb); + curl_easy_setopt(easy, CURLOPT_WRITEDATA, easy); + curl_easy_setopt(easy, CURLOPT_READFUNCTION, readcb); + /* tell curl that we want to send the payload */ + rctx.easy = easy; + rctx.blen = strlen(payload); + memcpy(rctx.buf, payload, rctx.blen); + curl_easy_setopt(easy, CURLOPT_READDATA, &rctx); + curl_easy_setopt(easy, CURLOPT_UPLOAD, 1L); - /* Perform the request, res gets the return code */ - res = curl_easy_perform(easy); - /* Check for errors */ - if(res != CURLE_OK) - fprintf(stderr, "curl_easy_perform() failed: %s\n", - curl_easy_strerror(res)); + /* Perform the request, res gets the return code */ + res = curl_easy_perform(easy); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); - /* always cleanup */ - curl_easy_cleanup(easy); - return 0; + /* always cleanup */ + curl_easy_cleanup(easy); + } + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/websocket.c b/docs/examples/websocket.c index be676839f7c5..be6cff64a2d7 100644 --- a/docs/examples/websocket.c +++ b/docs/examples/websocket.c @@ -138,31 +138,34 @@ static CURLcode websocket(CURL *curl) int main(int argc, const char *argv[]) { CURL *curl; - CURLcode res; + + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; curl = curl_easy_init(); - if(!curl) { - return 1; /* memory failure */ - } - if(argc == 2) - curl_easy_setopt(curl, CURLOPT_URL, argv[1]); - else - curl_easy_setopt(curl, CURLOPT_URL, "wss://example.com"); + if(curl) { + if(argc == 2) + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + else + curl_easy_setopt(curl, CURLOPT_URL, "wss://example.com"); - curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */ + curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */ - /* Perform the request, res gets the return code */ - res = curl_easy_perform(curl); - /* Check for errors */ - if(res != CURLE_OK) - fprintf(stderr, "curl_easy_perform() failed: %s\n", - curl_easy_strerror(res)); - else { - /* connected and ready */ - res = websocket(curl); - } + /* Perform the request, res gets the return code */ + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + else { + /* connected and ready */ + res = websocket(curl); + } - /* always cleanup */ - curl_easy_cleanup(curl); + /* always cleanup */ + curl_easy_cleanup(curl); + } + curl_global_cleanup(); return (int)res; } diff --git a/docs/examples/xmlstream.c b/docs/examples/xmlstream.c index 91c5387888c0..4f8401be4a91 100644 --- a/docs/examples/xmlstream.c +++ b/docs/examples/xmlstream.c @@ -131,8 +131,11 @@ int main(void) XML_SetElementHandler(parser, startElement, endElement); XML_SetCharacterDataHandler(parser, characterDataHandler); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + /* Initialize a libcurl handle. */ - curl_global_init(CURL_GLOBAL_DEFAULT); curl_handle = curl_easy_init(); curl_easy_setopt(curl_handle, CURLOPT_URL, "https://www.w3schools.com/xml/simple.xml"); @@ -166,5 +169,5 @@ int main(void) curl_easy_cleanup(curl_handle); curl_global_cleanup(); - return 0; + return (int)res; } From 1ea99afdc70e2e198c764ee05b794e505d776010 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 14 Oct 2025 14:39:50 +0200 Subject: [PATCH 439/465] scorecard: add perf support on linux When calling scorecard with --flame to produce a flamegraph, use "perf" on linux platforms to do the measurements. Update the scorecard documentation about it. Closes #19058 --- docs/internals/SCORECARD.md | 19 +++--- tests/http/scorecard.py | 11 +-- tests/http/testenv/curl.py | 133 ++++++++++++++++++++++++++++-------- 3 files changed, 118 insertions(+), 45 deletions(-) diff --git a/docs/internals/SCORECARD.md b/docs/internals/SCORECARD.md index 7839e0b61f65..546959760417 100644 --- a/docs/internals/SCORECARD.md +++ b/docs/internals/SCORECARD.md @@ -59,15 +59,9 @@ If you have configured curl with `--with-test-danted=` for a with arguments `--socks4` or `--socks5` to test performance with a SOCKS proxy involved. (Note: this does not work for HTTP/3) -## dtrace - -With the `--dtrace` option, scorecard produces a dtrace sample of the user stacks in `tests/http/gen/curl/curl.user_stacks`. On many platforms, `dtrace` requires **special permissions**. It is therefore invoked via `sudo` and you should make sure that sudo works for the run without prompting for a password. - -Note: the file is the trace of the last curl invocation by scorecard. Use the parameters to narrow down the runs to the particular case you are interested in. - ## flame graphs -With the excellent [Flame Graph](https://github.com/brendangregg/FlameGraph) by Brendan Gregg, scorecard can turn the `dtrace` samples into an interactive SVG. Set the environment variable `FLAMEGRAPH` to the location of your clone of that project and invoked scorecard with the `--flame` option. Like +With the excellent [Flame Graph](https://github.com/brendangregg/FlameGraph) by Brendan Gregg, scorecard can turn `perf`/`dtrace` samples into an interactive SVG. Either clone the `Flamegraph` repository next to your `curl` project or set the environment variable `FLAMEGRAPH` to the location of your clone. Then run scorecard with the `--flame` option, like ``` curl> FLAMEGRAPH=/Users/sei/projects/FlameGraph python3 tests/http/scorecard.py \ @@ -75,4 +69,13 @@ curl> FLAMEGRAPH=/Users/sei/projects/FlameGraph python3 tests/http/scorecard.py ``` and the SVG of the run is in `tests/http/gen/curl/curl.flamegraph.svg`. You can open that in Firefox and zoom in/out of stacks of interest. -Note: as with `dtrace`, the flame graph is for the last invocation of curl done by scorecard. +The flame graph is about the last run of `curl`. That is why you should add scorecard arguments +that restrict measurements to a single run. + +### Measures/Privileges + +The `--flame` option uses `perf` on linux and `dtrace` on macOS. Since both tools require special +privileges, they are run via the `sudo` command by scorecard. This means you need to issue a +`sudo` recently enough before running scorecard, so no new password check is needed. + +There is no support right now for measurements on other platforms. diff --git a/tests/http/scorecard.py b/tests/http/scorecard.py index 9c5417f1bf23..d987fc586b3f 100644 --- a/tests/http/scorecard.py +++ b/tests/http/scorecard.py @@ -195,7 +195,6 @@ def __init__(self, env: Env, curl_verbose: int, download_parallel: int = 0, server_addr: Optional[str] = None, - with_dtrace: bool = False, with_flame: bool = False, socks_args: Optional[List[str]] = None, limit_rate: Optional[str] = None): @@ -207,7 +206,6 @@ def __init__(self, env: Env, self.server_port = server_port self._silent_curl = not curl_verbose self._download_parallel = download_parallel - self._with_dtrace = with_dtrace self._with_flame = with_flame self._socks_args = socks_args self._limit_rate = limit_rate @@ -220,7 +218,6 @@ def info(self, msg): def mk_curl_client(self): return CurlClient(env=self.env, silent=self._silent_curl, server_addr=self.server_addr, - with_dtrace=self._with_dtrace, with_flame=self._with_flame, socks_args=self._socks_args) @@ -726,7 +723,6 @@ def run_score(args, protocol): verbose=args.verbose, curl_verbose=args.curl_verbose, download_parallel=args.download_parallel, - with_dtrace=args.dtrace, with_flame=args.flame, socks_args=socks_args, limit_rate=args.limit_rate) @@ -754,7 +750,6 @@ def run_score(args, protocol): server_port=server_port, verbose=args.verbose, curl_verbose=args.curl_verbose, download_parallel=args.download_parallel, - with_dtrace=args.dtrace, with_flame=args.flame, socks_args=socks_args, limit_rate=args.limit_rate) @@ -782,7 +777,7 @@ def run_score(args, protocol): server_port=server_port, verbose=args.verbose, curl_verbose=args.curl_verbose, download_parallel=args.download_parallel, - with_dtrace=args.dtrace, + with_flame=args.flame, socks_args=socks_args, limit_rate=args.limit_rate) card.setup_resources(server_docs, downloads) @@ -864,10 +859,8 @@ def main(): help="only start the servers") parser.add_argument("--remote", action='store', type=str, default=None, help="score against the remote server at :") - parser.add_argument("--dtrace", action='store_true', - default = False, help="produce dtrace of curl") parser.add_argument("--flame", action='store_true', - default = False, help="produce a flame graph on curl, implies --dtrace") + default = False, help="produce a flame graph on curl") parser.add_argument("--limit-rate", action='store', type=str, default=None, help="use curl's --limit-rate") diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py index dcff774a63ae..dc885ab8cba9 100644 --- a/tests/http/testenv/curl.py +++ b/tests/http/testenv/curl.py @@ -108,6 +108,42 @@ def __repr__(self): f'stats={self.stats}]' +class PerfProfile: + + def __init__(self, pid: int, run_dir): + self._pid = pid + self._run_dir = run_dir + self._proc = None + self._rc = 0 + self._file = os.path.join(self._run_dir, 'curl.perf_stacks') + + def start(self): + if os.path.exists(self._file): + os.remove(self._file) + args = [ + 'sudo', 'perf', 'record', '-F', '99', '-p', f'{self._pid}', + '-g', '--', 'sleep', '60' + ] + self._proc = subprocess.Popen(args, text=True, cwd=self._run_dir, shell=False) + assert self._proc + + def finish(self): + if self._proc: + self._proc.terminate() + self._rc = self._proc.returncode + with open(self._file, 'w') as cout: + p = subprocess.run([ + 'sudo', 'perf', 'script' + ], stdout=cout, cwd=self._run_dir, shell=False) + rc = p.returncode + if rc != 0: + raise Exception(f'perf returned error {rc}') + + @property + def file(self): + return self._file + + class DTraceProfile: def __init__(self, pid: int, run_dir): @@ -115,7 +151,7 @@ def __init__(self, pid: int, run_dir): self._run_dir = run_dir self._proc = None self._rc = 0 - self._file = os.path.join(self._run_dir, 'curl.user_stacks') + self._file = os.path.join(self._run_dir, 'curl.dtrace_stacks') def start(self): if os.path.exists(self._file): @@ -503,6 +539,7 @@ def __init__(self, env: Env, run_env: Optional[Dict[str, str]] = None, server_addr: Optional[str] = None, with_dtrace: bool = False, + with_perf: bool = False, with_flame: bool = False, socks_args: Optional[List[str]] = None): self.env = env @@ -514,9 +551,21 @@ def __init__(self, env: Env, self._headerfile = f'{self._run_dir}/curl.headers' self._log_path = f'{self._run_dir}/curl.log' self._with_dtrace = with_dtrace + self._with_perf = with_perf self._with_flame = with_flame + self._fg_dir = None if self._with_flame: - self._with_dtrace = True + self._fg_dir = os.path.join(self.env.project_dir, '../FlameGraph') + if 'FLAMEGRAPH' in os.environ: + self._fg_dir = os.environ['FLAMEGRAPH'] + if not os.path.exists(self._fg_dir): + raise Exception(f'FlameGraph checkout not found in {self._fg_dir}, set env variable FLAMEGRAPH') + if sys.platform.startswith('linux'): + self._with_perf = True + elif sys.platform.startswith('darwin'): + self._with_dtrace = True + else: + raise Exception(f'flame graphs unsupported on {sys.platform}') self._socks_args = socks_args self._silent = silent self._run_env = run_env @@ -809,6 +858,7 @@ def _run(self, args, intext='', with_stats: bool = False, exception = None profile = None tcpdump = None + perf = None dtrace = None if with_tcpdump: tcpdump = RunTcpDump(self.env, self._run_dir) @@ -826,7 +876,10 @@ def _run(self, args, intext='', with_stats: bool = False, profile = RunProfile(p.pid, started_at, self._run_dir) if intext is not None and False: p.communicate(input=intext.encode(), timeout=1) - if self._with_dtrace: + if self._with_perf: + perf = PerfProfile(p.pid, self._run_dir) + perf.start() + elif self._with_dtrace: dtrace = DTraceProfile(p.pid, self._run_dir) dtrace.start() ptimeout = 0.0 @@ -860,10 +913,12 @@ def _run(self, args, intext='', with_stats: bool = False, ended_at = datetime.now() if tcpdump: tcpdump.finish() + if perf: + perf.finish() if dtrace: dtrace.finish() - if self._with_flame and dtrace: - self._generate_flame(dtrace, args) + if self._with_flame: + self._generate_flame(args, dtrace=dtrace, perf=perf) coutput = open(self._stdoutfile).readlines() cerrput = open(self._stderrfile).readlines() return ExecResult(args=args, exit_code=exitcode, exception=exception, @@ -1004,37 +1059,59 @@ def fin_response(resp): fin_response(response) return r - def _generate_flame(self, dtrace: DTraceProfile, curl_args: List[str]): - log.info('generating flame graph from dtrace for this run') + def _perf_collapse(self, perf: PerfProfile, file_err): + if not os.path.exists(perf.file): + raise Exception(f'dtrace output file does not exist: {perf.file}') + fg_collapse = os.path.join(self._fg_dir, 'stackcollapse-perf.pl') + if not os.path.exists(fg_collapse): + raise Exception(f'FlameGraph script not found: {fg_collapse}') + stacks_collapsed = f'{perf.file}.collapsed' + log.info(f'collapsing stacks into {stacks_collapsed}') + with open(stacks_collapsed, 'w') as cout, open(file_err, 'w') as cerr: + p = subprocess.run([ + fg_collapse, perf.file + ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False) + rc = p.returncode + if rc != 0: + raise Exception(f'{fg_collapse} returned error {rc}') + return stacks_collapsed + + def _dtrace_collapse(self, dtrace: DTraceProfile, file_err): if not os.path.exists(dtrace.file): raise Exception(f'dtrace output file does not exist: {dtrace.file}') - if 'FLAMEGRAPH' not in os.environ: - raise Exception('Env variable FLAMEGRAPH not set') - fg_dir = os.environ['FLAMEGRAPH'] - if not os.path.exists(fg_dir): - raise Exception(f'FlameGraph directory not found: {fg_dir}') - - fg_collapse = os.path.join(fg_dir, 'stackcollapse.pl') + fg_collapse = os.path.join(self._fg_dir, 'stackcollapse.pl') if not os.path.exists(fg_collapse): raise Exception(f'FlameGraph script not found: {fg_collapse}') - - fg_gen_flame = os.path.join(fg_dir, 'flamegraph.pl') - if not os.path.exists(fg_gen_flame): - raise Exception(f'FlameGraph script not found: {fg_gen_flame}') - - file_collapsed = f'{dtrace.file}.collapsed' - file_svg = os.path.join(self._run_dir, 'curl.flamegraph.svg') - file_err = os.path.join(self._run_dir, 'curl.flamegraph.stderr') - log.info('waiting a sec for dtrace to finish flusheing its buffers') - time.sleep(1) - log.info(f'collapsing stacks into {file_collapsed}') - with open(file_collapsed, 'w') as cout, open(file_err, 'w') as cerr: + stacks_collapsed = f'{dtrace.file}.collapsed' + log.info(f'collapsing stacks into {stacks_collapsed}') + with open(stacks_collapsed, 'w') as cout, open(file_err, 'a') as cerr: p = subprocess.run([ fg_collapse, dtrace.file ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False) rc = p.returncode if rc != 0: raise Exception(f'{fg_collapse} returned error {rc}') + return stacks_collapsed + + def _generate_flame(self, curl_args: List[str], + dtrace: Optional[DTraceProfile] = None, + perf: Optional[PerfProfile] = None): + fg_gen_flame = os.path.join(self._fg_dir, 'flamegraph.pl') + file_svg = os.path.join(self._run_dir, 'curl.flamegraph.svg') + if not os.path.exists(fg_gen_flame): + raise Exception(f'FlameGraph script not found: {fg_gen_flame}') + + log.info('waiting a sec for perf/dtrace to finish flushing') + time.sleep(2) + log.info('generating flame graph for this run') + file_err = os.path.join(self._run_dir, 'curl.flamegraph.stderr') + if perf: + stacks_collapsed = self._perf_collapse(perf, file_err) + elif dtrace: + stacks_collapsed = self._dtrace_collapse(dtrace, file_err) + else: + raise Exception('no stacks measure given') + log.info(f'generating graph into {file_svg}') cmdline = ' '.join(curl_args) if len(cmdline) > 80: @@ -1043,11 +1120,11 @@ def _generate_flame(self, dtrace: DTraceProfile, curl_args: List[str]): else: title = cmdline subtitle = '' - with open(file_svg, 'w') as cout, open(file_err, 'w') as cerr: + with open(file_svg, 'w') as cout, open(file_err, 'a') as cerr: p = subprocess.run([ fg_gen_flame, '--colors', 'green', '--title', title, '--subtitle', subtitle, - file_collapsed + stacks_collapsed ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False) rc = p.returncode if rc != 0: From 61dcb56743e5e4a6a014b6e30b6d61c75355ff17 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 14 Oct 2025 10:49:53 +0200 Subject: [PATCH 440/465] openldap: explain a const removing typecast Closes #19056 --- lib/openldap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/openldap.c b/lib/openldap.c index fb771161d61d..b8afe99529e1 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -468,6 +468,10 @@ static CURLcode oldap_perform_mechs(struct Curl_easy *data) if(!li) return CURLE_FAILED_INIT; + /* Casting away the const for the 3rd parameter that the LDAP API expects as + a non-const char ** is potentially unsafe but we believe the lack of + const in the API was an oversight and that no LDAP implementation + actually modifies the input. */ rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)", (char **)CURL_UNCONST(supportedSASLMechanisms), 0, NULL, NULL, NULL, 0, &li->msgid); From 64ed2ea1968e912439442dd3ad6addd8a2acfb84 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 13 Oct 2025 22:57:01 +0200 Subject: [PATCH 441/465] examples: check more errors, fix cleanups, scope variables Inspired by Joshua's report on examples. Closes #19055 --- docs/examples/10-at-a-time.c | 68 +++++----- docs/examples/anyauthput.c | 7 +- docs/examples/cacertinmem.c | 105 ++++++++-------- docs/examples/chkspeed.c | 93 +++++++------- docs/examples/crawler.c | 93 +++++++------- docs/examples/debug.c | 12 +- docs/examples/ftpgetresp.c | 5 +- docs/examples/ftpupload.c | 4 +- docs/examples/ftpuploadresume.c | 8 +- docs/examples/getinmemory.c | 74 +++++------ docs/examples/ghiper.c | 18 +-- docs/examples/htmltidy.c | 47 +++---- docs/examples/http2-download.c | 14 +-- docs/examples/http2-pushinmemory.c | 9 +- docs/examples/http2-serverpush.c | 12 +- docs/examples/http2-upload.c | 128 ++++++++++--------- docs/examples/multi-app.c | 85 +++++++------ docs/examples/multi-debugcallback.c | 54 ++++---- docs/examples/multi-double.c | 74 ++++++----- docs/examples/multi-event.c | 16 +-- docs/examples/multi-formadd.c | 68 +++++----- docs/examples/multi-legacy.c | 184 ++++++++++++++-------------- docs/examples/multi-post.c | 93 +++++++------- docs/examples/multi-single.c | 47 +++---- docs/examples/multi-uv.c | 27 ++-- docs/examples/multithread.c | 10 +- docs/examples/postinmemory.c | 4 +- docs/examples/postit2.c | 13 +- docs/examples/progressfunc.c | 3 +- docs/examples/sftpuploadresume.c | 14 ++- docs/examples/smooth-gtk-thread.c | 18 +-- docs/examples/smtp-authzid.c | 5 +- docs/examples/smtp-expn.c | 3 +- docs/examples/smtp-mail.c | 5 +- docs/examples/smtp-ssl.c | 5 +- docs/examples/smtp-tls.c | 5 +- docs/examples/smtp-vrfy.c | 3 +- docs/examples/threaded-ssl.c | 18 +-- docs/examples/url2file.c | 47 +++---- docs/examples/urlapi.c | 10 +- docs/examples/usercertinmem.c | 77 ++++++------ docs/examples/xmlstream.c | 84 +++++++------ 42 files changed, 879 insertions(+), 790 deletions(-) diff --git a/docs/examples/10-at-a-time.c b/docs/examples/10-at-a-time.c index 48e0030040c5..87971cbde62f 100644 --- a/docs/examples/10-at-a-time.c +++ b/docs/examples/10-at-a-time.c @@ -104,52 +104,54 @@ static void add_transfer(CURLM *cm, unsigned int i, int *left) int main(void) { CURLM *cm; - CURLMsg *msg; - unsigned int transfers = 0; - int msgs_left = -1; - int left = 0; CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) return (int)res; cm = curl_multi_init(); + if(cm) { + CURLMsg *msg; + unsigned int transfers = 0; + int msgs_left = -1; + int left = 0; - /* Limit the amount of simultaneous connections curl should allow: */ - curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)MAX_PARALLEL); + /* Limit the amount of simultaneous connections curl should allow: */ + curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)MAX_PARALLEL); - for(transfers = 0; transfers < MAX_PARALLEL && transfers < NUM_URLS; - transfers++) - add_transfer(cm, transfers, &left); + for(transfers = 0; transfers < MAX_PARALLEL && transfers < NUM_URLS; + transfers++) + add_transfer(cm, transfers, &left); - do { - int still_alive = 1; - curl_multi_perform(cm, &still_alive); + do { + int still_alive = 1; + curl_multi_perform(cm, &still_alive); - /* !checksrc! disable EQUALSNULL 1 */ - while((msg = curl_multi_info_read(cm, &msgs_left)) != NULL) { - if(msg->msg == CURLMSG_DONE) { - char *url; - CURL *e = msg->easy_handle; - curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url); - fprintf(stderr, "R: %d - %s <%s>\n", - msg->data.result, curl_easy_strerror(msg->data.result), url); - curl_multi_remove_handle(cm, e); - curl_easy_cleanup(e); - left--; + /* !checksrc! disable EQUALSNULL 1 */ + while((msg = curl_multi_info_read(cm, &msgs_left)) != NULL) { + if(msg->msg == CURLMSG_DONE) { + char *url; + CURL *e = msg->easy_handle; + curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url); + fprintf(stderr, "R: %d - %s <%s>\n", + msg->data.result, curl_easy_strerror(msg->data.result), url); + curl_multi_remove_handle(cm, e); + curl_easy_cleanup(e); + left--; + } + else { + fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg); + } + if(transfers < NUM_URLS) + add_transfer(cm, transfers++, &left); } - else { - fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg); - } - if(transfers < NUM_URLS) - add_transfer(cm, transfers++, &left); - } - if(left) - curl_multi_wait(cm, NULL, 0, 1000, NULL); + if(left) + curl_multi_wait(cm, NULL, 0, 1000, NULL); - } while(left); + } while(left); - curl_multi_cleanup(cm); + curl_multi_cleanup(cm); + } curl_global_cleanup(); return EXIT_SUCCESS; diff --git a/docs/examples/anyauthput.c b/docs/examples/anyauthput.c index 81bb1fb9071d..8718ac98bbed 100644 --- a/docs/examples/anyauthput.c +++ b/docs/examples/anyauthput.c @@ -105,10 +105,13 @@ int main(int argc, char **argv) #ifdef UNDER_CE /* !checksrc! disable BANNEDFUNC 1 */ - stat(file, &file_info); + if(stat(file, &file_info) != 0) { #else - fstat(fileno(fp), &file_info); + if(fstat(fileno(fp), &file_info) != 0) { #endif + fclose(fp); + return 1; /* cannot continue */ + } /* In Windows, this inits the Winsock stuff */ res = curl_global_init(CURL_GLOBAL_ALL); diff --git a/docs/examples/cacertinmem.c b/docs/examples/cacertinmem.c index d72dc490018a..5855d872b658 100644 --- a/docs/examples/cacertinmem.c +++ b/docs/examples/cacertinmem.c @@ -116,63 +116,64 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer) int main(void) { CURL *ch; - CURLcode res; - res = curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) return (int)res; ch = curl_easy_init(); - curl_easy_setopt(ch, CURLOPT_VERBOSE, 0L); - curl_easy_setopt(ch, CURLOPT_HEADER, 0L); - curl_easy_setopt(ch, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); - curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, writefunction); - curl_easy_setopt(ch, CURLOPT_WRITEDATA, stdout); - curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, writefunction); - curl_easy_setopt(ch, CURLOPT_HEADERDATA, stderr); - curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM"); - curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 1L); - curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/"); - - /* Turn off the default CA locations, otherwise libcurl loads CA - * certificates from the locations that were detected/specified at - * build-time - */ - curl_easy_setopt(ch, CURLOPT_CAINFO, NULL); - curl_easy_setopt(ch, CURLOPT_CAPATH, NULL); - - /* first try: retrieve page without ca certificates -> should fail - * unless libcurl was built --with-ca-fallback enabled at build-time - */ - res = curl_easy_perform(ch); - if(res == CURLE_OK) - printf("*** transfer succeeded ***\n"); - else - printf("*** transfer failed ***\n"); - - /* use a fresh connection (optional) this option seriously impacts - * performance of multiple transfers but it is necessary order to - * demonstrate this example. recall that the ssl ctx callback is only called - * _before_ an SSL connection is established, therefore it does not affect - * existing verified SSL connections already in the connection cache - * associated with this handle. normally you would set the ssl ctx function - * before making any transfers, and not use this option. - */ - curl_easy_setopt(ch, CURLOPT_FRESH_CONNECT, 1L); - - /* second try: retrieve page using cacerts' certificate -> succeeds to load - * the certificate by installing a function doing the necessary - * "modifications" to the SSL CONTEXT just before link init - */ - curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); - res = curl_easy_perform(ch); - if(res == CURLE_OK) - printf("*** transfer succeeded ***\n"); - else - printf("*** transfer failed ***\n"); - - curl_easy_cleanup(ch); + if(ch) { + curl_easy_setopt(ch, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(ch, CURLOPT_HEADER, 0L); + curl_easy_setopt(ch, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, writefunction); + curl_easy_setopt(ch, CURLOPT_WRITEDATA, stdout); + curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, writefunction); + curl_easy_setopt(ch, CURLOPT_HEADERDATA, stderr); + curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM"); + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 1L); + curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/"); + + /* Turn off the default CA locations, otherwise libcurl loads CA + * certificates from the locations that were detected/specified at + * build-time + */ + curl_easy_setopt(ch, CURLOPT_CAINFO, NULL); + curl_easy_setopt(ch, CURLOPT_CAPATH, NULL); + + /* first try: retrieve page without ca certificates -> should fail + * unless libcurl was built --with-ca-fallback enabled at build-time + */ + res = curl_easy_perform(ch); + if(res == CURLE_OK) + printf("*** transfer succeeded ***\n"); + else + printf("*** transfer failed ***\n"); + + /* use a fresh connection (optional) this option seriously impacts + * performance of multiple transfers but it is necessary order to + * demonstrate this example. recall that the ssl ctx callback is only + * called _before_ an SSL connection is established, therefore it does not + * affect existing verified SSL connections already in the connection cache + * associated with this handle. normally you would set the ssl ctx function + * before making any transfers, and not use this option. + */ + curl_easy_setopt(ch, CURLOPT_FRESH_CONNECT, 1L); + + /* second try: retrieve page using cacerts' certificate -> succeeds to load + * the certificate by installing a function doing the necessary + * "modifications" to the SSL CONTEXT just before link init + */ + curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); + res = curl_easy_perform(ch); + if(res == CURLE_OK) + printf("*** transfer succeeded ***\n"); + else + printf("*** transfer failed ***\n"); + + curl_easy_cleanup(ch); + } curl_global_cleanup(); return (int)res; } diff --git a/docs/examples/chkspeed.c b/docs/examples/chkspeed.c index d4b2abbab819..996db393f584 100644 --- a/docs/examples/chkspeed.c +++ b/docs/examples/chkspeed.c @@ -162,62 +162,67 @@ int main(int argc, char *argv[]) /* init the curl session */ curl_handle = curl_easy_init(); + if(curl_handle) { - /* specify URL to get */ - curl_easy_setopt(curl_handle, CURLOPT_URL, url); + /* specify URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, url); - /* send all data to this function */ - curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteCallback); + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteCallback); - /* some servers do not like requests that are made without a user-agent - field, so we provide one */ - curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, - "libcurl-speedchecker/" CHKSPEED_VERSION); + /* some servers do not like requests that are made without a user-agent + field, so we provide one */ + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, + "libcurl-speedchecker/" CHKSPEED_VERSION); - /* get it! */ - res = curl_easy_perform(curl_handle); + /* get it! */ + res = curl_easy_perform(curl_handle); - if(CURLE_OK == res) { - curl_off_t val; + if(CURLE_OK == res) { + curl_off_t val; - /* check for bytes downloaded */ - res = curl_easy_getinfo(curl_handle, CURLINFO_SIZE_DOWNLOAD_T, &val); - if((CURLE_OK == res) && (val > 0)) - printf("Data downloaded: %lu bytes.\n", (unsigned long)val); - - /* check for total download time */ - res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME_T, &val); - if((CURLE_OK == res) && (val > 0)) - printf("Total download time: %lu.%06lu sec.\n", - (unsigned long)(val / 1000000), (unsigned long)(val % 1000000)); - - /* check for average download speed */ - res = curl_easy_getinfo(curl_handle, CURLINFO_SPEED_DOWNLOAD_T, &val); - if((CURLE_OK == res) && (val > 0)) - printf("Average download speed: %lu kbyte/sec.\n", - (unsigned long)(val / 1024)); + /* check for bytes downloaded */ + res = curl_easy_getinfo(curl_handle, CURLINFO_SIZE_DOWNLOAD_T, &val); + if((CURLE_OK == res) && (val > 0)) + printf("Data downloaded: %lu bytes.\n", (unsigned long)val); - if(prtall) { - /* check for name resolution time */ - res = curl_easy_getinfo(curl_handle, CURLINFO_NAMELOOKUP_TIME_T, &val); + /* check for total download time */ + res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME_T, &val); if((CURLE_OK == res) && (val > 0)) - printf("Name lookup time: %lu.%06lu sec.\n", - (unsigned long)(val / 1000000), (unsigned long)(val % 1000000)); + printf("Total download time: %lu.%06lu sec.\n", + (unsigned long)(val / 1000000), + (unsigned long)(val % 1000000)); - /* check for connect time */ - res = curl_easy_getinfo(curl_handle, CURLINFO_CONNECT_TIME_T, &val); + /* check for average download speed */ + res = curl_easy_getinfo(curl_handle, CURLINFO_SPEED_DOWNLOAD_T, &val); if((CURLE_OK == res) && (val > 0)) - printf("Connect time: %lu.%06lu sec.\n", - (unsigned long)(val / 1000000), (unsigned long)(val % 1000000)); + printf("Average download speed: %lu kbyte/sec.\n", + (unsigned long)(val / 1024)); + + if(prtall) { + /* check for name resolution time */ + res = curl_easy_getinfo(curl_handle, CURLINFO_NAMELOOKUP_TIME_T, &val); + if((CURLE_OK == res) && (val > 0)) + printf("Name lookup time: %lu.%06lu sec.\n", + (unsigned long)(val / 1000000), + (unsigned long)(val % 1000000)); + + /* check for connect time */ + res = curl_easy_getinfo(curl_handle, CURLINFO_CONNECT_TIME_T, &val); + if((CURLE_OK == res) && (val > 0)) + printf("Connect time: %lu.%06lu sec.\n", + (unsigned long)(val / 1000000), + (unsigned long)(val % 1000000)); + } + } + else { + fprintf(stderr, "Error while fetching '%s' : %s\n", + url, curl_easy_strerror(res)); } - } - else { - fprintf(stderr, "Error while fetching '%s' : %s\n", - url, curl_easy_strerror(res)); - } - /* cleanup curl stuff */ - curl_easy_cleanup(curl_handle); + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + } /* we are done with libcurl, so clean it up */ curl_global_cleanup(); diff --git a/docs/examples/crawler.c b/docs/examples/crawler.c index a7ca5fa2fe40..e8dbf244f91e 100644 --- a/docs/examples/crawler.c +++ b/docs/examples/crawler.c @@ -191,67 +191,70 @@ int main(void) signal(SIGINT, sighandler); LIBXML_TEST_VERSION multi_handle = curl_multi_init(); - curl_multi_setopt(multi_handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, max_con); - curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 6L); + if(multi_handle) { + curl_multi_setopt(multi_handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, max_con); + curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 6L); - /* enables http/2 if available */ + /* enables http/2 if available */ #ifdef CURLPIPE_MULTIPLEX - curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); + curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); #endif - /* sets html start page */ - curl_multi_add_handle(multi_handle, make_handle(start_page)); + /* sets html start page */ + curl_multi_add_handle(multi_handle, make_handle(start_page)); - pending = 0; - complete = 0; - still_running = 1; - while(still_running && !pending_interrupt) { - int numfds; - CURLMsg *m; + pending = 0; + complete = 0; + still_running = 1; + while(still_running && !pending_interrupt) { + int numfds; + CURLMsg *m; - curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds); - curl_multi_perform(multi_handle, &still_running); + curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds); + curl_multi_perform(multi_handle, &still_running); - /* See how the transfers went */ - m = NULL; - while((m = curl_multi_info_read(multi_handle, &msgs_left))) { - if(m->msg == CURLMSG_DONE) { - CURL *handle = m->easy_handle; - char *url; - struct memory *mem; - curl_easy_getinfo(handle, CURLINFO_PRIVATE, &mem); - curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &url); - if(m->data.result == CURLE_OK) { - long res_status; - curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &res_status); - if(res_status == 200) { - char *ctype; - curl_easy_getinfo(handle, CURLINFO_CONTENT_TYPE, &ctype); - printf("[%d] HTTP 200 (%s): %s\n", complete, ctype, url); - if(is_html(ctype) && mem->size > 100) { - if(pending < max_requests && (complete + pending) < max_total) { - pending += follow_links(multi_handle, mem, url); - still_running = 1; + /* See how the transfers went */ + m = NULL; + while((m = curl_multi_info_read(multi_handle, &msgs_left))) { + if(m->msg == CURLMSG_DONE) { + CURL *handle = m->easy_handle; + char *url; + struct memory *mem; + curl_easy_getinfo(handle, CURLINFO_PRIVATE, &mem); + curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &url); + if(m->data.result == CURLE_OK) { + long res_status; + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &res_status); + if(res_status == 200) { + char *ctype; + curl_easy_getinfo(handle, CURLINFO_CONTENT_TYPE, &ctype); + printf("[%d] HTTP 200 (%s): %s\n", complete, ctype, url); + if(is_html(ctype) && mem->size > 100) { + if(pending < max_requests && + (complete + pending) < max_total) { + pending += follow_links(multi_handle, mem, url); + still_running = 1; + } } } + else { + printf("[%d] HTTP %d: %s\n", complete, (int) res_status, url); + } } else { - printf("[%d] HTTP %d: %s\n", complete, (int) res_status, url); + printf("[%d] Connection failure: %s\n", complete, url); } + curl_multi_remove_handle(multi_handle, handle); + curl_easy_cleanup(handle); + free(mem->buf); + free(mem); + complete++; + pending--; } - else { - printf("[%d] Connection failure: %s\n", complete, url); - } - curl_multi_remove_handle(multi_handle, handle); - curl_easy_cleanup(handle); - free(mem->buf); - free(mem); - complete++; - pending--; } } + curl_multi_cleanup(multi_handle); } - curl_multi_cleanup(multi_handle); curl_global_cleanup(); return 0; } diff --git a/docs/examples/debug.c b/docs/examples/debug.c index 85fdea95d329..3c8355df05cf 100644 --- a/docs/examples/debug.c +++ b/docs/examples/debug.c @@ -32,10 +32,8 @@ struct data { char trace_ascii; /* 1 or 0 */ }; -static -void dump(const char *text, - FILE *stream, unsigned char *ptr, size_t size, - char nohex) +static void dump(const char *text, FILE *stream, unsigned char *ptr, + size_t size, char nohex) { size_t i; size_t c; @@ -83,10 +81,8 @@ void dump(const char *text, fflush(stream); } -static -int my_trace(CURL *handle, curl_infotype type, - char *data, size_t size, - void *userp) +static int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, void *userp) { struct data *config = (struct data *)userp; const char *text; diff --git a/docs/examples/ftpgetresp.c b/docs/examples/ftpgetresp.c index 7b6a6e3d2dae..6dce4ab7496a 100644 --- a/docs/examples/ftpgetresp.c +++ b/docs/examples/ftpgetresp.c @@ -30,8 +30,7 @@ * in a separate file using our own callback! * */ -static size_t -write_response(void *ptr, size_t size, size_t nmemb, void *data) +static size_t write_response(void *ptr, size_t size, size_t nmemb, void *data) { FILE *writehere = (FILE *)data; return fwrite(ptr, size, nmemb, writehere); @@ -88,5 +87,7 @@ int main(void) fclose(ftpfile); /* close the local file */ fclose(respfile); /* close the response file */ + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/ftpupload.c b/docs/examples/ftpupload.c index 7588a829532f..2bfb51f66e7c 100644 --- a/docs/examples/ftpupload.c +++ b/docs/examples/ftpupload.c @@ -84,8 +84,8 @@ int main(void) curl_off_t fsize; struct curl_slist *headerlist = NULL; - static const char buf_1 [] = "RNFR " UPLOAD_FILE_AS; - static const char buf_2 [] = "RNTO " RENAME_FILE_TO; + static const char buf_1[] = "RNFR " UPLOAD_FILE_AS; + static const char buf_2[] = "RNTO " RENAME_FILE_TO; /* get a FILE * of the file */ hd_src = fopen(LOCAL_FILE, "rb"); diff --git a/docs/examples/ftpuploadresume.c b/docs/examples/ftpuploadresume.c index 544b746873ce..13df8541a2d6 100644 --- a/docs/examples/ftpuploadresume.c +++ b/docs/examples/ftpuploadresume.c @@ -159,11 +159,13 @@ int main(void) return (int)res; curlhandle = curl_easy_init(); + if(curlhandle) { - upload(curlhandle, "ftp://user:pass@example.com/path/file", "C:\\file", - 0, 3); + upload(curlhandle, "ftp://user:pass@example.com/path/file", "C:\\file", + 0, 3); - curl_easy_cleanup(curlhandle); + curl_easy_cleanup(curlhandle); + } curl_global_cleanup(); return 0; diff --git a/docs/examples/getinmemory.c b/docs/examples/getinmemory.c index 589047097b54..aa31654c168a 100644 --- a/docs/examples/getinmemory.c +++ b/docs/examples/getinmemory.c @@ -38,8 +38,8 @@ struct MemoryStruct { size_t size; }; -static size_t -WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) +static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, + void *userp) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)userp; @@ -75,41 +75,43 @@ int main(void) /* init the curl session */ curl_handle = curl_easy_init(); - - /* specify URL to get */ - curl_easy_setopt(curl_handle, CURLOPT_URL, "https://www.example.com/"); - - /* send all data to this function */ - curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); - - /* we pass our 'chunk' struct to the callback function */ - curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); - - /* some servers do not like requests that are made without a user-agent - field, so we provide one */ - curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); - - /* get it! */ - res = curl_easy_perform(curl_handle); - - /* check for errors */ - if(res != CURLE_OK) { - fprintf(stderr, "curl_easy_perform() failed: %s\n", - curl_easy_strerror(res)); + if(curl_handle) { + + /* specify URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, "https://www.example.com/"); + + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); + + /* some servers do not like requests that are made without a user-agent + field, so we provide one */ + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + /* get it! */ + res = curl_easy_perform(curl_handle); + + /* check for errors */ + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } + else { + /* + * Now, our chunk.memory points to a memory block that is chunk.size + * bytes big and contains the remote file. + * + * Do something nice with it! + */ + + printf("%lu bytes retrieved\n", (unsigned long)chunk.size); + } + + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); } - else { - /* - * Now, our chunk.memory points to a memory block that is chunk.size - * bytes big and contains the remote file. - * - * Do something nice with it! - */ - - printf("%lu bytes retrieved\n", (unsigned long)chunk.size); - } - - /* cleanup curl stuff */ - curl_easy_cleanup(curl_handle); free(chunk.memory); diff --git a/docs/examples/ghiper.c b/docs/examples/ghiper.c index 50308fd47c38..e9844fc89e01 100644 --- a/docs/examples/ghiper.c +++ b/docs/examples/ghiper.c @@ -434,16 +434,18 @@ int main(void) g_io_add_watch(ch, G_IO_IN, fifo_cb, g); gmain = g_main_loop_new(NULL, FALSE); g->multi = curl_multi_init(); - curl_multi_setopt(g->multi, CURLMOPT_SOCKETFUNCTION, sock_cb); - curl_multi_setopt(g->multi, CURLMOPT_SOCKETDATA, g); - curl_multi_setopt(g->multi, CURLMOPT_TIMERFUNCTION, update_timeout_cb); - curl_multi_setopt(g->multi, CURLMOPT_TIMERDATA, g); + if(g->multi) { + curl_multi_setopt(g->multi, CURLMOPT_SOCKETFUNCTION, sock_cb); + curl_multi_setopt(g->multi, CURLMOPT_SOCKETDATA, g); + curl_multi_setopt(g->multi, CURLMOPT_TIMERFUNCTION, update_timeout_cb); + curl_multi_setopt(g->multi, CURLMOPT_TIMERDATA, g); - /* we do not call any curl_multi_socket*() function yet as we have no handles - added! */ + /* we do not call any curl_multi_socket*() function yet as we have no + handles added! */ - g_main_loop_run(gmain); - curl_multi_cleanup(g->multi); + g_main_loop_run(gmain); + curl_multi_cleanup(g->multi); + } curl_global_cleanup(); return 0; } diff --git a/docs/examples/htmltidy.c b/docs/examples/htmltidy.c index 952132fbc497..0bf3155570ce 100644 --- a/docs/examples/htmltidy.c +++ b/docs/examples/htmltidy.c @@ -92,42 +92,47 @@ int main(int argc, char **argv) if(res) return (int)res; - curl = curl_easy_init(); - curl_easy_setopt(curl, CURLOPT_URL, argv[1]); - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); - tdoc = tidyCreate(); tidyOptSetBool(tdoc, TidyForceOutput, yes); /* try harder */ tidyOptSetInt(tdoc, TidyWrapLen, 4096); tidySetErrorBuffer(tdoc, &tidy_errbuf); tidyBufInit(&docbuf); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &docbuf); - res = curl_easy_perform(curl); - if(!res) { - res = tidyParseBuffer(tdoc, &docbuf); /* parse the input */ - if(res >= 0) { - res = tidyCleanAndRepair(tdoc); /* fix any problems */ + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); + + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &docbuf); + res = curl_easy_perform(curl); + if(!res) { + res = tidyParseBuffer(tdoc, &docbuf); /* parse the input */ if(res >= 0) { - res = tidyRunDiagnostics(tdoc); /* load tidy error buffer */ + res = tidyCleanAndRepair(tdoc); /* fix any problems */ if(res >= 0) { - dumpNode(tdoc, tidyGetRoot(tdoc), 0); /* walk the tree */ - fprintf(stderr, "%s\n", tidy_errbuf.bp); /* show errors */ + res = tidyRunDiagnostics(tdoc); /* load tidy error buffer */ + if(res >= 0) { + dumpNode(tdoc, tidyGetRoot(tdoc), 0); /* walk the tree */ + fprintf(stderr, "%s\n", tidy_errbuf.bp); /* show errors */ + } } } } + else + fprintf(stderr, "%s\n", curl_errbuf); + + /* clean-up */ + curl_easy_cleanup(curl); } - else - fprintf(stderr, "%s\n", curl_errbuf); - /* clean-up */ - curl_easy_cleanup(curl); - curl_global_cleanup(); tidyBufFree(&docbuf); tidyBufFree(&tidy_errbuf); tidyRelease(tdoc); + + curl_global_cleanup(); + return (int)res; } diff --git a/docs/examples/http2-download.c b/docs/examples/http2-download.c index 634323466762..06902415e18d 100644 --- a/docs/examples/http2-download.c +++ b/docs/examples/http2-download.c @@ -56,9 +56,8 @@ struct transfer { #define NUM_HANDLES 1000 -static -void dump(const char *text, unsigned int num, unsigned char *ptr, size_t size, - char nohex) +static void dump(const char *text, unsigned int num, unsigned char *ptr, + size_t size, char nohex) { size_t i; size_t c; @@ -105,10 +104,8 @@ void dump(const char *text, unsigned int num, unsigned char *ptr, size_t size, } } -static -int my_trace(CURL *handle, curl_infotype type, - char *data, size_t size, - void *userp) +static int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, void *userp) { const char *text; struct transfer *t = (struct transfer *)userp; @@ -210,6 +207,8 @@ int main(int argc, char **argv) if(res) return (int)res; + memset(trans, 0, sizeof(trans)); + /* init a multi stack */ multi_handle = curl_multi_init(); @@ -242,6 +241,7 @@ int main(int argc, char **argv) } curl_multi_cleanup(multi_handle); + curl_global_cleanup(); return 0; } diff --git a/docs/examples/http2-pushinmemory.c b/docs/examples/http2-pushinmemory.c index 3e2b4af1c2a1..85bf0e34a745 100644 --- a/docs/examples/http2-pushinmemory.c +++ b/docs/examples/http2-pushinmemory.c @@ -37,8 +37,7 @@ struct Memory { size_t size; }; -static size_t -write_cb(void *contents, size_t size, size_t nmemb, void *userp) +static size_t write_cb(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct Memory *mem = (struct Memory *)userp; @@ -125,10 +124,8 @@ int main(void) { CURL *easy; CURLM *multi; - int still_running; /* keep number of running handles */ int transfers = 1; /* we start with one */ int i; - struct CURLMsg *m; CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) @@ -150,7 +147,10 @@ int main(void) curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &transfers); while(transfers) { + struct CURLMsg *m; + int still_running; /* keep number of running handles */ int rc; + CURLMcode mcode = curl_multi_perform(multi, &still_running); if(mcode) break; @@ -173,7 +173,6 @@ int main(void) curl_easy_cleanup(e); } } while(m); - } curl_multi_cleanup(multi); diff --git a/docs/examples/http2-serverpush.c b/docs/examples/http2-serverpush.c index 0d0e991776d9..e97be991a8cb 100644 --- a/docs/examples/http2-serverpush.c +++ b/docs/examples/http2-serverpush.c @@ -40,9 +40,7 @@ #error "too old libcurl, cannot do HTTP/2 server push!" #endif -static -void dump(const char *text, unsigned char *ptr, size_t size, - char nohex) +static void dump(const char *text, unsigned char *ptr, size_t size, char nohex) { size_t i; size_t c; @@ -89,10 +87,8 @@ void dump(const char *text, unsigned char *ptr, size_t size, } } -static -int my_trace(CURL *handle, curl_infotype type, - char *data, size_t size, - void *userp) +static int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, void *userp) { const char *text; (void)handle; @@ -216,7 +212,6 @@ int main(int argc, char *argv[]) CURL *easy; CURLM *multi_handle; int transfers = 1; /* we start with one */ - struct CURLMsg *m; const char *url = "https://localhost:8443/index.html"; if(argc == 2) @@ -246,6 +241,7 @@ int main(int argc, char *argv[]) curl_multi_setopt(multi_handle, CURLMOPT_PUSHDATA, &transfers); do { + struct CURLMsg *m; int still_running; /* keep number of running handles */ CURLMcode mc = curl_multi_perform(multi_handle, &still_running); diff --git a/docs/examples/http2-upload.c b/docs/examples/http2-upload.c index 9cc3c5652cbc..55162c03a3ad 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -68,8 +68,7 @@ #ifdef _MSC_VER #define gettimeofday(a, b) my_gettimeofday((a), (b)) -static -int my_gettimeofday(struct timeval *tp, void *tzp) +static int my_gettimeofday(struct timeval *tp, void *tzp) { (void)tzp; if(tp) { @@ -89,14 +88,14 @@ int my_gettimeofday(struct timeval *tp, void *tzp) struct input { FILE *in; + FILE *out; size_t bytes_read; /* count up */ CURL *hnd; int num; }; -static -void dump(const char *text, int num, unsigned char *ptr, size_t size, - char nohex) +static void dump(const char *text, int num, unsigned char *ptr, size_t size, + char nohex) { size_t i; size_t c; @@ -142,10 +141,8 @@ void dump(const char *text, int num, unsigned char *ptr, size_t size, } } -static -int my_trace(CURL *handle, curl_infotype type, - char *data, size_t size, - void *userp) +static int my_trace(CURL *handle, curl_infotype type, char *data, + size_t size, void *userp) { char timebuf[60]; const char *text; @@ -208,7 +205,6 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) static int setup(struct input *i, int num, const char *upload) { - FILE *out; char url[256]; char filename[128]; struct stat file_info; @@ -219,8 +215,8 @@ static int setup(struct input *i, int num, const char *upload) i->num = num; snprintf(filename, sizeof(filename), "dl-%d", num); - out = fopen(filename, "wb"); - if(!out) { + i->out = fopen(filename, "wb"); + if(!i->out) { fprintf(stderr, "error: could not open file %s for writing: %s\n", upload, strerror(errno)); return 1; @@ -232,7 +228,8 @@ static int setup(struct input *i, int num, const char *upload) if(!i->in) { fprintf(stderr, "error: could not open file %s for reading: %s\n", upload, strerror(errno)); - fclose(out); + fclose(i->out); + i->out = NULL; return 1; } @@ -244,46 +241,49 @@ static int setup(struct input *i, int num, const char *upload) #endif fprintf(stderr, "error: could not stat file %s: %s\n", upload, strerror(errno)); - fclose(out); + fclose(i->out); + i->out = NULL; return 1; } uploadsize = file_info.st_size; hnd = i->hnd = curl_easy_init(); + if(hnd) { - /* write to this file */ - curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out); + /* write to this file */ + curl_easy_setopt(hnd, CURLOPT_WRITEDATA, i->out); - /* we want to use our own read function */ - curl_easy_setopt(hnd, CURLOPT_READFUNCTION, read_callback); - /* read from this file */ - curl_easy_setopt(hnd, CURLOPT_READDATA, i); - /* provide the size of the upload */ - curl_easy_setopt(hnd, CURLOPT_INFILESIZE_LARGE, uploadsize); + /* we want to use our own read function */ + curl_easy_setopt(hnd, CURLOPT_READFUNCTION, read_callback); + /* read from this file */ + curl_easy_setopt(hnd, CURLOPT_READDATA, i); + /* provide the size of the upload */ + curl_easy_setopt(hnd, CURLOPT_INFILESIZE_LARGE, uploadsize); - /* send in the URL to store the upload as */ - curl_easy_setopt(hnd, CURLOPT_URL, url); + /* send in the URL to store the upload as */ + curl_easy_setopt(hnd, CURLOPT_URL, url); - /* upload please */ - curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L); + /* upload please */ + curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L); - /* please be verbose */ - curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace); - curl_easy_setopt(hnd, CURLOPT_DEBUGDATA, i); + /* please be verbose */ + curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(hnd, CURLOPT_DEBUGDATA, i); - /* HTTP/2 please */ - curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); + /* HTTP/2 please */ + curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); - /* we use a self-signed test server, skip verification during debugging */ - curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L); + /* we use a self-signed test server, skip verification during debugging */ + curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L); #if (CURLPIPE_MULTIPLEX > 0) - /* wait for pipe connection to confirm */ - curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); + /* wait for pipe connection to confirm */ + curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); #endif + } return 0; } @@ -296,7 +296,6 @@ int main(int argc, char **argv) struct input trans[NUM_HANDLES]; CURLM *multi_handle; int i; - int still_running = 0; /* keep number of running handles */ const char *filename = "index.html"; int num_transfers; @@ -318,41 +317,54 @@ int main(int argc, char **argv) if(res) return (int)res; + memset(trans, 0, sizeof(trans)); + /* init a multi stack */ multi_handle = curl_multi_init(); + if(multi_handle) { - for(i = 0; i < num_transfers; i++) { - if(setup(&trans[i], i, filename)) { - curl_global_cleanup(); - return 1; + int still_running = 0; /* keep number of running handles */ + + for(i = 0; i < num_transfers; i++) { + if(setup(&trans[i], i, filename)) { + curl_global_cleanup(); + return 1; + } + + /* add the individual transfer */ + curl_multi_add_handle(multi_handle, trans[i].hnd); } - /* add the individual transfer */ - curl_multi_add_handle(multi_handle, trans[i].hnd); - } + curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); - curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); + /* We do HTTP/2 so let's stick to one connection per host */ + curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 1L); - /* We do HTTP/2 so let's stick to one connection per host */ - curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 1L); + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); - do { - CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + if(mc) + break; - if(mc) - break; + } while(still_running); - } while(still_running); + for(i = 0; i < num_transfers; i++) + curl_multi_remove_handle(multi_handle, trans[i].hnd); - curl_multi_cleanup(multi_handle); + curl_multi_cleanup(multi_handle); + } for(i = 0; i < num_transfers; i++) { - curl_multi_remove_handle(multi_handle, trans[i].hnd); curl_easy_cleanup(trans[i].hnd); + + if(trans[i].in) + fclose(trans[i].in); + if(trans[i].out) + fclose(trans[i].out); } curl_global_cleanup(); diff --git a/docs/examples/multi-app.c b/docs/examples/multi-app.c index 8deee683709c..7dab0b04f147 100644 --- a/docs/examples/multi-app.c +++ b/docs/examples/multi-app.c @@ -37,21 +37,17 @@ * Download an HTTP file and upload an FTP file simultaneously. */ -#define HANDLECOUNT 2 /* Number of simultaneous transfers */ #define HTTP_HANDLE 0 /* Index for the HTTP transfer */ #define FTP_HANDLE 1 /* Index for the FTP transfer */ +#define HANDLECOUNT 2 /* Number of simultaneous transfers */ int main(void) { CURL *handles[HANDLECOUNT]; CURLM *multi_handle; - int still_running = 1; /* keep number of running handles */ int i; - CURLMsg *msg; /* for picking up messages with the transfer status */ - int msgs_left; /* how many messages are left */ - CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) return (int)res; @@ -68,52 +64,63 @@ int main(void) /* init a multi stack */ multi_handle = curl_multi_init(); + if(multi_handle) { - /* add the individual transfers */ - for(i = 0; i < HANDLECOUNT; i++) - curl_multi_add_handle(multi_handle, handles[i]); + int still_running = 1; /* keep number of running handles */ - while(still_running) { - CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + CURLMsg *msg; /* for picking up messages with the transfer status */ + int msgs_left; /* how many messages are left */ - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + /* add the individual transfers */ + for(i = 0; i < HANDLECOUNT; i++) + curl_multi_add_handle(multi_handle, handles[i]); - if(mc) - break; - } - /* See how the transfers went */ - /* !checksrc! disable EQUALSNULL 1 */ - while((msg = curl_multi_info_read(multi_handle, &msgs_left)) != NULL) { - if(msg->msg == CURLMSG_DONE) { - int idx; - - /* Find out which handle this message is about */ - for(idx = 0; idx < HANDLECOUNT; idx++) { - int found = (msg->easy_handle == handles[idx]); - if(found) - break; - } + while(still_running) { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); - switch(idx) { - case HTTP_HANDLE: - printf("HTTP transfer completed with status %d\n", msg->data.result); - break; - case FTP_HANDLE: - printf("FTP transfer completed with status %d\n", msg->data.result); + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + + if(mc) break; + } + + /* See how the transfers went */ + /* !checksrc! disable EQUALSNULL 1 */ + while((msg = curl_multi_info_read(multi_handle, &msgs_left)) != NULL) { + if(msg->msg == CURLMSG_DONE) { + int idx; + + /* Find out which handle this message is about */ + for(idx = 0; idx < HANDLECOUNT; idx++) { + int found = (msg->easy_handle == handles[idx]); + if(found) + break; + } + + switch(idx) { + case HTTP_HANDLE: + printf("HTTP transfer completed with status %d\n", msg->data.result); + break; + case FTP_HANDLE: + printf("FTP transfer completed with status %d\n", msg->data.result); + break; + } } } + + /* remove the transfers */ + for(i = 0; i < HANDLECOUNT; i++) + curl_multi_remove_handle(multi_handle, handles[i]); + + curl_multi_cleanup(multi_handle); } - /* remove the transfers and cleanup the handles */ - for(i = 0; i < HANDLECOUNT; i++) { - curl_multi_remove_handle(multi_handle, handles[i]); + /* Free the curl handles */ + for(i = 0; i < HANDLECOUNT; i++) curl_easy_cleanup(handles[i]); - } - curl_multi_cleanup(multi_handle); curl_global_cleanup(); return 0; diff --git a/docs/examples/multi-debugcallback.c b/docs/examples/multi-debugcallback.c index a27c238a5791..278a5b4a2e1e 100644 --- a/docs/examples/multi-debugcallback.c +++ b/docs/examples/multi-debugcallback.c @@ -83,10 +83,9 @@ static void dump(const char *text, FILE *stream, unsigned char *ptr, fflush(stream); } -static -int my_trace(CURL *handle, curl_infotype type, - unsigned char *data, size_t size, - void *userp) +static int my_trace(CURL *handle, curl_infotype type, + unsigned char *data, size_t size, + void *userp) { const char *text; @@ -123,43 +122,48 @@ int my_trace(CURL *handle, curl_infotype type, int main(void) { CURL *http_handle; - CURLM *multi_handle; - - int still_running = 0; /* keep number of running handles */ CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) return (int)res; http_handle = curl_easy_init(); + if(http_handle) { + + CURLM *multi_handle; - /* set the options (I left out a few, you get the point anyway) */ - curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); + /* set the options (I left out a few, you get the point anyway) */ + curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); - curl_easy_setopt(http_handle, CURLOPT_DEBUGFUNCTION, my_trace); - curl_easy_setopt(http_handle, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(http_handle, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(http_handle, CURLOPT_VERBOSE, 1L); - /* init a multi stack */ - multi_handle = curl_multi_init(); + /* init a multi stack */ + multi_handle = curl_multi_init(); + if(multi_handle) { - /* add the individual transfers */ - curl_multi_add_handle(multi_handle, http_handle); + int still_running = 0; /* keep number of running handles */ - do { - CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + /* add the individual transfers */ + curl_multi_add_handle(multi_handle, http_handle); - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); - if(mc) - break; + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); - } while(still_running); + if(mc) + break; - curl_multi_cleanup(multi_handle); + } while(still_running); - curl_easy_cleanup(http_handle); + curl_multi_cleanup(multi_handle); + } + + curl_easy_cleanup(http_handle); + } curl_global_cleanup(); diff --git a/docs/examples/multi-double.c b/docs/examples/multi-double.c index 8c5c5d687ad3..71ac7422d6d2 100644 --- a/docs/examples/multi-double.c +++ b/docs/examples/multi-double.c @@ -38,9 +38,6 @@ int main(void) { CURL *http_handle; CURL *http_handle2; - CURLM *multi_handle; - - int still_running = 1; /* keep number of running handles */ CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) @@ -49,46 +46,57 @@ int main(void) http_handle = curl_easy_init(); http_handle2 = curl_easy_init(); - /* set options */ - curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); + if(http_handle && + http_handle2) { + + CURLM *multi_handle; + + /* set options */ + curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); + + /* set options */ + curl_easy_setopt(http_handle2, CURLOPT_URL, "http://localhost/"); - /* set options */ - curl_easy_setopt(http_handle2, CURLOPT_URL, "http://localhost/"); + /* init a multi stack */ + multi_handle = curl_multi_init(); + if(multi_handle) { - /* init a multi stack */ - multi_handle = curl_multi_init(); + int still_running = 1; /* keep number of running handles */ - /* add the individual transfers */ - curl_multi_add_handle(multi_handle, http_handle); - curl_multi_add_handle(multi_handle, http_handle2); + /* add the individual transfers */ + curl_multi_add_handle(multi_handle, http_handle); + curl_multi_add_handle(multi_handle, http_handle2); - while(still_running) { - CURLMsg *msg; - int queued; - CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + while(still_running) { + CURLMsg *msg; + int queued; - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); - if(mc) - break; + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); - do { - msg = curl_multi_info_read(multi_handle, &queued); - if(msg) { - if(msg->msg == CURLMSG_DONE) { - /* a transfer ended */ - fprintf(stderr, "Transfer completed\n"); - } + if(mc) + break; + + do { + msg = curl_multi_info_read(multi_handle, &queued); + if(msg) { + if(msg->msg == CURLMSG_DONE) { + /* a transfer ended */ + fprintf(stderr, "Transfer completed\n"); + } + } + } while(msg); } - } while(msg); - } - curl_multi_remove_handle(multi_handle, http_handle); - curl_multi_remove_handle(multi_handle, http_handle2); + curl_multi_remove_handle(multi_handle, http_handle); + curl_multi_remove_handle(multi_handle, http_handle2); - curl_multi_cleanup(multi_handle); + curl_multi_cleanup(multi_handle); + } + } curl_easy_cleanup(http_handle); curl_easy_cleanup(http_handle2); diff --git a/docs/examples/multi-event.c b/docs/examples/multi-event.c index 62dc73b33fb6..af77101b638a 100644 --- a/docs/examples/multi-event.c +++ b/docs/examples/multi-event.c @@ -234,16 +234,18 @@ int main(int argc, char **argv) timeout = evtimer_new(base, on_timeout, NULL); curl_handle = curl_multi_init(); - curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); - curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); + if(curl_handle) { + curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); + curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); - while(argc-- > 1) { - add_download(argv[argc], argc); - } + while(argc-- > 1) { + add_download(argv[argc], argc); + } - event_base_dispatch(base); + event_base_dispatch(base); - curl_multi_cleanup(curl_handle); + curl_multi_cleanup(curl_handle); + } event_free(timeout); event_base_free(base); diff --git a/docs/examples/multi-formadd.c b/docs/examples/multi-formadd.c index 84312ffd160a..08d852ec6528 100644 --- a/docs/examples/multi-formadd.c +++ b/docs/examples/multi-formadd.c @@ -40,9 +40,6 @@ int main(void) { CURL *curl; - CURLM *multi_handle; - int still_running = 0; - struct curl_httppost *formpost = NULL; struct curl_httppost *lastptr = NULL; struct curl_slist *headerlist = NULL; @@ -76,50 +73,59 @@ int main(void) CURLFORM_END); ) - curl = curl_easy_init(); - multi_handle = curl_multi_init(); - /* initialize custom header list (stating that Expect: 100-continue is not wanted */ headerlist = curl_slist_append(headerlist, buf); - if(curl && multi_handle) { - /* what URL that receives this POST */ - curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/upload.cgi"); - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl = curl_easy_init(); + if(curl) { + CURLM *multi_handle; + + multi_handle = curl_multi_init(); + if(multi_handle) { + + int still_running = 0; + + /* what URL that receives this POST */ + curl_easy_setopt(curl, CURLOPT_URL, + "https://www.example.com/upload.cgi"); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); - CURL_IGNORE_DEPRECATION( - curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); - ) + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); + CURL_IGNORE_DEPRECATION( + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + ) - curl_multi_add_handle(multi_handle, curl); + curl_multi_add_handle(multi_handle, curl); - do { - CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); - if(mc) - break; + if(mc) + break; - } while(still_running); + } while(still_running); - curl_multi_cleanup(multi_handle); + curl_multi_cleanup(multi_handle); + } /* always cleanup */ curl_easy_cleanup(curl); + } + + CURL_IGNORE_DEPRECATION( + /* then cleanup the formpost chain */ + curl_formfree(formpost); + ) - CURL_IGNORE_DEPRECATION( - /* then cleanup the formpost chain */ - curl_formfree(formpost); - ) + /* free slist */ + curl_slist_free_all(headerlist); - /* free slist */ - curl_slist_free_all(headerlist); - } curl_global_cleanup(); + return 0; } diff --git a/docs/examples/multi-legacy.c b/docs/examples/multi-legacy.c index 63c238f2475a..19821ad6d327 100644 --- a/docs/examples/multi-legacy.c +++ b/docs/examples/multi-legacy.c @@ -43,21 +43,17 @@ * Download an HTTP file and upload an FTP file simultaneously. */ -#define HANDLECOUNT 2 /* Number of simultaneous transfers */ #define HTTP_HANDLE 0 /* Index for the HTTP transfer */ #define FTP_HANDLE 1 /* Index for the FTP transfer */ +#define HANDLECOUNT 2 /* Number of simultaneous transfers */ int main(void) { CURL *handles[HANDLECOUNT]; CURLM *multi_handle; - int still_running = 0; /* keep number of running handles */ int i; - CURLMsg *msg; /* for picking up messages with the transfer status */ - int msgs_left; /* how many messages are left */ - CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) return (int)res; @@ -74,124 +70,132 @@ int main(void) /* init a multi stack */ multi_handle = curl_multi_init(); + if(multi_handle) { - /* add the individual transfers */ - for(i = 0; i < HANDLECOUNT; i++) - curl_multi_add_handle(multi_handle, handles[i]); + int still_running = 0; /* keep number of running handles */ + + CURLMsg *msg; /* for picking up messages with the transfer status */ + int msgs_left; /* how many messages are left */ + + /* add the individual transfers */ + for(i = 0; i < HANDLECOUNT; i++) + curl_multi_add_handle(multi_handle, handles[i]); + + /* we start some action by calling perform right away */ + curl_multi_perform(multi_handle, &still_running); - /* we start some action by calling perform right away */ - curl_multi_perform(multi_handle, &still_running); + while(still_running) { - while(still_running) { - struct timeval timeout; - int rc; /* select() return code */ - CURLMcode mc; /* curl_multi_fdset() return code */ + struct timeval timeout; + int rc; /* select() return code */ + CURLMcode mc; /* curl_multi_fdset() return code */ - fd_set fdread; - fd_set fdwrite; - fd_set fdexcep; - int maxfd = -1; + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + int maxfd = -1; - long curl_timeo = -1; + long curl_timeo = -1; - FD_ZERO(&fdread); - FD_ZERO(&fdwrite); - FD_ZERO(&fdexcep); + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); - /* set a suitable timeout to play around with */ - timeout.tv_sec = 1; - timeout.tv_usec = 0; + /* set a suitable timeout to play around with */ + timeout.tv_sec = 1; + timeout.tv_usec = 0; - curl_multi_timeout(multi_handle, &curl_timeo); - if(curl_timeo >= 0) { + curl_multi_timeout(multi_handle, &curl_timeo); + if(curl_timeo >= 0) { #if defined(MSDOS) || defined(__AMIGA__) - timeout.tv_sec = (time_t)(curl_timeo / 1000); + timeout.tv_sec = (time_t)(curl_timeo / 1000); #else - timeout.tv_sec = curl_timeo / 1000; + timeout.tv_sec = curl_timeo / 1000; #endif - if(timeout.tv_sec > 1) - timeout.tv_sec = 1; - else + if(timeout.tv_sec > 1) + timeout.tv_sec = 1; + else #if defined(MSDOS) || defined(__AMIGA__) - timeout.tv_usec = (time_t)(curl_timeo % 1000) * 1000; + timeout.tv_usec = (time_t)(curl_timeo % 1000) * 1000; #else - timeout.tv_usec = (int)(curl_timeo % 1000) * 1000; + timeout.tv_usec = (int)(curl_timeo % 1000) * 1000; #endif - } + } - /* get file descriptors from the transfers */ - mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); + /* get file descriptors from the transfers */ + mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); - if(mc != CURLM_OK) { - fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); - break; - } + if(mc != CURLM_OK) { + fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); + break; + } - /* On success the value of maxfd is guaranteed to be >= -1. We call - select(maxfd + 1, ...); specially in case of (maxfd == -1) there are - no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- - to sleep 100ms, which is the minimum suggested value in the - curl_multi_fdset() doc. */ + /* On success the value of maxfd is guaranteed to be >= -1. We call + select(maxfd + 1, ...); specially in case of (maxfd == -1) there are + no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- + to sleep 100ms, which is the minimum suggested value in the + curl_multi_fdset() doc. */ - if(maxfd == -1) { + if(maxfd == -1) { #ifdef _WIN32 - Sleep(100); - rc = 0; + Sleep(100); + rc = 0; #else - /* Portable sleep for platforms other than Windows. */ - struct timeval wait = {0}; - wait.tv_usec = 100 * 1000; /* 100ms */ - rc = select(0, NULL, NULL, NULL, &wait); + /* Portable sleep for platforms other than Windows. */ + struct timeval wait = {0}; + wait.tv_usec = 100 * 1000; /* 100ms */ + rc = select(0, NULL, NULL, NULL, &wait); #endif - } - else { - /* Note that on some platforms 'timeout' may be modified by select(). - If you need access to the original value save a copy beforehand. */ - rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); - } - - switch(rc) { - case -1: - /* select error */ - break; - case 0: /* timeout */ - default: /* action */ - curl_multi_perform(multi_handle, &still_running); - break; - } - } - - /* See how the transfers went */ - /* !checksrc! disable EQUALSNULL 1 */ - while((msg = curl_multi_info_read(multi_handle, &msgs_left)) != NULL) { - if(msg->msg == CURLMSG_DONE) { - int idx; - - /* Find out which handle this message is about */ - for(idx = 0; idx < HANDLECOUNT; idx++) { - int found = (msg->easy_handle == handles[idx]); - if(found) - break; + } + else { + /* Note that on some platforms 'timeout' may be modified by select(). + If you need access to the original value save a copy beforehand. */ + rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); } - switch(idx) { - case HTTP_HANDLE: - printf("HTTP transfer completed with status %d\n", msg->data.result); + switch(rc) { + case -1: + /* select error */ break; - case FTP_HANDLE: - printf("FTP transfer completed with status %d\n", msg->data.result); + case 0: /* timeout */ + default: /* action */ + curl_multi_perform(multi_handle, &still_running); break; } } - } - curl_multi_cleanup(multi_handle); + /* See how the transfers went */ + /* !checksrc! disable EQUALSNULL 1 */ + while((msg = curl_multi_info_read(multi_handle, &msgs_left)) != NULL) { + if(msg->msg == CURLMSG_DONE) { + int idx; + + /* Find out which handle this message is about */ + for(idx = 0; idx < HANDLECOUNT; idx++) { + int found = (msg->easy_handle == handles[idx]); + if(found) + break; + } + + switch(idx) { + case HTTP_HANDLE: + printf("HTTP transfer completed with status %d\n", msg->data.result); + break; + case FTP_HANDLE: + printf("FTP transfer completed with status %d\n", msg->data.result); + break; + } + } + } + + curl_multi_cleanup(multi_handle); + } /* Free the curl handles */ for(i = 0; i < HANDLECOUNT; i++) curl_easy_cleanup(handles[i]); - curl_global_cleanup(); + curl_global_cleanup(); return 0; } diff --git a/docs/examples/multi-post.c b/docs/examples/multi-post.c index 45416b85114b..ac7d2f525205 100644 --- a/docs/examples/multi-post.c +++ b/docs/examples/multi-post.c @@ -33,77 +33,82 @@ int main(void) { - CURL *curl; - - CURLM *multi_handle; - int still_running = 0; - curl_mime *form = NULL; curl_mimepart *field = NULL; struct curl_slist *headerlist = NULL; static const char buf[] = "Expect:"; + CURL *curl; + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) return (int)res; curl = curl_easy_init(); - multi_handle = curl_multi_init(); + if(curl) { + CURLM *multi_handle; - if(curl && multi_handle) { - /* Create the form */ - form = curl_mime_init(curl); + multi_handle = curl_multi_init(); + if(multi_handle) { + int still_running = 0; - /* Fill in the file upload field */ - field = curl_mime_addpart(form); - curl_mime_name(field, "sendfile"); - curl_mime_filedata(field, "multi-post.c"); + /* Create the form */ + form = curl_mime_init(curl); - /* Fill in the filename field */ - field = curl_mime_addpart(form); - curl_mime_name(field, "filename"); - curl_mime_data(field, "multi-post.c", CURL_ZERO_TERMINATED); + /* Fill in the file upload field */ + field = curl_mime_addpart(form); + curl_mime_name(field, "sendfile"); + curl_mime_filedata(field, "multi-post.c"); - /* Fill in the submit field too, even if this is rarely needed */ - field = curl_mime_addpart(form); - curl_mime_name(field, "submit"); - curl_mime_data(field, "send", CURL_ZERO_TERMINATED); + /* Fill in the filename field */ + field = curl_mime_addpart(form); + curl_mime_name(field, "filename"); + curl_mime_data(field, "multi-post.c", CURL_ZERO_TERMINATED); - /* initialize custom header list (stating that Expect: 100-continue is not - wanted */ - headerlist = curl_slist_append(headerlist, buf); + /* Fill in the submit field too, even if this is rarely needed */ + field = curl_mime_addpart(form); + curl_mime_name(field, "submit"); + curl_mime_data(field, "send", CURL_ZERO_TERMINATED); - /* what URL that receives this POST */ - curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/upload.cgi"); - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + /* initialize custom header list (stating that Expect: 100-continue is + not wanted */ + headerlist = curl_slist_append(headerlist, buf); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); - curl_easy_setopt(curl, CURLOPT_MIMEPOST, form); + /* what URL that receives this POST */ + curl_easy_setopt(curl, CURLOPT_URL, + "https://www.example.com/upload.cgi"); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - curl_multi_add_handle(multi_handle, curl); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); + curl_easy_setopt(curl, CURLOPT_MIMEPOST, form); - do { - CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + curl_multi_add_handle(multi_handle, curl); - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); - if(mc) - break; - } while(still_running); + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); - curl_multi_cleanup(multi_handle); + if(mc) + break; + } while(still_running); + + curl_multi_cleanup(multi_handle); + } /* always cleanup */ curl_easy_cleanup(curl); + } - /* then cleanup the form */ - curl_mime_free(form); + /* then cleanup the form */ + curl_mime_free(form); + + /* free slist */ + curl_slist_free_all(headerlist); - /* free slist */ - curl_slist_free_all(headerlist); - } curl_global_cleanup(); + return 0; } diff --git a/docs/examples/multi-single.c b/docs/examples/multi-single.c index 3ba26e79db66..50736c720112 100644 --- a/docs/examples/multi-single.c +++ b/docs/examples/multi-single.c @@ -38,43 +38,48 @@ int main(void) { CURL *http_handle; - CURLM *multi_handle; - int still_running = 1; /* keep number of running handles */ CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) return (int)res; http_handle = curl_easy_init(); + if(http_handle) { - /* set the options (I left out a few, you get the point anyway) */ - curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); + CURLM *multi_handle; + int still_running = 1; /* keep number of running handles */ - /* init a multi stack */ - multi_handle = curl_multi_init(); + /* set the options (I left out a few, you get the point anyway) */ + curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); - /* add the individual transfers */ - curl_multi_add_handle(multi_handle, http_handle); + /* init a multi stack */ + multi_handle = curl_multi_init(); + if(multi_handle) { - do { - CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + /* add the individual transfers */ + curl_multi_add_handle(multi_handle, http_handle); - if(!mc) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); - if(mc) { - fprintf(stderr, "curl_multi_poll() failed, code %d.\n", (int)mc); - break; - } + if(!mc) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + + if(mc) { + fprintf(stderr, "curl_multi_poll() failed, code %d.\n", (int)mc); + break; + } - } while(still_running); + } while(still_running); - curl_multi_remove_handle(multi_handle, http_handle); + curl_multi_remove_handle(multi_handle, http_handle); - curl_easy_cleanup(http_handle); + curl_multi_cleanup(multi_handle); + } - curl_multi_cleanup(multi_handle); + curl_easy_cleanup(http_handle); + } curl_global_cleanup(); diff --git a/docs/examples/multi-uv.c b/docs/examples/multi-uv.c index b4f5587c0fb1..d2f18348e68a 100644 --- a/docs/examples/multi-uv.c +++ b/docs/examples/multi-uv.c @@ -241,21 +241,22 @@ int main(int argc, char **argv) uv_timer_init(uv.loop, &uv.timeout); uv.multi = curl_multi_init(); - curl_multi_setopt(uv.multi, CURLMOPT_SOCKETFUNCTION, cb_socket); - curl_multi_setopt(uv.multi, CURLMOPT_SOCKETDATA, &uv); - curl_multi_setopt(uv.multi, CURLMOPT_TIMERFUNCTION, cb_timeout); - curl_multi_setopt(uv.multi, CURLMOPT_TIMERDATA, &uv); + if(uv.multi) { + curl_multi_setopt(uv.multi, CURLMOPT_SOCKETFUNCTION, cb_socket); + curl_multi_setopt(uv.multi, CURLMOPT_SOCKETDATA, &uv); + curl_multi_setopt(uv.multi, CURLMOPT_TIMERFUNCTION, cb_timeout); + curl_multi_setopt(uv.multi, CURLMOPT_TIMERDATA, &uv); + + while(argc-- > 1) { + add_download(argv[argc], argc, uv.multi); + } - while(argc-- > 1) { - add_download(argv[argc], argc, uv.multi); + /* kickstart the thing */ + curl_multi_socket_action(uv.multi, CURL_SOCKET_TIMEOUT, 0, + &running_handles); + uv_run(uv.loop, UV_RUN_DEFAULT); + curl_multi_cleanup(uv.multi); } - - /* kickstart the thing */ - curl_multi_socket_action(uv.multi, CURL_SOCKET_TIMEOUT, 0, &running_handles); - uv_run(uv.loop, UV_RUN_DEFAULT); - curl_multi_cleanup(uv.multi); - curl_global_cleanup(); - curl_global_cleanup(); return 0; diff --git a/docs/examples/multithread.c b/docs/examples/multithread.c index 5818dfebee49..36836ef47533 100644 --- a/docs/examples/multithread.c +++ b/docs/examples/multithread.c @@ -52,13 +52,15 @@ static const char * const urls[NUMT]= { static void *pull_one_url(void *pindex) { - int i = *(int *)pindex; CURL *curl; curl = curl_easy_init(); - curl_easy_setopt(curl, CURLOPT_URL, urls[i]); - (void)curl_easy_perform(curl); /* ignores error */ - curl_easy_cleanup(curl); + if(curl) { + int i = *(int *)pindex; + curl_easy_setopt(curl, CURLOPT_URL, urls[i]); + (void)curl_easy_perform(curl); /* ignores error */ + curl_easy_cleanup(curl); + } return NULL; } diff --git a/docs/examples/postinmemory.c b/docs/examples/postinmemory.c index 2a8f2b6dd0c8..50b3b6fe7b27 100644 --- a/docs/examples/postinmemory.c +++ b/docs/examples/postinmemory.c @@ -35,8 +35,8 @@ struct MemoryStruct { size_t size; }; -static size_t -WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) +static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, + void *userp) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)userp; diff --git a/docs/examples/postit2.c b/docs/examples/postit2.c index c42ea812c118..57c7c86e3a2b 100644 --- a/docs/examples/postit2.c +++ b/docs/examples/postit2.c @@ -46,19 +46,18 @@ int main(int argc, char *argv[]) { CURL *curl; - CURLcode res; - curl_mime *form = NULL; - curl_mimepart *field = NULL; - struct curl_slist *headerlist = NULL; - static const char buf[] = "Expect:"; - - res = curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) return (int)res; curl = curl_easy_init(); if(curl) { + curl_mime *form = NULL; + curl_mimepart *field = NULL; + struct curl_slist *headerlist = NULL; + static const char buf[] = "Expect:"; + /* Create the form */ form = curl_mime_init(curl); diff --git a/docs/examples/progressfunc.c b/docs/examples/progressfunc.c index 012fd1e6aee1..35adc6c82d56 100644 --- a/docs/examples/progressfunc.c +++ b/docs/examples/progressfunc.c @@ -70,7 +70,6 @@ static int xferinfo(void *p, int main(void) { CURL *curl; - struct myprogress prog; CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) @@ -78,6 +77,8 @@ int main(void) curl = curl_easy_init(); if(curl) { + struct myprogress prog; + prog.lastruntime = 0; prog.curl = curl; diff --git a/docs/examples/sftpuploadresume.c b/docs/examples/sftpuploadresume.c index 4bb0f3e48ebb..8745abe78b8f 100644 --- a/docs/examples/sftpuploadresume.c +++ b/docs/examples/sftpuploadresume.c @@ -121,8 +121,6 @@ static int sftpResumeUpload(CURL *curlhandle, const char *remotepath, int main(void) { - const char *remote = "sftp://user:pass@example.com/path/filename"; - const char *filename = "filename"; CURL *curlhandle = NULL; CURLcode res = curl_global_init(CURL_GLOBAL_ALL); @@ -130,12 +128,16 @@ int main(void) return (int)res; curlhandle = curl_easy_init(); + if(curlhandle) { + const char *remote = "sftp://user:pass@example.com/path/filename"; + const char *filename = "filename"; - if(!sftpResumeUpload(curlhandle, remote, filename)) { - printf("resumed upload using curl %s failed\n", curl_version()); - } + if(!sftpResumeUpload(curlhandle, remote, filename)) { + printf("resumed upload using curl %s failed\n", curl_version()); + } - curl_easy_cleanup(curlhandle); + curl_easy_cleanup(curlhandle); + } curl_global_cleanup(); return 0; diff --git a/docs/examples/smooth-gtk-thread.c b/docs/examples/smooth-gtk-thread.c index 29d134db47b1..5a0bb2d05e97 100644 --- a/docs/examples/smooth-gtk-thread.c +++ b/docs/examples/smooth-gtk-thread.c @@ -67,22 +67,24 @@ size_t write_file(void *ptr, size_t size, size_t nmemb, FILE *stream) static void run_one(gchar *http, int j) { - FILE *outfile = fopen(urls[j], "wb"); CURL *curl; curl = curl_easy_init(); if(curl) { printf("j = %d\n", j); - /* Set the URL and transfer type */ - curl_easy_setopt(curl, CURLOPT_URL, http); + FILE *outfile = fopen(urls[j], "wb"); + if(outfile) { + /* Set the URL and transfer type */ + curl_easy_setopt(curl, CURLOPT_URL, http); - /* Write to the file */ - curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file); - (void)curl_easy_perform(curl); + /* Write to the file */ + curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file); + (void)curl_easy_perform(curl); - fclose(outfile); + fclose(outfile); + } curl_easy_cleanup(curl); } } diff --git a/docs/examples/smtp-authzid.c b/docs/examples/smtp-authzid.c index addc17691e0f..758a7fdaaf2a 100644 --- a/docs/examples/smtp-authzid.c +++ b/docs/examples/smtp-authzid.c @@ -95,8 +95,6 @@ static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) int main(void) { CURL *curl; - struct curl_slist *recipients = NULL; - struct upload_status upload_ctx = { 0 }; CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) @@ -104,6 +102,9 @@ int main(void) curl = curl_easy_init(); if(curl) { + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx = { 0 }; + /* This is the URL for your mailserver. In this example we connect to the smtp-submission port as we require an authenticated connection. */ curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com:587"); diff --git a/docs/examples/smtp-expn.c b/docs/examples/smtp-expn.c index baec49be6906..727880d6199e 100644 --- a/docs/examples/smtp-expn.c +++ b/docs/examples/smtp-expn.c @@ -42,7 +42,6 @@ int main(void) { CURL *curl; - struct curl_slist *recipients = NULL; CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) @@ -50,6 +49,8 @@ int main(void) curl = curl_easy_init(); if(curl) { + struct curl_slist *recipients = NULL; + /* This is the URL for your mailserver */ curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); diff --git a/docs/examples/smtp-mail.c b/docs/examples/smtp-mail.c index 6583fc47099f..d3f4346b8c0a 100644 --- a/docs/examples/smtp-mail.c +++ b/docs/examples/smtp-mail.c @@ -92,8 +92,6 @@ static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) int main(void) { CURL *curl; - struct curl_slist *recipients = NULL; - struct upload_status upload_ctx = { 0 }; CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) @@ -101,6 +99,9 @@ int main(void) curl = curl_easy_init(); if(curl) { + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx = { 0 }; + /* This is the URL for your mailserver */ curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); diff --git a/docs/examples/smtp-ssl.c b/docs/examples/smtp-ssl.c index f952441c9c6a..ca73b73fca9a 100644 --- a/docs/examples/smtp-ssl.c +++ b/docs/examples/smtp-ssl.c @@ -89,8 +89,6 @@ static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) int main(void) { CURL *curl; - struct curl_slist *recipients = NULL; - struct upload_status upload_ctx = { 0 }; CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) @@ -98,6 +96,9 @@ int main(void) curl = curl_easy_init(); if(curl) { + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx = { 0 }; + /* Set username and password */ curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); diff --git a/docs/examples/smtp-tls.c b/docs/examples/smtp-tls.c index 3eaea9d879fc..4f7379529c1e 100644 --- a/docs/examples/smtp-tls.c +++ b/docs/examples/smtp-tls.c @@ -89,8 +89,6 @@ static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp) int main(void) { CURL *curl; - struct curl_slist *recipients = NULL; - struct upload_status upload_ctx = { 0 }; CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) @@ -98,6 +96,9 @@ int main(void) curl = curl_easy_init(); if(curl) { + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx = { 0 }; + /* Set username and password */ curl_easy_setopt(curl, CURLOPT_USERNAME, "user"); curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); diff --git a/docs/examples/smtp-vrfy.c b/docs/examples/smtp-vrfy.c index 76dd8069adfa..33d439ec9c43 100644 --- a/docs/examples/smtp-vrfy.c +++ b/docs/examples/smtp-vrfy.c @@ -45,7 +45,6 @@ int main(void) { CURL *curl; - struct curl_slist *recipients = NULL; CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) @@ -53,6 +52,8 @@ int main(void) curl = curl_easy_init(); if(curl) { + struct curl_slist *recipients = NULL; + /* This is the URL for your mailserver */ curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); diff --git a/docs/examples/threaded-ssl.c b/docs/examples/threaded-ssl.c index 7f09a76fc187..5d984a670ab9 100644 --- a/docs/examples/threaded-ssl.c +++ b/docs/examples/threaded-ssl.c @@ -55,17 +55,19 @@ static const char * const urls[]= { static void *pull_one_url(void *pindex) { - int i = *(int *)pindex; CURL *curl; curl = curl_easy_init(); - curl_easy_setopt(curl, CURLOPT_URL, urls[i]); - /* this example does not verify the server's certificate, which means we - might be downloading stuff from an impostor */ - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); - (void)curl_easy_perform(curl); /* ignores error */ - curl_easy_cleanup(curl); + if(curl) { + int i = *(int *)pindex; + curl_easy_setopt(curl, CURLOPT_URL, urls[i]); + /* this example does not verify the server's certificate, which means we + might be downloading stuff from an impostor */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + (void)curl_easy_perform(curl); /* ignores error */ + curl_easy_cleanup(curl); + } return NULL; } diff --git a/docs/examples/url2file.c b/docs/examples/url2file.c index 2e8e225fce90..8e9e01db15df 100644 --- a/docs/examples/url2file.c +++ b/docs/examples/url2file.c @@ -38,10 +38,10 @@ static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) int main(int argc, char *argv[]) { + static const char *pagefilename = "page.out"; + CURLcode res; CURL *curl_handle; - static const char *pagefilename = "page.out"; - FILE *pagefile; if(argc < 2) { printf("Usage: %s \n", argv[0]); @@ -56,35 +56,38 @@ int main(int argc, char *argv[]) /* init the curl session */ curl_handle = curl_easy_init(); + if(curl_handle) { + FILE *pagefile; - /* set URL to get here */ - curl_easy_setopt(curl_handle, CURLOPT_URL, argv[1]); + /* set URL to get here */ + curl_easy_setopt(curl_handle, CURLOPT_URL, argv[1]); - /* Switch on full protocol/debug output while testing */ - curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); + /* Switch on full protocol/debug output while testing */ + curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); - /* disable progress meter, set to 0L to enable it */ - curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); + /* disable progress meter, set to 0L to enable it */ + curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); - /* send all data to this function */ - curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); - /* open the file */ - pagefile = fopen(pagefilename, "wb"); - if(pagefile) { + /* open the file */ + pagefile = fopen(pagefilename, "wb"); + if(pagefile) { - /* write the page body to this file handle */ - curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile); + /* write the page body to this file handle */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile); - /* get it! */ - res = curl_easy_perform(curl_handle); + /* get it! */ + res = curl_easy_perform(curl_handle); - /* close the header file */ - fclose(pagefile); - } + /* close the header file */ + fclose(pagefile); + } - /* cleanup curl stuff */ - curl_easy_cleanup(curl_handle); + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + } curl_global_cleanup(); diff --git a/docs/examples/urlapi.c b/docs/examples/urlapi.c index 8953146e4dad..82ef3e19aab9 100644 --- a/docs/examples/urlapi.c +++ b/docs/examples/urlapi.c @@ -34,8 +34,7 @@ int main(void) { - CURL *curl; - + CURL *curl = NULL; CURLU *urlp; CURLUcode uc; @@ -43,9 +42,6 @@ int main(void) if(res) return (int)res; - /* get a curl handle */ - curl = curl_easy_init(); - /* init Curl URL */ urlp = curl_url(); uc = curl_url_set(urlp, CURLUPART_URL, @@ -56,6 +52,8 @@ int main(void) goto cleanup; } + /* get a curl handle */ + curl = curl_easy_init(); if(curl) { /* set urlp to use as working URL */ curl_easy_setopt(curl, CURLOPT_CURLU, urlp); @@ -69,8 +67,6 @@ int main(void) if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); - - goto cleanup; } cleanup: diff --git a/docs/examples/usercertinmem.c b/docs/examples/usercertinmem.c index d95e2a1cddd1..c53fcde9cbce 100644 --- a/docs/examples/usercertinmem.c +++ b/docs/examples/usercertinmem.c @@ -162,45 +162,46 @@ int main(void) if(res) return (int)res; - curl_global_init(CURL_GLOBAL_ALL); ch = curl_easy_init(); - curl_easy_setopt(ch, CURLOPT_VERBOSE, 0L); - curl_easy_setopt(ch, CURLOPT_HEADER, 0L); - curl_easy_setopt(ch, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); - curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, writefunction); - curl_easy_setopt(ch, CURLOPT_WRITEDATA, stdout); - curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, writefunction); - curl_easy_setopt(ch, CURLOPT_HEADERDATA, stderr); - curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM"); - - /* both VERIFYPEER and VERIFYHOST are set to 0 in this case because there is - no CA certificate */ - - curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/"); - curl_easy_setopt(ch, CURLOPT_SSLKEYTYPE, "PEM"); - - /* first try: retrieve page without user certificate and key -> fails */ - res = curl_easy_perform(ch); - if(res == CURLE_OK) - printf("*** transfer succeeded ***\n"); - else - printf("*** transfer failed ***\n"); - - /* second try: retrieve page using user certificate and key -> succeeds - * load the certificate and key by installing a function doing the necessary - * "modifications" to the SSL CONTEXT just before link init - */ - curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); - res = curl_easy_perform(ch); - if(res == CURLE_OK) - printf("*** transfer succeeded ***\n"); - else - printf("*** transfer failed ***\n"); - - curl_easy_cleanup(ch); + if(ch) { + curl_easy_setopt(ch, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(ch, CURLOPT_HEADER, 0L); + curl_easy_setopt(ch, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, writefunction); + curl_easy_setopt(ch, CURLOPT_WRITEDATA, stdout); + curl_easy_setopt(ch, CURLOPT_HEADERFUNCTION, writefunction); + curl_easy_setopt(ch, CURLOPT_HEADERDATA, stderr); + curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM"); + + /* both VERIFYPEER and VERIFYHOST are set to 0 in this case because there + is no CA certificate */ + + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/"); + curl_easy_setopt(ch, CURLOPT_SSLKEYTYPE, "PEM"); + + /* first try: retrieve page without user certificate and key -> fails */ + res = curl_easy_perform(ch); + if(res == CURLE_OK) + printf("*** transfer succeeded ***\n"); + else + printf("*** transfer failed ***\n"); + + /* second try: retrieve page using user certificate and key -> succeeds + * load the certificate and key by installing a function doing + * the necessary "modifications" to the SSL CONTEXT just before link init + */ + curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, sslctx_function); + res = curl_easy_perform(ch); + if(res == CURLE_OK) + printf("*** transfer succeeded ***\n"); + else + printf("*** transfer failed ***\n"); + + curl_easy_cleanup(ch); + } curl_global_cleanup(); return (int)res; } diff --git a/docs/examples/xmlstream.c b/docs/examples/xmlstream.c index 4f8401be4a91..1131a3ce9e76 100644 --- a/docs/examples/xmlstream.c +++ b/docs/examples/xmlstream.c @@ -117,56 +117,60 @@ static size_t parseStreamCallback(void *contents, size_t length, size_t nmemb, int main(void) { CURL *curl_handle; - CURLcode res; - XML_Parser parser; - struct ParserStruct state; - /* Initialize the state structure for parsing. */ - memset(&state, 0, sizeof(state)); - state.ok = 1; - - /* Initialize a namespace-aware parser. */ - parser = XML_ParserCreateNS(NULL, '\0'); - XML_SetUserData(parser, &state); - XML_SetElementHandler(parser, startElement, endElement); - XML_SetCharacterDataHandler(parser, characterDataHandler); - - res = curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if(res) return (int)res; /* Initialize a libcurl handle. */ curl_handle = curl_easy_init(); - curl_easy_setopt(curl_handle, CURLOPT_URL, - "https://www.w3schools.com/xml/simple.xml"); - curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, parseStreamCallback); - curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)parser); - - printf("Depth Characters Closing Tag\n"); - - /* Perform the request and any follow-up parsing. */ - res = curl_easy_perform(curl_handle); - if(res != CURLE_OK) { - fprintf(stderr, "curl_easy_perform() failed: %s\n", - curl_easy_strerror(res)); - } - else if(state.ok) { - /* Expat requires one final call to finalize parsing. */ - if(XML_Parse(parser, NULL, 0, 1) == 0) { - enum XML_Error error_code = XML_GetErrorCode(parser); - fprintf(stderr, "Finalizing parsing failed with error code %d (%s).\n", - error_code, XML_ErrorString(error_code)); + if(curl) { + XML_Parser parser; + struct ParserStruct state; + + /* Initialize the state structure for parsing. */ + memset(&state, 0, sizeof(state)); + state.ok = 1; + + /* Initialize a namespace-aware parser. */ + parser = XML_ParserCreateNS(NULL, '\0'); + XML_SetUserData(parser, &state); + XML_SetElementHandler(parser, startElement, endElement); + XML_SetCharacterDataHandler(parser, characterDataHandler); + + curl_easy_setopt(curl_handle, CURLOPT_URL, + "https://www.w3schools.com/xml/simple.xml"); + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, parseStreamCallback); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)parser); + + printf("Depth Characters Closing Tag\n"); + + /* Perform the request and any follow-up parsing. */ + res = curl_easy_perform(curl_handle); + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); } - else { - printf(" --------------\n"); - printf(" %lu tags total\n", state.tags); + else if(state.ok) { + /* Expat requires one final call to finalize parsing. */ + if(XML_Parse(parser, NULL, 0, 1) == 0) { + enum XML_Error error_code = XML_GetErrorCode(parser); + fprintf(stderr, "Finalizing parsing failed with error code %d (%s).\n", + error_code, XML_ErrorString(error_code)); + } + else { + printf(" --------------\n"); + printf(" %lu tags total\n", state.tags); + } } + + /* Clean up. */ + free(state.characters.memory); + XML_ParserFree(parser); + + curl_easy_cleanup(curl_handle); } - /* Clean up. */ - free(state.characters.memory); - XML_ParserFree(parser); - curl_easy_cleanup(curl_handle); curl_global_cleanup(); return (int)res; From fe06127dedfc0047c9e748658f23d52f32117055 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Fri, 10 Oct 2025 15:42:27 -0400 Subject: [PATCH 442/465] tool_operate: retry on HTTP response codes 522 and 524 - Treat HTTP response codes 522 and 524 as a transient error since Cloudflare may use them instead of 504 to signal timeout. For example here is a 522 error message from Cloudflare: "The initial connection between Cloudflare's network and the origin web server timed out. As a result, the web page can not be displayed." Prior to this change the curl tool did not retry on HTTP response codes 522 and 524 when --retry was used. Fixes https://github.com/curl/curl/discussions/16143 Closes https://github.com/curl/curl/pull/19011 --- docs/cmdline-opts/retry.md | 4 ++-- src/tool_operate.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/cmdline-opts/retry.md b/docs/cmdline-opts/retry.md index f55d8edcca12..4d9e83cd5f40 100644 --- a/docs/cmdline-opts/retry.md +++ b/docs/cmdline-opts/retry.md @@ -20,8 +20,8 @@ Example: If a transient error is returned when curl tries to perform a transfer, it retries this number of times before giving up. Setting the number to 0 makes curl do no retries (which is the default). Transient error means either: a -timeout, an FTP 4xx response code or an HTTP 408, 429, 500, 502, 503 or 504 -response code. +timeout, an FTP 4xx response code or an HTTP 408, 429, 500, 502, 503, 504, 522 +or 524 response code. When curl is about to retry a transfer, it first waits one second and then for all forthcoming retries it doubles the waiting time until it reaches 10 diff --git a/src/tool_operate.c b/src/tool_operate.c index 397b2159e198..c7d01bb59af2 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -412,6 +412,8 @@ static CURLcode retrycheck(struct OperationConfig *config, case 502: /* Bad Gateway */ case 503: /* Service Unavailable */ case 504: /* Gateway Timeout */ + case 522: /* Connection Timed Out (Cloudflare) */ + case 524: /* Proxy Read Timeout (Cloudflare) */ retry = RETRY_HTTP; /* * At this point, we have already written data to the output From 97ae9ec8efe05bd0d82bbf9ee127c46bfae40c8c Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Sun, 12 Oct 2025 18:35:22 -0400 Subject: [PATCH 443/465] ws: fix type conversion check - Fix logic that checks whether a size_t will fit in a curl_off_t. Reported-by: Viktor Szakats Fixes https://github.com/curl/curl/issues/19017 Closes https://github.com/curl/curl/pull/19036 --- lib/ws.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ws.c b/lib/ws.c index 6c8f07e1776e..ec7923555030 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -654,8 +654,8 @@ static curl_off_t ws_payload_remain(curl_off_t payload_total, curl_off_t remain = payload_total - payload_offset; if((payload_total < 0) || (payload_offset < 0) || (remain < 0)) return -1; -#if SIZEOF_OFF_T <= SIZEOF_SIZE_T - if((curl_off_t)payload_buffered < 0) +#if SIZEOF_SIZE_T >= SIZEOF_CURL_OFF_T + if(payload_buffered > (size_t)CURL_OFF_T_MAX) return -1; #endif if(remain < (curl_off_t)payload_buffered) From 9441127394a697412f826c737b4e6e53bbc1a1c4 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 14 Oct 2025 18:08:27 +0200 Subject: [PATCH 444/465] http: look for trailing 'type=' in ftp:// without strstr - it could find a wrong string - this is faster Closes #19065 --- lib/http.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/lib/http.c b/lib/http.c index 6b1538a737e9..850bfaefa684 100644 --- a/lib/http.c +++ b/lib/http.c @@ -2040,27 +2040,26 @@ static CURLcode http_target(struct Curl_easy *data, if(result) return result; - if(curl_strequal("ftp", data->state.up.scheme)) { - if(data->set.proxy_transfer_mode) { - /* when doing ftp, append ;type= if not present */ - char *type = strstr(path, ";type="); - if(type && type[6] && type[7] == 0) { - switch(Curl_raw_toupper(type[6])) { - case 'A': - case 'D': - case 'I': - break; - default: - type = NULL; - } - } - if(!type) { - result = curlx_dyn_addf(r, ";type=%c", - data->state.prefer_ascii ? 'a' : 'i'); - if(result) - return result; + if(curl_strequal("ftp", data->state.up.scheme) && + data->set.proxy_transfer_mode) { + /* when doing ftp, append ;type= if not present */ + size_t len = strlen(path); + bool type_present = FALSE; + if((len >= 7) && !memcmp(&path[len - 7], ";type=", 6)) { + switch(Curl_raw_toupper(path[len - 1])) { + case 'A': + case 'D': + case 'I': + type_present = TRUE; + break; } } + if(!type_present) { + result = curlx_dyn_addf(r, ";type=%c", + data->state.prefer_ascii ? 'a' : 'i'); + if(result) + return result; + } } } From ae5fb4188deac102ee8d2b7cdd192f06340b04f0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 14 Oct 2025 17:40:18 +0200 Subject: [PATCH 445/465] lib: reduce use of data->conn-> If there are more than two of them in a function, use a local 'conn' variable instead. Closes #19063 --- lib/cfilters.c | 9 +++++---- lib/connect.c | 11 ++++++----- lib/http.c | 23 +++++++++++++---------- lib/multi.c | 46 +++++++++++++++++++++++++--------------------- lib/vssh/libssh.c | 16 +++++++++------- lib/vssh/libssh2.c | 7 ++++--- 6 files changed, 62 insertions(+), 50 deletions(-) diff --git a/lib/cfilters.c b/lib/cfilters.c index d0466f5fadb1..bd060f43dc98 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -932,13 +932,14 @@ Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex) void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex) { - if(data->conn && CONN_SOCK_IDX_VALID(sockindex)) { - struct Curl_cfilter *cf = data->conn->cfilter[sockindex]; + struct connectdata *conn = data->conn; + if(conn && CONN_SOCK_IDX_VALID(sockindex)) { + struct Curl_cfilter *cf = conn->cfilter[sockindex]; if(cf) (void)Curl_conn_cf_cntrl(cf, data, TRUE, CF_CTRL_FORGET_SOCKET, 0, NULL); - fake_sclose(data->conn->sock[sockindex]); - data->conn->sock[sockindex] = CURL_SOCKET_BAD; + fake_sclose(conn->sock[sockindex]); + conn->sock[sockindex] = CURL_SOCKET_BAD; } } diff --git a/lib/connect.c b/lib/connect.c index efe6248214e9..1c312095674d 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -158,20 +158,21 @@ void Curl_shutdown_start(struct Curl_easy *data, int sockindex, int timeout_ms, struct curltime *nowp) { struct curltime now; + struct connectdata *conn = data->conn; - DEBUGASSERT(data->conn); + DEBUGASSERT(conn); if(!nowp) { now = curlx_now(); nowp = &now; } - data->conn->shutdown.start[sockindex] = *nowp; - data->conn->shutdown.timeout_ms = (timeout_ms > 0) ? + conn->shutdown.start[sockindex] = *nowp; + conn->shutdown.timeout_ms = (timeout_ms > 0) ? (timediff_t)timeout_ms : ((data->set.shutdowntimeout > 0) ? data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS); /* Set a timer, unless we operate on the admin handle */ - if(data->mid && (data->conn->shutdown.timeout_ms > 0)) - Curl_expire_ex(data, nowp, data->conn->shutdown.timeout_ms, + if(data->mid && (conn->shutdown.timeout_ms > 0)) + Curl_expire_ex(data, nowp, conn->shutdown.timeout_ms, EXPIRE_SHUTDOWN); } diff --git a/lib/http.c b/lib/http.c index 850bfaefa684..db37995a12c7 100644 --- a/lib/http.c +++ b/lib/http.c @@ -1977,6 +1977,9 @@ static CURLcode http_target(struct Curl_easy *data, CURLcode result = CURLE_OK; const char *path = data->state.up.path; const char *query = data->state.up.query; +#ifndef CURL_DISABLE_PROXY + struct connectdata *conn = data->conn; +#endif if(data->set.str[STRING_TARGET]) { path = data->set.str[STRING_TARGET]; @@ -1984,7 +1987,7 @@ static CURLcode http_target(struct Curl_easy *data, } #ifndef CURL_DISABLE_PROXY - if(data->conn->bits.httpproxy && !data->conn->bits.tunnel_proxy) { + if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { /* Using a proxy but does not tunnel through it */ /* The path sent to the proxy is in fact the entire URL. But if the remote @@ -1998,8 +2001,8 @@ static CURLcode http_target(struct Curl_easy *data, if(!h) return CURLE_OUT_OF_MEMORY; - if(data->conn->host.dispname != data->conn->host.name) { - uc = curl_url_set(h, CURLUPART_HOST, data->conn->host.name, 0); + if(conn->host.dispname != conn->host.name) { + uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0); if(uc) { curl_url_cleanup(h); return CURLE_OUT_OF_MEMORY; @@ -2746,6 +2749,7 @@ static CURLcode http_add_hd(struct Curl_easy *data, Curl_HttpReq httpreq) { CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; switch(id) { case H1_HD_REQUEST: /* add the main request stuff */ @@ -2818,8 +2822,8 @@ static CURLcode http_add_hd(struct Curl_easy *data, #ifndef CURL_DISABLE_PROXY case H1_HD_PROXY_CONNECTION: - if(data->conn->bits.httpproxy && - !data->conn->bits.tunnel_proxy && + if(conn->bits.httpproxy && + !conn->bits.tunnel_proxy && !Curl_checkheaders(data, STRCONST("Proxy-Connection")) && !Curl_checkProxyheaders(data, data->conn, STRCONST("Proxy-Connection"))) result = curlx_dyn_add(req, "Proxy-Connection: Keep-Alive\r\n"); @@ -2832,11 +2836,10 @@ static CURLcode http_add_hd(struct Curl_easy *data, #ifndef CURL_DISABLE_ALTSVC case H1_HD_ALT_USED: - if(data->conn->bits.altused && - !Curl_checkheaders(data, STRCONST("Alt-Used"))) + if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) result = curlx_dyn_addf(req, "Alt-Used: %s:%d\r\n", - data->conn->conn_to_host.name, - data->conn->conn_to_port); + conn->conn_to_host.name, + conn->conn_to_port); break; #endif @@ -2849,7 +2852,7 @@ static CURLcode http_add_hd(struct Curl_easy *data, result = Curl_http2_request_upgrade(req, data); } #ifndef CURL_DISABLE_WEBSOCKETS - if(!result && data->conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) + if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) result = Curl_ws_request(data, req); #endif break; diff --git a/lib/multi.c b/lib/multi.c index 9ea8e9bc7f51..ca7c1bdd9542 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -939,11 +939,12 @@ static CURLcode mstate_connecting_pollset(struct Curl_easy *data, static CURLcode mstate_protocol_pollset(struct Curl_easy *data, struct easy_pollset *ps) { - if(data->conn) { + struct connectdata *conn = data->conn; + if(conn) { curl_socket_t sockfd; - if(data->conn->handler->proto_pollset) - return data->conn->handler->proto_pollset(data, ps); - sockfd = data->conn->sock[FIRSTSOCKET]; + if(conn->handler->proto_pollset) + return conn->handler->proto_pollset(data, ps); + sockfd = conn->sock[FIRSTSOCKET]; if(sockfd != CURL_SOCKET_BAD) { /* Default is to wait to something from the server */ return Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0); @@ -955,13 +956,14 @@ static CURLcode mstate_protocol_pollset(struct Curl_easy *data, static CURLcode mstate_do_pollset(struct Curl_easy *data, struct easy_pollset *ps) { - if(data->conn) { - if(data->conn->handler->doing_pollset) - return data->conn->handler->doing_pollset(data, ps); - else if(CONN_SOCK_IDX_VALID(data->conn->send_idx)) { + struct connectdata *conn = data->conn; + if(conn) { + if(conn->handler->doing_pollset) + return conn->handler->doing_pollset(data, ps); + else if(CONN_SOCK_IDX_VALID(conn->send_idx)) { /* Default is that we want to send something to the server */ return Curl_pollset_add_out( - data, ps, data->conn->sock[data->conn->send_idx]); + data, ps, conn->sock[conn->send_idx]); } } return CURLE_OK; @@ -970,13 +972,14 @@ static CURLcode mstate_do_pollset(struct Curl_easy *data, static CURLcode mstate_domore_pollset(struct Curl_easy *data, struct easy_pollset *ps) { - if(data->conn) { - if(data->conn->handler->domore_pollset) - return data->conn->handler->domore_pollset(data, ps); - else if(CONN_SOCK_IDX_VALID(data->conn->send_idx)) { + struct connectdata *conn = data->conn; + if(conn) { + if(conn->handler->domore_pollset) + return conn->handler->domore_pollset(data, ps); + else if(CONN_SOCK_IDX_VALID(conn->send_idx)) { /* Default is that we want to send something to the server */ return Curl_pollset_add_out( - data, ps, data->conn->sock[data->conn->send_idx]); + data, ps, conn->sock[conn->send_idx]); } } return CURLE_OK; @@ -985,22 +988,23 @@ static CURLcode mstate_domore_pollset(struct Curl_easy *data, static CURLcode mstate_perform_pollset(struct Curl_easy *data, struct easy_pollset *ps) { - if(!data->conn) + struct connectdata *conn = data->conn; + if(!conn) return CURLE_OK; - else if(data->conn->handler->perform_pollset) - return data->conn->handler->perform_pollset(data, ps); + else if(conn->handler->perform_pollset) + return conn->handler->perform_pollset(data, ps); else { /* Default is to obey the data->req.keepon flags for send/recv */ CURLcode result = CURLE_OK; - if(CURL_WANT_RECV(data) && CONN_SOCK_IDX_VALID(data->conn->recv_idx)) { + if(CURL_WANT_RECV(data) && CONN_SOCK_IDX_VALID(conn->recv_idx)) { result = Curl_pollset_add_in( - data, ps, data->conn->sock[data->conn->recv_idx]); + data, ps, conn->sock[conn->recv_idx]); } if(!result && Curl_req_want_send(data) && - CONN_SOCK_IDX_VALID(data->conn->send_idx)) { + CONN_SOCK_IDX_VALID(conn->send_idx)) { result = Curl_pollset_add_out( - data, ps, data->conn->sock[data->conn->send_idx]); + data, ps, conn->sock[conn->send_idx]); } return result; } diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 6bb32643af2d..3741db20dc63 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -1105,6 +1105,7 @@ static int myssh_in_AUTH_PASS(struct Curl_easy *data, static int myssh_in_AUTH_DONE(struct Curl_easy *data, struct ssh_conn *sshc) { + struct connectdata *conn = data->conn; if(!sshc->authed) { failf(data, "Authentication failure"); return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED); @@ -1113,10 +1114,10 @@ static int myssh_in_AUTH_DONE(struct Curl_easy *data, /* At this point we have an authenticated ssh session. */ infof(data, "Authentication complete"); Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */ - data->conn->recv_idx = FIRSTSOCKET; - data->conn->send_idx = -1; + conn->recv_idx = FIRSTSOCKET; + conn->send_idx = -1; - if(data->conn->handler->protocol == CURLPROTO_SFTP) { + if(conn->handler->protocol == CURLPROTO_SFTP) { myssh_to(data, sshc, SSH_SFTP_INIT); return SSH_NO_ERROR; } @@ -2428,14 +2429,15 @@ static CURLcode myssh_pollset(struct Curl_easy *data, struct easy_pollset *ps) { int flags = 0; - if(data->conn->waitfor & KEEP_RECV) + struct connectdata *conn = data->conn; + if(conn->waitfor & KEEP_RECV) flags |= CURL_POLL_IN; - if(data->conn->waitfor & KEEP_SEND) + if(conn->waitfor & KEEP_SEND) flags |= CURL_POLL_OUT; - if(!data->conn->waitfor) + if(!conn->waitfor) flags |= CURL_POLL_OUT; return flags ? - Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], flags, 0) : + Curl_pollset_change(data, ps, conn->sock[FIRSTSOCKET], flags, 0) : CURLE_OK; } diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index ee468bb35958..dc972dc9e67a 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -3061,12 +3061,13 @@ static CURLcode ssh_pollset(struct Curl_easy *data, struct easy_pollset *ps) { int flags = 0; - if(data->conn->waitfor & KEEP_RECV) + struct connectdata *conn = data->conn; + if(conn->waitfor & KEEP_RECV) flags |= CURL_POLL_IN; - if(data->conn->waitfor & KEEP_SEND) + if(conn->waitfor & KEEP_SEND) flags |= CURL_POLL_OUT; return flags ? - Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], flags, 0) : + Curl_pollset_change(data, ps, conn->sock[FIRSTSOCKET], flags, 0) : CURLE_OK; } From 5ac3541cb4ef3b721ce98cf0212b1195ff4c0568 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 15 Oct 2025 08:27:48 +0200 Subject: [PATCH 446/465] ftp: replace strstr() in ;type= handling Since it needs to be a trailing piece of the path avoiding strstr() is faster and more reliable. Also stopped checking the host name since it cannot actually be there since quite a long while back. The URL parser doesn't allow such a hostname. Moved the check into its own subfunction too. Closes #19069 --- lib/ftp.c | 59 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/lib/ftp.c b/lib/ftp.c index f633d213058a..58b34eab6d95 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -4420,10 +4420,38 @@ static void ftp_conn_dtor(void *key, size_t klen, void *entry) free(ftpc); } +static void type_url_check(struct Curl_easy *data, struct FTP *ftp) +{ + size_t len = strlen(ftp->path); + /* FTP URLs support an extension like ";type=" that + * we will try to get now! */ + if((len >= 7) && !memcmp(&ftp->path[len - 7], ";type=", 6)) { + char *type = &ftp->path[len - 7]; + char command = Curl_raw_toupper(type[6]); + + *type = 0; /* cut it off */ + + switch(command) { + case 'A': /* ASCII mode */ + data->state.prefer_ascii = TRUE; + break; + + case 'D': /* directory mode */ + data->state.list_only = TRUE; + break; + + case 'I': /* binary mode */ + default: + /* switch off ASCII */ + data->state.prefer_ascii = FALSE; + break; + } + } +} + static CURLcode ftp_setup_connection(struct Curl_easy *data, struct connectdata *conn) { - char *type; struct FTP *ftp; CURLcode result = CURLE_OK; struct ftp_conn *ftpc; @@ -4458,34 +4486,7 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data, ftp->path = &data->state.up.path[1]; /* do not include the initial slash */ - /* FTP URLs support an extension like ";type=" that - * we will try to get now! */ - type = strstr(ftp->path, ";type="); - - if(!type) - type = strstr(conn->host.rawalloc, ";type="); - - if(type) { - char command; - *type = 0; /* it was in the middle of the hostname */ - command = Curl_raw_toupper(type[6]); - - switch(command) { - case 'A': /* ASCII mode */ - data->state.prefer_ascii = TRUE; - break; - - case 'D': /* directory mode */ - data->state.list_only = TRUE; - break; - - case 'I': /* binary mode */ - default: - /* switch off ASCII */ - data->state.prefer_ascii = FALSE; - break; - } - } + type_url_check(data, ftp); /* get some initial data into the ftp struct */ ftp->transfer = PPTRANSFER_BODY; From be852e39b25a4abbb7e5ecbe89d72f410ccfb3a8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 15 Oct 2025 08:42:20 +0200 Subject: [PATCH 447/465] tftp: check for trailing ";mode=" in URL without strstr RFC 3617 defines two specific modes, "netascii" and "octet". This code now checks only for those trailing ones - and not in the hostname since they can't be there anymore. Assisted-by: Jay Satiro Closes #19070 --- docs/cmdline-opts/use-ascii.md | 9 +++++---- lib/tftp.c | 36 ++++++++++------------------------ src/tool_listhelp.c | 2 +- tests/data/test1093 | 4 ++-- 4 files changed, 18 insertions(+), 33 deletions(-) diff --git a/docs/cmdline-opts/use-ascii.md b/docs/cmdline-opts/use-ascii.md index 30cc860b0a21..4dba446ffebf 100644 --- a/docs/cmdline-opts/use-ascii.md +++ b/docs/cmdline-opts/use-ascii.md @@ -4,8 +4,8 @@ SPDX-License-Identifier: curl Short: B Long: use-ascii Help: Use ASCII/text transfer -Protocols: FTP LDAP -Category: ftp output ldap +Protocols: FTP LDAP TFTP +Category: ftp output ldap tftp Added: 5.0 Multi: boolean See-also: @@ -18,5 +18,6 @@ Example: # `--use-ascii` Enable ASCII transfer mode. For FTP, this can also be enforced by using a URL -that ends with `;type=A`. This option causes data sent to stdout to be in text -mode for Win32 systems. +that ends with `;type=A`. For TFTP, this can also be enforced by using a URL +that ends with `;mode=netascii`. This option causes data sent to stdout to be +in text mode for Win32 systems. diff --git a/lib/tftp.c b/lib/tftp.c index 0a9b8a8e870b..d9d978c24e90 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -1379,35 +1379,19 @@ static CURLcode tftp_do(struct Curl_easy *data, bool *done) static CURLcode tftp_setup_connection(struct Curl_easy *data, struct connectdata *conn) { - char *type; + char *path = data->state.up.path; + size_t len = strlen(path); conn->transport_wanted = TRNSPRT_UDP; - /* TFTP URLs support an extension like ";mode=" that - * we will try to get now! */ - type = strstr(data->state.up.path, ";mode="); - - if(!type) - type = strstr(conn->host.rawalloc, ";mode="); - - if(type) { - char command; - *type = 0; /* it was in the middle of the hostname */ - command = Curl_raw_toupper(type[6]); - - switch(command) { - case 'A': /* ASCII mode */ - case 'N': /* NETASCII mode */ - data->state.prefer_ascii = TRUE; - break; - - case 'O': /* octet mode */ - case 'I': /* binary mode */ - default: - /* switch off ASCII */ - data->state.prefer_ascii = FALSE; - break; - } + /* TFTP URLs support a trailing ";mode=netascii" or ";mode=octet" */ + if((len >= 14) && !memcmp(&path[len - 14], ";mode=netascii", 14)) { + data->state.prefer_ascii = TRUE; + path[len - 14] = 0; /* cut it there */ + } + else if((len >= 11) && !memcmp(&path[len - 11], ";mode=octet", 11)) { + data->state.prefer_ascii = FALSE; + path[len - 11] = 0; /* cut it there */ } return CURLE_OK; diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c index c8e31e77a6ae..21019c7de161 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -834,7 +834,7 @@ const struct helptxt helptext[] = { CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD}, {"-B, --use-ascii", "Use ASCII/text transfer", - CURLHELP_FTP | CURLHELP_OUTPUT | CURLHELP_LDAP}, + CURLHELP_FTP | CURLHELP_OUTPUT | CURLHELP_LDAP | CURLHELP_TFTP}, {"-u, --user ", "Server user and password", CURLHELP_IMPORTANT | CURLHELP_AUTH}, diff --git a/tests/data/test1093 b/tests/data/test1093 index 1bed99bec18f..a135876ae0c8 100644 --- a/tests/data/test1093 +++ b/tests/data/test1093 @@ -25,10 +25,10 @@ returned tftp -TFTP retrieve with mode=i +TFTP retrieve with mode=octet -"tftp://%HOSTIP:%TFTPPORT//%TESTNUMBER;mode=i" --use-ascii +"tftp://%HOSTIP:%TFTPPORT//%TESTNUMBER;mode=octet" --use-ascii From 182a5a9aae7290332792b14100db1a9451f75ab5 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 14 Oct 2025 15:53:37 +0200 Subject: [PATCH 448/465] quic: remove data_idle handling The transfer loop used to check the socket and if no poll events were seen, triggered a "DATA_IDLE" event into the filters to let them schedule times/do things anyway. Since we no longer check the socket, the filters have been called already and the DATA_IDLE event is unnecessary work. Remove it. Closes #19060 --- lib/cfilters.c | 7 ------- lib/cfilters.h | 8 +------- lib/transfer.c | 22 +++++----------------- lib/vquic/curl_ngtcp2.c | 10 ---------- lib/vquic/curl_osslq.c | 8 -------- lib/vquic/curl_quiche.c | 9 --------- 6 files changed, 6 insertions(+), 58 deletions(-) diff --git a/lib/cfilters.c b/lib/cfilters.c index bd060f43dc98..2ef5d75d431c 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -966,13 +966,6 @@ CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data) CF_CTRL_DATA_SETUP, 0, NULL); } -CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data) -{ - return cf_cntrl_all(data->conn, data, FALSE, - CF_CTRL_DATA_IDLE, 0, NULL); -} - - CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex) { if(!CONN_SOCK_IDX_VALID(sockindex)) diff --git a/lib/cfilters.h b/lib/cfilters.h index af38191a931d..2fab300b211a 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -118,7 +118,7 @@ typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf, */ /* data event arg1 arg2 return */ #define CF_CTRL_DATA_SETUP 4 /* 0 NULL first fail */ -#define CF_CTRL_DATA_IDLE 5 /* 0 NULL first fail */ +/* unused now 5 */ #define CF_CTRL_DATA_PAUSE 6 /* on/off NULL first fail */ #define CF_CTRL_DATA_DONE 7 /* premature NULL ignored */ #define CF_CTRL_DATA_DONE_SEND 8 /* 0 NULL ignored */ @@ -539,12 +539,6 @@ CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf, */ CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data); -/** - * Notify connection filters that now would be a good time to - * perform any idle, e.g. time related, actions. - */ -CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data); - /** * Notify connection filters that the transfer represented by `data` * is done with sending data (e.g. has uploaded everything). diff --git a/lib/transfer.c b/lib/transfer.c index e8c030687a5e..d20440fec744 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -244,8 +244,7 @@ static ssize_t xfer_recv_resp(struct Curl_easy *data, * buffer) */ static CURLcode sendrecv_dl(struct Curl_easy *data, - struct SingleRequest *k, - int *didwhat) + struct SingleRequest *k) { struct connectdata *conn = data->conn; CURLcode result = CURLE_OK; @@ -309,7 +308,6 @@ static CURLcode sendrecv_dl(struct Curl_easy *data, /* We only get a 0-length receive at the end of the response */ blen = (size_t)nread; is_eos = (blen == 0); - *didwhat |= KEEP_RECV; if(!blen) { /* if we receive 0 or less here, either the data transfer is done or the @@ -369,17 +367,15 @@ static CURLcode sendrecv_dl(struct Curl_easy *data, /* * Send data to upload to the server, when the socket is writable. */ -static CURLcode sendrecv_ul(struct Curl_easy *data, int *didwhat) +static CURLcode sendrecv_ul(struct Curl_easy *data) { /* We should not get here when the sending is already done. It * probably means that someone set `data-req.keepon |= KEEP_SEND` * when it should not. */ DEBUGASSERT(!Curl_req_done_sending(data)); - if(!Curl_req_done_sending(data)) { - *didwhat |= KEEP_SEND; + if(!Curl_req_done_sending(data)) return Curl_req_send_more(data); - } return CURLE_OK; } @@ -391,7 +387,6 @@ CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp) { struct SingleRequest *k = &data->req; CURLcode result = CURLE_OK; - int didwhat = 0; DEBUGASSERT(nowp); if(Curl_xfer_is_blocked(data)) { @@ -402,21 +397,14 @@ CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp) /* We go ahead and do a read if we have a readable socket or if the stream was rewound (in which case we have data in a buffer) */ if(k->keepon & KEEP_RECV) { - result = sendrecv_dl(data, k, &didwhat); + result = sendrecv_dl(data, k); if(result || data->req.done) goto out; } /* If we still have writing to do, we check if we have a writable socket. */ if(Curl_req_want_send(data) || (data->req.keepon & KEEP_SEND_TIMED)) { - result = sendrecv_ul(data, &didwhat); - if(result) - goto out; - } - - if(!didwhat) { - /* Transfer wanted to send/recv, but nothing was possible. */ - result = Curl_conn_ev_data_idle(data); + result = sendrecv_ul(data); if(result) goto out; } diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 68f346af780a..53665b1a3d1d 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2040,16 +2040,6 @@ static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf, } break; } - case CF_CTRL_DATA_IDLE: { - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - CURL_TRC_CF(data, cf, "data idle"); - if(stream && !stream->closed) { - result = check_and_set_expiry(cf, data, NULL); - if(result) - CURL_TRC_CF(data, cf, "data idle, check_and_set_expiry -> %d", result); - } - break; - } case CF_CTRL_CONN_INFO_UPDATE: if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 4d72797199c5..a49074346270 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -2207,14 +2207,6 @@ static CURLcode cf_osslq_cntrl(struct Curl_cfilter *cf, } break; } - case CF_CTRL_DATA_IDLE: { - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - CURL_TRC_CF(data, cf, "data idle"); - if(stream && !stream->closed) { - result = check_and_set_expiry(cf, data); - } - break; - } case CF_CTRL_CONN_INFO_UPDATE: if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 1ae159bd4cd6..55f6e79ebefc 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1232,15 +1232,6 @@ static CURLcode cf_quiche_cntrl(struct Curl_cfilter *cf, } break; } - case CF_CTRL_DATA_IDLE: { - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - if(stream && !stream->closed) { - result = cf_flush_egress(cf, data); - if(result) - CURL_TRC_CF(data, cf, "data idle, flush egress -> %d", result); - } - break; - } case CF_CTRL_CONN_INFO_UPDATE: if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; From 5e46318414590c99fc98709598e5e3441d63648b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emre=20=C3=87al=C4=B1=C5=9Fkan?= Date: Tue, 14 Oct 2025 21:35:54 +0300 Subject: [PATCH 449/465] transfer: reset retry count on each request Reported-by: plv1313 on github Fixes #18926 Closes #19066 --- lib/easy.c | 1 - lib/transfer.c | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/easy.c b/lib/easy.c index 877cf13b9baf..793a18f33eb8 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -1119,7 +1119,6 @@ void curl_easy_reset(CURL *d) data->progress.hide = TRUE; data->state.current_speed = -1; /* init to negative == impossible */ - data->state.retrycount = 0; /* reset the retry counter */ data->state.recent_conn_id = -1; /* clear remembered connection id */ /* zero out authentication data: */ diff --git a/lib/transfer.c b/lib/transfer.c index d20440fec744..d7014aab87e5 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -481,6 +481,14 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) { CURLcode result = CURLE_OK; + /* Reset the retry count at the start of each request. + * If the retry count is not reset, when the connection drops, + * it will not enter the retry mechanism on CONN_MAX_RETRIES + 1 attempts + * and will immediately throw + * "Connection died, tried CONN_MAX_RETRIES times before giving up". + * By resetting it here, we ensure each new request starts fresh. */ + data->state.retrycount = 0; + if(!data->set.str[STRING_SET_URL] && !data->set.uh) { /* we cannot do anything without URL */ failf(data, "No URL set"); From 62961d6cc57deb9beeba32d0ccdbdeec40eea096 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 14 Oct 2025 14:43:46 +0200 Subject: [PATCH 450/465] lib: stop NULL-checking conn->passwd and ->user They always point to a string. The string might be zero length. Closes #19059 --- lib/ftp.c | 2 +- lib/pop3.c | 3 +-- lib/vssh/libssh2.c | 9 ++------- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/ftp.c b/lib/ftp.c index 58b34eab6d95..fd957a2bb485 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -2606,7 +2606,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data, /* 331 Password required for ... (the server requires to send the user's password too) */ result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s", - data->conn->passwd ? data->conn->passwd : ""); + data->conn->passwd); if(!result) ftp_state(data, ftpc, FTP_PASS); } diff --git a/lib/pop3.c b/lib/pop3.c index a0fd881a791f..2fd496cb3142 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1057,8 +1057,7 @@ static CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code, } else /* Send the PASS command */ - result = Curl_pp_sendf(data, &pop3c->pp, "PASS %s", - conn->passwd ? conn->passwd : ""); + result = Curl_pp_sendf(data, &pop3c->pp, "PASS %s", conn->passwd); if(!result) pop3_state(data, POP3_PASS); diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index dc972dc9e67a..f9160944befe 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -3335,14 +3335,9 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) function to make the reuse checks properly be able to check this bit. */ connkeep(conn, "SSH default"); - if(conn->user) - infof(data, "User: '%s'", conn->user); - else - infof(data, "User: NULL"); + infof(data, "User: '%s'", conn->user); #ifdef CURL_LIBSSH2_DEBUG - if(conn->passwd) { - infof(data, "Password: %s", conn->passwd); - } + infof(data, "Password: %s", conn->passwd); sock = conn->sock[FIRSTSOCKET]; #endif /* CURL_LIBSSH2_DEBUG */ From b7f2355b8b5cfa137aa2848c4ace951a317718f9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 15 Oct 2025 10:48:42 +0200 Subject: [PATCH 451/465] urldata: make 'retrycount' a single byte Since it only counts up to 5 Closes #19071 --- lib/urldata.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/urldata.h b/lib/urldata.h index 30bbbae416e4..e181e294bb27 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -980,8 +980,6 @@ struct UrlState { char *first_host; int first_remote_port; curl_prot_t first_remote_protocol; - - int retrycount; /* number of retries on a new connection */ int os_errno; /* filled in with errno whenever an error occurs */ long followlocation; /* redirect counter */ int requests; /* request counter: redirects + authentication retakes */ @@ -1103,6 +1101,8 @@ struct UrlState { #ifndef CURL_DISABLE_HTTP struct http_negotiation http_neg; #endif + unsigned char retrycount; /* number of retries on a new connection, up to + CONN_MAX_RETRIES */ unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any) is this */ unsigned int creds_from:2; /* where is the server credentials originating From f8cd64e3abaae0ea7289c380362571060d0a1160 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 15 Oct 2025 10:56:47 +0200 Subject: [PATCH 452/465] urldata: make redirect counter 16 bit Instead of long (up to 64-bit) as the maximum allowed value set since b059f7deaf3 is 0x7fff. Saves 2 or 6 bytes. Closes #19072 --- lib/urldata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/urldata.h b/lib/urldata.h index e181e294bb27..c7e19201fe88 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -981,7 +981,6 @@ struct UrlState { int first_remote_port; curl_prot_t first_remote_protocol; int os_errno; /* filled in with errno whenever an error occurs */ - long followlocation; /* redirect counter */ int requests; /* request counter: redirects + authentication retakes */ #ifdef HAVE_SIGNAL /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */ @@ -1101,6 +1100,7 @@ struct UrlState { #ifndef CURL_DISABLE_HTTP struct http_negotiation http_neg; #endif + unsigned short followlocation; /* redirect counter */ unsigned char retrycount; /* number of retries on a new connection, up to CONN_MAX_RETRIES */ unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any) From 71d5525113171903deb9b97cc1913c30f515cc63 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 16 Oct 2025 08:32:57 +0200 Subject: [PATCH 453/465] connect: remove redundant condition in shutdown start Pointed out by CodeSonar Closes #19079 --- lib/connect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/connect.c b/lib/connect.c index 1c312095674d..5dc4e2fc747b 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -171,7 +171,7 @@ void Curl_shutdown_start(struct Curl_easy *data, int sockindex, ((data->set.shutdowntimeout > 0) ? data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS); /* Set a timer, unless we operate on the admin handle */ - if(data->mid && (conn->shutdown.timeout_ms > 0)) + if(data->mid) Curl_expire_ex(data, nowp, conn->shutdown.timeout_ms, EXPIRE_SHUTDOWN); } From 79553fb7c65668e0df4afade0f76a19a31dd1157 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 16 Oct 2025 09:01:17 +0200 Subject: [PATCH 454/465] RELEASE-NOTES: synced --- RELEASE-NOTES | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 986a21bea742..0930a2719e04 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,7 +4,7 @@ curl and libcurl 8.17.0 Command line options: 273 curl_easy_setopt() options: 308 Public functions in libcurl: 100 - Contributors: 3517 + Contributors: 3519 This release includes the following changes: @@ -48,6 +48,7 @@ This release includes the following bugfixes: o cf-socket: tweak a memcpy() to read better [177] o cf-socket: use the right byte order for ports in bindlocal [61] o cfilter: unlink and discard [46] + o checksrc: allow disabling warnings on FIXME/TODO comments [324] o checksrc: catch banned functions when preceded by `(` [146] o checksrc: fix possible endless loop when detecting `BANNEDFUNC` [149] o checksrc: fix possible endless loops/errors in the banned function logic [220] @@ -73,6 +74,7 @@ This release includes the following bugfixes: o cmdline-opts/_PROGRESS.md: explain the suffixes [154] o configure: add "-mt" for pthread support on HP-UX [52] o conn: fix hostname move on connection reuse [272] + o connect: remove redundant condition in shutdown start [289] o cookie: avoid saving a cookie file if no transfer was done [11] o cpool: make bundle->dest an array; fix UB [218] o curl_easy_getinfo: error code on NULL arg [2] @@ -102,11 +104,15 @@ This release includes the following bugfixes: o examples/synctime: fix null termination assumptions [297] o examples/synctime: make the sscanf not overflow the local buffer [252] o examples/usercertinmem: avoid stripping const [247] + o examples: call `curl_global_cleanup()` where missing [323] + o examples: check more errors, fix cleanups, scope variables [318] o examples: drop unused `curl/mprintf.h` includes [224] o examples: fix build issues in 'complicated' examples [243] o examples: fix two build issues surfaced with WinCE [223] o examples: fix two issues found by CodeQL [35] o examples: fix two more cases of `stat()` TOCTOU [147] + o examples: improve global init, error checks and returning errors [321] + o examples: return `curl_easy_perform()` results [322] o form.md: drop reference to MANUAL [178] o ftp: add extra buffer length check [195] o ftp: fix ftp_do_more returning with *completep unset [122] @@ -114,6 +120,7 @@ This release includes the following bugfixes: o ftp: fix the 213 scanner memchr buffer limit argument [196] o ftp: improve fragile check for first digit > 3 [194] o ftp: remove misleading comments [193] + o ftp: replace strstr() in ;type= handling [313] o ftp: simplify the 150/126 size scanner [288] o gnutls: check conversion of peer cert chain [275] o gtls: avoid potential use of uninitialized variable in trace output [83] @@ -123,6 +130,7 @@ This release includes the following bugfixes: o http2: cleanup pushed newhandle on fail [260] o http2: ingress handling edge cases [259] o http: handle user-defined connection headers [165] + o http: look for trailing 'type=' in ftp:// without strstr [315] o http: make Content-Length parser more WHATWG [183] o httpsrr: free old pointers when storing new [57] o INSTALL-CMAKE.md: document useful build targets [215] @@ -143,6 +151,7 @@ This release includes the following bugfixes: o lib: fix build error and compiler warnings with verbose strings disabled [173] o lib: remove personal names from comments [168] o lib: SSL connection reuse [301] + o lib: stop NULL-checking conn->passwd and ->user [309] o lib: upgrade/multiplex handling [136] o libcurl-multi.md: added curl_multi_get_offt mention [53] o libcurl-security.md: mention long-running connections [6] @@ -212,6 +221,7 @@ This release includes the following bugfixes: o pytest: skip specific tests for no-verbose builds [171] o quic: fix min TLS version handling [14] o quic: ignore EMSGSIZE on receive [4] + o quic: remove data_idle handling [311] o quiche: fix possible leaks on teardown [205] o quiche: fix verbose message when ip quadruple cannot be obtained. [128] o quiche: handle tls fail correctly [266] @@ -264,6 +274,7 @@ This release includes the following bugfixes: o tests/server: drop pointless memory allocation overrides [219] o tests/server: drop unsafe `open()` override in signal handler (Windows) [151] o tftp: check and act on tftp_set_timeouts() returning error [38] + o tftp: check for trailing ";mode=" in URL without strstr [312] o tftp: default timeout per block is now 15 seconds [156] o tftp: error requests for blank filenames [296] o tftp: handle tftp_multi_statemach() return code [65] @@ -293,13 +304,17 @@ This release includes the following bugfixes: o tool_operate: improve wording in retry message [37] o tool_operate: keep failed partial download for retry auto-resume [210] o tool_operate: keep the progress meter for --out-null [33] + o tool_operate: retry on HTTP response codes 522 and 524 [317] o tool_progress: handle possible integer overflows [164] o tool_progress: make max5data() use an algorithm [170] o transfer: avoid busy loop with tiny speed limit [100] + o transfer: reset retry count on each request [310] o unit1323: sync time types and printf masks, drop casts [211] o unit1664: drop casts, expand masks to full values [221] o url: make Curl_init_userdefined return void [213] o urldata: FILE is not a list-only protocol [9] + o urldata: make 'retrycount' a single byte [308] + o urldata: make redirect counter 16 bit [295] o vauth/digest: improve the digest parser [203] o vquic: fix idle-timeout checks (ms<-->ns), 64-bit log & honor 0=no-timeout [249] o vquic: handling of io improvements [239] @@ -316,6 +331,7 @@ This release includes the following bugfixes: o wolfssl: no double get_error() detail [188] o ws: clarify an error message [125] o ws: fix some edge cases [274] + o ws: fix type conversion check [316] o ws: reject curl_ws_recv called with NULL buffer with a buflen [118] This release includes the following known bugs: @@ -343,16 +359,16 @@ advice from friends like these: Adam Light, Alice Lee Poetics, Andrei Kurushin, Andrew Kirillov, Andrew Olsen, BobodevMm on github, Christian Schmitz, Dan Fandrich, Daniel Stenberg, Daniel Terhorst-North, dependabot[bot], - divinity76 on github, Emilio Pozuelo Monfort, Ethan Everett, + divinity76 on github, Emilio Pozuelo Monfort, Emre Çalışkan, Ethan Everett, Evgeny Grin (Karlson2k), fds242 on github, Harry Sintonen, Howard Chu, Ignat Loskutov, Javier Blazquez, Jicea, jmaggard10 on github, Johannes Schindelin, Joseph Birr-Pixton, Joshua Rogers, kapsiR on github, kuchara on github, Marcel Raad, Michael Osipov, Michał Petryka, Mitchell Blank Jr, Mohamed Daahir, Nir Azkiel, Patrick Monnerat, - Pocs Norbert, Ray Satiro, renovate[bot], rinsuki on github, Sakthi SK, - Samuel Dionne-Riel, Samuel Henrique, Stanislav Fort, Stefan Eissing, - tkzv on github, Viktor Szakats - (45 contributors) + plv1313 on github, Pocs Norbert, Ray Satiro, renovate[bot], + rinsuki on github, Sakthi SK, Samuel Dionne-Riel, Samuel Henrique, + Stanislav Fort, Stefan Eissing, tkzv on github, Viktor Szakats + (47 contributors) References to bug reports and discussions on issues: @@ -644,11 +660,13 @@ References to bug reports and discussions on issues: [286] = https://curl.se/bug/?i=18986 [287] = https://curl.se/bug/?i=18985 [288] = https://curl.se/bug/?i=18984 + [289] = https://curl.se/bug/?i=19079 [290] = https://curl.se/bug/?i=19042 [291] = https://curl.se/bug/?i=19040 [292] = https://curl.se/bug/?i=19039 [293] = https://curl.se/bug/?i=19029 [294] = https://curl.se/bug/?i=19035 + [295] = https://curl.se/bug/?i=19072 [296] = https://curl.se/bug/?i=19033 [297] = https://curl.se/bug/?i=19032 [298] = https://curl.se/bug/?i=19031 @@ -661,3 +679,17 @@ References to bug reports and discussions on issues: [305] = https://curl.se/bug/?i=19026 [306] = https://curl.se/bug/?i=19014 [307] = https://curl.se/bug/?i=18996 + [308] = https://curl.se/bug/?i=19071 + [309] = https://curl.se/bug/?i=19059 + [310] = https://curl.se/bug/?i=18926 + [311] = https://curl.se/bug/?i=19060 + [312] = https://curl.se/bug/?i=19070 + [313] = https://curl.se/bug/?i=19069 + [315] = https://curl.se/bug/?i=19065 + [316] = https://curl.se/bug/?i=19017 + [317] = https://curl.se/bug/?i=16143 + [318] = https://curl.se/bug/?i=19055 + [321] = https://curl.se/bug/?i=19053 + [322] = https://curl.se/bug/?i=19052 + [323] = https://curl.se/bug/?i=19051 + [324] = https://curl.se/bug/?i=19048 From c37ed9a11e57c2f416ab29c5fda8d6bd813acd89 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 14 Oct 2025 12:13:24 +0200 Subject: [PATCH 455/465] apple sectrust: add to features It should be visible in the feature list that libcurl is build with Apple SecTrust enabled. Closes #19057 --- CMakeLists.txt | 4 ++++ configure.ac | 4 ++++ docs/libcurl/curl_version_info.md | 7 +++++++ lib/version.c | 3 +++ lib/vtls/apple.c | 8 ++++---- lib/vtls/apple.h | 4 ++-- lib/vtls/vtls.c | 2 +- m4/curl-apple-sectrust.m4 | 7 +++++-- 8 files changed, 30 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b48b0452842d..bb2dc54f1d23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -767,6 +767,9 @@ endif() if(APPLE) option(USE_APPLE_SECTRUST "Use Apple OS-native certificate verification" OFF) if(USE_APPLE_SECTRUST) + if(NOT CURL_USE_OPENSSL AND NOT CURL_USE_GNUTLS) + message(FATAL_ERROR "Apple SecTrust is only supported with Openssl/GnuTLS") + endif() find_library(COREFOUNDATION_FRAMEWORK NAMES "Security") mark_as_advanced(COREFOUNDATION_FRAMEWORK) if(NOT COREFOUNDATION_FRAMEWORK) @@ -2173,6 +2176,7 @@ curl_add_if("HTTPSRR" _ssl_enabled AND USE_HTTPSRR) curl_add_if("PSL" USE_LIBPSL) curl_add_if("CAcert" CURL_CA_EMBED_SET) curl_add_if("SSLS-EXPORT" _ssl_enabled AND USE_SSLS_EXPORT) +curl_add_if("AppleSecTrust" USE_APPLE_SECTRUST AND _ssl_enabled AND (USE_OPENSSL OR USE_GNUTLS)) if(_items) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) list(SORT _items CASE INSENSITIVE) diff --git a/configure.ac b/configure.ac index 0880552cfbac..3b4ebf964988 100644 --- a/configure.ac +++ b/configure.ac @@ -5304,6 +5304,10 @@ if test "x$OPENSSL_ENABLED" = "x1" -o -n "$SSL_ENABLED"; then fi fi +if test "x$APPLE_SECTRUST_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES AppleSecTrust" +fi + if test "x$want_httpsrr" != "xno"; then SUPPORT_FEATURES="$SUPPORT_FEATURES HTTPSRR" fi diff --git a/docs/libcurl/curl_version_info.md b/docs/libcurl/curl_version_info.md index a9c97b39c596..3620f60ca68b 100644 --- a/docs/libcurl/curl_version_info.md +++ b/docs/libcurl/curl_version_info.md @@ -159,6 +159,13 @@ entry. HTTP Alt-Svc parsing and the associated options (Added in 7.64.1) +## `AppleSecTrust` + +*features* mask bit: non-existent + +libcurl was built with support for Apple's SecTrust service to verify +server certificates (Added in 8.17.0). + ## `AsynchDNS` *features* mask bit: CURL_VERSION_ASYNCHDNS diff --git a/lib/version.c b/lib/version.c index 3798fed6e1d9..7c9ac12fb93e 100644 --- a/lib/version.c +++ b/lib/version.c @@ -523,6 +523,9 @@ static const struct feat features_table[] = { #ifdef USE_LIBPSL FEATURE("PSL", NULL, CURL_VERSION_PSL), #endif +#ifdef USE_APPLE_SECTRUST + FEATURE("AppleSecTrust", NULL, 0), +#endif #ifdef USE_SPNEGO FEATURE("SPNEGO", NULL, CURL_VERSION_SPNEGO), #endif diff --git a/lib/vtls/apple.c b/lib/vtls/apple.c index c96ebe037bc6..87d5208d735a 100644 --- a/lib/vtls/apple.c +++ b/lib/vtls/apple.c @@ -46,16 +46,16 @@ #include "vtls.h" #include "apple.h" -#if defined(USE_SSL) && defined(USE_APPLE_SECTRUST) +#ifdef USE_APPLE_SECTRUST #include -#endif /* USE_SSL && USE_APPLE_SECTRUST */ +#endif /* The last #include files should be: */ #include "../curl_memory.h" #include "../memdebug.h" -#if defined(USE_SSL) && defined(USE_APPLE_SECTRUST) +#ifdef USE_APPLE_SECTRUST #define SSL_SYSTEM_VERIFIER #if (defined(MAC_OS_X_VERSION_MAX_ALLOWED) \ @@ -294,4 +294,4 @@ CURLcode Curl_vtls_apple_verify(struct Curl_cfilter *cf, return result; } -#endif /* USE_SSL && USE_APPLE_SECTRUST */ +#endif /* USE_APPLE_SECTRUST */ diff --git a/lib/vtls/apple.h b/lib/vtls/apple.h index c965a449f14f..3d84f8782288 100644 --- a/lib/vtls/apple.h +++ b/lib/vtls/apple.h @@ -26,7 +26,7 @@ #include "../curl_setup.h" -#if defined(USE_SSL) && defined(USE_APPLE_SECTRUST) +#ifdef USE_APPLE_SECTRUST struct Curl_cfilter; struct Curl_easy; struct ssl_peer; @@ -50,6 +50,6 @@ CURLcode Curl_vtls_apple_verify(struct Curl_cfilter *cf, void *cb_user_data, const unsigned char *ocsp_buf, size_t ocsp_len); -#endif /* USE_SSL && USE_APPLE_SECTRUST */ +#endif /* USE_APPLE_SECTRUST */ #endif /* HEADER_CURL_VTLS_APPLE_H */ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index b715dab035d2..7ee9699dbf0b 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -80,7 +80,7 @@ #ifdef USE_APPLE_SECTRUST #include -#endif /* USE_APPLE_SECTRUST */ +#endif /* The last #include files should be: */ #include "../curl_memory.h" diff --git a/m4/curl-apple-sectrust.m4 b/m4/curl-apple-sectrust.m4 index 792f719d38af..7ed2aa1e5bff 100644 --- a/m4/curl-apple-sectrust.m4 +++ b/m4/curl-apple-sectrust.m4 @@ -41,7 +41,10 @@ if test "x$OPT_APPLE_SECTRUST" = xyes; then ],[ build_for_apple="no" ]) - if test "x$build_for_apple" != "xno"; then + if test "x$build_for_apple" == "xno"; then + AC_MSG_ERROR([Apple SecTrust can only be enabled for Apple OS targets]) + fi + if test "x$OPENSSL_ENABLED" == "x1" -o "x$GNUTLS_ENABLED" == "x1"; then AC_MSG_RESULT(yes) AC_DEFINE(USE_APPLE_SECTRUST, 1, [enable Apple OS certificate validation]) APPLE_SECTRUST_ENABLED=1 @@ -49,7 +52,7 @@ if test "x$OPT_APPLE_SECTRUST" = xyes; then LDFLAGS="$LDFLAGS $APPLE_SECTRUST_LDFLAGS" LDFLAGSPC="$LDFLAGSPC $APPLE_SECTRUST_LDFLAGS" else - AC_MSG_RESULT(no) + AC_MSG_ERROR([Apple SecTrust is only supported for OpenSSL/GnuTLS builds]) fi else AC_MSG_RESULT(no) From 9c36eace607190d2e3931b04c8a36ee7c4b0120a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 16 Oct 2025 05:33:12 +0200 Subject: [PATCH 456/465] autotools: drop detection of ancient OpenSSL libs `RSAglue` and `rsaref` Closes #19078 --- m4/curl-openssl.m4 | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/m4/curl-openssl.m4 b/m4/curl-openssl.m4 index c421fbae883c..56245c9c2a9e 100644 --- a/m4/curl-openssl.m4 +++ b/m4/curl-openssl.m4 @@ -209,22 +209,7 @@ if test "x$OPT_OPENSSL" != xno; then AC_CHECK_LIB(ssl, SSL_connect) - if test "$ac_cv_lib_ssl_SSL_connect" != yes; then - dnl we didn't find the SSL lib, try the RSAglue/rsaref stuff - AC_MSG_CHECKING(for ssl with RSAglue/rsaref libs in use); - OLIBS=$LIBS - LIBS="-lRSAglue -lrsaref $LIBS" - AC_CHECK_LIB(ssl, SSL_connect) - if test "$ac_cv_lib_ssl_SSL_connect" != yes; then - dnl still no SSL_connect - AC_MSG_RESULT(no) - LIBS=$OLIBS - else - AC_MSG_RESULT(yes) - fi - - else - + if test "$ac_cv_lib_ssl_SSL_connect" = yes; then dnl Have the libraries--check for OpenSSL headers AC_CHECK_HEADERS(openssl/x509.h openssl/rsa.h openssl/crypto.h \ openssl/pem.h openssl/ssl.h openssl/err.h, From 1a81a8e478ec426316c98e24a30d16df483ed8db Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 15 Oct 2025 15:06:08 +0200 Subject: [PATCH 457/465] version: add GSS backend name and version MIT Kerberos version detection is implemented for autotools and cmake. Examples: ``` curl 8.17.0-DEV (x86_64-pc-linux-gnu) ... mbedTLS/3.6.4 libidn2/2.3.7 nghttp2/1.59.0 libgss/1.0.4 OpenLDAP/2.6.7 curl 8.17.0-DEV (x86_64-pc-linux-gnu) ... LibreSSL/4.1.1 libidn2/2.3.7 nghttp2/1.59.0 mit-krb5/1.20.1 OpenLDAP/2.6.7 curl 8.17.0-DEV (x86_64-pc-linux-gnu) ... LibreSSL/4.1.1 libidn2/2.3.7 nghttp2/1.59.0 mit-krb5 OpenLDAP/2.6.7 curl 8.17.0-DEV (x86_64-pc-linux-gnu) ... LibreSSL/4.1.1 nghttp2/1.59.0 mit-krb5/1.20.1 OpenLDAP/2.6.7 curl 8.17.0-DEV (aarch64e-apple-darwin24.6.0) ... GnuTLS/3.8.10 libidn2/2.3.8 libssh2/1.11.1 nghttp2/1.67.1 mit-krb5/1.22.1 ``` Also: - cmake/FindGSS: strip project name ("Kerberos 5 release") from the version string when detected via `krb5-config`. Closes #19073 --- CMake/FindGSS.cmake | 3 +++ CMakeLists.txt | 2 ++ configure.ac | 12 ++++++++++++ lib/curl_config.h.cmake | 3 +++ lib/version.c | 23 +++++++++++++++++++++++ 5 files changed, 43 insertions(+) diff --git a/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index db36cf2100bc..1661f208d2f8 100644 --- a/CMake/FindGSS.cmake +++ b/CMake/FindGSS.cmake @@ -128,6 +128,9 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr # Older versions may not have the "--version" parameter. In this case we just do not care. if(_gss_configure_failed) set(_gss_version 0) + else() + # Strip prefix string to leave the version number only + string(REPLACE "Kerberos 5 release " "" _gss_version "${_gss_version}") endif() execute_process(COMMAND ${_gss_configure_script} "--vendor" diff --git a/CMakeLists.txt b/CMakeLists.txt index bb2dc54f1d23..65eaaf670a5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1445,6 +1445,8 @@ if(CURL_USE_GSSAPI) if(GSS_FLAVOUR STREQUAL "GNU") set(HAVE_GSSGNU 1) + elseif(GSS_VERSION) # MIT + set(CURL_KRB5_VERSION "\"${GSS_VERSION}\"") endif() else() message(WARNING "GSSAPI has been requested, but no supporting libraries found. Skipping.") diff --git a/configure.ac b/configure.ac index 3b4ebf964988..999ab122a323 100644 --- a/configure.ac +++ b/configure.ac @@ -1909,6 +1909,18 @@ if test x"$want_gss" = xyes; then fi fi fi + gss_version="" + if test -n "$host_alias" -a -f "$GSSAPI_ROOT/bin/$host_alias-krb5-config"; then + gss_version=`$GSSAPI_ROOT/bin/$host_alias-krb5-config --version | $SED 's/Kerberos 5 release //'` + elif test "$PKGCONFIG" != "no"; then + gss_version=`$PKGCONFIG --modversion mit-krb5-gssapi` + elif test -f "$KRB5CONFIG"; then + gss_version=`$KRB5CONFIG --version | $SED 's/Kerberos 5 release //'` + fi + if test -n "$gss_version"; then + AC_MSG_NOTICE([GSS-API MIT Kerberos version detected: $gss_version]) + AC_DEFINE_UNQUOTED([CURL_KRB5_VERSION], ["$gss_version"], [MIT Kerberos version]) + fi else LDFLAGS="$LDFLAGS $GSSAPI_LIB_DIR" LDFLAGSPC="$LDFLAGSPC $GSSAPI_LIB_DIR" diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index be6fe4176e26..1fabc24c182f 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -318,6 +318,9 @@ /* if you have the GNU gssapi libraries */ #cmakedefine HAVE_GSSGNU 1 +/* MIT Kerberos version */ +#cmakedefine CURL_KRB5_VERSION ${CURL_KRB5_VERSION} + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_IFADDRS_H 1 diff --git a/lib/version.c b/lib/version.c index 7c9ac12fb93e..4c7e5712f0f9 100644 --- a/lib/version.c +++ b/lib/version.c @@ -77,6 +77,14 @@ #include #endif +#ifdef HAVE_GSSAPI +# ifdef HAVE_GSSGNU +# include +# else +# include +# endif +#endif + #ifdef USE_OPENLDAP #include #endif @@ -208,6 +216,9 @@ char *curl_version(void) #ifdef USE_GSASL char gsasl_buf[30]; #endif +#ifdef HAVE_GSSAPI + char gss_buf[40]; +#endif #ifdef USE_OPENLDAP char ldap_buf[30]; #endif @@ -274,6 +285,18 @@ char *curl_version(void) gsasl_check_version(NULL)); src[i++] = gsasl_buf; #endif +#ifdef HAVE_GSSAPI +#ifdef HAVE_GSSGNU + curl_msnprintf(gss_buf, sizeof(gss_buf), "libgss/%s", + GSS_VERSION); +#elif defined(CURL_KRB5_VERSION) + curl_msnprintf(gss_buf, sizeof(gss_buf), "mit-krb5/%s", + CURL_KRB5_VERSION); +#else + curl_msnprintf(gss_buf, sizeof(gss_buf), "mit-krb5"); +#endif + src[i++] = gss_buf; +#endif /* HAVE_GSSAPI */ #ifdef USE_OPENLDAP oldap_version(ldap_buf, sizeof(ldap_buf)); src[i++] = ldap_buf; From 800b0bec18e9c77e35912fac8321c791d7b57863 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 16 Oct 2025 16:29:56 +0200 Subject: [PATCH 458/465] GHA: bump LibreSSL to 4.2.0 Also move back URLs to GitHub, sources are available there again. Ref: https://github.com/libressl/portable/releases/tag/v4.2.0 Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-4.2.0-relnotes.txt Ref: #19050 Ref: #19081 Closes #19082 --- .github/workflows/http3-linux.yml | 4 ++-- .github/workflows/linux.yml | 4 ++-- .github/workflows/macos.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index c9495fe74ea8..ae220eb3e883 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -42,7 +42,7 @@ env: # handled in renovate.json OPENSSL_VERSION: 3.6.0 # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com - LIBRESSL_VERSION: 4.1.1 + LIBRESSL_VERSION: 4.2.0 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com AWSLC_VERSION: 1.61.4 # renovate: datasource=github-tags depName=google/boringssl versioning=semver registryUrl=https://github.com @@ -201,7 +201,7 @@ jobs: run: | cd ~ curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ - "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz + --location "https://github.com/libressl/portable/releases/download/v${LIBRESSL_VERSION}/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz cd "libressl-${LIBRESSL_VERSION}" cmake -B . -G Ninja -DLIBRESSL_APPS=OFF -DLIBRESSL_TESTS=OFF -DCMAKE_INSTALL_PREFIX=/home/runner/libressl/build cmake --build . diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index e0e256fbb3ab..71390502dc70 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -38,7 +38,7 @@ env: CURL_CI: github CURL_CLANG_TIDYFLAGS: '-checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.ArrayBound,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,-clang-analyzer-valist.Uninitialized' # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com - LIBRESSL_VERSION: 4.1.1 + LIBRESSL_VERSION: 4.2.0 # renovate: datasource=github-tags depName=wolfSSL/wolfssl versioning=semver extractVersion=^v?(?.+)-stable$ registryUrl=https://github.com WOLFSSL_VERSION: 5.8.2 # renovate: datasource=github-tags depName=Mbed-TLS/mbedtls versioning=semver registryUrl=https://github.com @@ -384,7 +384,7 @@ jobs: if: ${{ contains(matrix.build.install_steps, 'libressl') && steps.cache-libressl.outputs.cache-hit != 'true' }} run: | curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ - "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz + --location "https://github.com/libressl/portable/releases/download/v${LIBRESSL_VERSION}/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz cd "libressl-${LIBRESSL_VERSION}" cmake -B . -G Ninja -DLIBRESSL_APPS=OFF -DLIBRESSL_TESTS=OFF -DCMAKE_INSTALL_PREFIX=/home/runner/libressl cmake --build . diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 7e85cb71e18b..2ac37381ea46 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -59,7 +59,7 @@ jobs: MATRIX_BUILD: ${{ matrix.build.generate && 'cmake' || 'autotools' }} MATRIX_OPTIONS: ${{ matrix.build.options }} # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com - LIBRESSL_VERSION: 4.1.1 + LIBRESSL_VERSION: 4.2.0 strategy: fail-fast: false matrix: @@ -122,7 +122,7 @@ jobs: if: ${{ contains(matrix.build.install_steps, 'libressl') && steps.cache-libressl.outputs.cache-hit != 'true' }} run: | curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 60 --retry 3 --retry-connrefused \ - "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz + --location "https://github.com/libressl/portable/releases/download/v${LIBRESSL_VERSION}/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz cd "libressl-${LIBRESSL_VERSION}" cmake -B . -G Ninja \ -DCMAKE_INSTALL_PREFIX=/Users/runner/libressl \ From c8d6643df212791edee705a94c890335dac8762b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 16 Oct 2025 18:10:41 +0200 Subject: [PATCH 459/465] GHA/windows: stop installing Perl `Win32-Process*` modules It's complex and did not help stabilizing CI runs. Hard to say, but I'm suspicious it's related to the CI errors -1073741502, 0xC0000142, seen in the 'build examples' and 'disk space used' steps. Ref: #18526 Reverts 52775a7fb4ba63d66d60067dea4a5293fb7c55a1 #18296 Closes #19083 --- .github/workflows/windows.yml | 124 ---------------------------------- 1 file changed, 124 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index b5e31ee9c183..28143fdc5a00 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -39,63 +39,6 @@ env: CURL_CI: github jobs: - build-cache: - name: 'Build caches' - runs-on: ${{ matrix.image }} - timeout-minutes: 15 - defaults: - run: - shell: msys2 {0} - strategy: - fail-fast: false - matrix: - image: [windows-2022, windows-11-arm] - steps: - - name: 'install build prereqs' - if: ${{ steps.cache-perl-win32-pkgs.outputs.cache-hit != 'true' }} - uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0 - with: - msystem: msys - install: gcc make - - - name: 'perl version' - run: perl --version | tee "$GITHUB_WORKSPACE"/perlversion - - - name: 'cache perl packages' - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - id: cache-perl-win32-pkgs - env: - cache-name: cache-perl-win32-pkgs - with: - path: C:\perl-win32-pkgs - key: ${{ runner.os }}-${{ runner.arch }}-build-${{ env.cache-name }}-${{ hashFiles('perlversion') }} - - - name: 'build perl packages' - if: ${{ steps.cache-perl-win32-pkgs.outputs.cache-hit != 'true' }} - run: | - cd /c - mkdir perl-win32-pkgs - cd perl-win32-pkgs - sed -i.bak 's/#define I_CRYPT//g' /usr/lib/perl5/core_perl/CORE/config.h - - # https://metacpan.org/pod/Win32::Process - curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ - --location "https://cpan.metacpan.org/authors/id/J/JD/JDB/Win32-Process-0.17.tar.gz" | tar -xz - cd Win32-Process-0.17 - perl Makefile.PL - sed -i.bak 's/-lcrypt//g' Makefile - make - cd .. - - # https://metacpan.org/pod/Win32::Process::List - curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 6 --retry-connrefused \ - --location "https://cpan.metacpan.org/authors/id/R/RP/RPAGITSCH/Win32-Process-List-0.09.tar.gz" | tar -xz - cd Win32-Process-List-0.09 - perl Makefile.PL - sed -i.bak 's/-lcrypt//g' Makefile - make - cd .. - cygwin: name: "cygwin, ${{ matrix.build == 'cmake' && 'CM' || 'AM' }} ${{ matrix.platform }} ${{ matrix.name }}" runs-on: windows-2022 @@ -242,8 +185,6 @@ jobs: msys2: # both msys and mingw-w64 name: "${{ matrix.sys == 'msys' && 'msys2' || 'mingw' }}, ${{ matrix.build == 'cmake' && 'CM' || 'AM' }} ${{ matrix.env }} ${{ matrix.name }} ${{ matrix.test }}" - needs: - - build-cache runs-on: ${{ matrix.image || 'windows-2022' }} timeout-minutes: 15 defaults: @@ -431,37 +372,6 @@ jobs: /c/ProgramData/chocolatey/choco.exe install --yes --no-progress --limit-output --timeout 180 --force stunnel || true perl --version | tee "$GITHUB_WORKSPACE"/perlversion - - name: 'cache perl packages' - if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' && matrix.sys != 'msys' }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - id: cache-perl-win32-pkgs - env: - cache-name: cache-perl-win32-pkgs - with: - path: C:\perl-win32-pkgs - key: ${{ runner.os }}-${{ runner.arch }}-build-${{ env.cache-name }}-${{ hashFiles('perlversion') }} - - - name: 'install test prereqs perl' - if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - timeout-minutes: 5 - run: &perl-win32-pkgs-install | - perl --version - if [ -d /c/perl-win32-pkgs ]; then - pushd /c/perl-win32-pkgs - pushd Win32-Process-0.17 - install -D blib/arch/auto/Win32/Process/Process.dll /usr/lib/perl5/site_perl/auto/Win32/Process/Process.dll - install -D blib/lib/Win32/Process.pm /usr/lib/perl5/site_perl/Win32/Process.pm - popd - pushd Win32-Process-List-0.09 - install -D blib/arch/auto/Win32/Process/List/List.dll /usr/lib/perl5/site_perl/auto/Win32/Process/List/List.dll - install -D blib/lib/auto/Win32/Process/List/autosplit.ix /usr/lib/perl5/site_perl/auto/Win32/Process/List/autosplit.ix - install -D blib/lib/Win32/Process/List.pm /usr/lib/perl5/site_perl/Win32/Process/List.pm - install -D blib/lib/Win32/Process/processes.pl /usr/lib/perl5/site_perl/Win32/Process/processes.pl - popd - popd - fi - perl -MWin32::Process -MWin32::Process::List -e 1 && echo '! Modules loading OK.' || echo '! Failed to load modules.' - - name: 'run tests' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} timeout-minutes: 10 @@ -503,8 +413,6 @@ jobs: mingw-w64-standalone-downloads: name: 'dl-mingw, CM ${{ matrix.ver }}-${{ matrix.env }} ${{ matrix.name }}' - needs: - - build-cache runs-on: windows-2022 timeout-minutes: 15 defaults: @@ -661,21 +569,6 @@ jobs: python3 -m pip --disable-pip-version-check --no-input --no-cache-dir install --progress-bar off --prefer-binary -r tests/requirements.txt perl --version | tee "$GITHUB_WORKSPACE"/perlversion - - name: 'cache perl packages' - if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - id: cache-perl-win32-pkgs - env: - cache-name: cache-perl-win32-pkgs - with: - path: C:\perl-win32-pkgs - key: ${{ runner.os }}-${{ runner.arch }}-build-${{ env.cache-name }}-${{ hashFiles('perlversion') }} - - - name: 'install test prereqs perl' - if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - timeout-minutes: 5 - run: *perl-win32-pkgs-install - - name: 'run tests' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} timeout-minutes: 10 @@ -802,8 +695,6 @@ jobs: msvc: name: 'msvc, CM ${{ matrix.arch }}-${{ matrix.plat }} ${{ matrix.name }}' - needs: - - build-cache runs-on: ${{ matrix.image || 'windows-2022' }} timeout-minutes: 15 defaults: @@ -1055,21 +946,6 @@ jobs: fi perl --version | tee "$GITHUB_WORKSPACE"/perlversion - - name: 'cache perl packages' - if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - id: cache-perl-win32-pkgs - env: - cache-name: cache-perl-win32-pkgs - with: - path: C:\perl-win32-pkgs - key: ${{ runner.os }}-${{ runner.arch }}-build-${{ env.cache-name }}-${{ hashFiles('perlversion') }} - - - name: 'install test prereqs perl' - if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - timeout-minutes: 5 - run: *perl-win32-pkgs-install - - name: 'run tests' if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} timeout-minutes: 10 From 3c0604bba46286b7ac6915ed19bb47bc3273c97a Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 15 Oct 2025 20:22:20 +0200 Subject: [PATCH 460/465] GHA: sync up `curl -V` step descriptions Also to make it easier to recognize. Also: - GHA/linux-old: split steps to match other jobs. - GHA: add `--disable` where missing. Closes #19084 --- .github/workflows/http3-linux.yml | 4 ++-- .github/workflows/linux-old.yml | 26 ++++++++++++++++---------- .github/workflows/linux.yml | 4 ++-- .github/workflows/macos.yml | 4 ++-- .github/workflows/windows.yml | 8 ++++---- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index ae220eb3e883..38d2fb6ac025 100644 --- a/.github/workflows/http3-linux.yml +++ b/.github/workflows/http3-linux.yml @@ -661,8 +661,8 @@ jobs: make -C bld V=1 fi - - name: 'check curl -V output' - run: bld/src/curl -V + - name: 'curl -V' + run: bld/src/curl --disable -V - name: 'build tests' if: ${{ !contains(matrix.build.install_steps, 'skipall') }} diff --git a/.github/workflows/linux-old.yml b/.github/workflows/linux-old.yml index fde23de811c2..e145633708de 100644 --- a/.github/workflows/linux-old.yml +++ b/.github/workflows/linux-old.yml @@ -80,14 +80,18 @@ jobs: with: persist-credentials: false - - name: 'cmake build-only (out-of-tree)' + - name: 'cmake build-only configure (out-of-tree)' run: | mkdir bld-1 cd bld-1 cmake .. -DCMAKE_UNITY_BUILD=ON -DCURL_WERROR=ON -DBUILD_SHARED_LIBS=ON \ -DCURL_USE_GNUTLS=ON -DENABLE_ARES=OFF -DCURL_ZSTD=OFF -DCURL_USE_GSSAPI=OFF -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=OFF -DUSE_LIBRTMP=ON - VERBOSE=1 make install - src/curl --disable --version + + - name: 'cmake build-only build' + run: VERBOSE=1 make -C bld-1 install + + - name: 'cmake build-only curl -V' + run: bld-1/src/curl --disable --version - name: 'cmake build-only configure log' if: ${{ !cancelled() }} @@ -118,9 +122,10 @@ jobs: grep -F '#define' bld-cares/lib/curl_config.h | sort || true - name: 'cmake build' - run: | - make -C bld-cares - bld-cares/src/curl --disable --version + run: make -C bld-cares + + - name: 'cmake curl -V' + run: bld-cares/src/curl --disable --version - name: 'cmake install' run: make -C bld-cares install @@ -135,7 +140,7 @@ jobs: run: make -C bld-cares curl-examples-build - name: 'autoreconf' - run: autoreconf -if + run: autoreconf -fi - name: 'autotools configure (out-of-tree, c-ares, zstd, gssapi)' run: | @@ -155,9 +160,10 @@ jobs: grep -F '#define' bld-am/lib/curl_config.h | sort || true - name: 'autotools build' - run: | - make -C bld-am - bld-am/src/curl --disable --version + run: make -C bld-am + + - name: 'autotools curl -V' + run: bld-am/src/curl --disable --version - name: 'autotools install' run: make -C bld-am install diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 71390502dc70..2d674dc195cf 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -638,9 +638,9 @@ jobs: fi ./scripts/singleuse.pl --unit "${libcurla}" - - name: 'check curl -V output' + - name: 'curl -V' if: ${{ matrix.build.make-custom-target != 'tidy' }} - run: bld/src/curl -V + run: bld/src/curl --disable -V - name: 'curl install' run: | diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 2ac37381ea46..1e9f2408a8ba 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -461,7 +461,7 @@ jobs: make -C bld V=1 fi - - name: 'curl version' + - name: 'curl -V' run: bld/src/curl --disable --version - name: 'curl install' @@ -705,5 +705,5 @@ jobs: make -C bld V=1 fi - - name: 'curl version' + - name: 'curl -V' run: bld/src/curl --disable --version diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 28143fdc5a00..975b592c7ce1 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -130,7 +130,7 @@ jobs: make -C bld V=1 install fi - - name: 'curl version' + - name: 'curl -V' timeout-minutes: 1 run: | PATH=/usr/bin @@ -332,7 +332,7 @@ jobs: make -C bld V=1 install fi - - name: 'curl version' + - name: 'curl -V' timeout-minutes: 1 run: | if [ "${MATRIX_BUILD}" = 'cmake' ]; then @@ -547,7 +547,7 @@ jobs: PATH="/d/my-cache/${MATRIX_DIR}/bin:$PATH" cmake --build bld - - name: 'curl version' + - name: 'curl -V' timeout-minutes: 1 run: | /usr/bin/find . \( -name '*.exe' -o -name '*.dll' -o -name '*.a' \) -exec file '{}' \; @@ -907,7 +907,7 @@ jobs: timeout-minutes: 5 run: cmake --build bld --config "${MATRIX_TYPE}" --parallel 5 - - name: 'curl version' + - name: 'curl -V' timeout-minutes: 1 run: | /usr/bin/find . \( -name '*.exe' -o -name '*.dll' -o -name '*.lib' -o -name '*.pdb' \) -exec file '{}' \; From c8aaa5d2f21f9eba973f8cfac12621819502102f Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 15 Oct 2025 19:45:48 +0200 Subject: [PATCH 461/465] scripts: pass `--` before passing xargs Also: - GHA/checkdocs: escape `.` in -E regex expression. Closes #19076 --- .github/workflows/appveyor-status.yml | 2 +- .github/workflows/checkdocs.yml | 2 +- scripts/cmakelint.sh | 3 ++- scripts/firefox-db2pem.sh | 2 +- scripts/perlcheck.sh | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/appveyor-status.yml b/.github/workflows/appveyor-status.yml index 5269f3ca65b9..48e11b0e3d3c 100644 --- a/.github/workflows/appveyor-status.yml +++ b/.github/workflows/appveyor-status.yml @@ -29,7 +29,7 @@ jobs: APPVEYOR_REPOSITORY: ${{ github.event.repository.full_name }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - echo "${APPVEYOR_TARGET_URL}" | sed 's/\/project\//\/api\/projects\//' | xargs -t -n1 curl -s | \ + echo "${APPVEYOR_TARGET_URL}" | sed 's/\/project\//\/api\/projects\//' | xargs -t -n1 curl -s -- | \ jq -c '.build.jobs[] | {target_url: ($target_url + "/job/" + .jobId), context: (.name | sub("^(Environment: )?"; "AppVeyor / ")), state: (.status | sub("queued"; "pending") diff --git a/.github/workflows/checkdocs.yml b/.github/workflows/checkdocs.yml index 91ed7452d19c..58f5f29f8b4c 100644 --- a/.github/workflows/checkdocs.yml +++ b/.github/workflows/checkdocs.yml @@ -69,7 +69,7 @@ jobs: # run: git ls-files -z '*.md' | xargs -0 -n1 .github/scripts/trimmarkdownheader.pl # # - name: 'check prose' - # run: git ls-files -z '*.md' | grep -Evz 'CHECKSRC.md|DISTROS.md|curl_mprintf.md|CURLOPT_INTERFACE.md|interface.md' | xargs -0 proselint README + # run: git ls-files -z '*.md' | grep -Evz 'CHECKSRC\.md|DISTROS\.md|curl_mprintf\.md|CURLOPT_INTERFACE\.md|interface\.md' | xargs -0 proselint -- README # # # This is for CHECKSRC and files with aggressive exclamation mark needs # - name: 'create second proselint config' diff --git a/scripts/cmakelint.sh b/scripts/cmakelint.sh index 788f0873055b..9462081f218b 100755 --- a/scripts/cmakelint.sh +++ b/scripts/cmakelint.sh @@ -77,4 +77,5 @@ cd "$(dirname "$0")"/.. --max-branches 12 \ --max-arguments 5 \ --max-localvars 15 \ - --max-statements 50 + --max-statements 50 \ + -- diff --git a/scripts/firefox-db2pem.sh b/scripts/firefox-db2pem.sh index 2a4b9ceace16..c774ab9107c1 100755 --- a/scripts/firefox-db2pem.sh +++ b/scripts/firefox-db2pem.sh @@ -57,5 +57,5 @@ sed -e 's/ *[CcGTPpu]*,[CcGTPpu]*,[CcGTPpu]* *$//' -e 's/\(.*\)/"\1"/' | \ sort | \ while read -r nickname; \ do echo "$nickname" | sed -e "s/Builtin Object Token://g"; \ - echo "$nickname" | xargs -I{} certutil -d "$db" -L -a -n {} ; \ + echo "$nickname" | xargs -I{} certutil -d "$db" -L -a -n -- {} ; \ done >> "$out" diff --git a/scripts/perlcheck.sh b/scripts/perlcheck.sh index 7de0f6dbb559..7ec23983d5e6 100755 --- a/scripts/perlcheck.sh +++ b/scripts/perlcheck.sh @@ -48,4 +48,4 @@ echo "parallel: ${procs}" # strip off the leading ./ to make the grep regexes work properly find . -type f \( -name '*.pl' -o -name '*.pm' \) | sed 's@^\./@@' fi -} | xargs -n 1 -P "${procs}" perl -c -Itests +} | xargs -n 1 -P "${procs}" perl -c -Itests -- From da06621d617ab498a989afe75b7c2a4193d619e4 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 15 Oct 2025 19:46:35 +0200 Subject: [PATCH 462/465] firefox-db2pem.sh: add macOS support, tidy-ups Cherry-picked from #19076 Closes #19086 --- scripts/firefox-db2pem.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/firefox-db2pem.sh b/scripts/firefox-db2pem.sh index c774ab9107c1..634e429b504f 100755 --- a/scripts/firefox-db2pem.sh +++ b/scripts/firefox-db2pem.sh @@ -32,7 +32,11 @@ set -eu -db=$(ls -1d "$HOME"/.mozilla/firefox/*default*) +if [ -d "$HOME/Library/Application Support"/Firefox/Profiles ]; then + db=$(ls -1d "$HOME/Library/Application Support"/Firefox/Profiles/*default*) +else + db=$(ls -1d "$HOME"/.mozilla/firefox/*default*) +fi out="${1:-}" if test -z "$out"; then @@ -55,7 +59,7 @@ certutil -L -h 'Builtin Object Token' -d "$db" | \ grep ' *[CcGTPpu]*,[CcGTPpu]*,[CcGTPpu]* *$' | \ sed -e 's/ *[CcGTPpu]*,[CcGTPpu]*,[CcGTPpu]* *$//' -e 's/\(.*\)/"\1"/' | \ sort | \ -while read -r nickname; \ - do echo "$nickname" | sed -e "s/Builtin Object Token://g"; \ - echo "$nickname" | xargs -I{} certutil -d "$db" -L -a -n -- {} ; \ +while read -r nickname; do + echo "$nickname" | sed 's/Builtin Object Token://g' + echo "$nickname" | xargs -I{} certutil -d "$db" -L -a -n {} done >> "$out" From f91be14bfb79021e3b9ba769955c1f2c4351e9bf Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 16 Oct 2025 21:47:42 +0200 Subject: [PATCH 463/465] openldap: limit max incoming size Set the maximum allowed size of an incoming LDAP message, which to OpenLDAP means that it allows malloc() up to this size. If not set, there is no limit and we instead risk a malloc() failure. The limit is arbitrarily set to 256K as I can't figure out what a reasonable value should be. OpenLDAP docs: https://openldap.org/software/man.cgi?query=lber-sockbuf&apropos=0&sektion=0&manpath=OpenLDAP+2.6-Release&arch=default&format=html Bug: https://issues.oss-fuzz.com/issues/432441303 Closes #19087 --- lib/openldap.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/openldap.c b/lib/openldap.c index b8afe99529e1..1b26b6e1b4d9 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -659,6 +659,19 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done) /* Do not chase referrals. */ ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); + { + ber_len_t max = 256*1024; + Sockbuf *sb; + if(ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, (void **)&sb) || + /* Set the maximum allowed size of an incoming message, which to + OpenLDAP means that it will malloc() memory up to this size. If not + set, there is no limit and we instead risk a malloc() failure. */ + ber_sockbuf_ctrl(sb, LBER_SB_OPT_SET_MAX_INCOMING, &max)) { + result = CURLE_FAILED_INIT; + goto out; + } + } + #ifdef USE_SSL if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) { result = oldap_ssl_connect(data, OLDAP_SSL); From 5a3168d4ab996131fc489e7943a2919b7405b55a Mon Sep 17 00:00:00 2001 From: Karthik Das <92445174+devkdas@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:25:56 +0530 Subject: [PATCH 464/465] Update curl_ngtcp2.c --- lib/vquic/curl_ngtcp2.c | 796 +++++++++++++++++++--------------------- 1 file changed, 384 insertions(+), 412 deletions(-) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 53665b1a3d1d..97ad43766809 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -57,6 +57,7 @@ #include "../cf-socket.h" #include "../connect.h" #include "../progress.h" +#include "../strerror.h" #include "../curlx/dynbuf.h" #include "../http1.h" #include "../select.h" @@ -72,12 +73,14 @@ #include "../curlx/warnless.h" -/* The last 2 #include files should be in this order */ +/* The last 3 #include files should be in this order */ +#include "../curl_printf.h" #include "../curl_memory.h" #include "../memdebug.h" #define QUIC_MAX_STREAMS (256*1024) +#define QUIC_MAX_DATA (1*1024*1024) #define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS) /* A stream window is the maximum amount we need to buffer for @@ -99,6 +102,8 @@ (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2 /* Receive and Send max number of chunks just follows from the * chunk size and window size */ +#define H3_STREAM_RECV_CHUNKS \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) #define H3_STREAM_SEND_CHUNKS \ (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) @@ -110,8 +115,8 @@ void Curl_ngtcp2_ver(char *p, size_t len) { const ngtcp2_info *ng2 = ngtcp2_version(0); const nghttp3_info *ht3 = nghttp3_version(0); - (void)curl_msnprintf(p, len, "ngtcp2/%s nghttp3/%s", - ng2->version_str, ht3->version_str); + (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s", + ng2->version_str, ht3->version_str); } struct cf_ngtcp2_ctx { @@ -143,8 +148,8 @@ struct cf_ngtcp2_ctx { uint64_t max_bidi_streams; /* max bidi streams we can open */ size_t earlydata_max; /* max amount of early data supported by server on session reuse */ - size_t earlydata_skip; /* sending bytes to skip when earlydata - is accepted by peer */ + size_t earlydata_skip; /* sending bytes to skip when earlydata + * is accepted by peer */ CURLcode tls_vrfy_result; /* result of TLS peer verification */ int qlogfd; BIT(initialized); @@ -227,11 +232,11 @@ static void cf_ngtcp2_setup_keep_alive(struct Curl_cfilter *cf, struct pkt_io_ctx; static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx); +static CURLcode cf_progress_egress(struct Curl_cfilter *cf, struct Curl_easy *data, struct pkt_io_ctx *pktx); -static CURLcode cf_progress_egress(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct pkt_io_ctx *pktx); /** * All about the H3 internals of a stream @@ -267,7 +272,7 @@ static void h3_stream_hash_free(unsigned int id, void *stream) } static CURLcode h3_data_setup(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data) { struct cf_ngtcp2_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); @@ -285,7 +290,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf, stream->id = -1; /* on send, we control how much we put into the buffer */ Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp, - H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE); + H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE); stream->sendbuf_len_in_flight = 0; Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); @@ -300,38 +305,9 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf, return CURLE_OK; } -struct cf_ngtcp2_sfind_ctx { - curl_int64_t stream_id; - struct h3_stream_ctx *stream; - unsigned int mid; -}; - -static bool cf_ngtcp2_sfind(unsigned int mid, void *value, void *user_data) -{ - struct cf_ngtcp2_sfind_ctx *fctx = user_data; - struct h3_stream_ctx *stream = value; - - if(fctx->stream_id == stream->id) { - fctx->mid = mid; - fctx->stream = stream; - return FALSE; - } - return TRUE; /* continue */ -} - -static struct h3_stream_ctx * -cf_ngtcp2_get_stream(struct cf_ngtcp2_ctx *ctx, curl_int64_t stream_id) -{ - struct cf_ngtcp2_sfind_ctx fctx; - fctx.stream_id = stream_id; - fctx.stream = NULL; - Curl_uint_hash_visit(&ctx->streams, cf_ngtcp2_sfind, &fctx); - return fctx.stream; -} - static void cf_ngtcp2_stream_close(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct h3_stream_ctx *stream) + struct Curl_easy *data, + struct h3_stream_ctx *stream) { struct cf_ngtcp2_ctx *ctx = cf->ctx; DEBUGASSERT(data); @@ -367,7 +343,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) } /* ngtcp2 default congestion controller does not perform pacing. Limit - the maximum packet burst to MAX_PKT_BURST packets. */ + the maximum packet burst to MAX_PKT_BURST packets. */ #define MAX_PKT_BURST 10 struct pkt_io_ctx { @@ -378,7 +354,7 @@ struct pkt_io_ctx { }; static void pktx_update_time(struct pkt_io_ctx *pktx, - struct Curl_cfilter *cf) + struct Curl_cfilter *cf) { struct cf_ngtcp2_ctx *ctx = cf->ctx; @@ -388,8 +364,8 @@ static void pktx_update_time(struct pkt_io_ctx *pktx, } static void pktx_init(struct pkt_io_ctx *pktx, - struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_cfilter *cf, + struct Curl_easy *data) { pktx->cf = cf; pktx->data = data; @@ -398,8 +374,8 @@ static void pktx_init(struct pkt_io_ctx *pktx, } static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, - uint64_t datalen, void *user_data, - void *stream_user_data); + uint64_t datalen, void *user_data, + void *stream_user_data); static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) { @@ -424,7 +400,7 @@ static void quic_printf(void *user_data, const char *fmt, ...) #endif static void qlog_callback(void *user_data, uint32_t flags, - const void *data, size_t datalen) + const void *data, size_t datalen) { struct Curl_cfilter *cf = user_data; struct cf_ngtcp2_ctx *ctx = cf->ctx; @@ -437,6 +413,7 @@ static void qlog_callback(void *user_data, uint32_t flags, ctx->qlogfd = -1; } } + } static void quic_settings(struct cf_ngtcp2_ctx *ctx, @@ -490,7 +467,7 @@ static uint16_t mtu_probes[] = { } static CURLcode init_ngh3_conn(struct Curl_cfilter *cf, - struct Curl_easy *data); + struct Curl_easy *data); static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) { @@ -557,7 +534,7 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) } static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf, - struct Curl_easy *data); + struct Curl_easy *data); static bool cf_ngtcp2_err_is_fatal(int code) { @@ -567,7 +544,7 @@ static bool cf_ngtcp2_err_is_fatal(int code) } static void cf_ngtcp2_err_set(struct Curl_cfilter *cf, - struct Curl_easy *data, int code) + struct Curl_easy *data, int code) { struct cf_ngtcp2_ctx *ctx = cf->ctx; if(!ctx->last_error.error_code) { @@ -591,7 +568,7 @@ static bool cf_ngtcp2_h3_err_is_fatal(int code) } static void cf_ngtcp2_h3_err_set(struct Curl_cfilter *cf, - struct Curl_easy *data, int code) + struct Curl_easy *data, int code) { struct cf_ngtcp2_ctx *ctx = cf->ctx; if(!ctx->last_error.error_code) { @@ -733,7 +710,7 @@ static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id, rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id); if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { - return NGTCP2_ERR_CALLBACK_FAILURE; + return NGHTTP2_ERR_CALLBACK_FAILURE; } return 0; @@ -912,6 +889,7 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf, } else { pktx_update_time(pktx, cf); + ngtcp2_path_storage_zero(&pktx->ps); } expiry = ngtcp2_conn_get_expiry(ctx->qconn); @@ -1193,7 +1171,7 @@ static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id, rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id, app_error_code); - if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) { + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { return NGHTTP3_ERR_CALLBACK_FAILURE; } @@ -1245,7 +1223,7 @@ static nghttp3_callbacks ngh3_callbacks = { }; static CURLcode init_ngh3_conn(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data) { struct cf_ngtcp2_ctx *ctx = cf->ctx; int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id; @@ -1356,10 +1334,8 @@ static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, *pnread = 0; /* handshake verification failed in callback, do not recv anything */ - if(ctx->tls_vrfy_result) { - result = ctx->tls_vrfy_result; - goto denied; - } + if(ctx->tls_vrfy_result) + return ctx->tls_vrfy_result; pktx_init(&pktx, cf, data); @@ -1390,9 +1366,6 @@ static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, out: result = Curl_1st_err(result, cf_progress_egress(cf, data, &pktx)); result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); -denied: - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %d, %zu", - stream ? stream->id : -1, blen, result, *pnread); CF_DATA_RESTORE(cf, save); return result; } @@ -1561,7 +1534,7 @@ static CURLcode h3_stream_open(struct Curl_cfilter *cf, nva[i].flags = NGHTTP3_NV_FLAG_NONE; } - rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &sid, data); + rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &sid, NULL); if(rc) { failf(data, "can get bidi streams"); result = CURLE_SEND_ERROR; @@ -1607,7 +1580,6 @@ static CURLcode h3_stream_open(struct Curl_cfilter *cf, "%d (%s)", stream->id, rc, nghttp3_strerror(rc)); break; } - cf_ngtcp2_stream_close(cf, data, stream); result = CURLE_SEND_ERROR; goto out; } @@ -1629,189 +1601,185 @@ static CURLcode h3_stream_open(struct Curl_cfilter *cf, } static CURLcode cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, bool eos, - size_t *pnwritten) -{ - struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - struct cf_call_data save; - struct pkt_io_ctx pktx; - CURLcode result = CURLE_OK; - - CF_DATA_SAVE(save, cf, data); - DEBUGASSERT(cf->connected); - DEBUGASSERT(ctx->qconn); - DEBUGASSERT(ctx->h3conn); - pktx_init(&pktx, cf, data); - *pnwritten = 0; - - /* handshake verification failed in callback, do not send anything */ - if(ctx->tls_vrfy_result) { - result = ctx->tls_vrfy_result; - goto denied; - } - - (void)eos; /* use for stream EOF and block handling */ - result = cf_progress_ingress(cf, data, &pktx); - if(result) - goto out; - - if(!stream || stream->id < 0) { - if(ctx->shutdown_started) { - CURL_TRC_CF(data, cf, "cannot open stream on closed connection"); - result = CURLE_SEND_ERROR; - goto out; - } - result = h3_stream_open(cf, data, buf, len, pnwritten); - if(result) { - CURL_TRC_CF(data, cf, "failed to open stream -> %d", result); - goto out; - } - stream = H3_STREAM_CTX(ctx, data); - } - else if(stream->xfer_result) { - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id); - cf_ngtcp2_stream_close(cf, data, stream); - result = stream->xfer_result; - goto out; - } - else if(stream->closed) { - if(stream->resp_hds_complete) { - /* Server decided to close the stream after having sent us a final - * response. This is valid if it is not interested in the request - * body. This happens on 30x or 40x responses. - * We silently discard the data sent, since this is not a transport - * error situation. */ - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data" - "on closed stream with response", stream->id); - result = CURLE_OK; - *pnwritten = len; - goto out; - } - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) " - "-> stream closed", stream->id, len); - result = CURLE_HTTP3; - goto out; - } - else if(ctx->shutdown_started) { - CURL_TRC_CF(data, cf, "cannot send on closed connection"); - result = CURLE_SEND_ERROR; - goto out; - } - else { - result = Curl_bufq_write(&stream->sendbuf, buf, len, pnwritten); - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to " - "sendbuf(len=%zu) -> %d, %zu", - stream->id, len, result, *pnwritten); - if(result) - goto out; - (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id); - } - - if(*pnwritten > 0 && !ctx->tls_handshake_complete && ctx->use_earlydata) - ctx->earlydata_skip += *pnwritten; - - DEBUGASSERT(!result); - result = cf_progress_egress(cf, data, &pktx); - -out: - result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); -denied: - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %d, %zu", - stream ? stream->id : -1, len, result, *pnwritten); - CF_DATA_RESTORE(cf, save); - return result; -} - -static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, - struct sockaddr_storage *remote_addr, - socklen_t remote_addrlen, int ecn, - void *userp) -{ - struct pkt_io_ctx *pktx = userp; - struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx; - ngtcp2_pkt_info pi; - ngtcp2_path path; - int rv; - - if(ecn) - CURL_TRC_CF(pktx->data, pktx->cf, "vquic_recv(len=%zu, ecn=%x)", - pktlen, ecn); - ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr, - (socklen_t)ctx->q.local_addrlen); - ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr, - remote_addrlen); - pi.ecn = (uint8_t)ecn; - - rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts); - if(rv) { - CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)", - ngtcp2_strerror(rv), rv); - cf_ngtcp2_err_set(pktx->cf, pktx->data, rv); - - if(rv == NGTCP2_ERR_CRYPTO) - /* this is a "TLS problem", but a failed certificate verification - is a common reason for this */ - return CURLE_PEER_FAILED_VERIFICATION; - return CURLE_RECV_ERROR; - } - return CURLE_OK; -} - -static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct pkt_io_ctx *pktx) -{ - struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct pkt_io_ctx local_pktx; - CURLcode result = CURLE_OK; - - if(!pktx) { - pktx_init(&local_pktx, cf, data); - pktx = &local_pktx; - } - else { - pktx_update_time(pktx, cf); - ngtcp2_path_storage_zero(&pktx->ps); - } - - result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); - if(result) - return result; - - return vquic_recv_packets(cf, data, &ctx->q, 1000, recv_pkt, pktx); -} - -/** - * Read a network packet to send from ngtcp2 into `buf`. - * Return number of bytes written or -1 with *err set. - */ -static CURLcode read_pkt_to_send(void *userp, - unsigned char *buf, size_t buflen, - size_t *pnread) -{ - struct pkt_io_ctx *x = userp; - struct cf_ngtcp2_ctx *ctx = x->cf->ctx; - nghttp3_vec vec[16]; - nghttp3_ssize veccnt; - ngtcp2_ssize ndatalen; - uint32_t flags; - int64_t stream_id; - int fin; - ssize_t n; - - *pnread = 0; - veccnt = 0; - stream_id = -1; - fin = 0; - - /* ngtcp2 may want to put several frames from different streams into - * this packet. `NGTCP2_WRITE_STREAM_FLAG_MORE` tells it to do so. - * When `NGTCP2_ERR_WRITE_MORE` is returned, we *need* to make - * another iteration. - * When ngtcp2 is happy (because it has no other frame that would fit - * or it has nothing more to send), it returns the total length - * of the assembled packet. This may be 0 if there was nothing to send. */ + const void *buf, size_t len, bool eos, + size_t *pnwritten) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); + struct cf_call_data save; + struct pkt_io_ctx pktx; + CURLcode result = CURLE_OK; + + CF_DATA_SAVE(save, cf, data); + DEBUGASSERT(cf->connected); + DEBUGASSERT(ctx->qconn); + DEBUGASSERT(ctx->h3conn); + pktx_init(&pktx, cf, data); + *pnwritten = 0; + + /* handshake verification failed in callback, do not send anything */ + if(ctx->tls_vrfy_result) + return ctx->tls_vrfy_result; + + (void)eos; /* use for stream EOF and block handling */ + result = cf_progress_ingress(cf, data, &pktx); + if(result) + goto out; + + if(!stream || stream->id < 0) { + if(ctx->shutdown_started) { + CURL_TRC_CF(data, cf, "cannot open stream on closed connection"); + result = CURLE_SEND_ERROR; + goto out; + } + result = h3_stream_open(cf, data, buf, len, pnwritten); + if(result) { + CURL_TRC_CF(data, cf, "failed to open stream -> %d", result); + goto out; + } + stream = H3_STREAM_CTX(ctx, data); + } + else if(stream->xfer_result) { + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id); + cf_ngtcp2_stream_close(cf, data, stream); + result = stream->xfer_result; + goto out; + } + else if(stream->closed) { + if(stream->resp_hds_complete) { + /* Server decided to close the stream after having sent us a final + * response. This is valid if it is not interested in the request + * body. This happens on 30x or 40x responses. + * We silently discard the data sent, since this is not a transport + * error situation. */ + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data" + "on closed stream with response", stream->id); + result = CURLE_OK; + *pnwritten = len; + goto out; + } + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) " + "-> stream closed", stream->id, len); + result = CURLE_HTTP3; + goto out; + } + else if(ctx->shutdown_started) { + CURL_TRC_CF(data, cf, "cannot send on closed connection"); + result = CURLE_SEND_ERROR; + goto out; + } + else { + result = Curl_bufq_write(&stream->sendbuf, buf, len, pnwritten); + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to " + "sendbuf(len=%zu) -> %d, %zu", + stream->id, len, result, *pnwritten); + if(result) + goto out; + (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id); + } + + if(*pnwritten > 0 && !ctx->tls_handshake_complete && ctx->use_earlydata) + ctx->earlydata_skip += *pnwritten; + + DEBUGASSERT(!result); + result = cf_progress_egress(cf, data, &pktx); + + out: + result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); + + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %d, %zu", + stream ? stream->id : -1, len, result, *pnwritten); + CF_DATA_RESTORE(cf, save); + return result; + } + + static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, + struct sockaddr_storage *remote_addr, + socklen_t remote_addrlen, int ecn, + void *userp) + { + struct pkt_io_ctx *pktx = userp; + struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx; + ngtcp2_pkt_info pi; + ngtcp2_path path; + int rv; + + ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr, + (socklen_t)ctx->q.local_addrlen); + ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr, + remote_addrlen); + pi.ecn = (uint8_t)ecn; + + rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts); + if(rv) { + CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)", + ngtcp2_strerror(rv), rv); + cf_ngtcp2_err_set(pktx->cf, pktx->data, rv); + + if(rv == NGTCP2_ERR_CRYPTO) + /* this is a "TLS problem", but a failed certificate verification + is a common reason for this */ + return CURLE_PEER_FAILED_VERIFICATION; + return CURLE_RECV_ERROR; + } + + return CURLE_OK; + } + + static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct pkt_io_ctx *pktx) + { + struct cf_ngtcp2_ctx *ctx = cf->ctx; + struct pkt_io_ctx local_pktx; + CURLcode result = CURLE_OK; + + if(!pktx) { + pktx_init(&local_pktx, cf, data); + pktx = &local_pktx; + } + else { + pktx_update_time(pktx, cf); + ngtcp2_path_storage_zero(&pktx->ps); + } + + result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); + if(result) + return result; + + return vquic_recv_packets(cf, data, &ctx->q, 1000, recv_pkt, pktx); + } + + /** + * Read a network packet to send from ngtcp2 into `buf`. + * Return number of bytes written or -1 with *err set. + */ + static CURLcode read_pkt_to_send(void *userp, + unsigned char *buf, size_t buflen, + size_t *pnread) + { + struct pkt_io_ctx *x = userp; + struct cf_ngtcp2_ctx *ctx = x->cf->ctx; + nghttp3_vec vec[16]; + nghttp3_ssize veccnt; + ngtcp2_ssize ndatalen; + uint32_t flags; + int64_t stream_id; + int fin; + ssize_t n; + + *pnread = 0; + veccnt = 0; + stream_id = -1; + fin = 0; + + /* ngtcp2 may want to put several frames from different streams into + * this packet. `NGTCP2_WRITE_STREAM_FLAG_MORE` tells it to do so. + * When `NGTCP2_ERR_WRITE_MORE` is returned, we *need* to make + * another iteration. + * When ngtcp2 is happy (because it has no other frame that would fit + * or it has nothing more to send), it returns the total length + * of the assembled packet. This may be 0 if there was nothing to send. */ for(;;) { if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) { @@ -1838,13 +1806,13 @@ static CURLcode read_pkt_to_send(void *userp, else if(n < 0) { switch(n) { case NGTCP2_ERR_STREAM_DATA_BLOCKED: { - struct h3_stream_ctx *stream; + struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data); DEBUGASSERT(ndatalen == -1); nghttp3_conn_block_stream(ctx->h3conn, stream_id); CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] block quic flow", (curl_int64_t)stream_id); - stream = cf_ngtcp2_get_stream(ctx, stream_id); - if(stream) /* it might be not one of our h3 streams? */ + DEBUGASSERT(stream); + if(stream) stream->quic_flow_blocked = TRUE; n = 0; break; @@ -1893,10 +1861,9 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, { struct cf_ngtcp2_ctx *ctx = cf->ctx; size_t nread; - size_t max_payload_size, path_max_payload_size; + size_t max_payload_size, path_max_payload_size, max_pktcnt; size_t pktcnt = 0; size_t gsolen = 0; /* this disables gso until we have a clue */ - size_t send_quantum; CURLcode curlcode; struct pkt_io_ctx local_pktx; @@ -1932,69 +1899,71 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, max_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(ctx->qconn); path_max_payload_size = ngtcp2_conn_get_path_max_tx_udp_payload_size(ctx->qconn); - send_quantum = ngtcp2_conn_get_send_quantum(ctx->qconn); - CURL_TRC_CF(data, cf, "egress, collect and send packets, quantum=%zu", - send_quantum); + /* maximum number of packets buffered before we flush to the socket */ + max_pktcnt = CURLMIN(MAX_PKT_BURST, + ctx->q.sendbuf.chunk_size / max_payload_size); + for(;;) { /* add the next packet to send, if any, to our buffer */ curlcode = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size, read_pkt_to_send, pktx, &nread); - if(curlcode == CURLE_AGAIN) - break; - else if(curlcode) - return curlcode; - else { - size_t buflen = Curl_bufq_len(&ctx->q.sendbuf); - if((buflen >= send_quantum) || - ((buflen + gsolen) >= ctx->q.sendbuf.chunk_size)) - break; - DEBUGASSERT(nread > 0); - ++pktcnt; - if(pktcnt == 1) { - /* first packet in buffer. This is either of a known, "good" - * payload size or it is a PMTUD. We will see. */ - gsolen = nread; - } - else if(nread > gsolen || - (gsolen > path_max_payload_size && nread != gsolen)) { - /* The just added packet is a PMTUD *or* the one(s) before the - * just added were PMTUD and the last one is smaller. - * Flush the buffer before the last add. */ - curlcode = vquic_send_tail_split(cf, data, &ctx->q, - gsolen, nread, nread); - if(curlcode) { - if(curlcode == CURLE_AGAIN) { - Curl_expire(data, 1, EXPIRE_QUIC); - return CURLE_OK; - } - return curlcode; + if(curlcode) { + if(curlcode != CURLE_AGAIN) + return curlcode; + /* Nothing more to add, flush and leave */ + curlcode = vquic_send(cf, data, &ctx->q, gsolen); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; } - pktcnt = 0; + return curlcode; } - else if(nread < gsolen) { - /* Reached MAX_PKT_BURST *or* - * the capacity of our buffer *or* - * last add was shorter than the previous ones, flush */ - break; + goto out; + } + + DEBUGASSERT(nread > 0); + if(pktcnt == 0) { + /* first packet in buffer. This is either of a known, "good" + * payload size or it is a PMTUD. We will see. */ + gsolen = nread; + } + else if(nread > gsolen || + (gsolen > path_max_payload_size && nread != gsolen)) { + /* The just added packet is a PMTUD *or* the one(s) before the + * just added were PMTUD and the last one is smaller. + * Flush the buffer before the last add. */ + curlcode = vquic_send_tail_split(cf, data, &ctx->q, + gsolen, nread, nread); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; } + pktcnt = 0; + continue; } - } - if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) { - /* time to send */ - CURL_TRC_CF(data, cf, "egress, send collected %zu packets in %zu bytes", - pktcnt, Curl_bufq_len(&ctx->q.sendbuf)); - curlcode = vquic_send(cf, data, &ctx->q, gsolen); - if(curlcode) { - if(curlcode == CURLE_AGAIN) { - Curl_expire(data, 1, EXPIRE_QUIC); - return CURLE_OK; + if(++pktcnt >= max_pktcnt || nread < gsolen) { + /* Reached MAX_PKT_BURST *or* + * the capacity of our buffer *or* + * last add was shorter than the previous ones, flush */ + curlcode = vquic_send(cf, data, &ctx->q, gsolen); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; } - return curlcode; + /* pktbuf has been completely sent */ + pktcnt = 0; } - pktx_update_time(pktx, cf); - ngtcp2_conn_update_pkt_tx_time(ctx->qconn, pktx->ts); } + +out: return CURLE_OK; } @@ -2011,8 +1980,8 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf, } static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf, - struct Curl_easy *data, - int event, int arg1, void *arg2) + struct Curl_easy *data, + int event, int arg1, void *arg2) { struct cf_ngtcp2_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -2040,11 +2009,19 @@ static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf, } break; } + case CF_CTRL_DATA_IDLE: { + struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); + CURL_TRC_CF(data, cf, "data idle"); + if(stream && !stream->closed) { + result = check_and_set_expiry(cf, data, NULL); + if(result) + CURL_TRC_CF(data, cf, "data idle, check_and_set_expiry -> %d", result); + } + break; + } case CF_CTRL_CONN_INFO_UPDATE: - if(!cf->sockindex && cf->connected) { + if(!cf->sockindex && cf->connected) cf->conn->httpversion_seen = 30; - Curl_conn_set_multiplex(cf->conn); - } break; default: break; @@ -2227,7 +2204,7 @@ static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) if(cf && data && ctx) { unsigned char *quic_tp = NULL; size_t quic_tp_len = 0; -#ifdef HAVE_OPENSSL_EARLYDATA +#if defined(HAVE_OPENSSL_EARLYDATA) ngtcp2_ssize tplen; uint8_t tpbuf[256]; @@ -2480,7 +2457,11 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, CURLcode result; const struct Curl_sockaddr_ex *sockaddr = NULL; int qfd; - static const struct alpn_spec ALPN_SPEC_H3 = {{ "h3", "h3-29" }, 2}; + /* Declare all variables at the top for C90 compliance */ + uint32_t chosen_quic_version = NGTCP2_PROTO_VER_V1; /* Default to v1 */ + static const struct alpn_spec ALPN_SPEC_H3 = { + { "h3", "h3-29" }, 2 + }; DEBUGASSERT(ctx->initialized); ctx->dcid.datalen = NGTCP2_MAX_CIDLEN; @@ -2501,7 +2482,8 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, if(result) return result; - if(Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL)) + Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL); + if(!sockaddr) return CURLE_QUIC_CONNECT_ERROR; ctx->q.local_addrlen = sizeof(ctx->q.local_addr); rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr, @@ -2515,11 +2497,22 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, ngtcp2_addr_init(&ctx->connected_path.remote, &sockaddr->curl_sa_addr, (socklen_t)sockaddr->addrlen); - rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid, - &ctx->connected_path, - NGTCP2_PROTO_VER_V1, &ng_callbacks, - &ctx->settings, &ctx->transport_params, - Curl_ngtcp2_mem(), cf); + /* chosen_quic_version is now declared at the top. Assign value here. */ + if(data->set.quic_version == 2) { + chosen_quic_version = NGTCP2_PROTO_VER_V2; + } + /* Use NGTCP2_PROTO_VER_V1 if quic_version is 0 or 1 (default init). */ + + rc = ngtcp2_conn_client_new_versioned(&ctx->qconn, &ctx->dcid, &ctx->scid, + &ctx->connected_path, + chosen_quic_version, /* Use the chosen version */ + NGTCP2_CALLBACKS_VERSION, + &ng_callbacks, + NGTCP2_SETTINGS_VERSION, + &ctx->settings, + NGTCP2_TRANSPORT_PARAMS_VERSION, + &ctx->transport_params, + NULL, cf); if(rc) return CURLE_QUIC_CONNECT_ERROR; @@ -2560,8 +2553,8 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, } static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) + struct Curl_easy *data, + bool *done) { struct cf_ngtcp2_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -2622,40 +2615,20 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, out: if(result == CURLE_RECV_ERROR && ctx->qconn && ngtcp2_conn_in_draining_period(ctx->qconn)) { - const ngtcp2_ccerr *cerr = ngtcp2_conn_get_ccerr(ctx->qconn); - - result = CURLE_COULDNT_CONNECT; - if(cerr) { - CURL_TRC_CF(data, cf, "connect error, type=%d, code=%" - FMT_PRIu64, - cerr->type, (curl_uint64_t)cerr->error_code); - switch(cerr->type) { - case NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION: - CURL_TRC_CF(data, cf, "error in version negotiation"); - break; - default: - if(cerr->error_code >= NGTCP2_CRYPTO_ERROR) { - CURL_TRC_CF(data, cf, "crypto error, tls alert=%u", - (unsigned int)(cerr->error_code & 0xffu)); - } - else if(cerr->error_code == NGTCP2_CONNECTION_REFUSED) { - CURL_TRC_CF(data, cf, "connection refused by server"); - /* When a QUIC server instance is shutting down, it may send us a - * CONNECTION_CLOSE with this code right away. We want - * to keep on trying in this case. */ - result = CURLE_WEIRD_SERVER_REPLY; - } - } - } + /* When a QUIC server instance is shutting down, it may send us a + * CONNECTION_CLOSE right away. Our connection then enters the DRAINING + * state. The CONNECT may work in the near future again. Indicate + * that as a "weird" reply. */ + result = CURLE_WEIRD_SERVER_REPLY; } #ifndef CURL_DISABLE_VERBOSE_STRINGS if(result) { struct ip_quadruple ip; - if(!Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip)) - infof(data, "QUIC connect to %s port %u failed: %s", - ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); + Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); + infof(data, "QUIC connect to %s port %u failed: %s", + ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); } #endif if(!result && ctx->qconn) { @@ -2668,8 +2641,8 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, } static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, - struct Curl_easy *data, - int query, int *pres1, void *pres2) + struct Curl_easy *data, + int query, int *pres1, void *pres2) { struct cf_ngtcp2_ctx *ctx = cf->ctx; struct cf_call_data save; @@ -2728,7 +2701,7 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, case CF_QUERY_SSL_CTX_INFO: { struct curl_tlssessioninfo *info = pres2; if(Curl_vquic_tls_get_ssl_info(&ctx->tls, - (query == CF_QUERY_SSL_CTX_INFO), info)) + (query == CF_QUERY_SSL_CTX_INFO), info)) return CURLE_OK; break; } @@ -2747,50 +2720,46 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, } static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *input_pending) -{ - struct cf_ngtcp2_ctx *ctx = cf->ctx; - bool alive = FALSE; - const ngtcp2_transport_params *rp; - struct cf_call_data save; - - CF_DATA_SAVE(save, cf, data); - *input_pending = FALSE; - if(!ctx->qconn || ctx->shutdown_started) - goto out; - - /* We do not announce a max idle timeout, but when the peer does - * it will close the connection when it expires. */ - rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); - if(rp && rp->max_idle_timeout) { - timediff_t idletime_ms = curlx_timediff(curlx_now(), ctx->q.last_io); - if(idletime_ms > 0) { - uint64_t max_idle_ms = - (uint64_t)(rp->max_idle_timeout / NGTCP2_MILLISECONDS); - if((uint64_t)idletime_ms > max_idle_ms) - goto out; - } - } - - if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) - goto out; - - alive = TRUE; - if(*input_pending) { - CURLcode result; - /* This happens before we have sent off a request and the connection is - not in use by any other transfer, there should not be any data here, - only "protocol frames" */ - *input_pending = FALSE; - result = cf_progress_ingress(cf, data, NULL); - CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result); - alive = result ? FALSE : TRUE; - } + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + bool alive = FALSE; + const ngtcp2_transport_params *rp; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + *input_pending = FALSE; + if(!ctx->qconn || ctx->shutdown_started) + goto out; + + /* We do not announce a max idle timeout, but when the peer does + * it will close the connection when it expires. */ + rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); + if(rp && rp->max_idle_timeout) { + timediff_t idletime = curlx_timediff(curlx_now(), ctx->q.last_io); + if(idletime > 0 && (uint64_t)idletime > rp->max_idle_timeout) + goto out; + } + + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + goto out; + + alive = TRUE; + if(*input_pending) { + CURLcode result; + /* This happens before we have sent off a request and the connection is + not in use by any other transfer, there should not be any data here, + only "protocol frames" */ + *input_pending = FALSE; + result = cf_progress_ingress(cf, data, NULL); + CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result); + alive = result ? FALSE : TRUE; + } out: - CF_DATA_RESTORE(cf, save); - return alive; + CF_DATA_RESTORE(cf, save); + return alive; } struct Curl_cftype Curl_cft_http3 = { @@ -2817,7 +2786,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, const struct Curl_addrinfo *ai) { struct cf_ngtcp2_ctx *ctx = NULL; - struct Curl_cfilter *cf = NULL; + struct Curl_cfilter *cf = NULL, *udp_cf = NULL; CURLcode result; (void)data; @@ -2831,39 +2800,42 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); if(result) goto out; - cf->conn = conn; - result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC); + result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); if(result) goto out; - cf->next->conn = cf->conn; - cf->next->sockindex = cf->sockindex; + + cf->conn = conn; + udp_cf->conn = cf->conn; + udp_cf->sockindex = cf->sockindex; + cf->next = udp_cf; out: *pcf = (!result) ? cf : NULL; if(result) { - if(cf) - Curl_conn_cf_discard_chain(&cf, data); - else if(ctx) - cf_ngtcp2_ctx_free(ctx); + if(udp_cf) + Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); + Curl_safefree(cf); + cf_ngtcp2_ctx_free(ctx); } return result; } bool Curl_conn_is_ngtcp2(const struct Curl_easy *data, - const struct connectdata *conn, - int sockindex) + const struct connectdata *conn, + int sockindex) { - struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; + struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; - (void)data; - for(; cf; cf = cf->next) { - if(cf->cft == &Curl_cft_http3) - return TRUE; - if(cf->cft->flags & CF_TYPE_IP_CONNECT) - return FALSE; - } - return FALSE; + (void)data; + for(; cf; cf = cf->next) { + if(cf->cft == &Curl_cft_http3) + return TRUE; + if(cf->cft->flags & CF_TYPE_IP_CONNECT) + return FALSE; + } + return FALSE; } - + #endif + From 0d7c7a699f47aa92dd4d647a7ce5fa1641917ad2 Mon Sep 17 00:00:00 2001 From: Karthik Das <92445174+devkdas@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:26:52 +0530 Subject: [PATCH 465/465] Add retry delay and quic version to config --- src/tool_cfgable.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index 48148a88ad5b..7b4ee8083586 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -52,6 +52,8 @@ struct OperationConfig *config_alloc(void) config->ftp_skip_ip = TRUE; config->file_clobber_mode = CLOBBER_DEFAULT; config->upload_flags = CURLULFLAG_SEEN; + config->retry_delay_ms = RETRY_SLEEP_DEFAULT; + config->quic_version = 0; /* Default to 0, flag not used */ curlx_dyn_init(&config->postdata, MAX_FILE2MEMORY); return config; } @@ -189,7 +191,6 @@ static void free_config_fields(struct OperationConfig *config) tool_safefree(config->ech); tool_safefree(config->ech_config); tool_safefree(config->ech_public); - tool_safefree(config->knownhosts); } void config_free(struct OperationConfig *config) @@ -259,7 +260,7 @@ static void free_globalconfig(void) tool_safefree(global->trace_dump); if(global->trace_fopened && global->trace_stream) - curlx_fclose(global->trace_stream); + fclose(global->trace_stream); global->trace_stream = NULL; tool_safefree(global->libcurl);