diff --git a/.circleci/config.yml b/.circleci/config.yml index c67f572c527e..63eae308c49f 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: @@ -61,44 +61,21 @@ 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: 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; } - configure-openssl-no-verbose: - steps: - - run: - command: | - autoreconf -fi - ./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-werror \ - --with-openssl --disable-verbose \ - || { tail -1000 config.log; false; } - configure-no-proxy: steps: - 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; } @@ -107,7 +84,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; } @@ -116,26 +93,16 @@ 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; } - 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: 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; } @@ -163,24 +130,6 @@ jobs: - build - test - no-verbose: - executor: ubuntu - steps: - - checkout - - install-deps - - configure-openssl-no-verbose - - build - - wolfssh: - executor: ubuntu - steps: - - checkout - - install-deps - - install-wolfssl - - install-wolfssh - - configure-wolfssh - - build - no-proxy: executor: ubuntu steps: @@ -250,14 +199,6 @@ workflows: jobs: - no-proxy - openssl-no-verbose: - jobs: - - no-verbose - - wolfssl-wolfssh: - jobs: - - wolfssh - arm-openssl: jobs: - arm diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 701a5d01cfc4..bd5661bea41a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,4 +7,15 @@ updates: - package-ecosystem: 'github-actions' directory: '/' schedule: - interval: 'weekly' + interval: 'monthly' + commit-message: + prefix: 'GHA:' + + - package-ecosystem: 'pip' + directories: + - '/.github/scripts' + - '/tests' + schedule: + interval: 'monthly' + commit-message: + prefix: 'GHA:' 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/cmp-config.pl b/.github/scripts/cmp-config.pl index 88df37b795bb..3ad0570e2839 100755 --- a/.github/scripts/cmp-config.pl +++ b/.github/scripts/cmp-config.pl @@ -45,6 +45,8 @@ '#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_H 1' => 1, '#define HAVE_GSSAPI_GSSAPI_KRB5_H 1' => 1, '#define HAVE_INTTYPES_H 1' => 1, '#define HAVE_LDAP_H 1' => 1, @@ -56,7 +58,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 +79,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/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 766eeeb87c6f..bbbbef571968 100755 --- a/.github/scripts/codespell.sh +++ b/.github/scripts/codespell.sh @@ -9,12 +9,11 @@ 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/*' \ --skip 'scripts/wcurl' \ - --skip 'winbuild/*' \ --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/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/.github/scripts/spellcheck.words b/.github/scripts/pyspelling.words similarity index 99% rename from .github/scripts/spellcheck.words rename to .github/scripts/pyspelling.words index 13b7b2f3674d..a5c28091301f 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/pyspelling.words @@ -97,6 +97,7 @@ changeset CharConv charset charsets +checkdocs checksrc checksums chgrp @@ -122,6 +123,7 @@ CMakeLists CNA CNAME CNAMEs +CodeQL CODESET codeset CodeSonar @@ -230,9 +232,9 @@ else's encodings enctype endianness -enums Engler enum +enums epoll EPRT EPSV @@ -292,7 +294,9 @@ getinfo GETing getpwuid ggcov +GHA Ghedini +giga Gisle Glesys globbed @@ -355,7 +359,6 @@ HTTPS https HTTPSRR hyper's -Högskolan IANA Icecast ICONV @@ -423,7 +426,6 @@ Krb krb Kubernetes Kuhrt -Kungliga Largefile LDAP ldap @@ -618,6 +620,7 @@ PEM pem perl permafailing +peta PINGs pipelining PKCS @@ -742,6 +745,7 @@ scp SDK se SEB +SecTrust SEK selectable Serv @@ -847,7 +851,7 @@ Tatsuhiro TBD TCP tcpdump -Tekniska +tera testability testcurl TFTP @@ -929,6 +933,7 @@ VC vcpkg vexxhost Viktor +virtualized Virtuozzo VLAN VM diff --git a/.github/scripts/spellcheck.yaml b/.github/scripts/pyspelling.yaml similarity index 92% rename from .github/scripts/spellcheck.yaml rename to .github/scripts/pyspelling.yaml index 05ddf0d937f1..8e26b76189bc 100644 --- a/.github/scripts/spellcheck.yaml +++ b/.github/scripts/pyspelling.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/winbuild/.gitignore b/.github/scripts/requirements-docs.txt similarity index 84% rename from winbuild/.gitignore rename to .github/scripts/requirements-docs.txt index 0d7f2b276f76..bd50e5010efb 100644 --- a/winbuild/.gitignore +++ b/.github/scripts/requirements-docs.txt @@ -2,5 +2,4 @@ # # SPDX-License-Identifier: curl -*.idb -*.inc +pyspelling==2.11 diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt new file mode 100644 index 000000000000..4533b2cfd7d9 --- /dev/null +++ b/.github/scripts/requirements.txt @@ -0,0 +1,9 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +cmakelang==0.6.13 +codespell==2.4.1 +pytype==2024.10.11 +reuse==6.1.2 +ruff==0.14.0 diff --git a/.github/scripts/spacecheck.pl b/.github/scripts/spacecheck.pl index e61d30b5b0c9..fbd064db3ba2 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 = ( @@ -54,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/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/.github/scripts/typos.toml b/.github/scripts/typos.toml index 46301615cd4f..28dcad73bec4 100644 --- a/.github/scripts/typos.toml +++ b/.github/scripts/typos.toml @@ -9,9 +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)$", + "^(eyeballers|HELO_smtp|optin|passin|perfec|SMTP_HELO)$", + "^(clen|req_clen|smtp_perform_helo|smtp_state_helo_resp|Tru64|_stati64)$", + "secur32", + "proxys", # this should be limited to tests/http/*. Short for secure proxy. ] extend-ignore-re = [ @@ -20,10 +21,12 @@ extend-ignore-re = [ [files] extend-exclude = [ - ".github/scripts/codespell-ignore.txt", - ".github/scripts/spellcheck.words", + ".github/scripts/codespell-ignore.words", + ".github/scripts/pyspelling.words", "docs/THANKS", "packages/*", + "projects/Windows/tmpl/curl.vcxproj", + "projects/Windows/tmpl/libcurl.vcxproj", "scripts/wcurl", - "winbuild/*", + "tests/data/test*", ] 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/.github/workflows/appveyor-status.yml b/.github/workflows/appveyor-status.yml index cb7f96b1907e..48e11b0e3d3c 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 }} @@ -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 917efc539891..58f5f29f8b4c 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.0.0 # with: # persist-credentials: false # @@ -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' @@ -93,18 +93,18 @@ jobs: name: 'linkcheck' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: 'mdlinkcheck' run: ./scripts/mdlinkcheck - spellcheck: - name: 'spellcheck' + pyspelling: + name: 'pyspelling' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -113,19 +113,29 @@ 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@35a02bae020e6999c5c37fabaf447f2eb8822ca7 # 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 + # setup the custom wordlist + grep -v '^#' .github/scripts/pyspelling.words > wordlist.txt + aspell --version + pyspelling --version + pyspelling --verbose --jobs 5 --config .github/scripts/pyspelling.yaml badwords-synopsis: name: 'badwords, synopsis' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -141,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 @@ -153,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 061a192297d9..a0337904f2c7 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -12,24 +12,20 @@ name: 'Source' - master - '*/ci' paths-ignore: - - '**/*.md' - '.circleci/**' - 'appveyor.*' - 'Dockerfile' - 'plan9/**' - 'tests/data/**' - - 'winbuild/**' pull_request: branches: - master paths-ignore: - - '**/*.md' - '.circleci/**' - 'appveyor.*' - 'Dockerfile' - 'plan9/**' - 'tests/data/**' - - 'winbuild/**' permissions: {} @@ -38,73 +34,72 @@ jobs: name: 'checksrc' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - 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 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: 'install' - 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: 'REUSE check' + run: | + source ~/venv/bin/activate + reuse lint - name: 'codespell' run: | + source ~/venv/bin/activate codespell --version .github/scripts/codespell.sh - 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 - name: 'cmakelint' - run: scripts/cmakelint.sh + run: | + source ~/venv/bin/activate + scripts/cmakelint.sh + + - name: 'perlcheck' + run: | + scripts/perlcheck.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 - - 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 + run: | + source ~/venv/bin/activate + scripts/pythonlint.sh complexity: name: 'complexity' runs-on: ubuntu-latest timeout-minutes: 3 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -125,13 +120,15 @@ 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 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: 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 25a8f8cbc0fa..58eaa35be5ba 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,12 +13,10 @@ name: 'CodeQL' - '**/*.md' - '.circleci/**' - 'appveyor.*' - - 'docs/**' - 'packages/**' - 'plan9/**' - 'projects/**' - 'tests/data/**' - - 'winbuild/**' pull_request: branches: - master @@ -26,12 +24,10 @@ name: 'CodeQL' - '**/*.md' - '.circleci/**' - 'appveyor.*' - - 'docs/**' - 'packages/**' - 'plan9/**' - 'projects/**' - 'tests/data/**' - - 'winbuild/**' schedule: - cron: '0 0 * * 4' @@ -41,21 +37,97 @@ concurrency: permissions: {} jobs: - codeql: + gha_python: 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 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: 'initialize' - uses: github/codeql-action/init@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3 + uses: github/codeql-action/init@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 with: languages: actions, python queries: security-extended - name: 'perform analysis' - uses: github/codeql-action/analyze@d3678e237b9c32a6c9bffb3315c335f976f3549f # v3 + uses: github/codeql-action/analyze@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 + + c: + 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: + platform: [Linux, Windows] + env: + MATRIX_PLATFORM: '${{ matrix.platform }}' + steps: + - name: 'install prereqs' + if: ${{ matrix.platform == 'Linux' }} + 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 libssh-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 + with: + persist-credentials: false + + - name: 'initialize' + uses: github/codeql-action/init@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 + with: + languages: cpp + build-mode: manual + trap-caching: false + + - name: 'build' + timeout-minutes: 10 + shell: bash + run: | + 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 + cmake --build . --verbose + src/Debug/curl.exe --disable --version + else + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + + # MultiSSL + 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 \ + -DCURL_DISABLE_VERBOSE_STRINGS=ON + cmake --build _bld1 + 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 + 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 + cmake --build _bld2 --target servers + + _bld1/src/curl --disable --version + _bld2/src/curl --disable --version + fi + + - name: 'perform analysis' + uses: github/codeql-action/analyze@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 diff --git a/.github/workflows/configure-vs-cmake.yml b/.github/workflows/configure-vs-cmake.yml index 984fccd59221..5c35051f6a34 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 @@ -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 @@ -131,9 +131,9 @@ 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 + - 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 704a78d2cd28..91b0382a7562 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 }} @@ -49,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' @@ -60,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: @@ -78,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' @@ -107,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' @@ -125,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' @@ -152,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 bf6c69bfcfd0..c6b4e775ebe2 100644 --- a/.github/workflows/distcheck.yml +++ b/.github/workflows/distcheck.yml @@ -28,12 +28,14 @@ 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 - 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 @@ -47,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@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: 'release-tgz' path: 'curl-99.98.97.tar.gz' @@ -58,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 @@ -73,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' @@ -84,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 @@ -97,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' @@ -108,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 @@ -123,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' @@ -134,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 @@ -147,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' @@ -156,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 @@ -168,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' @@ -190,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' @@ -212,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' @@ -228,12 +230,14 @@ 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 - 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 @@ -248,12 +252,13 @@ 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' }} 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 @@ -262,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 @@ -297,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/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/hacktoberfest-accepted.yml b/.github/workflows/hacktoberfest-accepted.yml deleted file mode 100644 index 916b354481ca..000000000000 --- a/.github/workflows/hacktoberfest-accepted.yml +++ /dev/null @@ -1,72 +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: - # requires issues AND pull-requests write permissions to edit labels on PRs! - issues: write - pull-requests: write - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - 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' diff --git a/.github/workflows/http3-linux.yml b/.github/workflows/http3-linux.yml index 1a7ff07d5f25..38d2fb6ac025 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 @@ -42,25 +40,23 @@ env: MAKEFLAGS: -j 5 CURL_CI: github # handled in renovate.json - OPENSSL_VERSION: 3.5.2 - # handled in renovate.json - QUICTLS_VERSION: 3.3.0 + OPENSSL_VERSION: 3.6.0 # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com - LIBRESSL_VERSION: 4.1.0 + LIBRESSL_VERSION: 4.2.0 # renovate: datasource=github-tags depName=awslabs/aws-lc versioning=semver registryUrl=https://github.com - AWSLC_VERSION: 1.60.0 + 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 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 + NGTCP2_VERSION: 1.16.0 # 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 @@ -71,16 +67,16 @@ jobs: steps: - name: 'cache openssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - id: cache-openssl-http3 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + 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 }} - name: 'cache libressl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-libressl env: cache-name: cache-libressl @@ -89,7 +85,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.3.0 id: cache-awslc env: cache-name: cache-awslc @@ -98,7 +94,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.3.0 id: cache-boringssl env: cache-name: cache-boringssl @@ -106,17 +102,8 @@ jobs: path: ~/boringssl/build key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.BORINGSSL_VERSION }} - - name: 'cache quictls' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - 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@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-gnutls env: cache-name: cache-gnutls @@ -125,7 +112,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.3.0 id: cache-wolfssl env: cache-name: cache-wolfssl @@ -134,7 +121,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.3.0 id: cache-nghttp3 env: cache-name: cache-nghttp3 @@ -143,16 +130,16 @@ 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.3.0 id: cache-ngtcp2 env: 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@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-ngtcp2-boringssl env: cache-name: cache-ngtcp2-boringssl @@ -161,21 +148,20 @@ 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.3.0 id: cache-nghttp2 env: 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' || @@ -193,17 +179,20 @@ 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" - 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 @@ -240,22 +229,13 @@ 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: | 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" \ @@ -290,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 @@ -300,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 \ @@ -332,10 +308,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 + 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 linux: @@ -362,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' @@ -411,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 @@ -471,11 +436,13 @@ 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 - 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 +451,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 +462,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,26 +470,25 @@ 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 echo 'CC=gcc-12' >> "$GITHUB_ENV" echo 'CXX=g++-12' >> "$GITHUB_ENV" - name: 'cache openssl' if: ${{ matrix.build.name == 'openssl' || matrix.build.name == 'openssl-quic' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - id: cache-openssl-http3 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + 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 }} fail-on-cache-miss: true - name: 'cache libressl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-libressl env: cache-name: cache-libressl @@ -532,7 +498,7 @@ jobs: fail-on-cache-miss: true - name: 'cache awslc' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-awslc env: cache-name: cache-awslc @@ -542,7 +508,7 @@ jobs: fail-on-cache-miss: true - name: 'cache boringssl' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-boringssl env: cache-name: cache-boringssl @@ -551,19 +517,9 @@ jobs: key: ${{ runner.os }}-http3-build-${{ env.cache-name }}-${{ env.BORINGSSL_VERSION }} fail-on-cache-miss: true - - name: 'cache quictls' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - 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@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-gnutls env: cache-name: cache-gnutls @@ -574,7 +530,7 @@ jobs: - name: 'cache wolfssl' if: ${{ matrix.build.name == 'wolfssl' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-wolfssl env: cache-name: cache-wolfssl @@ -584,7 +540,7 @@ jobs: fail-on-cache-miss: true - name: 'cache nghttp3' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-nghttp3 env: cache-name: cache-nghttp3 @@ -594,17 +550,17 @@ jobs: fail-on-cache-miss: true - name: 'cache ngtcp2' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-ngtcp2 env: 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' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-ngtcp2-boringssl env: cache-name: cache-ngtcp2-boringssl @@ -614,18 +570,18 @@ jobs: fail-on-cache-miss: true - name: 'cache nghttp2' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-nghttp2 env: 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' if: ${{ matrix.build.name == 'quiche' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-quiche env: cache-name: cache-quiche @@ -654,7 +610,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 @@ -681,7 +637,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 @@ -705,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') }} @@ -720,8 +676,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') }} @@ -738,8 +694,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/label.yml b/.github/workflows/label.yml index b84702a8a1b9..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: {} @@ -19,10 +20,10 @@ 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 + - 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 352986eb0473..e145633708de 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: {} @@ -70,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 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. @@ -78,18 +76,26 @@ 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 - - name: 'cmake build-only (out-of-tree, libssh2)' + - 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=ON -DCURL_USE_LIBSSH=OFF -DUSE_LIBRTMP=ON - make install - src/curl --disable --version + -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 + + - 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() }} + run: cat bld-1/CMakeFiles/CMake*.log 2>/dev/null || true - name: 'cmake build-only curl_config.h' run: | @@ -98,7 +104,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 @@ -106,15 +112,20 @@ 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::' 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 @@ -129,25 +140,30 @@ jobs: run: make -C bld-cares curl-examples-build - name: 'autoreconf' - run: autoreconf -if + run: autoreconf -fi - - name: 'configure (out-of-tree, c-ares, libssh2, zstd, gssapi)' + - name: 'autotools 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 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::' 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 ed206ec03c42..2d674dc195cf 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 }} @@ -39,22 +37,18 @@ 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 - LIBRESSL_VERSION: 4.1.0 + # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com + 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=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 - AWSLC_VERSION: 1.60.0 + 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.5.2 - # handled in renovate.json - QUICTLS_VERSION: 3.3.0 + OPENSSL_VERSION: 3.6.0 # renovate: datasource=github-tags depName=rustls/rustls-ffi versioning=semver registryUrl=https://github.com RUSTLS_VERSION: 0.15.0 # handled in renovate.json @@ -75,33 +69,32 @@ jobs: fail-fast: false matrix: build: - - name: 'libressl heimdal' - install_packages: zlib1g-dev 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: zlib1g-dev 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 - 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_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_packages: valgrind + 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 @@ -109,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 @@ -116,10 +110,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 @@ -135,17 +129,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 @@ -154,33 +146,32 @@ 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 + configure: CFLAGS=-std=gnu89 --with-openssl --enable-debug --disable-verbose 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 - name: 'openssl !ipv6 !--libcurl !--digest-auth' @@ -192,17 +183,17 @@ 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' - 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 @@ -221,29 +212,67 @@ 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_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 + 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 libgss-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: 'scanbuild' - install_packages: clang-tools clang libssl-dev libssh2-1-dev + - name: 'scan-build H3 c-ares' + install_packages: clang-tools clang libidn2-dev libnghttp2-dev install_steps: skipall - configure: --with-openssl --enable-debug --with-libssh2 --disable-unity + 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 + --disable-verbose - name: 'address-sanitizer' - install_packages: zlib1g-dev libssh2-1-dev 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 - 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 -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: zlib1g-dev clang libtsan2 + install_packages: clang libtsan2 install_steps: pytest openssl-tsan CFLAGS: -fsanitize=thread -g LDFLAGS: -fsanitize=thread @@ -279,7 +308,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 @@ -302,6 +331,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' || '' }} @@ -312,10 +342,12 @@ 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 + if [ -n "${INSTALL_PACKAGES_BREW}" ]; then + HOMEBREW_NO_AUTO_UPDATE=1 /home/linuxbrew/.linuxbrew/bin/brew install ${INSTALL_PACKAGES_BREW} + fi - name: 'install prereqs' if: ${{ contains(matrix.build.name, 'i686') }} @@ -328,20 +360,19 @@ 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') }} 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 - name: 'cache libressl' if: ${{ contains(matrix.build.install_steps, 'libressl') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-libressl env: cache-name: cache-libressl @@ -355,12 +386,13 @@ jobs: 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 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') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-wolfssl-all env: cache-name: cache-wolfssl-all @@ -381,7 +413,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.3.0 id: cache-wolfssl-opensslextra env: cache-name: cache-wolfssl-opensslextra @@ -396,34 +428,13 @@ 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 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-mbedtls env: cache-name: cache-mbedtls-threadsafe @@ -446,7 +457,7 @@ jobs: - name: 'cache openldap-static' if: ${{ contains(matrix.build.install_steps, 'openldap-static') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-openldap-static env: cache-name: cache-openldap-static @@ -466,7 +477,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.3.0 id: cache-openssl-tsan env: cache-name: cache-openssl-tsan @@ -483,28 +494,9 @@ jobs: make make -j1 install_sw - - name: 'cache quictls' - if: ${{ contains(matrix.build.install_steps, 'quictls') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - 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@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-awslc env: cache-name: cache-awslc @@ -517,15 +509,14 @@ 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 . - name: 'cache boringssl' if: ${{ contains(matrix.build.install_steps, 'boringssl') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-boringssl env: cache-name: cache-boringssl @@ -546,7 +537,7 @@ jobs: - name: 'cache rustls' if: ${{ contains(matrix.build.install_steps, 'rustls') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-rustls env: cache-name: cache-rustls @@ -579,7 +570,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 @@ -610,7 +601,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 @@ -647,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: | @@ -671,8 +662,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') }} @@ -681,18 +672,13 @@ jobs: TEST_TARGET: ${{ matrix.build.torture && 'test-torture' || 'test-ci' }} 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 - TFLAGS+=' ~2056 ~2057 ~2077 ~2078' # memory leaks from Curl_auth_decode_spnego_message() -> gss_import_name() - fi + 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 - [ -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 @@ -708,8 +694,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') }} @@ -717,7 +703,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 5e817dd4bdd1..1e9f2408a8ba 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 }} @@ -60,8 +58,8 @@ 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 - LIBRESSL_VERSION: 4.1.0 + # renovate: datasource=github-tags depName=libressl/portable versioning=semver registryUrl=https://github.com + LIBRESSL_VERSION: 4.2.0 strategy: fail-fast: false matrix: @@ -106,12 +104,13 @@ 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::' - name: 'cache libressl' if: ${{ contains(matrix.build.install_steps, 'libressl') }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-libressl env: cache-name: cache-libressl @@ -123,11 +122,9 @@ 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 + --location "https://github.com/libressl/portable/releases/download/v${LIBRESSL_VERSION}/libressl-${LIBRESSL_VERSION}.tar.gz" | tar -xz 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 \ @@ -137,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 @@ -161,7 +158,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 \ @@ -254,45 +251,60 @@ 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) - - 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 + 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 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' + - 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 + 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 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 - - 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 + 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 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/krb5 + -DCURL_CLANG_TIDY=ON -DCLANG_TIDY=/opt/homebrew/opt/llvm/bin/clang-tidy + + - 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 @@ -302,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' @@ -342,7 +354,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: | @@ -351,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 @@ -369,7 +381,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 @@ -424,7 +436,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 @@ -449,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' @@ -461,6 +473,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 @@ -469,14 +482,13 @@ 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 + ~/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, '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' }} @@ -498,13 +510,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 + [ -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, '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 @@ -539,52 +551,63 @@ jobs: strategy: fail-fast: false matrix: - compiler: [gcc-12, gcc-13, gcc-14, llvm@15, llvm@18, clang] - # Xcode support matrix as of 2024-07, with default macOS SDK versions and OS names, years: + # Sources: + # 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 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 - # 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-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-14, macos-15] + 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-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-15, xcode: '14.1' } - - { image: macos-15, xcode: '14.2' } - - { image: macos-15, xcode: '14.3.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: '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-13, compiler: 'llvm@18' } + - { 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-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' }} @@ -601,10 +624,11 @@ 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::' + 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 @@ -638,7 +662,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 \ @@ -656,7 +680,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 \ @@ -681,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/non-native.yml b/.github/workflows/non-native.yml index 3c76ed9de852..8dccb9e39964 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 }} @@ -49,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' @@ -63,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 \ @@ -94,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' @@ -144,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 }}' @@ -166,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 @@ -194,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; } @@ -263,7 +261,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -286,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 0938142df92b..975b592c7ce1 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 }} @@ -41,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 - with: - msystem: msys - install: gcc make - - - name: 'perl version' - run: perl --version | tee "$GITHUB_WORKSPACE"/perlversion - - - name: 'cache perl packages' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - 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 @@ -112,8 +53,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 @@ -125,8 +66,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 @@ -135,12 +76,12 @@ jobs: libnghttp2-devel ${{ matrix.install }} - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: 'autoreconf' - if: ${{ matrix.build == 'automake' }} + if: ${{ matrix.build == 'autotools' }} timeout-minutes: 2 run: | PATH=/usr/bin @@ -162,7 +103,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 @@ -189,7 +130,7 @@ jobs: make -C bld V=1 install fi - - name: 'curl version' + - name: 'curl -V' timeout-minutes: 1 run: | PATH=/usr/bin @@ -244,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: @@ -284,7 +223,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 }} @@ -300,7 +239,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 }} @@ -313,7 +252,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 @@ -369,7 +308,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 @@ -393,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 @@ -433,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@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - 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 @@ -505,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: @@ -560,7 +466,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 @@ -572,7 +478,7 @@ jobs: ${{ matrix.install }} - name: 'cache compiler (gcc ${{ matrix.ver }}-${{ matrix.env }})' - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 id: cache-compiler with: path: D:\my-cache @@ -596,7 +502,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 @@ -641,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 '{}' \; @@ -660,24 +566,9 @@ 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' - if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - 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 @@ -721,13 +612,11 @@ 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 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false @@ -760,7 +649,7 @@ jobs: --host="${TRIPLET}" \ --with-schannel --with-winidn \ --without-libpsl \ - --disable-dependency-tracking + --disable-dependency-tracking --enable-option-checking=fatal fi - name: 'configure log' @@ -806,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: @@ -896,7 +783,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') }} @@ -918,7 +805,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 @@ -952,9 +839,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)" @@ -1021,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 '{}' \; @@ -1056,25 +942,10 @@ 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 - - name: 'cache perl packages' - if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }} - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - 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 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/CMake/FindGSS.cmake b/CMake/FindGSS.cmake index 9000445acb3f..1661f208d2f8 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,16 +41,12 @@ set(_gnu_modname "gss") set(_mit_modname "mit-krb5-gssapi") -set(_heimdal_modname "heimdal-gssapi") 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 "") @@ -59,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() @@ -69,37 +65,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 +97,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,157 +120,93 @@ 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) + 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" + 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) - set(GSS_FLAVOUR "Heimdal") # most probably, should not really matter - else() - if(_gss_vendor MATCHES "H|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?) - 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 + set(_gss_libdir_suffixes "") - if(_gss_INCLUDE_DIRS) # jay, 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) + 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") + 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() - 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 ${_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}) - get_filename_component(_gss_calculated_potential_root "${_gss_INCLUDE_DIRS}" DIRECTORY) - 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") - elseif(GSS_FLAVOUR STREQUAL "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") - set(_gss_libname "gssapi32") - else() - set(_gss_libname "libgssapi") - endif() - endif() + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + cmake_path(GET _gss_INCLUDE_DIRS PARENT_PATH _gss_calculated_potential_root) 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") - set(_gss_libname "gssapi_krb5") - else() - set(_gss_libname "gssapi") - endif() + get_filename_component(_gss_calculated_potential_root "${_gss_INCLUDE_DIRS}" DIRECTORY) endif() + list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root}) - 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() + if(NOT GSS_FLAVOUR) + message(FATAL_ERROR "GNU or MIT GSS is required") + 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) + 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") - if(NOT _gss_version) # for old CMake versions? - set(_gss_version ${_gss_${_mit_modname}_VERSION}) - endif() + set(GSS_PC_REQUIRES ${_mit_modname}) 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() + 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() @@ -304,33 +219,21 @@ 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") +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") 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") + get_filename_component(_mit_version + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE) 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(WIN32 AND _mit_version) set(GSS_VERSION "${_mit_version}") 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/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/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/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/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() diff --git a/CMakeLists.txt b/CMakeLists.txt index 0265162e74d3..65eaaf670a5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,13 @@ endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU") string(APPEND _target_flags " GCC") 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") endif() @@ -311,6 +318,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") @@ -737,6 +764,26 @@ 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) + 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) + 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) @@ -1364,23 +1411,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) @@ -1415,38 +1445,8 @@ if(CURL_USE_GSSAPI) if(GSS_FLAVOUR STREQUAL "GNU") set(HAVE_GSSGNU 1) - else() - 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() - - 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() - endif() - unset(_include_list) - cmake_pop_check_state() + elseif(GSS_VERSION) # MIT + set(CURL_KRB5_VERSION "\"${GSS_VERSION}\"") endif() else() message(WARNING "GSSAPI has been requested, but no supporting libraries found. Skipping.") @@ -1521,7 +1521,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() @@ -1984,6 +1984,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 @@ -2114,8 +2117,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) @@ -2175,6 +2178,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) @@ -2309,8 +2313,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}") 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 && \ 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/Makefile.am b/Makefile.am index b5ab0442a81d..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 \ @@ -66,9 +65,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 +76,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/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/RELEASE-NOTES b/RELEASE-NOTES index 04e1ad4779d9..0930a2719e04 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -1,19 +1,338 @@ -curl and libcurl 8.16.1 +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: 3499 + Public functions in libcurl: 100 + Contributors: 3519 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] + 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] + 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: + 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] + 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 `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 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] + 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] + 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] + 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: 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 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] + 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 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] + 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/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: 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: 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] + 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 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] + 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: 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] + 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 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: 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] + 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] + 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] + 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 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] + 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] + 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] + 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: 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] + 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 + 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] + 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] + 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 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] + 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] + 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: 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] + 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 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] + 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 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] + 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] + 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: 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] + 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] + 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] + 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 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: @@ -27,9 +346,9 @@ 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 The winbuild build system o Windows CE support See https://curl.se/dev/deprecate.html @@ -37,11 +356,340 @@ 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) + 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, 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, + 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: + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 + [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 diff --git a/REUSE.toml b/REUSE.toml index 81c214863fcd..40531913af3b 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -39,15 +39,6 @@ path = [ "tests/certs/**", "tests/data/test**", "tests/valgrind.supp", - # checksrc control files - "lib/.checksrc", - "lib/curlx/.checksrc", - "lib/vauth/.checksrc", - "lib/vquic/.checksrc", - "lib/vssh/.checksrc", - "lib/vtls/.checksrc", - "src/.checksrc", - "tests/server/.checksrc", ] SPDX-FileCopyrightText = "Daniel Stenberg, , et al." SPDX-License-Identifier = "curl" diff --git a/acinclude.m4 b/acinclude.m4 index fe10c2ec9715..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-* @@ -1474,14 +1484,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 @@ -1492,6 +1494,11 @@ AC_DEFUN([CURL_PREPARE_BUILDINFO], [ if test "x$compiler_id" = 'xGNU_C'; then curl_pflags="${curl_pflags} GCC" fi + if test "$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 diff --git a/appveyor.sh b/appveyor.sh index 1e4c16362fa5..4be76095ee4a 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 @@ -94,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 effd8589d17e..af6ecd2c159b 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' @@ -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/configure.ac b/configure.ac index af005beffd12..999ab122a323 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) @@ -211,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 @@ -275,11 +272,17 @@ 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 ]) +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") @@ -523,6 +526,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' @@ -1835,51 +1840,14 @@ if test x"$want_gss" = xyes; then gnu_gss=yes ], [ - dnl not found, check Heimdal or MIT - AC_CHECK_HEADERS([gssapi/gssapi.h], [], [not_mit=1]) + dnl not found, check for MIT 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, 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) - ] - ) - 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]) - ]) + dnl MIT not found + AC_MSG_ERROR([MIT or GNU GSS library required, but not found]) fi ] ) @@ -1889,7 +1857,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 @@ -1941,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" @@ -1956,8 +1936,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 @@ -2017,6 +1995,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 @@ -2205,20 +2184,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"]) @@ -2244,12 +2270,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" @@ -2293,8 +2313,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)" @@ -2407,28 +2427,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 ********************************************************************** @@ -4340,11 +4338,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" ;; *) ;; @@ -5017,8 +5013,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 @@ -5320,6 +5316,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 @@ -5457,9 +5457,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 @@ -5575,6 +5572,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/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/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/DEPRECATE.md b/docs/DEPRECATE.md index 65c630cbeebe..43c94875b175 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 @@ -60,7 +53,22 @@ 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 + +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 @@ -79,3 +87,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/ECH.md b/docs/ECH.md index 969bbfa27f54..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: @@ -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) @@ -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/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-CMAKE.md b/docs/INSTALL-CMAKE.md index ea761fa99a0e..e5c6b0d375e6 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` @@ -229,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` @@ -364,12 +363,12 @@ 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` - `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` @@ -448,8 +447,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. @@ -477,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/Heimdal/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). @@ -502,6 +498,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 `scripts/firefox-db2pem.sh` + # Migrating from Visual Studio IDE Project Files We recommend using CMake to build curl with MSVC. @@ -546,59 +562,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..453071afd57b 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 @@ -152,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 @@ -193,9 +213,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 @@ -217,7 +237,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: @@ -274,28 +294,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: @@ -309,29 +333,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 @@ -347,7 +375,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 +389,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 @@ -409,18 +435,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 @@ -444,8 +474,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" ``` @@ -494,9 +526,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 @@ -506,11 +536,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` diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index de993c3e4bcd..b6b00e924a73 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -29,16 +29,14 @@ 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 - wolfSSL 3.4.6 - OpenLDAP 2.0 - - MIT Kerberos 1.2.4 - - Heimdal ? + - MIT Kerberos 1.3 - nghttp2 1.15.0 - - Winsock 2.2 (on Windows 95+ and Windows CE .NET 4.1+) ## Build tools diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 170132f507d3..d4e4423094ef 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 @@ -37,18 +38,17 @@ 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 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 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 @@ -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 @@ -87,6 +85,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 @@ -122,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 @@ -230,12 +237,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 @@ -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 @@ -334,13 +339,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 @@ -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 @@ -554,6 +538,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 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 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 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/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/docs/TODO b/docs/TODO index 1e22814f385f..6c3ba904e721 100644 --- a/docs/TODO +++ b/docs/TODO @@ -23,24 +23,17 @@ 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 +245,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 +257,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 +278,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 +334,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 @@ -395,21 +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.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 @@ -549,8 +487,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 @@ -584,7 +522,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. @@ -913,14 +851,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/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/_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/_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* 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. 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/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/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/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/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..e791e36adf34 100644 --- a/docs/cmdline-opts/follow.md +++ b/docs/cmdline-opts/follow.md @@ -4,11 +4,14 @@ SPDX-License-Identifier: curl Long: follow Help: Follow redirects per spec Category: http +Protocols: HTTP Added: 8.16.0 Multi: boolean See-also: - request - location + - proto-redir + - max-redirs Example: - -X POST --follow $URL --- @@ -23,3 +26,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/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/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. 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/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/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/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/knownhosts.md b/docs/cmdline-opts/knownhosts.md new file mode 100644 index 000000000000..4b6386dd24ec --- /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: + - --knownhosts 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/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/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/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/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/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/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..4d9e83cd5f40 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 -response code. +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, 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 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-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 b11137df0a63..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 @@ -14,4 +15,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/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/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/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). 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/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 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. 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/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/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/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/docs/examples/.checksrc b/docs/examples/.checksrc new file mode 100644 index 000000000000..e35dccc7261d --- /dev/null +++ b/docs/examples/.checksrc @@ -0,0 +1,27 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +allowfunc fclose +allowfunc fdopen +allowfunc fopen +allowfunc fprintf +allowfunc gmtime +allowfunc localtime +allowfunc open +allowfunc printf +allowfunc snprintf +allowfunc socket +allowfunc sscanf +allowfunc strerror +allowfunc vsnprintf + +# Use of curl printf functions is discouraged +banfunc curl_maprintf +banfunc curl_mfprintf +banfunc curl_mprintf +banfunc curl_msnprintf +banfunc curl_mvaprintf +banfunc curl_mvfprintf +banfunc curl_mvprintf +banfunc curl_mvsnprintf diff --git a/docs/examples/.gitignore b/docs/examples/.gitignore index 4b78bd78dd05..788eefe1ef17 100644 --- a/docs/examples/.gitignore +++ b/docs/examples/.gitignore @@ -35,7 +35,6 @@ getreferrer ghiper headerapi hiperfifo -href_extractor hsts-preload htmltidy http-options @@ -69,6 +68,7 @@ interface ipv6 keepalive localport +log_failed_transfers maxconnects multi-app multi-debugcallback diff --git a/docs/examples/10-at-a-time.c b/docs/examples/10-at-a-time.c index 38a0f24ac62f..87971cbde62f 100644 --- a/docs/examples/10-at-a-time.c +++ b/docs/examples/10-at-a-time.c @@ -104,49 +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; - curl_global_init(CURL_GLOBAL_ALL); + 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--; - } - else { - fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg); + /* !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); } - 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/CMakeLists.txt b/docs/examples/CMakeLists.txt index cb1d983890c6..c86e8439fda7 100644 --- a/docs/examples/CMakeLists.txt +++ b/docs/examples/CMakeLists.txt @@ -24,20 +24,27 @@ 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) - 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") + 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 # warning LNK4221: This object file does not define any previously undefined public symbols, @@ -49,21 +56,38 @@ 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() + 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 27d4ce741bd4..0885b925c417 100644 --- a/docs/examples/Makefile.am +++ b/docs/examples/Makefile.am @@ -24,7 +24,8 @@ AUTOMAKE_OPTIONS = foreign nostdinc -EXTRA_DIST = CMakeLists.txt 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.example b/docs/examples/Makefile.example index cfb59c94ef10..fbbca8a9a9c0 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) $< $(CFLAGS) $(LDFLAGS) $(LIBS) -o $(TARGET) diff --git a/docs/examples/Makefile.inc b/docs/examples/Makefile.inc index acec3b93854b..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 \ @@ -132,6 +133,7 @@ check_PROGRAMS = \ smtp-tls \ smtp-vrfy \ sslbackend \ + synctime \ unixsocket \ url2file \ urlapi \ @@ -139,10 +141,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 \ @@ -151,12 +162,6 @@ COMPLICATED_EXAMPLES = \ htmltidy.c \ htmltitle.cpp \ multi-event.c \ - multi-uv.c \ - multithread.c \ - sessioninfo.c \ smooth-gtk-thread.c \ - synctime.c \ - threaded-ssl.c \ - usercertinmem.c \ version-check.pl \ xmlstream.c 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 c62250dce372..8718ac98bbed 100644 --- a/docs/examples/anyauthput.c +++ b/docs/examples/anyauthput.c @@ -104,13 +104,21 @@ int main(int argc, char **argv) return 2; #ifdef UNDER_CE - stat(file, &file_info); + /* !checksrc! disable BANNEDFUNC 1 */ + 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 */ - 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(); @@ -160,5 +168,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 ec12df58bf18..5855d872b658 100644 --- a/docs/examples/cacertinmem.c +++ b/docs/examples/cacertinmem.c @@ -26,6 +26,8 @@ * */ +/* Requires: USE_OPENSSL */ + #include #include #include @@ -34,6 +36,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) { @@ -43,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[] = @@ -68,22 +79,22 @@ 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; (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++) { @@ -99,67 +110,70 @@ 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; - 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 - */ - rv = curl_easy_perform(ch); - if(rv == 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); - rv = curl_easy_perform(ch); - if(rv == 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)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 264c514ba4c7..996db393f584 100644 --- a/docs/examples/chkspeed.c +++ b/docs/examples/chkspeed.c @@ -100,7 +100,7 @@ int main(int argc, char *argv[]) case 'm': case 'M': if(argv[0][2] == '=') { - long m = strtol((*argv) + 3, NULL, 10); + int m = atoi((*argv) + 3); switch(m) { case 1: url = URL_1M; @@ -156,66 +156,73 @@ 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(); + 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/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 da40953d918a..cebbd3cdcff0 100644 --- a/docs/examples/cookie_interface.c +++ b/docs/examples/cookie_interface.c @@ -32,7 +32,10 @@ #include #include -#include + +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif static int print_cookies(CURL *curl) { @@ -69,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]; @@ -93,10 +99,10 @@ main(void) printf("-----------------------------------------------\n" "Setting a cookie \"PREF\" via cookie interface:\n"); /* Netscape format cookie */ - curl_msnprintf(nline, sizeof(nline), "%s\t%s\t%s\t%s\t%.0f\t%s\t%s", - ".example.com", "TRUE", "/", "FALSE", - difftime(time(NULL) + 31337, (time_t)0), - "PREF", "hello example, i like you!"); + snprintf(nline, sizeof(nline), "%s\t%s\t%s\t%s\t%.0f\t%s\t%s", + ".example.com", "TRUE", "/", "FALSE", + difftime(time(NULL) + 31337, (time_t)0), + "PREF", "hello example, I like you!"); res = curl_easy_setopt(curl, CURLOPT_COOKIELIST, nline); if(res != CURLE_OK) { fprintf(stderr, "Curl curl_easy_setopt failed: %s\n", @@ -109,7 +115,7 @@ main(void) modified, likely not what you intended. For more information refer to the CURLOPT_COOKIELIST documentation. */ - curl_msnprintf(nline, sizeof(nline), + snprintf(nline, sizeof(nline), "Set-Cookie: OLD_PREF=3d141414bf4209321; " "expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.example.com"); res = curl_easy_setopt(curl, CURLOPT_COOKIELIST, nline); diff --git a/docs/examples/crawler.c b/docs/examples/crawler.c index 6b737652d40e..e8dbf244f91e 100644 --- a/docs/examples/crawler.c +++ b/docs/examples/crawler.c @@ -182,72 +182,79 @@ 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); + 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)); - - 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); - - /* 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; + /* 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; + + 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; + } } } + 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 5303c833f5ea..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; @@ -128,6 +124,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 +151,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 d30b944bbc95..c22a3601010e 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) { @@ -458,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; @@ -465,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); @@ -472,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; } @@ -490,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 */ @@ -517,6 +517,7 @@ int main(int argc, char **argv) } else { perror("epoll_wait"); + curl_global_cleanup(); return 1; } } @@ -539,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 b28f057c8242..79dfd3452178 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) { @@ -423,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); @@ -447,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 0860c9457bea..f827c68390a7 100644 --- a/docs/examples/fileupload.c +++ b/docs/examples/fileupload.c @@ -46,17 +46,25 @@ 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 + /* !checksrc! disable BANNEDFUNC 1 */ if(stat("debugit", &file_info) != 0) { #else if(fstat(fileno(fd), &file_info) != 0) { #endif fclose(fd); + curl_global_cleanup(); return 1; /* cannot continue */ } @@ -99,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..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); @@ -47,15 +46,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 +87,7 @@ int main(void) fclose(ftpfile); /* close the local file */ fclose(respfile); /* close the response file */ - return 0; + curl_global_cleanup(); + + 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 6e7bece70dee..2bfb51f66e7c 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,28 +81,39 @@ 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; + 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 + /* !checksrc! disable BANNEDFUNC 1 */ + 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); + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) { + fclose(hd_src); + return (int)res; + } /* get a curl handle */ curl = curl_easy_init(); @@ -127,8 +141,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); @@ -146,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 b02ad928a6dc..13df8541a2d6 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; @@ -154,13 +154,18 @@ 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(); + 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/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..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; @@ -66,53 +66,57 @@ 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(); - - /* 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); /* 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..e9844fc89e01 100644 --- a/docs/examples/ghiper.c +++ b/docs/examples/ghiper.c @@ -421,22 +421,31 @@ 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); 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/headerapi.c b/docs/examples/headerapi.c index 95c366884a42..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 */ @@ -69,7 +72,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); @@ -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 35a519b63e41..cc22e70abbe4 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) { @@ -426,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); @@ -455,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..0bf3155570ce 100644 --- a/docs/examples/htmltidy.c +++ b/docs/examples/htmltidy.c @@ -76,36 +76,45 @@ 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(); + if(argc != 2) { + printf("usage: %s \n", argv[0]); + return 1; + } + + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + + tdoc = tidyCreate(); + tidyOptSetBool(tdoc, TidyForceOutput, yes); /* try harder */ + tidyOptSetInt(tdoc, TidyWrapLen, 4096); + tidySetErrorBuffer(tdoc, &tidy_errbuf); + tidyBufInit(&docbuf); + + 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); - 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) { + 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 */ } @@ -117,14 +126,13 @@ int main(int argc, char **argv) /* clean-up */ curl_easy_cleanup(curl); - tidyBufFree(&docbuf); - tidyBufFree(&tidy_errbuf); - tidyRelease(tdoc); - return err; - } - else - printf("usage: %s \n", argv[0]); - return 0; + tidyBufFree(&docbuf); + tidyBufFree(&tidy_errbuf); + tidyRelease(tdoc); + + curl_global_cleanup(); + + 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 954cdcbc6d94..06902415e18d 100644 --- a/docs/examples/http2-download.c +++ b/docs/examples/http2-download.c @@ -36,7 +36,10 @@ /* curl stuff */ #include -#include + +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif #ifndef CURLPIPE_MULTIPLEX /* This little trick makes sure that we do not enable pipelining for libcurls @@ -53,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; @@ -102,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; @@ -149,7 +149,7 @@ static int setup(struct transfer *t, int num) hnd = t->easy = curl_easy_init(); - curl_msnprintf(filename, 128, "dl-%d", num); + snprintf(filename, sizeof(filename), "dl-%d", num); t->out = fopen(filename, "wb"); if(!t->out) { @@ -187,11 +187,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]); @@ -201,12 +203,20 @@ int main(int argc, char **argv) else num_transfers = 3; /* suitable default */ + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; + + memset(trans, 0, sizeof(trans)); + /* 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); @@ -231,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 873883ca504d..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,12 @@ 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) + return (int)res; /* init a multi stack */ multi = curl_multi_init(); @@ -146,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; @@ -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. @@ -170,11 +173,10 @@ int main(void) curl_easy_cleanup(e); } } while(m); - } - 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 df4e49ea5887..e97be991a8cb 100644 --- a/docs/examples/http2-serverpush.c +++ b/docs/examples/http2-serverpush.c @@ -31,15 +31,16 @@ /* curl stuff */ #include -#include + +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif #ifndef CURLPIPE_MULTIPLEX #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; @@ -86,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; @@ -173,7 +172,7 @@ static int server_push_callback(CURL *parent, (void)parent; - curl_msnprintf(filename, 128, "push%u", count++); + snprintf(filename, sizeof(filename), "push%u", count++); /* here's a new stream, save it in a new file for each new push */ out = fopen(filename, "wb"); @@ -209,15 +208,19 @@ 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 */ - struct CURLMsg *m; const char *url = "https://localhost:8443/index.html"; 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(); @@ -226,6 +229,7 @@ int main(int argc, char *argv[]) /* set options */ if(setup(easy, url)) { fprintf(stderr, "failed\n"); + curl_global_cleanup(); return 1; } @@ -237,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); @@ -267,7 +272,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 482889ea1857..55162c03a3ad 100644 --- a/docs/examples/http2-upload.c +++ b/docs/examples/http2-upload.c @@ -45,11 +45,17 @@ #ifdef _WIN32 #undef stat #define stat _stat +#undef fstat +#define fstat _fstat +#define fileno _fileno +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf #endif /* curl stuff */ #include -#include #ifndef CURLPIPE_MULTIPLEX /* This little trick makes sure that we do not enable pipelining for libcurls @@ -62,20 +68,19 @@ #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) { /* 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; } @@ -83,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; @@ -136,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; @@ -158,10 +161,9 @@ 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); + 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: @@ -203,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; @@ -213,68 +214,76 @@ 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); - out = fopen(filename, "wb"); - if(!out) { + snprintf(filename, sizeof(filename), "dl-%d", num); + 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; } - curl_msnprintf(url, 256, "https://localhost:8443/upload-%d", num); + snprintf(url, sizeof(url), "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); + fclose(i->out); + i->out = NULL; 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 + /* !checksrc! disable BANNEDFUNC 1 */ + 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); + 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; } @@ -283,10 +292,10 @@ 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; - int still_running = 0; /* keep number of running handles */ const char *filename = "index.html"; int num_transfers; @@ -304,40 +313,61 @@ int main(int argc, char **argv) else num_transfers = 3; + res = curl_global_init(CURL_GLOBAL_ALL); + 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)) - return 1; + int still_running = 0; /* keep number of running handles */ - /* add the individual transfer */ - curl_multi_add_handle(multi_handle, trans[i].hnd); - } + 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); + } + + 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(); + 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 3743e1b5b9c8..2aef62fc6713 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,8 +89,23 @@ int main(int argc, char **argv) if(!hd_src) return 2; + /* 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) { +#endif + fclose(hd_src); + return 1; /* cannot continue */ + } + /* 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(); @@ -126,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 new file mode 100644 index 000000000000..fe5f02f882c8 --- /dev/null +++ b/docs/examples/log_failed_transfers.c @@ -0,0 +1,342 @@ +/*************************************************************************** + * _ _ ____ _ + * 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. + * + */ + +#ifndef UNDER_CE +#include +#endif +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#include +#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; + } + +#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) { + 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) +{ + CURLcode res; + 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"; + + res = curl_global_init(CURL_GLOBAL_ALL); + if(res) { + fprintf(stderr, "curl_global_init failed\n"); + return (int)res; + } + + /* 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 { +#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; + } + + 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); +#ifndef UNDER_CE + else { + fprintf(stderr, "Failed to write transfer log to %s: %s\n", + t->logfile, strerror(errno)); + } +#endif + + 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"); + } + + 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..7dab0b04f147 100644 --- a/docs/examples/multi-app.c +++ b/docs/examples/multi-app.c @@ -37,20 +37,20 @@ * 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; /* Allocate one curl handle per transfer */ for(i = 0; i < HANDLECOUNT; i++) @@ -64,52 +64,64 @@ 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 738732279dbd..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,39 +122,50 @@ 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) { - /* 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; - curl_easy_setopt(http_handle, CURLOPT_DEBUGFUNCTION, my_trace); - curl_easy_setopt(http_handle, CURLOPT_VERBOSE, 1L); + /* set the options (I left out a few, you get the point anyway) */ + curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); - /* init a multi stack */ - multi_handle = curl_multi_init(); + curl_easy_setopt(http_handle, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(http_handle, CURLOPT_VERBOSE, 1L); - /* 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); + int still_running = 0; /* keep number of running handles */ - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + /* add the individual transfers */ + curl_multi_add_handle(multi_handle, http_handle); - if(mc) - break; + do { + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); - } 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; - curl_easy_cleanup(http_handle); + } while(still_running); + + curl_multi_cleanup(multi_handle); + } + + 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..71ac7422d6d2 100644 --- a/docs/examples/multi-double.c +++ b/docs/examples/multi-double.c @@ -38,56 +38,70 @@ 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) + return (int)res; 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) { - /* set options */ - curl_easy_setopt(http_handle2, CURLOPT_URL, "http://localhost/"); + CURLM *multi_handle; - /* init a multi stack */ - multi_handle = curl_multi_init(); + /* set options */ + curl_easy_setopt(http_handle, CURLOPT_URL, "https://www.example.com/"); - /* add the individual transfers */ - curl_multi_add_handle(multi_handle, http_handle); - curl_multi_add_handle(multi_handle, http_handle2); + /* set options */ + curl_easy_setopt(http_handle2, CURLOPT_URL, "http://localhost/"); - while(still_running) { - CURLMsg *msg; - int queued; - CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + /* init a multi stack */ + multi_handle = curl_multi_init(); + if(multi_handle) { - if(still_running) - /* wait for activity, timeout or "nothing" */ - mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + int still_running = 1; /* keep number of running handles */ - if(mc) - break; + /* add the individual transfers */ + curl_multi_add_handle(multi_handle, http_handle); + curl_multi_add_handle(multi_handle, http_handle2); - 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(still_running) { + CURLMsg *msg; + int queued; + + CURLMcode mc = curl_multi_perform(multi_handle, &still_running); + + if(still_running) + /* wait for activity, timeout or "nothing" */ + mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); + + if(mc) + break; + + do { + 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); + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/multi-event.c b/docs/examples/multi-event.c index f2c3e87c2b3c..af77101b638a 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) { @@ -219,28 +219,33 @@ 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(); 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 58c7e641c4a1..08d852ec6528 100644 --- a/docs/examples/multi-formadd.c +++ b/docs/examples/multi-formadd.c @@ -40,14 +40,15 @@ 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; 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. */ @@ -72,49 +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; - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); - CURL_IGNORE_DEPRECATION( - curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); - ) + /* 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_IGNORE_DEPRECATION( + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + ) - 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; + 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_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); + + curl_global_cleanup(); - /* free slist */ - curl_slist_free_all(headerlist); - } return 0; } diff --git a/docs/examples/multi-legacy.c b/docs/examples/multi-legacy.c index b0c37ea8d54a..19821ad6d327 100644 --- a/docs/examples/multi-legacy.c +++ b/docs/examples/multi-legacy.c @@ -43,20 +43,20 @@ * 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; /* Allocate one curl handle per transfer */ for(i = 0; i < HANDLECOUNT; i++) @@ -70,122 +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 */ - /* we start some action by calling perform right away */ - curl_multi_perform(multi_handle, &still_running); + /* add the individual transfers */ + for(i = 0; i < HANDLECOUNT; i++) + curl_multi_add_handle(multi_handle, handles[i]); - while(still_running) { - struct timeval timeout; - int rc; /* select() return code */ - CURLMcode mc; /* curl_multi_fdset() return code */ + /* we start some action by calling perform right away */ + curl_multi_perform(multi_handle, &still_running); - fd_set fdread; - fd_set fdwrite; - fd_set fdexcep; - int maxfd = -1; + while(still_running) { - long curl_timeo = -1; + struct timeval timeout; + int rc; /* select() return code */ + CURLMcode mc; /* curl_multi_fdset() return code */ - FD_ZERO(&fdread); - FD_ZERO(&fdwrite); - FD_ZERO(&fdexcep); + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + int maxfd = -1; - /* set a suitable timeout to play around with */ - timeout.tv_sec = 1; - timeout.tv_usec = 0; + long curl_timeo = -1; - curl_multi_timeout(multi_handle, &curl_timeo); - if(curl_timeo >= 0) { + 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; + + 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(); + return 0; } diff --git a/docs/examples/multi-post.c b/docs/examples/multi-post.c index 84af48f4bfb5..ac7d2f525205 100644 --- a/docs/examples/multi-post.c +++ b/docs/examples/multi-post.c @@ -33,72 +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); + + curl_global_cleanup(); - /* free slist */ - curl_slist_free_all(headerlist); - } return 0; } diff --git a/docs/examples/multi-single.c b/docs/examples/multi-single.c index 0ead96f4871f..50736c720112 100644 --- a/docs/examples/multi-single.c +++ b/docs/examples/multi-single.c @@ -38,41 +38,48 @@ int main(void) { CURL *http_handle; - 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(); + 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 1a61745dfa3f..d2f18348e68a 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 @@ -85,7 +87,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) { @@ -167,9 +169,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 +187,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; @@ -224,31 +226,38 @@ 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); 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(); return 0; } diff --git a/docs/examples/multithread.c b/docs/examples/multithread.c index ceee94022a39..36836ef47533 100644 --- a/docs/examples/multithread.c +++ b/docs/examples/multithread.c @@ -26,6 +26,8 @@ * */ +/* Requires: HAVE_PTHREAD_H */ + #include #include #include @@ -48,14 +50,17 @@ static const char * const urls[NUMT]= { "www.example" }; -static void *pull_one_url(void *url) +static void *pull_one_url(void *pindex) { CURL *curl; curl = curl_easy_init(); - curl_easy_setopt(curl, CURLOPT_URL, url); - 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; } @@ -69,17 +74,20 @@ static void *pull_one_url(void *url) 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], 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/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 be5e8c33e667..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) { @@ -66,5 +67,7 @@ int main(void) curl_easy_cleanup(curl); } - return 0; + curl_global_cleanup(); + + 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..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; @@ -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 0d9034612a56..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 */ @@ -115,5 +117,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..57c7c86e3a2b 100644 --- a/docs/examples/postit2.c +++ b/docs/examples/postit2.c @@ -46,17 +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:"; - - 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); @@ -100,5 +101,8 @@ int main(int argc, char *argv[]) /* free slist */ curl_slist_free_all(headerlist); } + + curl_global_cleanup(); + return 0; } diff --git a/docs/examples/progressfunc.c b/docs/examples/progressfunc.c index e164f03ca5c5..35adc6c82d56 100644 --- a/docs/examples/progressfunc.c +++ b/docs/examples/progressfunc.c @@ -70,11 +70,15 @@ 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) { + struct myprogress prog; + prog.lastruntime = 0; prog.curl = curl; @@ -93,5 +97,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 31a320124168..cea07fd56698 100644 --- a/docs/examples/sepheaders.c +++ b/docs/examples/sepheaders.c @@ -39,57 +39,65 @@ static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) int main(void) { 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); - - /* open the header file */ - headerfile = fopen(headerfilename, "wb"); - if(!headerfile) { - curl_easy_cleanup(curl_handle); - return -1; - } + /* close the body file */ + fclose(bodyfile); - /* open the body file */ - bodyfile = fopen(bodyfilename, "wb"); - if(!bodyfile) { + /* cleanup curl stuff */ 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! */ - 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 0; + return (int)res; } diff --git a/docs/examples/sessioninfo.c b/docs/examples/sessioninfo.c index 225b1ae5a516..c7ea52ccc2e8 100644 --- a/docs/examples/sessioninfo.c +++ b/docs/examples/sessioninfo.c @@ -29,6 +29,12 @@ /* 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 + #include #include @@ -40,22 +46,22 @@ 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; (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) { + 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++) { @@ -67,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); } @@ -89,25 +96,22 @@ static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) int main(void) { - 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) { 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; } 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..8745abe78b8f 100644 --- a/docs/examples/sftpuploadresume.c +++ b/docs/examples/sftpuploadresume.c @@ -121,18 +121,23 @@ 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; - curl_global_init(CURL_GLOBAL_ALL); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + 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/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 49a412d95843..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); - 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); } } @@ -169,7 +171,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); @@ -214,5 +218,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/smtp-authzid.c b/docs/examples/smtp-authzid.c index daaeab16943c..758a7fdaaf2a 100644 --- a/docs/examples/smtp-authzid.c +++ b/docs/examples/smtp-authzid.c @@ -95,12 +95,16 @@ 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) { + 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"); @@ -158,5 +162,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..727880d6199e 100644 --- a/docs/examples/smtp-expn.c +++ b/docs/examples/smtp-expn.c @@ -42,11 +42,15 @@ 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) { + struct curl_slist *recipients = NULL; + /* This is the URL for your mailserver */ curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); @@ -77,5 +81,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..d3f4346b8c0a 100644 --- a/docs/examples/smtp-mail.c +++ b/docs/examples/smtp-mail.c @@ -92,12 +92,16 @@ 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) { + 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"); @@ -146,5 +150,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..ca73b73fca9a 100644 --- a/docs/examples/smtp-ssl.c +++ b/docs/examples/smtp-ssl.c @@ -89,12 +89,16 @@ 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) { + 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"); @@ -166,5 +170,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..4f7379529c1e 100644 --- a/docs/examples/smtp-tls.c +++ b/docs/examples/smtp-tls.c @@ -89,12 +89,16 @@ 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) { + 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"); @@ -169,5 +173,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..33d439ec9c43 100644 --- a/docs/examples/smtp-vrfy.c +++ b/docs/examples/smtp-vrfy.c @@ -45,11 +45,15 @@ 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) { + struct curl_slist *recipients = NULL; + /* This is the URL for your mailserver */ curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); @@ -77,5 +81,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 ba5f09cb075a..da2c7ea0f362 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -55,32 +55,36 @@ * 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 + +#ifndef _WIN32 +int main(void) { printf("Platform not supported.\n"); return 1; } +#else + +#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 -#ifdef _WIN32 #include -#else -#error "This example requires Windows." -#endif +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif #define MAX_STRING 256 #define MAX_STRING1 MAX_STRING + 1 @@ -113,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) { @@ -121,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) { @@ -129,43 +133,43 @@ 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((nmemb >= 5) && !strncmp((char *)ptr, "Date:", 5)) { if(ShowAllHeader == 0) - fprintf(stderr, "HTTP Server. %s", (char *)(ptr)); + fprintf(stderr, "HTTP Server. %.*s", (int)nmemb, (char *)ptr); if(AutoSyncTime == 1) { + int RetVal = 0; + char *field = ptr; *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; - } + 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; + 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((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; @@ -241,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; @@ -251,7 +256,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]); @@ -281,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; @@ -298,16 +306,14 @@ 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); 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,5 +364,10 @@ int main(int argc, char *argv[]) conf_init(conf); curl_easy_cleanup(curl); } + + curl_global_cleanup(); + return RetValue; } +#endif /* CURL_WINDOWS_UWP */ +#endif /* _WIN32 */ diff --git a/docs/examples/threaded-ssl.c b/docs/examples/threaded-ssl.c index 161182eec1e1..5d984a670ab9 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 @@ -52,37 +53,43 @@ static const char * const urls[]= { "https://www4.example.com/", }; -static void *pull_one_url(void *url) +static void *pull_one_url(void *pindex) { CURL *curl; curl = curl_easy_init(); - curl_easy_setopt(curl, CURLOPT_URL, url); - /* 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); - 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; } 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], 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 @@ -95,5 +102,7 @@ int main(int argc, char **argv) fprintf(stderr, "Thread %d terminated\n", i); } + curl_global_cleanup(); + return 0; } 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 9ed7da5a84a6..8e9e01db15df 100644 --- a/docs/examples/url2file.c +++ b/docs/examples/url2file.c @@ -38,50 +38,58 @@ static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) int main(int argc, char *argv[]) { - CURL *curl_handle; static const char *pagefilename = "page.out"; - FILE *pagefile; + + CURLcode res; + CURL *curl_handle; if(argc < 2) { printf("Usage: %s \n", argv[0]); 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(); + 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! */ - 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(); - return 0; + return (int)res; } diff --git a/docs/examples/urlapi.c b/docs/examples/urlapi.c index 2ed78eb11fc6..82ef3e19aab9 100644 --- a/docs/examples/urlapi.c +++ b/docs/examples/urlapi.c @@ -34,14 +34,13 @@ int main(void) { - CURL *curl; - CURLcode res; - + CURL *curl = NULL; CURLU *urlp; CURLUcode uc; - /* get a curl handle */ - curl = curl_easy_init(); + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; /* init Curl URL */ urlp = curl_url(); @@ -53,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); @@ -66,12 +67,11 @@ int main(void) if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); - - goto cleanup; } 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 670ae4dc718e..c53fcde9cbce 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. @@ -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 @@ -47,7 +49,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; } @@ -97,7 +99,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 +120,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"); } @@ -155,51 +157,51 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer) int main(void) { CURL *ch; - CURLcode rv; - 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 */ - rv = curl_easy_perform(ch); - if(rv == CURLE_OK) { - printf("*** transfer succeeded ***\n"); - } - else { - printf("*** transfer failed ***\n"); - } + CURLcode res = curl_global_init(CURL_GLOBAL_ALL); + if(res) + return (int)res; - /* 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); - rv = curl_easy_perform(ch); - if(rv == CURLE_OK) { - printf("*** transfer succeeded ***\n"); - } - else { - printf("*** transfer failed ***\n"); + ch = curl_easy_init(); + 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_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..1131a3ce9e76 100644 --- a/docs/examples/xmlstream.c +++ b/docs/examples/xmlstream.c @@ -117,54 +117,61 @@ 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); + CURLcode 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"); - 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 0; + return (int)res; } 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/docs/internals/CODE_STYLE.md b/docs/internals/CODE_STYLE.md index dadec934ddc4..0d072c04c306 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 @@ -361,6 +362,6 @@ This is the full list of functions generally banned. strtok_r strtol strtoul - vsnprint + vsnprintf vsprintf wcsdup 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/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() 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_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_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/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_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/docs/libcurl/curl_multi_notify_disable.md b/docs/libcurl/curl_multi_notify_disable.md new file mode 100644 index 000000000000..11113a5898dd --- /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, CURLMNOTIFY_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..4a0da77714c2 --- /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, CURLMNOTIFY_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/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). diff --git a/docs/libcurl/curl_version_info.md b/docs/libcurl/curl_version_info.md index 8a8671dbf907..3620f60ca68b 100644 --- a/docs/libcurl/curl_version_info.md +++ b/docs/libcurl/curl_version_info.md @@ -159,19 +159,26 @@ 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 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 +192,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 +214,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 +227,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 +239,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 +252,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 +265,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 +285,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 +305,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 +333,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 +347,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 +368,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 +380,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-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/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/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 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 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/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_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 a25ac0a72c74..db053e311e75 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,12 +29,12 @@ 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 -- 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/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/CURLMOPT_NOTIFYDATA.md b/docs/libcurl/opts/CURLMOPT_NOTIFYDATA.md new file mode 100644 index 000000000000..ad57cbea1414 --- /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 notify_cb(CURLM *multi, unsigned int notification, + CURL *easy, void *notifyp) +{ + struct priv *p = notifyp; + 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, notify_cb); + curl_multi_setopt(multi, CURLMOPT_NOTIFYDATA, &setup); + curl_multi_notify_enable(multi, CURLMNOTIFY_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..0e10aa918787 --- /dev/null +++ b/docs/libcurl/opts/CURLMOPT_NOTIFYFUNCTION.md @@ -0,0 +1,130 @@ +--- +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 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, notify_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 right now. In the future, new ones might be +added. + +## 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). + +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. + +## CURLMNOTIFY_EASY_DONE + +When enabled via curl_multi_notify_enable(3), this notification is triggered +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. + +*easy* identifies the transfer involved. This may be one of the +application's own easy handle or an internal handle. + +**notifyp** is set with CURLMOPT_NOTIFYDATA(3). + +# DEFAULT + +NULL (no callback) + +# %PROTOCOLS% + +# EXAMPLE + +~~~c +struct priv { + void *ours; +}; + +static void notify_cb(CURLM *multi, unsigned int notification, + CURL *easy, void *notifyp) +{ + struct priv *p = notifyp; + 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, notify_cb); + curl_multi_setopt(multi, CURLMOPT_NOTIFYDATA, &setup); + curl_multi_notify_enable(multi, CURLMNOTIFY_INFO_READ); +} +~~~ + +# %AVAILABILITY% + +# RETURN VALUE + +Returns CURLM_OK. 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_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 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_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_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_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/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_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_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_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/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/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..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 @@ -120,7 +124,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_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). 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_SOCKOPTFUNCTION.md b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md index 0efdd0b3be5e..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 @@ -96,7 +98,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_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_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_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: 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/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 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. 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); 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. 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 bfcf357bf6fb..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 @@ -558,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 @@ -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 @@ -590,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 @@ -666,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 @@ -704,7 +708,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 @@ -715,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 @@ -796,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 @@ -880,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 @@ -1068,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 @@ -1128,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 @@ -1139,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/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/docs/tests/CI.md b/docs/tests/CI.md index d101e3563c71..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,55 +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 / fuzzing | stable | fuzzing results | - | CI / macos ... | stable | all errors and failures | - | 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 | -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)). +- 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 @@ -90,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. 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/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/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/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 diff --git a/include/curl/multi.h b/include/curl/multi.h index 782541f1abbd..4e30637ef565 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; @@ -464,7 +470,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; /* @@ -518,6 +526,26 @@ CURL_EXTERN CURLMcode curl_multi_waitfds(CURLM *multi, unsigned int size, unsigned int *fd_count); +/* + * Notifications dispatched by a multi handle, when enabled. + */ +#define CURLMNOTIFY_INFO_READ 0 +#define CURLMNOTIFY_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 a0b41aeb2473..063cea57e6f2 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,28 @@ 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_NOTIFYFUNCTION) \ + if(!curlcheck_multinotify_cb(value)) \ + Wcurl_multi_setopt_err_notifycb(); \ 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); \ }) @@ -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) @@ -246,17 +250,22 @@ 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_multinotify_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 */ #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,132 +274,134 @@ __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_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") -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 */ /* 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 */ @@ -673,7 +684,7 @@ CURLWARNING(_curl_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 @@ -704,60 +715,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 +776,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 +809,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 +839,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 +938,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/.checksrc b/lib/.checksrc deleted file mode 100644 index 22ca8e0b5370..000000000000 --- a/lib/.checksrc +++ /dev/null @@ -1,5 +0,0 @@ -banfunc snprintf -banfunc sscanf -banfunc strerror -banfunc strtol -banfunc vsnprint diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 3476d55b096a..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) @@ -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 "$" @@ -150,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) @@ -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 "$" @@ -186,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) @@ -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) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_OPTIONS ${CURL_COVERAGE_LDFLAGS}) + else() + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY LINK_FLAGS ${CURL_COVERAGE_LDFLAGS}) + endif() + endif() target_include_directories(${LIB_SHARED} INTERFACE "$" @@ -272,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/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/Makefile.inc b/lib/Makefile.inc index 524fdcc53d5a..f06af2ca70e3 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -26,10 +26,12 @@ LIB_CURLX_CFILES = \ curlx/base64.c \ curlx/dynbuf.c \ + curlx/fopen.c \ curlx/inet_ntop.c \ curlx/inet_pton.c \ curlx/multibyte.c \ curlx/nonblock.c \ + curlx/strerr.c \ curlx/strparse.c \ curlx/timediff.c \ curlx/timeval.c \ @@ -43,10 +45,12 @@ 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 \ curlx/nonblock.h \ + curlx/strerr.h \ curlx/strparse.h \ curlx/timediff.h \ curlx/timeval.h \ @@ -75,6 +79,7 @@ LIB_VAUTH_HFILES = \ vauth/vauth.h LIB_VTLS_CFILES = \ + vtls/apple.c \ vtls/cipher_suite.c \ vtls/gtls.c \ vtls/hostcheck.c \ @@ -92,6 +97,7 @@ LIB_VTLS_CFILES = \ vtls/x509asn1.c LIB_VTLS_HFILES = \ + vtls/apple.h \ vtls/cipher_suite.h \ vtls/gtls.h \ vtls/hostcheck.h \ @@ -127,8 +133,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 \ @@ -158,6 +163,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 \ @@ -182,7 +188,6 @@ LIB_CFILES = \ fake_addrinfo.c \ file.c \ fileinfo.c \ - fopen.c \ formdata.c \ ftp.c \ ftplistparser.c \ @@ -209,7 +214,6 @@ LIB_CFILES = \ idn.c \ if2ip.c \ imap.c \ - krb5.c \ ldap.c \ llist.c \ macos.c \ @@ -221,6 +225,7 @@ LIB_CFILES = \ mqtt.c \ multi.c \ multi_ev.c \ + multi_ntfy.c \ netrc.c \ noproxy.c \ openldap.c \ @@ -288,11 +293,11 @@ LIB_HFILES = \ curl_des.h \ curl_endian.h \ curl_fnmatch.h \ + curl_fopen.h \ curl_get_line.h \ curl_gethostname.h \ curl_gssapi.h \ curl_hmac.h \ - curl_krb5.h \ curl_ldap.h \ curl_md4.h \ curl_md5.h \ @@ -323,7 +328,6 @@ LIB_HFILES = \ fake_addrinfo.h \ file.h \ fileinfo.h \ - fopen.h \ formdata.h \ ftp.h \ ftplistparser.h \ @@ -354,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/altsvc.c b/lib/altsvc.c index c7448692fb56..449bea8528dc 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -31,19 +31,18 @@ #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" #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" @@ -227,7 +226,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 +237,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; } @@ -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; } @@ -391,7 +390,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/amigaos.c b/lib/amigaos.c index ac6d6b41937d..e51236d1260a 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", + 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/asyn-ares.c b/lib/asyn-ares.c index e955990878ac..040100acec36 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 @@ -94,22 +105,10 @@ #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" -/* 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; @@ -303,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 @@ -372,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; } @@ -513,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) { @@ -746,9 +748,13 @@ 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 */ - CURL_TRC_DNS(data, "asyn-ares: servers=%s", - ares_get_servers_csv(ares->channel)); +#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); + ares_free_string(csv); + } #endif #ifdef HAVE_CARES_GETADDRINFO @@ -778,7 +784,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); @@ -790,7 +796,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; diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index ca6830a0bee1..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" @@ -199,14 +198,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 +211,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,10 +219,7 @@ 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); + curl_msnprintf(service, sizeof(service), "%d", addr_ctx->port); rc = Curl_getaddrinfo_ex(addr_ctx->hostname, service, &addr_ctx->hints, &addr_ctx->res); @@ -274,11 +253,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 +267,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 +298,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 +337,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 +488,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 +511,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) @@ -650,6 +610,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 = 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/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/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 d67bbd55adfb..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; @@ -433,6 +432,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"); @@ -551,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); @@ -600,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 5e4c20444e79..6b7130be83f5 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 @@ -63,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" @@ -156,12 +152,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; @@ -356,7 +357,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; @@ -367,7 +368,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; @@ -407,8 +407,14 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, do_more = TRUE; } else { - do_more = (curlx_timediff(now, bs->last_attempt_started) >= - bs->attempt_delay_ms); + 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, " "start next attempt"); @@ -421,7 +427,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; } @@ -454,10 +460,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; @@ -472,14 +478,17 @@ 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; } - 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; @@ -493,21 +502,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; } @@ -627,26 +649,36 @@ 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) + curl_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; + curl_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 ? " " : "", diff --git a/lib/cf-socket.c b/lib/cf-socket.c index f449ca36caf7..758641e40dbe 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 @@ -65,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" @@ -83,10 +79,10 @@ #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 */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -117,7 +113,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; @@ -139,7 +135,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 } } @@ -336,12 +332,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; } @@ -369,13 +364,24 @@ 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) /* 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; @@ -453,7 +459,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 @@ -648,7 +654,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; @@ -751,8 +757,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; } } @@ -790,10 +796,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 @@ -803,7 +809,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; @@ -825,8 +831,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 @@ -904,8 +910,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; @@ -1054,13 +1060,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; } } @@ -1086,7 +1092,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; @@ -1332,7 +1338,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) { @@ -1342,7 +1349,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; } } @@ -1363,7 +1370,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 } @@ -1501,7 +1508,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; } @@ -1569,7 +1576,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; } @@ -1764,6 +1771,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; @@ -1860,6 +1872,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); @@ -1876,10 +1889,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; } @@ -2040,13 +2049,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 @@ -2061,6 +2070,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 @@ -2079,6 +2089,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 */ @@ -2106,29 +2117,32 @@ 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 = 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; + } +#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; } - - infof(data, "Connection accepted from server"); -#ifndef HAVE_ACCEPT4 - (void)curlx_nonblock(s_accepted, TRUE); /* enable non-blocking */ #endif + infof(data, "Connection accepted from server"); + /* Replace any filter on SECONDARY with one listening on this socket */ ctx->listening = FALSE; ctx->accepted = TRUE; diff --git a/lib/cf-socket.h b/lib/cf-socket.h index 88c08fe7c0c0..e5fc176ee19c 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. @@ -80,7 +81,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 @@ -157,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/cfilters.c b/lib/cfilters.c index efd2ac6f63d4..2ef5d75d431c 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" @@ -383,29 +382,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; } @@ -936,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; } } @@ -969,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 815b72a6e801..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 */ @@ -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. + * 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_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); /** * Discard all cfilters starting with `*pcf` and clearing it afterwards. @@ -543,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/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/conncache.c b/lib/conncache.c index 1393bb565be0..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" @@ -79,7 +78,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 +90,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 +319,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(); @@ -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 f0628d6206ed..5dc4e2fc747b 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 @@ -78,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" @@ -162,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) + Curl_expire_ex(data, nowp, conn->shutdown.timeout_ms, EXPIRE_SHUTDOWN); } @@ -270,7 +267,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 */ @@ -621,3 +618,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/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 35d33268f966..59a841a303c7 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -80,17 +80,16 @@ 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" -/* 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" @@ -1195,7 +1194,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 +1227,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; } @@ -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); } @@ -1583,7 +1582,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 +1601,7 @@ static CURLcode cookie_output(struct Curl_easy *data, error: if(out && !use_stdout) - fclose(out); + curlx_fclose(out); free(tempstore); return error; } @@ -1658,18 +1657,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/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 22212ac86f8e..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" @@ -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_config.h.cmake b/lib/curl_config.h.cmake index ca516710e42c..1fabc24c182f 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 */ @@ -315,15 +315,12 @@ /* 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 - /* 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 @@ -421,9 +418,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 @@ -706,9 +700,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 @@ -791,6 +782,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/fopen.c b/lib/curl_fopen.c similarity index 88% rename from lib/fopen.c rename to lib/curl_fopen.c index b28977317a8b..c41cff21cde9 100644 --- a/lib/fopen.c +++ b/lib/curl_fopen.c @@ -27,15 +27,11 @@ #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 "fopen.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" +#include "curl_fopen.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -102,11 +98,12 @@ 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( #ifdef UNDER_CE + /* !checksrc! disable BANNEDFUNC 1 */ stat(filename, &sb) == -1 #else fstat(fileno(*fh), &sb) == -1 @@ -114,7 +111,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)); @@ -125,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); } @@ -137,14 +134,16 @@ 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; - *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_gssapi.c b/lib/curl_gssapi.c index 92b867f7753b..42ccaa3e2962 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); } @@ -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 " @@ -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_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/lib/curl_mem_undef.h b/lib/curl_mem_undef.h index acc3a9226aef..2be114cbd5e6 100644 --- a/lib/curl_mem_undef.h +++ b/lib/curl_mem_undef.h @@ -30,30 +30,8 @@ #undef realloc #undef free #ifdef _WIN32 -#undef _tcsdup +#undef Curl_tcsdup #endif -#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) -#endif -#undef fdopen -#undef fclose - -#endif /* CURLDEBUG */ - #undef HEADER_CURL_MEMORY_H #undef HEADER_CURL_MEMDEBUG_H 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_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 8eb63fb94954..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" @@ -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); diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 72c118affcc0..694d14df4f09 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 @@ -506,15 +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, ...); - 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 */ # include @@ -776,7 +767,7 @@ # endif #endif -#if defined(USE_LIBSSH2) || defined(USE_LIBSSH) || defined(USE_WOLFSSH) +#if defined(USE_LIBSSH2) || defined(USE_LIBSSH) #define USE_SSH #endif @@ -959,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 @@ -988,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__)) @@ -1012,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 */ @@ -1083,9 +1078,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 +1101,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/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/curl_threads.c b/lib/curl_threads.c index 2750f5ad9f78..68bfddddcbcd 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" @@ -64,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; @@ -100,61 +100,19 @@ 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 (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))) { -#ifdef UNDER_CE + curl_thread_t t = CreateThread(NULL, 0, func, arg, 0, NULL); + if(!t) { DWORD gle = GetLastError(); /* !checksrc! disable ERRNOVAR 1 */ int err = (gle == ERROR_ACCESS_DENIED || gle == ERROR_NOT_ENOUGH_MEMORY) ? EACCES : EINVAL; CURL_SETERRNO(err); -#endif return curl_thread_t_null; } return t; @@ -170,7 +128,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); @@ -178,16 +136,7 @@ int Curl_thread_join(curl_thread_t *hnd) Curl_thread_destroy(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..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) @@ -66,22 +60,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/curl_trc.c b/lib/curl_trc.c index 52671f4eaeb4..0b91315e3668 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); } @@ -272,6 +271,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 +294,37 @@ 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 @@ -640,8 +657,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; @@ -657,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/curl_trc.h b/lib/curl_trc.h index fa0999250fbe..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,13 @@ 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; + int log_level; +}; #ifndef CURL_DISABLE_FTP extern struct curl_trc_feat Curl_trc_feat_ftp; @@ -118,6 +125,10 @@ 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) +#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, ...) \ @@ -136,8 +147,11 @@ 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) +#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, ...) \ @@ -168,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 @@ -184,11 +199,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 */ @@ -196,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 && \ @@ -208,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 */ @@ -220,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/curlx/.checksrc b/lib/curlx/.checksrc deleted file mode 100644 index 22ca8e0b5370..000000000000 --- a/lib/curlx/.checksrc +++ /dev/null @@ -1,5 +0,0 @@ -banfunc snprintf -banfunc sscanf -banfunc strerror -banfunc strtol -banfunc vsnprint 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/lib/curlx/curlx.h b/lib/curlx/curlx.h index 9f7bd3a975ea..480e91950de0 100644 --- a/lib/curlx/curlx.h +++ b/lib/curlx/curlx.h @@ -58,12 +58,18 @@ #include "version_win32.h" /* provides curlx_verify_windows_version() */ +#include "strerr.h" +/* The curlx_strerror() function */ + #include "strparse.h" /* The curlx_str_* parsing functions */ #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..b44cbbdfced2 --- /dev/null +++ b/lib/curlx/fopen.h @@ -0,0 +1,58 @@ +#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" + +#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); +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 +#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_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/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/curlx/multibyte.c b/lib/curlx/multibyte.c index 30380275cc7e..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/en-us/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/curlx/strerr.c b/lib/curlx/strerr.c new file mode 100644 index 000000000000..e5227554e563 --- /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((DWORD)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/version_win32.c b/lib/curlx/version_win32.c index 8d0af68fcfe0..7e415dfe89d9 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"))); + GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")); +#if defined(__clang__) && __clang_major__ >= 16 +#pragma clang diagnostic pop +#endif onetime = FALSE; } diff --git a/lib/curlx/winapi.c b/lib/curlx/winapi.c index 6069424becc5..de1218cec7f5 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 @@ -38,19 +38,17 @@ /* adjust for old MSVC */ #if defined(_MSC_VER) && (_MSC_VER < 1900) -# define SNPRINTF _snprintf +#define SNPRINTF _snprintf #else #define SNPRINTF snprintf #endif +#endif /* !WITHOUT_LIBCURL */ -#endif /* !BUILDING_LIBCURL */ - -#ifdef _WIN32 -/* 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. */ -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]; @@ -66,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) @@ -86,13 +84,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) @@ -101,14 +96,14 @@ 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" #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 @@ -125,10 +120,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/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/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 030b026fe297..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" @@ -377,6 +376,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]); @@ -510,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; } @@ -759,7 +761,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 +781,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 +818,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 +840,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; @@ -887,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; @@ -1062,7 +1065,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/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 0a4b6faf5256..793a18f33eb8 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; @@ -1110,7 +1109,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)); @@ -1120,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/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/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 749759653d5a..fe07df5d2a92 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,10 +66,11 @@ #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 */ -#include "curl_printf.h" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -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); @@ -491,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; @@ -510,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 d8553e325694..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" @@ -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 29c2f789a3e9..fd957a2bb485 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -53,13 +53,11 @@ #include "fileinfo.h" #include "ftplistparser.h" #include "curl_range.h" -#include "curl_krb5.h" #include "strcase.h" #include "vtls/vtls.h" #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" @@ -72,9 +70,10 @@ #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" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -142,11 +141,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 +171,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, @@ -272,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 */ }; @@ -430,6 +429,10 @@ 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() @@ -446,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)Curl_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) @@ -476,13 +482,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 @@ -495,7 +502,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); @@ -577,28 +584,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) @@ -625,14 +610,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 +635,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 +718,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; @@ -1026,7 +1011,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) { @@ -1073,7 +1058,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", @@ -1100,12 +1085,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; @@ -1114,28 +1099,30 @@ 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; } } 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 */ 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", @@ -1145,7 +1132,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", @@ -1222,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) { @@ -1435,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; @@ -1900,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; @@ -2106,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; @@ -2141,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; @@ -2336,7 +2324,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') @@ -2362,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; @@ -2431,7 +2420,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; } @@ -2508,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; } } } @@ -2629,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); } @@ -2812,25 +2789,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 */ @@ -3401,7 +3359,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 */ @@ -3494,7 +3452,6 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, * * BLOCKING */ - static CURLcode ftp_sendquote(struct Curl_easy *data, struct ftp_conn *ftpc, @@ -3525,7 +3482,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; @@ -3617,7 +3574,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; @@ -3632,6 +3588,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: @@ -3650,7 +3609,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; } } @@ -3781,7 +3739,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, @@ -3971,7 +3928,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; @@ -4463,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; @@ -4501,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; 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/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 2d122fb9996b..41db274c5d4e 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 { @@ -279,13 +278,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; @@ -709,7 +704,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; @@ -824,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 @@ -851,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 */ @@ -892,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. */ @@ -952,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; @@ -971,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; } @@ -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) @@ -1559,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; @@ -1639,18 +1636,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/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 9525158bcc7c..28989764b90f 100644 --- a/lib/hsts.c +++ b/lib/hsts.c @@ -32,17 +32,16 @@ #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" #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; } @@ -379,7 +378,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 +523,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 +541,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/http.c b/lib/http.c index e01de6f4772c..db37995a12c7 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" @@ -263,6 +262,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 @@ -324,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; @@ -338,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; @@ -368,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; @@ -507,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; } @@ -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")) @@ -1782,16 +1795,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; @@ -1923,7 +1936,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; } @@ -1939,13 +1952,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 */ @@ -1963,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]; @@ -1970,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 @@ -1984,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; @@ -2026,27 +2043,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; + } } } @@ -2289,7 +2305,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 @@ -2481,8 +2497,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"))) { @@ -2495,8 +2511,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) { @@ -2508,15 +2524,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; @@ -2622,6 +2639,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"; @@ -2635,17 +2653,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 = ", "; @@ -2659,9 +2689,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 */ @@ -2702,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 */ @@ -2774,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"); @@ -2788,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 @@ -2805,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; @@ -2888,7 +2935,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; } @@ -3074,32 +3121,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; @@ -3571,10 +3636,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 +3778,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 +3819,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 +3878,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 +3930,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 +4052,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/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 e2cdc9181f5f..4e2d59ff5187 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" @@ -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 { @@ -734,7 +732,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, @@ -1030,6 +1028,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; } @@ -1214,48 +1213,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 +1264,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); } } @@ -1589,11 +1589,12 @@ 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 = 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); @@ -1829,7 +1830,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; } @@ -2042,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 */ @@ -2060,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) { @@ -2080,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)); @@ -2543,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; } @@ -2696,6 +2706,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 +2911,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 +2930,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 +2947,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 +2956,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 +2982,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/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 2d742856ce81..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" @@ -215,9 +214,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, @@ -237,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; @@ -317,8 +315,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 +329,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 +336,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 +345,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 +354,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 +365,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 +413,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/httpsrr.c b/lib/httpsrr.c index df93ac34ac04..ae2c106bcef2 100644 --- a/lib/httpsrr.c +++ b/lib/httpsrr.c @@ -33,13 +33,10 @@ #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" -#define MAX_ALPN_LENGTH 255 - static CURLcode httpsrr_decode_alpn(const char *cp, size_t len, unsigned char *alpns) { @@ -100,6 +97,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; @@ -109,6 +107,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; @@ -118,6 +117,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; @@ -188,6 +188,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; 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 91ee59c02a72..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; } } @@ -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/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/imap.c b/lib/imap.c index 41aec8ffab73..47757d3f2978 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" @@ -210,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 @@ -1943,9 +1943,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/krb5.c b/lib/krb5.c deleted file mode 100644 index 563d724bbbc8..000000000000 --- a/lib/krb5.c +++ /dev/null @@ -1,947 +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 void 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); - - 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; /* error */ - - if(iscmd) { - error = curlx_base64_encode(buffer, curlx_sitouz(bytes), - &cmd_buffer, &cmd_size); - if(error) { - free(buffer); - return; /* 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); - 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); - } - } - 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)); - } - free(buffer); -} - -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) { - if(length < len) - len = length; - - /* WTF: this ignores all errors writing to the socket */ - do_sec_send(data, conn, sockindex, buffer, len); - 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/ldap.c b/lib/ldap.c index c66a56d7bb24..0b475d07bbc4 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -93,11 +93,19 @@ #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" +#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. */ @@ -119,30 +127,31 @@ 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 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 -#endif +#define ldap_free_urldesc ldap_free_urldesc_low + +#endif /* !HAVE_LDAP_URL_PARSE */ #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 @@ -190,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 @@ -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; @@ -346,10 +348,10 @@ 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)); + 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; } @@ -532,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); @@ -546,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; - } - - result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1); - 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); } - + 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 */ @@ -634,22 +625,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 +637,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 { @@ -726,7 +719,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; @@ -741,10 +734,10 @@ static void _ldap_trace(const char *fmt, ...) return; va_start(args, fmt); - vfprintf(stderr, fmt, args); + curl_mvfprintf(stderr, fmt, args); va_end(args); } -#endif +#endif /* DEBUG_LDAP */ #ifndef HAVE_LDAP_URL_PARSE @@ -793,10 +786,11 @@ 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 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; @@ -997,27 +991,27 @@ 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 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) 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; @@ -1044,10 +1038,10 @@ static void _ldap_free_urldesc(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 */ 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/md4.c b/lib/md4.c index b9c98d6c4aea..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" @@ -247,18 +246,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 */ @@ -342,7 +329,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 +347,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 +365,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..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" @@ -282,18 +281,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 */ @@ -382,7 +369,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 +387,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 +405,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 +423,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..7ded52c1e97c 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -29,9 +29,9 @@ #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" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -68,7 +68,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 +79,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 @@ -116,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); @@ -311,7 +308,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", @@ -321,14 +319,15 @@ 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)) 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); @@ -336,13 +335,14 @@ 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)) 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 +354,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 +372,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 +390,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", @@ -418,13 +421,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); @@ -436,7 +433,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); @@ -453,7 +451,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; } @@ -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/memdebug.h b/lib/memdebug.h index 30469b99a503..c2b7fad9528b 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -42,40 +42,15 @@ #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 _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 */ -#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 -#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..b403d29b1fd9 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) && \ @@ -48,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" @@ -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; } @@ -204,16 +205,16 @@ 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: 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(); @@ -1411,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); @@ -1687,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 35afe012075f..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. @@ -54,7 +53,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.c b/lib/multi.c index 918928d03cc5..ca7c1bdd9542 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" @@ -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, 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, 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); @@ -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, CURLMNOTIFY_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); @@ -522,8 +537,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 @@ -924,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); @@ -940,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; @@ -955,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; @@ -970,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; } @@ -1103,6 +1122,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) { @@ -1135,8 +1155,9 @@ CURLMcode Curl_multi_pollset(struct Curl_easy *data, caller, ps->n, timeout_count); break; } - CURL_TRC_M_TIMEOUTS(data); + CURL_TRC_EASY_TIMERS(data); } +#endif if(expect_sockets && !ps->n && data->multi && !Curl_uint_bset_contains(&data->multi->dirty, data->mid) && @@ -1277,7 +1298,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 @@ -2752,6 +2773,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)", @@ -2783,6 +2807,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 @@ -2829,6 +2856,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 */ @@ -2898,6 +2927,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); @@ -3050,7 +3080,15 @@ 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) { + struct time_node *n = Curl_node_elem(e); + CURL_TRC_TIMER(data, n->eid, "has expired"); + } + } +#endif (void)add_next_timeout(mrc->now, multi, data); Curl_multi_mark_dirty(data); } @@ -3170,6 +3208,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; @@ -3259,6 +3300,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; @@ -3275,6 +3322,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); } @@ -3284,6 +3333,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); } @@ -3292,6 +3343,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); } @@ -3323,6 +3376,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; @@ -3350,15 +3406,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) { - struct Curl_easy *data = Curl_splayget(multi->timetree); - CURL_TRC_M(data, "multi_timeout() says this has expired"); + data = Curl_splayget(multi->timetree); } +#endif /* 0 means immediately */ *timeout_ms = 0; } @@ -3368,6 +3428,18 @@ 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); + if(e) { + struct time_node *n = Curl_node_elem(e); + CURL_TRC_TIMER(data, n->eid, "gives multi timeout in %ldms", + *timeout_ms); + } + } +#endif + return CURLM_OK; } @@ -3387,8 +3459,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 +3477,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 +3548,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 +3557,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 +3580,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 +3614,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 +3643,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 +3668,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"); } /* @@ -3982,6 +4039,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) @@ -3990,12 +4065,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); } } @@ -4003,15 +4080,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 61c639d9e48d..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" @@ -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) */ @@ -509,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); @@ -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/multi_ntfy.c b/lib/multi_ntfy.c new file mode 100644 index 000000000000..fe7cc0503a76 --- /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, CURLMNOTIFY_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 > CURLMNOTIFY_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 > CURLMNOTIFY_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/curl_krb5.h b/lib/multi_ntfy.h similarity index 50% rename from lib/curl_krb5.h rename to lib/multi_ntfy.h index 574340fd3c58..d920b3295d4b 100644 --- a/lib/curl_krb5.h +++ b/lib/multi_ntfy.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_KRB5_H -#define HEADER_CURL_KRB5_H +#ifndef HEADER_CURL_MULTI_NTFY_H +#define HEADER_CURL_MULTI_NTFY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -24,31 +24,34 @@ * ***************************************************************************/ -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 *); +#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; }; -#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 */ +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/lib/netrc.c b/lib/netrc.c index 447ee095852d..f06dff8ed515 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -39,10 +39,10 @@ #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 */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -76,7 +76,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 +99,7 @@ static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf) done: curlx_dyn_free(&linebuf); if(file) - fclose(file); + curlx_fclose(file); return ret; } @@ -436,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; @@ -447,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..20a335993da1 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; @@ -98,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/lib/openldap.c b/lib/openldap.c index da26d4a78d06..1b26b6e1b4d9 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" @@ -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 @@ -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); @@ -531,18 +535,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. */ - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); - 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; @@ -618,12 +623,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; @@ -654,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); @@ -946,18 +964,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; - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); - 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; } @@ -986,8 +1004,11 @@ 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); - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); + 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)) { + ldap_free_urldesc(lud); + return CURLE_FAILED_INIT; + } } #endif @@ -1171,8 +1192,9 @@ 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])) + if(bvals[i].bv_len && + (ISBLANK(bvals[i].bv_val[0]) || + ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))) binval = TRUE; else { /* check for unprintable characters */ @@ -1213,7 +1235,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); @@ -1222,6 +1243,7 @@ static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf, break; } + ber_free(ber, 0); ldap_msgfree(msg); return result; } diff --git a/lib/pingpong.c b/lib/pingpong.c index 003ad58441c7..3f6da71eae2c 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" @@ -99,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) @@ -117,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 */ @@ -182,10 +177,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 +199,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 +206,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 +255,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 +321,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/pop3.c b/lib/pop3.c index f5ecfd178ba6..2fd496cb3142 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" @@ -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 @@ -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); @@ -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); @@ -1377,18 +1376,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); diff --git a/lib/progress.c b/lib/progress.c index fdae3194c55d..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,61 +56,45 @@ 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); } } /* 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) { + curl_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 */ + 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 */ + curl_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 @@ -139,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; @@ -503,7 +487,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; @@ -517,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 */ } @@ -559,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 % */ - max5data(total_expected_size, max5[2]), /* total size */ - dl_estm.percent, /* 3 letters */ /* rcvd % */ - max5data(p->dl.cur_size, max5[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 */ - time_total, /* 8 letters */ /* total time */ - time_spent, /* 8 letters */ /* time spent */ - time_left, /* 8 letters */ /* time left */ - max5data(p->current_speed, max5[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 a1a5e42c2bb0..cbfcbf27409b 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 @@ -41,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" @@ -149,12 +145,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 +175,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/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 8751ada55987..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" @@ -139,7 +138,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/rtsp.c b/lib/rtsp.c index 1d5f44f91b24..1f952a07cccb 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; @@ -556,12 +558,13 @@ 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) { 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/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/sendf.c b/lib/sendf.c index 551bb5ca81a6..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" @@ -857,7 +856,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; } } @@ -878,7 +877,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 5adfe4dbebb0..7097c7f7b015 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" @@ -443,6 +442,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 +619,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 +723,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 +733,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 +745,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); @@ -814,10 +817,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; @@ -844,7 +847,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); @@ -876,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)) { @@ -951,7 +957,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; @@ -1963,15 +1969,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: /* @@ -2209,6 +2208,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 @@ -2217,6 +2217,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 @@ -2226,9 +2227,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 @@ -2238,9 +2241,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 @@ -2633,8 +2638,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: /* @@ -2643,8 +2655,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; @@ -2889,8 +2908,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/sha256.c b/lib/sha256.c index 6f519add58a9..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" @@ -231,8 +230,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/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 81cf6e7cc1f4..2aa8e96644a9 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" @@ -546,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; @@ -566,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); @@ -578,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; } } @@ -662,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); @@ -718,12 +729,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 +761,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); @@ -1104,7 +1115,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 +1144,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; diff --git a/lib/smtp.c b/lib/smtp.c index 5dba1f9ea8c2..76ed4f280afd 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" @@ -206,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 @@ -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; @@ -989,19 +988,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/lib/socketpair.c b/lib/socketpair.c index 4151a9bb979a..45e908bbf3a9 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) { @@ -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" @@ -154,7 +153,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 +187,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/socks.c b/lib/socks.c index fc6c9730f875..10fca7b44c99 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" @@ -44,51 +45,78 @@ #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" +#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) @@ -98,14 +126,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 +144,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; @@ -150,37 +177,13 @@ int 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) @@ -191,274 +194,215 @@ 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 */ + if(Curl_bufq_len(&sx->iobuf) < min_bytes) { + failf(data, "Failed to receive SOCKS response, " + "proxy closed connection"); + return CURLPX_RECV_CONNECT; + } + 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; +} - /* socks4a does not resolve anything locally */ - sxstate(sx, cf, data, CONNECT_REQ_INIT); - goto CONNECT_REQ_INIT; +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; + + *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 * @@ -479,72 +423,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_skip(&sx->iobuf, 8); + 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; @@ -557,27 +623,77 @@ 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; - return socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, - "initial SOCKS5 request"); + 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; + + 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_skip(&sx->iobuf, 2); + + 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 */ + 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; + 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, @@ -585,17 +701,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 @@ -605,499 +726,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_skip(&sx->iobuf, 2); - 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; } @@ -1118,6 +1234,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; @@ -1129,17 +1246,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 : @@ -1154,29 +1267,55 @@ 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; + if(Curl_trc_is_verbose(data)) { + struct ip_quadruple ipquad; + bool is_ipv6; + 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); - } -#endif - socks_proxy_cf_free(cf); + else + infof(data, "Opened %sSOCKS connection", + (sockindex == SECONDARYSOCKET) ? "2nd " : ""); } +#endif + socks_proxy_cf_free(cf); + cf->connected = TRUE; +out: *done = cf->connected; return result; } @@ -1193,15 +1332,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/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_gssapi.c b/lib/socks_gssapi.c index 0a7ddd5ff1dc..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" @@ -49,8 +48,6 @@ #define MAX_GSS_LEN 1024 -static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; - /* * Helper GSS-API error functions. */ @@ -134,6 +131,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 * +----+------+-----+----------------+ @@ -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); @@ -195,9 +194,10 @@ 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); Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); failf(data, "Failed to initial GSS-API token."); @@ -215,7 +215,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; @@ -227,7 +226,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; @@ -236,7 +234,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; @@ -357,8 +354,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 diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 49210585b0f0..54049e8c9928 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" @@ -71,7 +71,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, CURLcode code; size_t actualread; size_t written; - int result; + CURLcode result; /* Needs GSS-API authentication */ SECURITY_STATUS status; unsigned long sspi_ret_flags = 0; @@ -83,13 +83,14 @@ 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; 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 * +----+------+-----+----------------+ @@ -103,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; @@ -131,17 +133,20 @@ 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")), 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."); @@ -173,16 +178,12 @@ 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); - 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."); @@ -193,6 +194,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)); @@ -220,10 +226,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) @@ -242,7 +245,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, 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; } @@ -276,7 +280,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, 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; } @@ -289,7 +294,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 +307,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 */ @@ -320,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 @@ -399,35 +403,34 @@ 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 + + + etbuf_size = 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) { + 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; 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,22 +453,21 @@ 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); if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI encryption response."); - result = CURLE_COULDNT_CONNECT; + if(!result) + result = CURLE_COULDNT_CONNECT; goto error; } @@ -499,7 +501,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, 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; } @@ -514,8 +517,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 +534,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 +557,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,23 +576,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 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) { diff --git a/lib/strerror.c b/lib/strerror.c index f0f36ed1b716..5b82d7f96556 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -24,19 +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 - -#ifdef USE_LIBIDN2 -#include -#endif +#include #ifdef USE_WINDOWS_SSPI #include "curl_sspi.h" @@ -44,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" @@ -552,319 +541,12 @@ 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; -#ifdef WSAEDISCON /* missing in SalfordC! */ - case WSAEDISCON: - p = "Disconnected"; - break; -#endif - /* 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) +const char *Curl_sspi_strerror(SECURITY_STATUS err, char *buf, size_t buflen) { #ifdef _WIN32 DWORD old_win_err = GetLastError(); @@ -974,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 424fb5b7b5e1..c52503ed9316 100644 --- a/lib/strerror.h +++ b/lib/strerror.h @@ -24,13 +24,8 @@ * ***************************************************************************/ -#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); +const char *Curl_sspi_strerror(SECURITY_STATUS err, char *buf, size_t buflen); #endif #endif /* HEADER_CURL_STRERROR_H */ 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 cc827c1b3e8a..5c25bc2eaa36 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" @@ -108,15 +107,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 { @@ -164,7 +163,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); @@ -713,7 +712,7 @@ static void printsub(struct Curl_easy *data, else /* bad input */ return; } - if(length < 1) { + if(length <= 1) { infof(data, "(Empty suboption?)"); return; } @@ -732,7 +731,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: @@ -759,8 +758,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) { @@ -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); @@ -925,14 +924,21 @@ 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 !data || !!strchr(data, CURL_IAC); +} + /* * suboption() * * Look at the sub-option buffer, and try to be helpful to the other * 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]; @@ -941,56 +947,74 @@ static void 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: - 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(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; + } + 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) { 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(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; + } + 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; failf(data,"Sending data failed (%d)",err); + return CURLE_SEND_ERROR; } 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 = 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)) + return CURLE_BAD_FUNCTION_ARGUMENT; /* Add the variable if it fits */ 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) { @@ -1000,16 +1024,14 @@ static void suboption(struct Curl_easy *data, struct TELNET *tn) printsub(data, '>', &temp[2], len-2); break; } - return; + return CURLE_OK; } - /* * sendsuboption() * * Send suboption information to the server side. */ - static void sendsuboption(struct Curl_easy *data, struct TELNET *tn, int option) { @@ -1064,7 +1086,6 @@ static void sendsuboption(struct Curl_easy *data, } } - static CURLcode telrcv(struct Curl_easy *data, struct TELNET *tn, @@ -1204,7 +1225,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 +1239,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; @@ -1350,7 +1375,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 */ diff --git a/lib/tftp.c b/lib/tftp.c index 4c2fadc2caf8..d9d978c24e90 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,10 +62,10 @@ #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 */ -#include "curl_printf.h" +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -126,6 +125,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 +139,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); }; @@ -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; @@ -462,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) @@ -473,18 +475,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, @@ -494,7 +496,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, @@ -504,7 +506,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, @@ -535,11 +537,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))); + failf(data, "%s", curlx_strerror(SOCKERRNO, buffer, sizeof(buffer))); + return CURLE_SEND_ERROR; } - free(filename); break; case TFTP_EVENT_OACK: @@ -565,7 +568,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; @@ -620,7 +623,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; } @@ -645,7 +648,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; } @@ -671,7 +674,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; } } @@ -748,8 +751,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; } } @@ -793,7 +796,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 */ @@ -819,7 +822,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 */ @@ -962,6 +965,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 +1017,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 @@ -1034,7 +1040,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; @@ -1090,18 +1096,33 @@ 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->rbytes >= 0) && 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) { @@ -1184,7 +1205,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) { @@ -1237,7 +1258,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) { @@ -1307,7 +1328,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")); @@ -1358,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/lib/transfer.c b/lib/transfer.c index 1297a3e82d26..d7014aab87e5 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" @@ -245,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; @@ -283,7 +281,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; @@ -310,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 @@ -370,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; } @@ -392,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)) { @@ -403,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; } @@ -494,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"); @@ -623,7 +618,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 45d44bac738f..f0fe7d3d4135 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" @@ -98,7 +97,6 @@ #include "hsts.h" #include "noproxy.h" #include "cfilters.h" -#include "curl_krb5.h" #include "idn.h" /* And now for the protocols */ @@ -126,9 +124,10 @@ #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" + +/* The last 2 #include files should be in this order */ #include "curl_memory.h" #include "memdebug.h" @@ -356,20 +355,26 @@ 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->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 */ +#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; @@ -429,36 +434,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); @@ -488,7 +463,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 ; @@ -500,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 @@ -525,14 +498,13 @@ 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 */ 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; } @@ -556,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) @@ -599,7 +560,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); @@ -902,8 +862,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; @@ -972,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; @@ -1263,6 +1224,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; @@ -1448,10 +1410,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]); @@ -1610,7 +1568,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, @@ -1786,7 +1744,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 @@ -1828,8 +1786,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) @@ -2040,7 +1999,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]); @@ -2098,9 +2057,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; @@ -2148,7 +2108,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); @@ -2366,7 +2327,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; @@ -2714,7 +2675,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; @@ -3025,10 +2986,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); @@ -3326,6 +3287,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 @@ -3380,15 +3349,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); @@ -3466,10 +3429,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) @@ -3749,7 +3709,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/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/lib/urlapi.c b/lib/urlapi.c index c89852794e05..0a6ae5ba1a7c 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -37,16 +37,17 @@ #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" +#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 */ @@ -459,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; } @@ -1428,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; @@ -1452,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; } } @@ -1500,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) @@ -1578,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; } } @@ -1663,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/urldata.h b/lib/urldata.h index cf181af641fd..c7e19201fe88 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 @@ -190,13 +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 -# endif -# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H -# include +# include # endif #endif @@ -234,25 +229,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; @@ -304,6 +280,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 { @@ -408,7 +387,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? */ @@ -599,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. */ @@ -703,20 +685,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, @@ -1012,10 +980,7 @@ 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 */ #ifdef HAVE_SIGNAL /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */ @@ -1135,6 +1100,9 @@ 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) is this */ unsigned int creds_from:2; /* where is the server credentials originating @@ -1239,9 +1207,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 */ @@ -1390,9 +1355,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 */ @@ -1604,9 +1569,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/lib/vauth/.checksrc b/lib/vauth/.checksrc deleted file mode 100644 index 22ca8e0b5370..000000000000 --- a/lib/vauth/.checksrc +++ /dev/null @@ -1,5 +0,0 @@ -banfunc snprintf -banfunc sscanf -banfunc strerror -banfunc strtol -banfunc vsnprint 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..0a0b3580ed09 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 */ @@ -194,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) @@ -269,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; @@ -404,7 +420,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 +443,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 +473,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 +723,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 +746,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 +759,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 +783,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 +799,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 +814,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 +865,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 +912,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 +923,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 +933,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/digest_sspi.c b/lib/vauth/digest_sspi.c index c74b8f865397..5bf37705653a 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); @@ -195,9 +194,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, + NULL); if(status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) @@ -277,7 +276,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; @@ -365,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; @@ -474,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); } @@ -488,7 +486,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 */ @@ -521,6 +518,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 +528,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; } @@ -540,7 +539,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); @@ -591,11 +590,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, NULL); curlx_unicodefree(spn); if(status == SEC_I_COMPLETE_NEEDED || 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..a414d0a35961 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" @@ -226,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; } diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c index ea26f82750a6..c1953e114569 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; @@ -240,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. * @@ -275,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; @@ -282,8 +281,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 +391,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.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/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index d45e2db38e1f..071617182e7e 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; @@ -170,13 +169,13 @@ 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, 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; @@ -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; @@ -277,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; @@ -308,15 +305,15 @@ 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, 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/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/spnego_sspi.c b/lib/vauth/spnego_sspi.c index 9c4812526121..935468f3a65e 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; @@ -128,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) { @@ -168,12 +167,11 @@ 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, - nego->credentials, &expiry); + nego->credentials, NULL); if(nego->status != SEC_E_OK) return CURLE_AUTH_ERROR; @@ -211,18 +209,16 @@ 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; 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; @@ -243,15 +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, - &expiry); + 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); @@ -259,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; @@ -269,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; @@ -308,7 +302,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/vauth/vauth.c b/lib/vauth/vauth.c index 1b44aa6de1ad..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; @@ -100,7 +99,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/vauth/vauth.h b/lib/vauth/vauth.h index d9e73a0ed12f..9a33ca0c2317 100644 --- a/lib/vauth/vauth.h +++ b/lib/vauth/vauth.h @@ -236,13 +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 -# endif -# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H -# include +# include # endif #endif @@ -317,7 +312,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; diff --git a/lib/version.c b/lib/version.c index a2d486720091..4c7e5712f0f9 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 @@ -78,6 +77,14 @@ #include #endif +#ifdef HAVE_GSSAPI +# ifdef HAVE_GSSGNU +# include +# else +# include +# endif +#endif + #ifdef USE_OPENLDAP #include #endif @@ -89,7 +96,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 +107,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 +123,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 +139,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 +155,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 @@ -209,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 @@ -219,7 +229,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 +240,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 +252,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,10 +281,22 @@ 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 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; @@ -368,10 +390,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) @@ -526,6 +546,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/vquic/.checksrc b/lib/vquic/.checksrc deleted file mode 100644 index 22ca8e0b5370..000000000000 --- a/lib/vquic/.checksrc +++ /dev/null @@ -1,5 +0,0 @@ -banfunc snprintf -banfunc sscanf -banfunc strerror -banfunc strtol -banfunc vsnprint diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 6470f1506d15..97ad43766809 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -149,7 +149,7 @@ struct cf_ngtcp2_ctx { 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 */ + * is accepted by peer */ CURLcode tls_vrfy_result; /* result of TLS peer verification */ int qlogfd; BIT(initialized); @@ -232,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 @@ -272,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); @@ -290,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); @@ -306,8 +306,8 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf, } 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); @@ -343,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 { @@ -354,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; @@ -364,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; @@ -374,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) { @@ -393,14 +393,14 @@ 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 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; @@ -420,6 +420,17 @@ 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; @@ -436,6 +447,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; @@ -450,7 +467,7 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx, } 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) { @@ -467,13 +484,22 @@ 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, 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) @@ -508,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) { @@ -518,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) { @@ -542,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) { @@ -684,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; @@ -863,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); @@ -1093,7 +1120,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) @@ -1107,7 +1134,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 { @@ -1144,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; } @@ -1196,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; @@ -1339,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)); - - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %dm, %zu", - stream ? stream->id : -1, blen, result, *pnread); CF_DATA_RESTORE(cf, save); return result; } @@ -1445,10 +1469,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, @@ -1514,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; @@ -1581,181 +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) - 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; - } - - 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)) { @@ -1956,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; @@ -2180,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]; @@ -2433,9 +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; @@ -2471,11 +2497,22 @@ static const struct alpn_spec ALPN_SPEC_H3 = { 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; @@ -2516,8 +2553,8 @@ static const struct alpn_spec ALPN_SPEC_H3 = { } 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; @@ -2604,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; @@ -2664,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; } @@ -2683,46 +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 = 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; - } + 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 = { @@ -2785,19 +2822,20 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, } 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 + diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 3586ad0d556a..a49074346270 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,9 +56,9 @@ #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" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" @@ -186,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; @@ -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 */ @@ -453,32 +452,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, @@ -507,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"; @@ -546,12 +549,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) - Curl_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); + curlx_strerror(sockerr, extramsg, sizeof(extramsg)); + 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 */ @@ -564,9 +567,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); } @@ -866,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) { @@ -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); @@ -1178,8 +1176,8 @@ static const struct alpn_spec ALPN_SPEC_H3 = { 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); @@ -1229,6 +1227,9 @@ static const struct alpn_spec ALPN_SPEC_H3 = { 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); @@ -1269,12 +1270,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; @@ -1426,12 +1431,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) { @@ -1850,9 +1859,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) @@ -2198,17 +2207,11 @@ 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) + if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; + Curl_conn_set_multiplex(cf->conn); + } break; default: break; @@ -2234,7 +2237,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)) { @@ -2242,9 +2245,10 @@ 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) + if(idle_ms && idletime > 0 && (uint64_t)idletime > idle_ms) goto out; } @@ -2400,7 +2404,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; @@ -2414,23 +2418,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; } @@ -2457,7 +2460,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 179ccf8aa1ac..55f6e79ebefc 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" @@ -53,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" @@ -75,15 +73,13 @@ * 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. */ 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 { @@ -112,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 @@ -150,14 +146,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, @@ -662,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; } } @@ -867,9 +873,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; } @@ -955,10 +961,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, @@ -1230,18 +1232,11 @@ 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) + if(!cf->sockindex && cf->connected) { cf->conn->httpversion_seen = 30; + Curl_conn_set_multiplex(cf->conn); + } break; default: break; @@ -1256,9 +1251,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); @@ -1302,7 +1295,9 @@ static const struct alpn_spec ALPN_SPEC_H3 = { 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); @@ -1358,9 +1353,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); } @@ -1441,9 +1433,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; @@ -1502,6 +1496,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; } } @@ -1509,6 +1504,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; } @@ -1638,7 +1634,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; @@ -1653,22 +1649,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/vquic/vquic-tls.c b/lib/vquic/vquic-tls.c index 4bdd23c981cd..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" @@ -130,7 +129,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 +169,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/vquic/vquic.c b/lib/vquic/vquic.c index 3a0ac872383f..30917b835af0 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" @@ -45,11 +43,10 @@ #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 */ -#include "../curl_printf.h" +/* The last 2 #include files should be in this order */ #include "../curl_memory.h" #include "../memdebug.h" @@ -57,7 +54,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) @@ -127,6 +124,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}; @@ -183,12 +181,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; @@ -196,19 +196,21 @@ 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) ; 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. */ @@ -218,9 +220,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, @@ -228,20 +237,24 @@ 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; } - - return CURLE_OK; +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 result; } static CURLcode vquic_send_packets(struct Curl_cfilter *cf, @@ -268,6 +281,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; @@ -291,8 +307,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); @@ -371,7 +385,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; @@ -413,20 +427,20 @@ 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; } - 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; goto out; } - CURL_TRC_CF(data, cf, "recvmmsg() -> %d packets", mcount); + ++calls; for(i = 0; i < mcount; ++i) { total_nread += mmsg[i].msg_len; @@ -456,8 +470,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; } @@ -473,8 +487,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))]; @@ -483,7 +498,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)); @@ -496,45 +511,45 @@ 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; } 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; } - Curl_strerror(SOCKERRNO, errstr, sizeof(errstr)); + curlx_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); @@ -545,8 +560,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; } @@ -561,7 +576,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; @@ -580,13 +595,13 @@ 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; } - 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; @@ -594,6 +609,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); @@ -603,8 +619,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 */ @@ -658,15 +674,16 @@ 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) 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/.checksrc b/lib/vssh/.checksrc deleted file mode 100644 index 22ca8e0b5370..000000000000 --- a/lib/vssh/.checksrc +++ /dev/null @@ -1,5 +0,0 @@ -banfunc snprintf -banfunc sscanf -banfunc strerror -banfunc strtol -banfunc vsnprint 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/libssh.c b/lib/vssh/libssh.c index 695532ff8514..3741db20dc63 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); @@ -765,35 +764,34 @@ static int myssh_in_SFTP_QUOTE_STATVFS(struct Curl_easy *data, #else #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64 #endif - CURLcode result; - 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); + CURLcode result = CURLE_OK; + 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) { - 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; @@ -1107,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); @@ -1115,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; } @@ -1156,12 +1155,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; @@ -1191,8 +1196,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) { @@ -1235,6 +1240,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); @@ -1320,8 +1329,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; @@ -1329,51 +1337,43 @@ 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; - 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 (%" 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; @@ -1387,8 +1387,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; @@ -1398,8 +1397,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 */ @@ -1409,10 +1407,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 */ @@ -1566,6 +1562,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) @@ -1591,7 +1599,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); @@ -1673,6 +1682,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; @@ -1694,10 +1705,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; @@ -1718,20 +1733,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; } @@ -1808,10 +1831,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 +1840,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)) { @@ -1840,9 +1861,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"); @@ -1851,6 +1870,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) || @@ -1875,6 +1895,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 */ @@ -1976,6 +1999,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); @@ -1995,6 +2020,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); @@ -2011,6 +2038,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", @@ -2026,6 +2055,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); @@ -2041,6 +2072,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", @@ -2055,6 +2088,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", @@ -2394,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; } @@ -2409,19 +2445,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 */ @@ -2572,7 +2605,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 @@ -2889,7 +2922,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 +2932,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. @@ -3157,7 +3191,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; @@ -3170,7 +3204,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 5dfc377ec14e..f9160944befe 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,14 +64,14 @@ #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" #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" @@ -177,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; @@ -464,26 +460,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 +594,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 " @@ -686,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); @@ -755,24 +731,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 +796,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; @@ -892,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) @@ -920,7 +880,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); @@ -978,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; @@ -994,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; @@ -1013,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; } @@ -1075,15 +1051,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, @@ -1141,8 +1123,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) { @@ -1216,9 +1198,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) { @@ -1245,15 +1224,15 @@ 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(stat(sshc->rsa, &sbuf)) { + 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(stat(sshc->rsa, &sbuf)) { + else if(curlx_stat(sshc->rsa, &sbuf)) { Curl_safefree(sshc->rsa); } } @@ -1262,10 +1241,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. */ @@ -1355,11 +1334,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; } @@ -1379,11 +1358,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; } @@ -1449,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; @@ -1871,8 +1851,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; } } @@ -1994,15 +1975,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) { - /* 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) { - 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) @@ -2015,21 +1993,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; } @@ -2288,24 +2264,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; @@ -2405,6 +2381,9 @@ 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; + /* append filename and extra output */ result = curlx_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename); if(result) @@ -2430,18 +2409,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; @@ -2633,7 +2603,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; @@ -3091,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; } @@ -3263,12 +3234,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) @@ -3276,9 +3247,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) @@ -3291,12 +3262,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) @@ -3304,9 +3275,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) @@ -3364,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 */ @@ -3410,12 +3376,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 @@ -4027,7 +4000,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; @@ -4040,7 +4013,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/vssh/ssh.h b/lib/vssh/ssh.h index 75b31bd931f5..e09111e63f66 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" @@ -123,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; @@ -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/lib/vtls/.checksrc b/lib/vtls/.checksrc deleted file mode 100644 index 22ca8e0b5370..000000000000 --- a/lib/vtls/.checksrc +++ /dev/null @@ -1,5 +0,0 @@ -banfunc snprintf -banfunc sscanf -banfunc strerror -banfunc strtol -banfunc vsnprint diff --git a/lib/vtls/apple.c b/lib/vtls/apple.c new file mode 100644 index 000000000000..87d5208d735a --- /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" + +#ifdef USE_APPLE_SECTRUST +#include +#endif + +/* The last #include files should be: */ +#include "../curl_memory.h" +#include "../memdebug.h" + + +#ifdef 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((sec_result == kSecTrustResultUnspecified) || + (sec_result == 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_APPLE_SECTRUST */ diff --git a/lib/vtls/apple.h b/lib/vtls/apple.h new file mode 100644 index 000000000000..3d84f8782288 --- /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" + +#ifdef 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_APPLE_SECTRUST */ + +#endif /* HEADER_CURL_VTLS_APPLE_H */ 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 f38c90e66c34..1c0a6fb2d610 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -48,16 +48,17 @@ #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 */ #include "../progress.h" #include "../select.h" #include "../strdup.h" +#include "../curlx/fopen.h" #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" @@ -68,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; @@ -189,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 @@ -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; } @@ -453,62 +454,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, @@ -519,7 +533,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; @@ -1519,31 +1533,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) { @@ -1566,16 +1625,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) @@ -1584,13 +1643,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); @@ -1598,37 +1659,121 @@ 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. */ + 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) { + /* convert the given DER or PEM encoded Certificate to the native + gnutls_x509_crt_t format */ + 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; + } + } - /* verify_status is a bitmask of gnutls_certificate_status bits */ - if(verify_status & GNUTLS_CERT_INVALID) { + /* 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, " 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); @@ -1636,22 +1781,19 @@ 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; - 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)", @@ -1659,7 +1801,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"); } @@ -1724,61 +1866,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) { @@ -1813,7 +1900,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; @@ -2064,7 +2151,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); @@ -2195,13 +2282,13 @@ 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; } 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/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/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/mbedtls.c b/lib/vtls/mbedtls.c index 7b1a31e42f5b..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; @@ -918,6 +917,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 +968,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 +1017,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 @@ -1113,8 +1114,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 +1137,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; @@ -1160,7 +1173,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); @@ -1280,6 +1293,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 +1308,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: @@ -1316,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 a49203ab07d2..533acdaf8db7 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -63,10 +63,10 @@ #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" #include #include @@ -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 @@ -140,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 */ @@ -276,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); @@ -296,20 +293,15 @@ 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; +#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 */ } static CURLcode X509V3_ext(struct Curl_easy *data, @@ -340,7 +332,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)); @@ -366,9 +360,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); @@ -750,8 +743,9 @@ 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; return -1; } @@ -1634,7 +1628,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; @@ -1777,8 +1778,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)); @@ -1822,6 +1821,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) { @@ -1843,6 +1843,7 @@ static CURLcode x509_name_oneline(X509_NAME *a, struct dynbuf *d) } return result; } +#endif /** * Global SSL init @@ -2167,14 +2168,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; @@ -2398,7 +2401,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; @@ -2409,7 +2412,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; @@ -2586,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; } @@ -2608,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; @@ -2799,7 +2812,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; } @@ -2846,10 +2859,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); } @@ -2865,11 +2878,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 */ @@ -2934,10 +2948,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; } @@ -3160,7 +3173,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 */ @@ -3168,17 +3188,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 @@ -3287,14 +3307,14 @@ 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"); #endif - *imported = TRUE; + *padded = TRUE; } X509_free(x509); } @@ -3309,125 +3329,181 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data, return result; } -#endif -static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf, - struct Curl_easy *data, - X509_STORE *store) +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; - - 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; + bool have_native_check = FALSE; - 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 */ @@ -3437,34 +3513,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 +3549,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 +3594,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 +3610,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 +3618,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 +3663,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 +3690,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 +3711,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(); @@ -3660,6 +3737,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; @@ -3667,7 +3745,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); @@ -3900,7 +3978,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 +4081,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]; @@ -4110,7 +4186,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 @@ -4238,12 +4314,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 +4344,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 +4556,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; @@ -4605,7 +4680,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); @@ -4718,11 +4793,8 @@ 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 */ - - /* https://groups.google.com/group/mailing.openssl.users/browse_thread - /thread/d61858dae102c6c7 */ + /* 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) break; /* failed */ @@ -4765,6 +4837,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); @@ -4801,7 +4876,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 @@ -4821,221 +4897,326 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl) #define infof_certstack(data, ssl) #endif -#define MAX_CERT_NAME_LENGTH 2048 - -CURLcode Curl_ossl_check_peer_cert(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct ossl_ctx *octx, - struct ssl_peer *peer) +static CURLcode ossl_check_issuer(struct Curl_cfilter *cf, + struct Curl_easy *data, + X509 *server_cert) { - struct connectdata *conn = cf->conn; - 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; + X509 *issuer = NULL; BIO *fp = NULL; - char error_buffer[256]=""; + 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; - BIO *mem = BIO_new(BIO_s_mem()); + 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; - DEBUGASSERT(octx); + 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(), error_buffer, - sizeof(error_buffer)) ); - return CURLE_OUT_OF_MEMORY; + 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(data->set.ssl.certinfo) - /* asked to gather certificate info */ - (void)ossl_certchain(data, octx->ssl); + infof(data, "%s certificate:", Curl_ssl_cf_is_proxy(cf) ? + "Proxy" : "Server"); - octx->server_cert = SSL_get1_peer_certificate(octx->ssl); - if(!octx->server_cert) { - BIO_free(mem); - if(!strict) - return CURLE_OK; + result = x509_name_oneline(X509_get_subject_name(server_cert), &dname); + infof(data, " subject: %s", result ? "[NONE]" : curlx_dyn_ptr(&dname)); - failf(data, "SSL: could not get peer certificate"); - return CURLE_PEER_FAILED_VERIFICATION; + 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)); - infof(data, "%s certificate:", - Curl_ssl_cf_is_proxy(cf) ? "Proxy" : "Server"); +out: + BIO_free(mem); + curlx_dyn_free(&dname); + return result; +} +#endif /* ! CURL_DISABLE_VERBOSE_STRINGS */ - 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); +#ifdef USE_APPLE_SECTRUST +struct ossl_certs_ctx { + STACK_OF(X509) *sk; + size_t num_certs; +}; - 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); - } +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; - BIO_free(mem); + 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(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); + 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, + struct ossl_ctx *octx, + struct ssl_peer *peer) +{ + struct connectdata *conn = cf->conn; + 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 ossl_verify; + bool strict = (conn_config->verifypeer || conn_config->verifyhost); + 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) 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"); + server_cert = SSL_get1_peer_certificate(octx->ssl); + if(!server_cert) { + if(!strict) + goto out; + + failf(data, "SSL: could not get peer certificate"); result = CURLE_PEER_FAILED_VERIFICATION; + 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; - } - } +#ifndef CURL_DISABLE_VERBOSE_STRINGS + result = ossl_infof_cert(cf, data, server_cert); + if(result) + goto out; + infof_certstack(data, octx->ssl); +#endif - 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(conn_config->verifyhost) { + result = ossl_verifyhost(data, conn, peer, server_cert); + if(result) + goto out; + } - 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; - } + ossl_verify = SSL_get_verify_result(octx->ssl); + ssl_config->certverifyresult = ossl_verify; - 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); + verified = (ossl_verify == X509_V_OK); + if(verified) + infof(data, "SSL certificate verified via OpenSSL."); + +#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; } @@ -5106,10 +5287,10 @@ 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)); + 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); @@ -5292,10 +5473,10 @@ 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)); + 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); @@ -5366,6 +5547,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: @@ -5388,10 +5570,10 @@ 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)); + 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; @@ -5411,10 +5593,10 @@ 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"); + curl_msnprintf(error_buffer, sizeof(error_buffer), + "Connection closed abruptly"); } failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d", error_buffer, sockerr); @@ -5456,6 +5638,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; @@ -5477,15 +5660,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 */ @@ -5498,23 +5681,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; @@ -5534,7 +5722,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 = '_'; @@ -5542,17 +5730,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 */ @@ -5575,16 +5763,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/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/rustls.c b/lib/vtls/rustls.c index 221a7a6215ad..ff2dea82b606 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -28,18 +28,17 @@ #ifdef USE_RUSTLS -#include "../curl_printf.h" - #include +#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" @@ -121,7 +120,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; } @@ -170,7 +169,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; } @@ -188,16 +187,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, @@ -290,7 +281,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) { @@ -405,22 +396,24 @@ 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; } - while(!feof(f)) { + for(;;) { uint8_t buf[256]; 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 @@ -432,7 +425,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; @@ -525,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); } @@ -1110,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); @@ -1212,13 +1205,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; @@ -1231,8 +1225,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); } { @@ -1315,7 +1309,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) { @@ -1393,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 1afc6790cc51..ae5834d84342 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -47,11 +47,11 @@ #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" #include "x509asn1.h" -#include "../curl_printf.h" #include "../multiif.h" #include "../system_win32.h" #include "../curlx/version_win32.h" @@ -109,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+) */ @@ -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) || \ @@ -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; @@ -563,7 +563,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" @@ -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; @@ -612,7 +611,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); @@ -659,7 +658,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 +677,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 +699,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()); @@ -771,7 +770,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; @@ -796,8 +797,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 +835,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]) @@ -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 @@ -1050,7 +1049,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 +1258,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); @@ -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; @@ -2440,8 +2439,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 */ @@ -2453,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; @@ -2468,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. @@ -2554,10 +2552,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"))); + 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 */ @@ -2580,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_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 { diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index 17e42707631d..d72790e9df57 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" @@ -552,7 +551,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) */ @@ -612,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]; @@ -668,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; } @@ -685,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 @@ -693,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; @@ -737,6 +735,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, } cleanup: + LocalFree(alt_name_info); Curl_safefree(cert_hostname_buff); if(pCertContextServer) @@ -889,7 +888,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 +909,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; } } diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index f17f9142bed1..7ee9699dbf0b 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" @@ -68,18 +65,23 @@ #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" #include "../curlx/warnless.h" #include "../curlx/base64.h" -#include "../curl_printf.h" #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 + /* The last #include files should be: */ #include "../curl_memory.h" #include "../memdebug.h" @@ -292,62 +294,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 */ @@ -803,7 +843,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 +905,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; @@ -1053,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 ? ")" : "")); } } @@ -1862,7 +1902,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; } @@ -1993,6 +2033,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 " 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); diff --git a/lib/vtls/vtls_scache.c b/lib/vtls/vtls_scache.c index 662539cd8960..763b474cfc7d 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" @@ -49,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: */ @@ -374,7 +370,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]) { @@ -905,7 +901,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, " @@ -917,6 +912,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; } diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index afbb9b82182c..d4a0e066fa03 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 @@ -362,8 +361,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) && @@ -1095,9 +1097,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, @@ -1633,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; } @@ -1879,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) { @@ -1921,7 +1918,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; @@ -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; } @@ -2055,9 +2052,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 fe47e81a87d8..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" @@ -199,7 +198,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 +455,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); @@ -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/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/lib/ws.c b/lib/ws.c index 3b654281604b..ec7923555030 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" @@ -453,7 +452,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) | @@ -545,7 +544,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; @@ -582,7 +581,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; @@ -648,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_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) + 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, @@ -659,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 */ @@ -680,8 +700,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; } @@ -982,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; } @@ -1268,6 +1294,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 +1386,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 @@ -1443,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; @@ -1502,7 +1537,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; @@ -1576,9 +1611,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) { @@ -1806,7 +1841,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; @@ -1876,7 +1911,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/m4/curl-apple-sectrust.m4 b/m4/curl-apple-sectrust.m4 new file mode 100644 index 000000000000..7ed2aa1e5bff --- /dev/null +++ b/m4/curl-apple-sectrust.m4 @@ -0,0 +1,61 @@ +#*************************************************************************** +# _ _ ____ _ +# 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_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 + APPLE_SECTRUST_LDFLAGS='-framework CoreFoundation -framework CoreServices -framework Security' + LDFLAGS="$LDFLAGS $APPLE_SECTRUST_LDFLAGS" + LDFLAGSPC="$LDFLAGSPC $APPLE_SECTRUST_LDFLAGS" + else + AC_MSG_ERROR([Apple SecTrust is only supported for OpenSSL/GnuTLS builds]) + fi +else + AC_MSG_RESULT(no) +fi + +]) 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/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 ]) 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, 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.]), diff --git a/packages/OS400/ccsidcurl.c b/packages/OS400/ccsidcurl.c index a9c04d5a420e..b40367fd960b 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; @@ -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); 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/packages/OS400/os400sys.c b/packages/OS400/os400sys.c index 7be72085498b..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); @@ -333,6 +349,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/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 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 =========== 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/renovate.json b/renovate.json index efb9064dabf2..102bf42521fd 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": [ @@ -82,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": [ diff --git a/scripts/.checksrc b/scripts/.checksrc new file mode 100644 index 000000000000..03e98fee8925 --- /dev/null +++ b/scripts/.checksrc @@ -0,0 +1,5 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +allowfunc printf diff --git a/scripts/Makefile.am b/scripts/Makefile.am index cfa3d3e740a9..da9b6b4b7723 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 .checksrc dist_bin_SCRIPTS = wcurl 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/checksrc.pl b/scripts/checksrc.pl index 43b819553791..7059d6857500 100755 --- a/scripts/checksrc.pl +++ b/scripts/checksrc.pl @@ -53,15 +53,29 @@ "gets" => 1, "strtok" => 1, "sprintf" => 1, + "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, "strncat" => 1, "strncpy" => 1, "strtok_r" => 1, + "strtol" => 1, "strtoul" => 1, "_mbscat" => 1, "_mbsncat" => 1, "_tcscat" => 1, + "_tcsdup" => 1, "_tcsncat" => 1, "_wcscat" => 1, "_wcsncat" => 1, @@ -73,9 +87,25 @@ "LoadLibraryEx" => 1, "LoadLibraryExA" => 1, "LoadLibraryExW" => 1, + "WSASocket" => 1, + "WSASocketA" => 1, + "WSASocketW" => 1, "_waccess" => 1, "_access" => 1, "access" => 1, + "accept" => 1, + "accept4" => 1, + "freeaddrinfo" => 1, + "getaddrinfo" => 1, + "recv" => 1, + "send" => 1, + "socket" => 1, + "socketpair" => 1, + "fclose" => 1, + "fdopen" => 1, + "fopen" => 1, + "open" => 1, + "stat" => 1, ); my %warnings_extended = ( @@ -104,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', @@ -172,6 +203,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"; @@ -515,7 +550,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"); } @@ -878,17 +913,17 @@ 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; checkwarn("BANNEDFUNC", $line, length($prefix), $file, $ol, "use of $bad is banned"); - my $replace = 'x' x (length($bad) + 1); - $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 @@ -907,8 +942,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, @@ -936,7 +971,6 @@ sub scanfile { my $diff = $second - $first; checkwarn("INDENTATION", $line, length($1), $file, $ol, "not indented $indent steps (uses $diff)"); - } } } 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..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" diff --git a/scripts/managen b/scripts/managen index 459b651240a6..0c75148fd170 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"; } @@ -245,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"; } @@ -265,8 +291,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; } @@ -477,7 +503,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 @@ -635,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) { ; } @@ -671,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; @@ -720,7 +750,7 @@ sub single { } my @leading; if($protocols) { - push @leading, protocols($manpage, $standalone, $protocols); + push @leading, protocols($f, $line, $manpage, $standalone, $protocols); } if($standalone) { @@ -728,7 +758,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]"; @@ -740,7 +771,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"; @@ -750,11 +783,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"; @@ -766,20 +803,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"; @@ -803,7 +843,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 = ","; @@ -813,7 +853,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"; } @@ -826,7 +866,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 "; @@ -840,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/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"; diff --git a/scripts/perlcheck.sh b/scripts/perlcheck.sh new file mode 100755 index 000000000000..7ec23983d5e6 --- /dev/null +++ b/scripts/perlcheck.sh @@ -0,0 +1,51 @@ +#!/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")"/.. + +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 + 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 -P "${procs}" perl -c -Itests -- 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/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/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 ;; diff --git a/src/.checksrc b/src/.checksrc index 7b71afb23689..bc97c06028da 100644 --- a/src/.checksrc +++ b/src/.checksrc @@ -1,5 +1,5 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + enable STDERR -banfunc snprintf -banfunc sscanf -banfunc strtol -banfunc vsnprint diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 37ca979bab99..a70c96b7650f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,9 +123,19 @@ 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() + +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) + set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_OPTIONS ${CURL_COVERAGE_LDFLAGS}) + else() + set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_FLAGS ${CURL_COVERAGE_LDFLAGS}) endif() endif() diff --git a/src/Makefile.inc b/src/Makefile.inc index 1086c07febb1..fa5583755203 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -34,28 +34,34 @@ # 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 \ ../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 \ - ../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 \ ../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 e8f4b0a407ae..c367959ccb3e 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 @@ -112,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; @@ -192,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); @@ -200,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"); @@ -848,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); @@ -973,7 +976,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/curlinfo.c b/src/curlinfo.c index d601904f3eef..da75a45876cf 100644 --- a/src/curlinfo.c +++ b/src/curlinfo.c @@ -236,18 +236,17 @@ 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++) + /* !checksrc! disable BANNEDFUNC 1 */ printf("%s\n", disabled[i]); return 0; 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/src/tool_cb_dbg.c b/src/tool_cb_dbg.c index 6a587cc1cc63..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 @@ -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; } } @@ -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== Info: %.*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 6af9d1947e1e..2ea88017051e 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) { @@ -116,7 +118,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)) { @@ -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); @@ -215,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; @@ -246,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); @@ -293,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 @@ -459,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_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_cb_wrt.c b/src/tool_cb_wrt.c index 6fbf80753de3..724706b7a1af 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" @@ -55,12 +50,13 @@ 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; 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); } @@ -92,14 +89,16 @@ 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); } } 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_cfgable.c b/src/tool_cfgable.c index 0321848b0d5a..7b4ee8083586 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -53,6 +53,7 @@ struct OperationConfig *config_alloc(void) 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; } diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 5e7222a8a86d..630f23fd9654 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) \ @@ -76,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; @@ -112,6 +98,7 @@ struct OperationConfig { char *proxyuserpwd; char *proxy; char *noproxy; + char *knownhosts; char *mail_from; struct curl_slist *mail_rcpt; char *mail_auth; @@ -209,7 +196,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. */ @@ -239,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? */ @@ -257,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 */ @@ -352,8 +339,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_doswin.c b/src/tool_doswin.c index 4ed90ba8c50f..8e9e5f023d39 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 @@ -83,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 ----- @@ -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); } @@ -472,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; @@ -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) { @@ -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(;;) { @@ -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) @@ -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); @@ -835,11 +834,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 +847,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; } @@ -873,7 +870,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; } @@ -884,14 +881,14 @@ 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; } /* 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()); + errorf("socket error: %d", SOCKERRNO); break; } @@ -899,18 +896,18 @@ 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; } /* 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; } @@ -932,6 +929,7 @@ curl_socket_t win32_stdin_read_thread(void) if(stdin_thread) { TerminateThread(stdin_thread, 1); + CloseHandle(stdin_thread); stdin_thread = NULL; } diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c index 223c66bdf503..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; @@ -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 @@ -190,44 +190,44 @@ 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) - fclose(out); + curlx_fclose(out); } easysrc_free(); diff --git a/src/tool_filetime.c b/src/tool_filetime.c index c818fe3ada20..6dc2fbbe4234 100644 --- a/src/tool_filetime.c +++ b/src/tool_filetime.c @@ -62,25 +62,26 @@ 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 0x%08lx", + 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 0x%08lx", + GetLastError()); } #else struct_stat statbuf; - if(stat(filename, &statbuf) != -1) { + if(curlx_stat(filename, &statbuf) != -1) { *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; } @@ -117,15 +118,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 0x%08lx", + 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 0x%08lx", + filetime, GetLastError()); } #elif defined(HAVE_UTIMES) @@ -133,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) @@ -142,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_findfile.c b/src/tool_findfile.c index 72868f4b4f73..02898a8fb1b5 100644 --- a/src/tool_findfile.c +++ b/src/tool_findfile.c @@ -24,13 +24,13 @@ #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 - -#ifdef HAVE_FCNTL_H -#include #endif #include "tool_findfile.h" @@ -69,11 +69,11 @@ 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 = open(c, O_RDONLY); + int fd = curlx_open(c, O_RDONLY); if(fd >= 0) { char *path = strdup(c); close(fd); @@ -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_formparse.c b/src/tool_formparse.c index b5ab10a00f80..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. */ @@ -563,14 +565,16 @@ static int get_param_part(char endchar, endpos--; sep = *p; *endpos = '\0'; - fp = fopen(hdrfile, FOPEN_READTEXT); - if(!fp) + fp = curlx_fopen(hdrfile, FOPEN_READTEXT); + 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); - 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 6be57dbd5c31..0cff5b558d9b 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -196,8 +196,9 @@ 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}, + {"knownhosts", ARG_FILE, ' ', C_KNOWNHOSTS}, + {"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}, @@ -627,7 +628,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 +638,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; } @@ -736,7 +737,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,9 +751,9 @@ static CURLcode set_trace_config(const char *token) global->tracetime = toggle; } else { - char buffer[32]; - msnprintf(buffer, sizeof(buffer), "%c%.*s", toggle ? '+' : '-', - (int)len, name); + char buffer[64]; + curl_msnprintf(buffer, sizeof(buffer), "%c%.*s,-lib-ids", + toggle ? '+' : '-', (int)len, name); result = curl_global_trace(buffer); if(result) goto out; @@ -899,7 +903,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 +921,7 @@ static ParameterError set_data(cmdline_t cmd, } if(file && (file != stdin)) - fclose(file); + curlx_fclose(file); if(err) return err; @@ -1012,8 +1016,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) @@ -1093,7 +1098,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)) { @@ -1103,7 +1108,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; @@ -1136,7 +1141,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) @@ -1205,7 +1210,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\" " @@ -1215,10 +1220,10 @@ 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); + config->ech_config = curl_maprintf("ecl:%s",tmpcfg); free(tmpcfg); if(!config->ech_config) return PARAM_NO_MEM; @@ -1241,7 +1246,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; @@ -1262,10 +1267,14 @@ static ParameterError parse_header(struct OperationConfig *config, err = PARAM_READ_ERROR; curlx_dyn_free(&line); if(!use_stdin) - fclose(file); + curlx_fclose(file); } } 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 @@ -1397,8 +1406,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) @@ -1535,7 +1544,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; @@ -1544,7 +1553,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) @@ -2028,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"); @@ -2043,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; @@ -2108,7 +2111,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; @@ -2130,7 +2132,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; @@ -2163,11 +2164,126 @@ 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_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; + 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 +2343,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,20 +2372,10 @@ 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); 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; @@ -2406,10 +2496,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 +2513,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 +2581,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 +2599,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 +2618,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 +2634,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 +2661,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 +2683,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 +2695,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 +2721,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 +2750,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); @@ -2786,7 +2797,6 @@ static ParameterError opt_filestring(struct OperationConfig *config, else global->parallel_host = (unsigned short)val; break; - break; case C_PARALLEL_MAX: /* --parallel-max */ err = str2unum(&val, nextarg); if(err) @@ -2947,18 +2957,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)); } 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_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_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 dd030f09bc92..13124133eaf3 100644 --- a/src/tool_ipfs.c +++ b/src/tool_ipfs.c @@ -76,19 +76,19 @@ 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; - 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; @@ -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_listhelp.c b/src/tool_listhelp.c index ecbd8bf4595e..21019c7de161 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -341,9 +341,12 @@ 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_FTP}, + CURLHELP_DEPRECATED}, {" --libcurl ", "Generate libcurl code for this command line", CURLHELP_CURL | CURLHELP_GLOBAL}, @@ -831,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/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..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 = vaprintf(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); + } } /* @@ -120,15 +121,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 2c3030096f6a..c7d01bb59af2 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 @@ -164,7 +160,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 +171,7 @@ static curl_off_t vms_realfilesize(const char *name, if(ret_stat) count += ret_stat; } - fclose(file); + curlx_fclose(file); return count; } @@ -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 { @@ -340,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, @@ -357,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) || @@ -372,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. */ @@ -382,6 +402,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) { @@ -391,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 @@ -408,6 +431,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); @@ -436,8 +460,8 @@ static CURLcode retrycheck(struct OperationConfig *config, ": HTTP error", ": FTP error" }; + bool truncate = TRUE; /* truncate output file */ - sleeptime = per->retry_sleep; if(RETRY_HTTP == retry) { curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after); if(retry_after) { @@ -464,22 +488,72 @@ 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 == 1 ? "" : "s"), + (sleeptime%1000L ? "." : ""), + (sleeptime%1000L ? 3 : 0), + sleeptime%1000L, + (sleeptime == 1000L ? "" : "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; + + /* 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(outs->bytes && outs->filename && outs->stream) { + if(truncate && outs->bytes && outs->filename && outs->stream) { #ifndef __MINGW32CE__ struct_stat fileinfo; @@ -581,29 +655,31 @@ 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); } - 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); 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; } } /* 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) { @@ -653,7 +729,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; @@ -661,8 +737,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 @@ -689,13 +764,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); @@ -793,22 +868,24 @@ static CURLcode etag_compare(struct OperationConfig *config) ParameterError pe; /* open file for reading: */ - FILE *file = fopen(config->etag_compare_file, FOPEN_READTEXT); - if(!file) + FILE *file = curlx_fopen(config->etag_compare_file, FOPEN_READTEXT); + 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) { - 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) - fclose(file); + curlx_fclose(file); errorf("Failed to allocate memory for custom etag header"); return CURLE_OUT_OF_MEMORY; } @@ -818,7 +895,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; @@ -836,7 +913,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); @@ -886,11 +963,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); @@ -949,7 +1026,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); @@ -967,7 +1044,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; @@ -980,7 +1057,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 @@ -992,11 +1069,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); @@ -1066,8 +1143,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))); + } } } @@ -1186,7 +1266,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 */ @@ -1270,8 +1350,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; @@ -1455,26 +1535,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) @@ -1496,12 +1558,11 @@ 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, &uv->s->still_running); - check_multi_info(uv); } } @@ -1511,7 +1572,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); @@ -1562,8 +1623,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: @@ -1587,8 +1648,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: @@ -1623,18 +1682,15 @@ 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); - if(result && !s->result) - s->result = result; - /* early exit called */ if(s->wrapitup) { if(s->still_running && !s->wrapitup_processed) { @@ -1647,13 +1703,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; @@ -1671,8 +1720,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; @@ -1699,9 +1748,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 */ @@ -1748,6 +1797,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 CURLMNOTIFY_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; @@ -1765,6 +1835,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, CURLMNOTIFY_INFO_READ); + result = add_parallel_transfers(s->multi, s->share, &s->more_transfers, &s->added_transfers); if(result) { @@ -1803,13 +1877,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 : @@ -1927,7 +2002,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 @@ -1951,7 +2026,7 @@ static CURLcode is_using_schannel(int *using) if(result) return result; } - *using = using_schannel; + *pusing = using_schannel; return result; } @@ -1997,7 +2072,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) && \ @@ -2181,7 +2256,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) @@ -2263,7 +2338,6 @@ CURLcode operate(int argc, argv_item_t argv[]) } varcleanup(); - curl_free(global->knownhosts); return result; } 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 bc22b9d5b7b5..5cf3527ce2a5 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; } @@ -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; @@ -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_progress.c b/src/tool_progress.c index 666fe9869cd7..2fcc7ff85e3d 100644 --- a/src/tool_progress.c +++ b/src/tool_progress.c @@ -31,48 +31,33 @@ 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) - - 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); + /* a signed 64-bit value is 8192 petabytes maximum */ + const char unit[] = { 'k', 'M', 'G', 'T', 'P', 0 }; + int k = 0; + if(bytes < 100000) { + curl_msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); + return max5; + } - /* 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 */ + 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 */ + curl_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; } @@ -113,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 @@ -122,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); } } @@ -144,6 +130,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,38 +184,38 @@ 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; } } 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 */ @@ -273,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 */, - - 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" :""); + 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" :""); return TRUE; } return FALSE; @@ -306,14 +301,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; } } 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_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_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_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_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 225cf91fd4e6..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 */ @@ -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) { @@ -667,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; @@ -691,30 +796,15 @@ 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 */ } 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); @@ -734,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; } @@ -782,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/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 diff --git a/src/var.c b/src/var.c index 612735016c95..79c8307248f1 100644 --- a/src/var.c +++ b/src/var.c @@ -455,9 +455,11 @@ 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)); + char errbuf[STRERROR_LEN]; + errorf("Failed to open %s: %s", line, + curlx_strerror(errno, errbuf, sizeof(errbuf))); err = PARAM_READ_ERROR; } } @@ -469,7 +471,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/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/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/data/Makefile.am b/tests/data/Makefile.am index daed381e4781..99c287507f76 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -109,10 +109,10 @@ 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 test766 test767 test768 test769 test770 test771 \ \ 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 \ @@ -209,12 +209,12 @@ 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 \ test1606 test1607 test1608 test1609 test1610 test1611 test1612 test1613 \ -test1614 test1615 test1616 \ +test1614 test1615 test1616 test1617 \ test1620 test1621 \ \ test1630 test1631 test1632 test1633 test1634 test1635 \ @@ -228,11 +228,11 @@ test1670 test1671 \ test1680 test1681 test1682 test1683 \ \ test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \ -test1708 test1709 test1710 \ +test1708 test1709 test1710 test1711 \ \ 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 \ \ @@ -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/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/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 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/test1185 b/tests/data/test1185 index 8b14f4c5ffcb..7323c59a0dce 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(); @@ -74,6 +74,9 @@ 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 ? /* comment doesn't end @@ -124,7 +127,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) { @@ -192,7 +195,13 @@ 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: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) @@ -201,7 +210,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 41 warnings 5 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 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/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" 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/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/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 + + + + 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/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/test1705 b/tests/data/test1705 index b56982ae40f5..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` @@ -224,14 +224,14 @@ 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: .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. @@ -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. 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. 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... ]% +. + + + 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/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 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 + + + + 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/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/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 + 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/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/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 + + + 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/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 + + + 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/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 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/http/requirements.txt b/tests/http/requirements.txt index c87960560864..3b81a2ca13b0 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==46.0.2 +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/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/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()}' diff --git a/tests/http/test_02_download.py b/tests/http/test_02_download.py index 4ec781148c94..26da1d2feee9 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(): @@ -609,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 @@ -654,6 +657,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 +697,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 038721fbf9b4..7d2677447671 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,35 @@ 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') + @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) + 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/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_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..619ecd25e6f1 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") @@ -432,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: 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/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 diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py index 7c3f6e72d97c..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): @@ -126,6 +162,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 @@ -500,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 @@ -511,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 @@ -806,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) @@ -823,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 @@ -857,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, @@ -895,6 +953,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') @@ -998,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: @@ -1037,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: 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'): 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): 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/Makefile.inc b/tests/libtest/Makefile.inc index 40ec0d1559d5..67ffabad0b3d 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -34,13 +34,16 @@ UTILS_C = memptr.c testutil.c testtrace.c UTILS_H = testutil.h testtrace.h unitcheck.h CURLX_C = \ - ../../lib/curlx/warnless.c \ + ../../lib/curl_threads.c \ + ../../lib/curlx/fopen.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 = \ @@ -73,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 \ @@ -87,10 +91,11 @@ 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 \ - 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/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..5ab4db024c58 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; } @@ -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)) @@ -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..a0a6b95db847 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; } @@ -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)) @@ -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/cli_ws_data.c b/tests/libtest/cli_ws_data.c index 36d5dea25b1c..26cecc19fea3 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; @@ -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/first.h b/tests/libtest/first.h index 1592922e39a8..52a6395ad19b 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__) && \ @@ -429,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/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; } 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/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/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/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/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; +} diff --git a/tests/server/memptr.c b/tests/libtest/lib1902.c similarity index 61% rename from tests/server/memptr.c rename to tests/libtest/lib1902.c index 247bbf13ab81..8e5929e33827 100644 --- a/tests/server/memptr.c +++ b/tests/libtest/lib1902.c @@ -23,25 +23,26 @@ ***************************************************************************/ #include "first.h" -#include "curl_memory.h" +#include "memdebug.h" -#ifdef UNDER_CE -#define system_strdup _strdup -#else -#define system_strdup strdup -#endif +static CURLcode test_lib1902(const char *URL) +{ + CURLcode res = CURLE_OK; + CURL *curl; -#if defined(_MSC_VER) && defined(_DLL) -# pragma warning(push) -# pragma warning(disable:4232) /* MSVC extension, dllimport identity */ -#endif + curl_global_init(CURL_GLOBAL_ALL); -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; + curl = curl_easy_init(); + if(curl) { + easy_setopt(curl, CURLOPT_COOKIEFILE, URL); + easy_setopt(curl, CURLOPT_COOKIEJAR, URL); -#if defined(_MSC_VER) && defined(_DLL) -# pragma warning(pop) -#endif + /* 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; +} 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/lib3026.c b/tests/libtest/lib3026.c index 2b35a258417a..75d419cb5875 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,15 +55,12 @@ 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", + 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; @@ -84,8 +71,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/libtest/lib500.c b/tests/libtest/lib500.c index 0586c1407f9c..ffb974f4f0cb 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) @@ -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..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; @@ -51,16 +52,17 @@ 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)); + 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 */ } /* 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); @@ -68,21 +70,21 @@ 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); - 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 +93,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 +104,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 +113,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 +146,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/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/libtest/lib518.c b/tests/libtest/lib518.c index 86eddec003e9..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) @@ -77,7 +79,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 +89,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; } @@ -287,7 +289,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/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/lib525.c b/tests/libtest/lib525.c index 6c7d6503667a..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; @@ -42,16 +43,17 @@ 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)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); return TEST_ERR_FOPEN; } /* 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); @@ -59,15 +61,15 @@ 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); - 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 +151,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..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) @@ -74,7 +76,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 +86,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; } @@ -289,7 +291,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 9868474d01b3..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; @@ -42,16 +43,17 @@ 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)); + 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 */ } /* 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); @@ -59,21 +61,21 @@ 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); - 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 +84,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 +112,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/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/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/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/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); 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..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; @@ -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..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; @@ -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..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; @@ -243,16 +244,17 @@ 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)); + errno, curlx_strerror(errno, errbuf, sizeof(errbuf))); curl_mfprintf(stderr, "Error opening file '%s'\n", libtest_arg2); return TEST_ERR_FOPEN; } /* 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); @@ -260,9 +262,9 @@ 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); - 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 +272,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 +358,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..c0d5b1a43686 100644 --- a/tests/libtest/lib591.c +++ b/tests/libtest/lib591.c @@ -39,17 +39,18 @@ static CURLcode test_lib591(const char *URL) start_test_timing(); - upload = fopen(libtest_arg3, "rb"); + 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; } res_global_init(CURL_GLOBAL_ALL); if(res) { - fclose(upload); + curlx_fclose(upload); return res; } @@ -71,8 +72,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); @@ -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/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; +} 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 = <, 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; 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/requirements.txt b/tests/requirements.txt index 706043ac395f..501c1fc69359 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.11.0,<=0.12.0 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 4945e94cdabb..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; @@ -639,9 +640,6 @@ sub checksystemfeatures { } } } - if($libcurl =~ /wolfssh/i) { - $feature{"wolfssh"} = 1; - } } elsif($_ =~ /^Protocols: (.*)/i) { $proto = $1; diff --git a/tests/server/.checksrc b/tests/server/.checksrc index 8b1bcabe7789..a4e094e1c913 100644 --- a/tests/server/.checksrc +++ b/tests/server/.checksrc @@ -1 +1,18 @@ -allowfunc strtoul +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +allowfunc accept +allowfunc fclose +allowfunc fopen +allowfunc fprintf +allowfunc freeaddrinfo +allowfunc getaddrinfo +allowfunc open +allowfunc printf +allowfunc recv +allowfunc send +allowfunc snprintf +allowfunc socket +allowfunc sscanf +allowfunc vsnprintf diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index 2e3791c77490..c335e885b255 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -30,15 +30,17 @@ 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 = \ ../../lib/curlx/base64.c \ - ../../lib/curlx/inet_pton.c \ + ../../lib/curlx/fopen.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 dc49723da313..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"; @@ -441,9 +444,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++; } } @@ -482,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; } @@ -492,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; } @@ -517,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; } @@ -540,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 44dd272ce2b3..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); @@ -148,7 +147,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..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"; @@ -782,15 +787,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++; } } @@ -827,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 67829922dc92..5e8bdc15cea3 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; @@ -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 */ @@ -358,7 +360,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; } @@ -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)); @@ -1045,9 +1055,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++; } } @@ -1094,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; } @@ -1103,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; } @@ -1127,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; } @@ -1149,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; } @@ -1182,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; } @@ -1209,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 c8b21beee90c..48728bfd01a4 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; } @@ -371,12 +373,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'; - *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); @@ -404,16 +414,15 @@ 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 */ 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]; @@ -452,13 +461,13 @@ static unsigned int 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 */ @@ -557,25 +566,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; } @@ -940,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]; @@ -1060,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; } @@ -1165,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"); @@ -1219,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; @@ -1279,9 +1291,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++; } } @@ -1290,15 +1300,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++; } } @@ -1342,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; } @@ -1379,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 4d599e16b61a..1f2460ec2908 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; } @@ -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; @@ -831,9 +834,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++; } } @@ -850,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; } @@ -872,7 +872,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; } @@ -924,7 +924,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 2b94e529383f..caa5605534e4 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 */ @@ -330,7 +332,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", @@ -389,7 +391,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; @@ -413,7 +415,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,14 +426,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; - part = strtoul(p, &endp, 16); - if(ISXDIGIT(*p)) + const char *endp = p; + if(!curlx_str_hex(&endp, &part, 0xffff)) p = endp; else p++; @@ -443,17 +444,17 @@ static int sws_ProcessRequest(struct sws_httprequest *req) else portp = p + 1; - req->testno = part; + req->testno = (long)part; } else 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; @@ -707,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; @@ -725,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; } @@ -745,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); } @@ -755,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) @@ -884,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) { @@ -948,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]; @@ -1028,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 { @@ -1050,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; } @@ -1089,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); @@ -1141,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); @@ -1182,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; } } @@ -1213,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 = ""; @@ -1235,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; } @@ -1255,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; } @@ -1337,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; } @@ -1349,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; } @@ -1813,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) { @@ -1835,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; } @@ -1851,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; } @@ -1888,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, @@ -1898,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; @@ -1918,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; @@ -1938,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; } @@ -1978,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]; @@ -2071,15 +2082,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 +2102,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++; } } @@ -2157,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; } @@ -2166,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; } @@ -2202,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; } @@ -2228,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; } @@ -2266,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; } @@ -2346,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; } @@ -2381,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; @@ -2451,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 193afac1377e..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; @@ -607,9 +608,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++; } } @@ -656,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; } @@ -666,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; } @@ -691,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; } @@ -714,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; } @@ -900,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; } @@ -1007,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 */ } @@ -1100,7 +1104,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; @@ -1109,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; @@ -1122,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; } @@ -1358,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 26a5dd17f708..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); } @@ -133,7 +134,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; } @@ -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 */ @@ -229,12 +221,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 @@ -249,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); @@ -263,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); @@ -276,6 +269,7 @@ void set_advisor_read_lock(const char *filename) { FILE *lockfile; int error = 0; + char errbuf[STRERROR_LEN]; int res; do { @@ -283,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) @@ -309,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 */ @@ -350,7 +346,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 @@ -381,7 +377,7 @@ static void exit_signal_handler(int signum) #else #define OPENMODE S_IRUSR | S_IWUSR #endif - int fd = open(serverlogfile, O_WRONLY|O_CREAT|O_APPEND, OPENMODE); + 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); @@ -422,7 +418,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) { @@ -487,8 +483,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 +504,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; @@ -570,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); @@ -580,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; @@ -602,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 @@ -623,15 +626,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 } @@ -696,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); @@ -712,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 */ @@ -721,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. */ @@ -733,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 @@ -746,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 */ @@ -757,27 +756,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, @@ -792,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; @@ -805,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; } @@ -829,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..."); } @@ -866,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; } @@ -895,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; } @@ -932,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; } 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> }), ""); 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/unit1302.c b/tests/unit/unit1302.c index 54693631ff54..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(memcmp(out, e->output, e->olen)) { - fprintf(stderr, "Test %u URL encoded badly. Got '%s', expected '%s'\n", - i, out, e->output); + if(out && memcmp(out, e->output, e->olen)) { + 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/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, 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..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) { - 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 %" 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, + result, + 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/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, 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/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}, 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"); 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..6903c70e9298 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, [%" CURL_FORMAT_CURL_OFF_T "] line %d\n", + i, orgline, rc, 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,14 +382,14 @@ 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]; 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)); } } @@ -409,14 +409,14 @@ 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]; 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)); } } @@ -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/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; diff --git a/tests/unit/unit3214.c b/tests/unit/unit3214.c index 34549fc2966c..d992a35dc0db 100644 --- a/tests/unit/unit3214.c +++ b/tests/unit/unit3214.c @@ -28,21 +28,22 @@ 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); } } /* 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 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 -)