Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot]
52e8c0af99
ci: Update actions/upload-artifact digest to 4cec3d8 2025-02-21 19:55:07 +00:00
197 changed files with 3298 additions and 4868 deletions

View File

@ -3,117 +3,55 @@
#
# SPDX-License-Identifier: curl
#
# Input: cmdline docs markdown files, they get modified *in place*
#
# Strip off the leading meta-data/header part, remove all known curl symbols
# and long command line options. Also clean up whatever else the spell checker
# might have a problem with that we still deem is fine.
# Input: a cmdline docs markdown, it gets modified *in place*
#
# The main purpose is to strip off the leading meta-data part, but also to
# clean up whatever else the spell checker might have a problem with that we
# still deem is fine.
open(S, "<./docs/libcurl/symbols-in-versions")
|| die "can't find symbols-in-versions";
while(<S>) {
if(/^([^ ]*) /) {
push @asyms, $1;
my $header = 1;
while(1) {
# set this if the markdown has no meta-data header to skip
if($ARGV[0] eq "--no-header") {
shift @ARGV;
$header = 0;
}
else {
last;
}
}
close(S);
# init the opts table with "special" options not easy to figure out
my @aopts = (
'--ftp-ssl-reqd', # old alias
);
my $f = $ARGV[0];
open(O, "<./docs/options-in-versions")
|| die "can't find options-in-versions";
while(<O>) {
chomp;
if(/^([^ ]+)/) {
my $o = $1;
push @aopts, $o;
if($o =~ /^--no-(.*)/) {
# for the --no options, also make one without it
push @aopts, "--$1";
open(F, "<$f") or die;
my $ignore = $header;
my $sepcount = 0;
my @out;
while(<F>) {
if(/^---/ && $header) {
if(++$sepcount == 2) {
$ignore = 0;
}
elsif($o =~ /^--disable-(.*)/) {
# for the --disable options, also make the special ones
push @aopts, "--$1";
push @aopts, "--no-$1";
}
}
}
close(O);
open(C, "<./.github/scripts/spellcheck.curl")
|| die "can't find spellcheck.curl";
while(<C>) {
if(/^\#/) {
next;
}
chomp;
if(/^([^ ]+)/) {
push @asyms, $1;
}
next if($ignore);
# strip out backticked words
$_ =~ s/`[^`]+`//g;
# strip out all long command line options
$_ =~ s/--[a-z0-9-]+//g;
# strip out https URLs, we don't want them spellchecked
$_ =~ s!https://[a-z0-9\#_/.-]+!!gi;
push @out, $_;
}
close(C);
close(F);
# longest symbols first
my @syms = sort { length($b) <=> length($a) } @asyms;
# longest cmdline options first
my @opts = sort { length($b) <=> length($a) } @aopts;
sub process {
my ($f) = @_;
my $ignore = 0;
my $sepcount = 0;
my $out;
my $line = 0;
open(F, "<$f") or die;
while(<F>) {
$line++;
if(/^---/ && ($line == 1)) {
$ignore = 1;
next;
}
elsif(/^---/ && $ignore) {
$ignore = 0;
next;
}
next if($ignore);
my $l = $_;
# strip out backticked words
$l =~ s/`[^`]+`//g;
# **bold**
$l =~ s/\*\*(\S.*?)\*\*//g;
# *italics*
$l =~ s/\*(\S.*?)\*//g;
# strip out https URLs, we don't want them spellchecked
$l =~ s!https://[a-z0-9\#_/.-]+!!gi;
$out .= $l;
}
close(F);
# cut out all known curl cmdline options
map { $out =~ s/$_//g; } (@opts);
# cut out all known curl symbols
map { $out =~ s/\b$_\b//g; } (@syms);
if(!$ignore) {
open(O, ">$f") or die;
print O $out;
close(O);
}
}
for my $f (@ARGV) {
process($f);
if(!$ignore) {
open(O, ">$f") or die;
print O @out;
close(O);
}

86
.github/scripts/cleanspell.pl vendored Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env perl
# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
#
# SPDX-License-Identifier: curl
#
# Given: a libcurl curldown man page
# Outputs: the same file, minus the SYNOPSIS and the EXAMPLE sections
#
my $f = $ARGV[0];
open(F, "<$f") or die;
my @out;
my $ignore = 0;
while(<F>) {
if($_ =~ /^# (SYNOPSIS|EXAMPLE)/) {
$ignore = 1;
}
elsif($ignore && ($_ =~ /^# [A-Z]/)) {
$ignore = 0;
}
elsif(!$ignore) {
# **bold**
$_ =~ s/\*\*(\S.*?)\*\*//g;
# *italics*
$_ =~ s/\*(\S.*?)\*//g;
$_ =~ s/CURL(M|SH|U|H)code//g;
$_ =~ s/CURL_[A-Z0-9_]*//g;
$_ =~ s/CURLALTSVC_[A-Z0-9_]*//g;
$_ =~ s/CURLAUTH_[A-Z0-9_]*//g;
$_ =~ s/CURLE_[A-Z0-9_]*//g;
$_ =~ s/CURLFORM_[A-Z0-9_]*//g;
$_ =~ s/CURLFTP_[A-Z0-9_]*//g;
$_ =~ s/CURLFTPAUTH_[A-Z0-9_]*//g;
$_ =~ s/CURLFTPMETHOD_[A-Z0-9_]*//g;
$_ =~ s/CURLFTPSSL_[A-Z0-9_]*//g;
$_ =~ s/CURLGSSAPI_[A-Z0-9_]*//g;
$_ =~ s/CURLHEADER_[A-Z0-9_]*//g;
$_ =~ s/CURLINFO_[A-Z0-9_]*//g;
$_ =~ s/CURLM_[A-Z0-9_]*//g;
$_ =~ s/CURLMIMEOPT_[A-Z0-9_]*//g;
$_ =~ s/CURLMOPT_[A-Z0-9_]*//g;
$_ =~ s/CURLOPT_[A-Z0-9_]*//g;
$_ =~ s/CURLPIPE_[A-Z0-9_]*//g;
$_ =~ s/CURLPROTO_[A-Z0-9_]*//g;
$_ =~ s/CURLPROXY_[A-Z0-9_]*//g;
$_ =~ s/CURLPX_[A-Z0-9_]*//g;
$_ =~ s/CURLSHE_[A-Z0-9_]*//g;
$_ =~ s/CURLSHOPT_[A-Z0-9_]*//g;
$_ =~ s/CURLSSLOPT_[A-Z0-9_]*//g;
$_ =~ s/CURLSSH_[A-Z0-9_]*//g;
$_ =~ s/CURLSSLBACKEND_[A-Z0-9_]*//g;
$_ =~ s/CURLU_[A-Z0-9_]*//g;
$_ =~ s/CURLUPART_[A-Z0-9_]*//g;
#$_ =~ s/\bCURLU\b//g; # stand-alone CURLU
$_ =~ s/CURLUE_[A-Z0-9_]*//g;
$_ =~ s/CURLHE_[A-Z0-9_]*//g;
$_ =~ s/CURLWS_[A-Z0-9_]*//g;
$_ =~ s/CURLKH[A-Z0-9_]*//g;
$_ =~ s/CURLUPART_[A-Z0-9_]*//g;
$_ =~ s/CURLUSESSL_[A-Z0-9_]*//g;
$_ =~ s/CURLPAUSE_[A-Z0-9_]*//g;
$_ =~ s/CURLHSTS_[A-Z0-9_]*//g;
$_ =~ s/curl_global_([a-z_]*)//g;
$_ =~ s/curl_(strequal|strnequal|formadd|waitfd|formget|getdate|formfree)//g;
$_ =~ s/curl_easy_([a-z]*)//g;
$_ =~ s/curl_multi_([a-z_]*)//g;
$_ =~ s/curl_mime_(subparts|addpart|filedata|data_cb)//g;
$_ =~ s/curl_ws_(send|recv|meta)//g;
$_ =~ s/curl_url_(dup)//g;
$_ =~ s/curl_pushheader_by(name|num)//g;
$_ =~ s/libcurl-(env|ws)//g;
$_ =~ s/libcurl\\-(env|ws)//g;
$_ =~ s/(^|\W)((tftp|https|http|ftp):\/\/[a-z0-9\-._~%:\/?\#\[\]\@!\$&'()*+,;=\\]+)//gi;
push @out, $_;
}
}
close(F);
open(O, ">$f") or die;
for my $l (@out) {
print O $l;
}
close(O);

View File

@ -1,151 +0,0 @@
# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
#
# SPDX-License-Identifier: curl
#
# common variable types + structs
# callback typedefs
# public functions names
# some man page names
curl_fileinfo
curl_forms
curl_hstsentry
curl_httppost
curl_index
curl_khkey
curl_pushheaders
curl_waitfd
CURLcode
CURLformoption
CURLHcode
CURLMcode
CURLMsg
CURLSHcode
CURLUcode
curl_calloc_callback
curl_chunk_bgn_callback
curl_chunk_end_callback
curl_conv_callback
curl_debug_callback
curl_fnmatch_callback
curl_formget_callback
curl_free_callback
curl_hstsread_callback
curl_hstswrite_callback
curl_ioctl_callback
curl_malloc_callback
curl_multi_timer_callback
curl_opensocket_callback
curl_prereq_callback
curl_progress_callback
curl_push_callback
curl_read_callback
curl_realloc_callback
curl_resolver_start_callback
curl_seek_callback
curl_socket_callback
curl_sockopt_callback
curl_ssl_ctx_callback
curl_strdup_callback
curl_trailer_callback
curl_write_callback
curl_xferinfo_callback
curl_strequal
curl_strnequal
curl_mime_init
curl_mime_free
curl_mime_addpart
curl_mime_name
curl_mime_filename
curl_mime_type
curl_mime_encoder
curl_mime_data
curl_mime_filedata
curl_mime_data_cb
curl_mime_subparts
curl_mime_headers
curl_formadd
curl_formget
curl_formfree
curl_getdate
curl_getenv
curl_version
curl_easy_escape
curl_escape
curl_easy_unescape
curl_unescape
curl_free
curl_global_init
curl_global_init_mem
curl_global_cleanup
curl_global_trace
curl_global_sslset
curl_slist_append
curl_slist_free_all
curl_getdate
curl_share_init
curl_share_setopt
curl_share_cleanup
curl_version_info
curl_easy_strerror
curl_share_strerror
curl_easy_pause
curl_easy_ssls_import
curl_easy_ssls_export
curl_easy_init
curl_easy_setopt
curl_easy_perform
curl_easy_cleanup
curl_easy_getinfo
curl_easy_duphandle
curl_easy_reset
curl_easy_recv
curl_easy_send
curl_easy_upkeep
curl_easy_header
curl_easy_nextheader
curl_mprintf
curl_mfprintf
curl_msprintf
curl_msnprintf
curl_mvprintf
curl_mvfprintf
curl_mvsprintf
curl_mvsnprintf
curl_maprintf
curl_mvaprintf
curl_multi_init
curl_multi_add_handle
curl_multi_remove_handle
curl_multi_fdset
curl_multi_waitfds
curl_multi_wait
curl_multi_poll
curl_multi_wakeup
curl_multi_perform
curl_multi_cleanup
curl_multi_info_read
curl_multi_strerror
curl_multi_socket
curl_multi_socket_action
curl_multi_socket_all
curl_multi_timeout
curl_multi_setopt
curl_multi_assign
curl_multi_get_handles
curl_pushheader_bynum
curl_pushheader_byname
curl_multi_waitfds
curl_easy_option_by_name
curl_easy_option_by_id
curl_easy_option_next
curl_url
curl_url_cleanup
curl_url_dup
curl_url_get
curl_url_set
curl_url_strerror
curl_ws_recv
curl_ws_send
curl_ws_meta
libcurl-env
libcurl-ws

View File

@ -251,7 +251,6 @@ Feltzing
ffi
filesize
filesystem
FindCURL
FLOSS
fnmatch
footguns
@ -951,6 +950,7 @@ winbuild
WinIDN
WinLDAP
winsock
winssl
Wireshark
wolfSSH
wolfSSL

View File

@ -107,8 +107,20 @@ jobs:
persist-credentials: false
name: checkout
- name: trim all *.md files in docs/
run: .github/scripts/cleancmd.pl $(find docs -name "*.md")
- name: trim all man page *.md files
run: find docs -name "*.md" ! -name "_*" -print0 | xargs -0 -n1 .github/scripts/cleancmd.pl
- name: trim libcurl man page *.md files
run: find docs/libcurl \( -name "curl_*.md" -o -name "libcurl*.md" \) -print0 | xargs -0 -n1 .github/scripts/cleanspell.pl
- name: trim libcurl option man page *.md files
run: find docs/libcurl/opts -name "CURL*.md" -print0 | xargs -0 -n1 .github/scripts/cleanspell.pl
- name: trim cmdline docs markdown _*.md files
run: find docs/cmdline-opts -name "_*.md" -print0 | xargs -0 -n1 .github/scripts/cleancmd.pl --no-header
- name: trim docs/ markdown _*.md files
run: git ls-files docs/*.md docs/internals/*.md | xargs -n1 .github/scripts/cleancmd.pl --no-header
- name: setup the custom wordlist
run: grep -v '^#' .github/scripts/spellcheck.words > wordlist.txt

View File

@ -19,9 +19,6 @@ concurrency:
permissions: {}
env:
MAKEFLAGS: -j 5
jobs:
maketgz-and-verify-in-tree:
runs-on: ubuntu-latest
@ -46,7 +43,7 @@ jobs:
- name: 'maketgz'
run: SOURCE_DATE_EPOCH=1711526400 ./scripts/maketgz 99.98.97
- uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4
- uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
with:
name: 'release-tgz'
path: 'curl-99.98.97.tar.gz'
@ -58,9 +55,9 @@ jobs:
tar xvf curl-99.98.97.tar.gz
pushd curl-99.98.97
./configure --prefix=$HOME/temp --without-ssl --without-libpsl
make
make test-ci
make install
make -j5
make -j5 test-ci
make -j5 install
popd
# basic check of the installed files
bash scripts/installcheck.sh $HOME/temp
@ -83,8 +80,8 @@ jobs:
mkdir build
pushd build
../curl-99.98.97/configure --without-ssl --without-libpsl
make
make test-ci
make -j5
make -j5 test-ci
popd
rm -rf build
rm -rf curl-99.98.97
@ -106,9 +103,9 @@ jobs:
mkdir build
pushd build
../configure --without-ssl --enable-debug "--prefix=${PWD}/pkg" --without-libpsl
make
make test-ci
make install
make -j5
make -j5 test-ci
make -j5 install
verify-out-of-tree-cmake:
runs-on: ubuntu-latest
@ -125,7 +122,7 @@ jobs:
tar xvf curl-99.98.97.tar.gz
pushd curl-99.98.97
cmake -B build -DCURL_WERROR=ON -DCURL_USE_LIBPSL=OFF
make -C build
make -C build -j5
missing-files:
runs-on: ubuntu-latest

View File

@ -232,7 +232,6 @@ jobs:
--with-ngtcp2=$HOME/ngtcp2/build --enable-warnings --enable-werror --enable-debug --disable-ntlm
--with-test-nghttpx="$HOME/nghttp2/build/bin/nghttpx"
--with-openssl=$HOME/quictls/build --enable-ssls-export
--with-libuv
- name: gnutls
PKG_CONFIG_PATH: '$HOME/gnutls/build/lib/pkgconfig:$HOME/nghttp3/build/lib/pkgconfig:$HOME/ngtcp2/build/lib/pkgconfig:$HOME/nghttp2/build/lib/pkgconfig'
@ -241,7 +240,6 @@ jobs:
--with-ngtcp2=$HOME/ngtcp2/build --enable-warnings --enable-werror --enable-debug
--with-test-nghttpx="$HOME/nghttp2/build/bin/nghttpx"
--with-gnutls=$HOME/gnutls/build --enable-ssls-export
--with-libuv
- name: wolfssl
PKG_CONFIG_PATH: '$HOME/wolfssl/build/lib/pkgconfig:$HOME/nghttp3/build/lib/pkgconfig:$HOME/ngtcp2/build/lib/pkgconfig:$HOME/nghttp2/build/lib/pkgconfig'
@ -251,7 +249,6 @@ jobs:
--with-test-nghttpx="$HOME/nghttp2/build/bin/nghttpx"
--with-wolfssl=$HOME/wolfssl/build
--enable-ech --enable-ssls-export
--with-libuv
- name: wolfssl
PKG_CONFIG_PATH: '$HOME/wolfssl/build/lib/pkgconfig:$HOME/nghttp3/build/lib/pkgconfig:$HOME/ngtcp2/build/lib/pkgconfig:$HOME/nghttp2/build/lib/pkgconfig'
@ -260,7 +257,6 @@ jobs:
-DTEST_NGHTTPX="$HOME/nghttp2/build/bin/nghttpx"
-DHTTPD_NGHTTPX="$HOME/nghttp2/build/bin/nghttpx"
-DUSE_ECH=ON
-DCURL_USE_LIBUV=ON
- name: openssl-quic
PKG_CONFIG_PATH: '$HOME/openssl/build/lib64/pkgconfig'
@ -270,7 +266,6 @@ jobs:
--with-test-nghttpx="$HOME/nghttp2/build/bin/nghttpx"
--with-openssl=$HOME/openssl/build --with-openssl-quic
--with-nghttp3=$HOME/nghttp3/build
--with-libuv
- name: quiche
configure: >-
@ -280,7 +275,6 @@ jobs:
--with-quiche=$HOME/quiche/target/release
--with-test-nghttpx="$HOME/nghttp2/build/bin/nghttpx"
--with-ca-fallback
--with-libuv
- name: quiche
PKG_CONFIG_PATH: '$HOME/quiche/target/release'
@ -290,7 +284,6 @@ jobs:
-DTEST_NGHTTPX="$HOME/nghttp2/build/bin/nghttpx"
-DHTTPD_NGHTTPX="$HOME/nghttp2/build/bin/nghttpx"
-DCURL_CA_FALLBACK=ON
-DCURL_USE_LIBUV=ON
steps:
- name: 'install prereqs'
@ -302,7 +295,7 @@ jobs:
libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev libev-dev libc-ares-dev \
nettle-dev libp11-kit-dev libtspi-dev libunistring-dev guile-2.2-dev libtasn1-bin \
libtasn1-6-dev libidn2-0-dev gawk gperf libtss2-dev dns-root-data bison gtk-doc-tools \
texinfo texlive texlive-extra-utils autopoint libev-dev libuv1-dev \
texinfo texlive texlive-extra-utils autopoint libev-dev \
apache2 apache2-dev libnghttp2-dev vsftpd
python3 -m venv $HOME/venv
echo 'CC=gcc-12' >> $GITHUB_ENV
@ -434,45 +427,46 @@ jobs:
export PKG_CONFIG_PATH="${{ matrix.build.PKG_CONFIG_PATH }}"
fi
if [ -n '${{ matrix.build.generate }}' ]; then
cmake -B bld -G Ninja \
cmake -B . -G Ninja \
-DCMAKE_C_COMPILER_TARGET=$(uname -m)-pc-linux-gnu -DBUILD_STATIC_LIBS=ON \
-DCMAKE_UNITY_BUILD=ON -DCURL_TEST_BUNDLES=ON -DCURL_WERROR=ON \
${{ matrix.build.generate }}
else
mkdir bld && cd bld && ../configure --enable-unity --enable-test-bundles --enable-warnings --enable-werror \
--disable-dependency-tracking \
./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-warnings --enable-werror \
${{ matrix.build.configure }}
fi
- name: 'configure log'
if: ${{ !cancelled() }}
run: cat bld/config.log bld/CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true
run: cat config.log CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true
- name: 'curl_config.h'
run: |
echo '::group::raw'; cat bld/lib/curl_config.h || true; echo '::endgroup::'
grep -F '#define' bld/lib/curl_config.h | sort || true
echo '::group::raw'; cat lib/curl_config.h || true; echo '::endgroup::'
grep -F '#define' lib/curl_config.h | sort || true
- name: 'test configs'
run: grep -H -v '^#' bld/tests/config bld/tests/http/config.ini || true
run: |
cat tests/config || true
cat tests/http/config.ini || true
- name: 'build'
run: |
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld --verbose
cmake --build . --verbose
else
make -C bld V=1
make V=1
fi
- name: 'check curl -V output'
run: bld/src/curl -V
run: ./src/curl -V
- name: 'build tests'
run: |
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld --verbose --target testdeps
cmake --build . --verbose --target testdeps
else
make -C bld V=1 -C tests
make V=1 -C tests
fi
- name: 'install test prereqs'
@ -486,9 +480,9 @@ jobs:
run: |
source $HOME/venv/bin/activate
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld --verbose --target test-ci
cmake --build . --verbose --target test-ci
else
make -C bld V=1 test-ci
make V=1 test-ci
fi
- name: 'install pytest prereqs'
@ -496,23 +490,23 @@ jobs:
source $HOME/venv/bin/activate
python3 -m pip install -r tests/http/requirements.txt
- name: 'run pytest event based'
- name: 'run pytest'
env:
CURL_TEST_EVENT: 1
TFLAGS: '${{ matrix.build.tflags }}'
CURL_CI: github
PYTEST_ADDOPTS: '--color=yes'
run: |
source $HOME/venv/bin/activate
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld --verbose --target curl-pytest-ci
cmake --build . --verbose --target curl-pytest-ci
else
make -C bld V=1 pytest-ci
make V=1 pytest-ci
fi
- name: 'build examples'
run: |
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld --verbose --target curl-examples
cmake --build . --verbose --target curl-examples
else
make -C bld V=1 examples
make V=1 examples
fi

View File

@ -304,8 +304,7 @@ jobs:
libtool autoconf automake pkgconf ninja-build \
${{ matrix.build.install_steps != 'skipall' && matrix.build.install_steps != 'skiprun' && 'stunnel4' || '' }} \
libpsl-dev libbrotli-dev libzstd-dev \
${{ matrix.build.install_packages }} \
${{ contains(matrix.build.install_steps, 'pytest') && 'apache2 apache2-dev libnghttp2-dev vsftpd' || '' }}
${{ matrix.build.install_packages }}
python3 -m venv $HOME/venv
- name: 'install prereqs'
@ -320,6 +319,11 @@ jobs:
${{ matrix.build.install_packages }}
python3 -m venv $HOME/venv
- name: 'install prereqs for pytest'
if: contains(matrix.build.install_steps, 'pytest')
run: |
sudo apt-get -o Dpkg::Use-Pty=0 install apache2 apache2-dev libnghttp2-dev vsftpd
- name: 'install dependencies'
if: startsWith(matrix.build.container, 'alpine')
run: |
@ -556,7 +560,7 @@ jobs:
cd $HOME
curl -sSf --compressed https://sh.rustup.rs/ | sh -s -- -y
source $HOME/.cargo/env
rustup toolchain install stable --profile minimal
rustup toolchain install nightly
- name: 'build rustls'
if: contains(matrix.build.install_steps, 'rustls') && steps.cache-rustls.outputs.cache-hit != 'true'
@ -589,37 +593,37 @@ jobs:
export PKG_CONFIG_PATH="${{ matrix.build.PKG_CONFIG_PATH }}"
fi
if [ -n '${{ matrix.build.generate }}' ]; then
cmake -B bld -G Ninja \
cmake -B . -G Ninja \
-DCMAKE_INSTALL_PREFIX="$HOME/curl" \
-DCMAKE_C_COMPILER_TARGET=$(uname -m)-pc-linux-gnu -DBUILD_STATIC_LIBS=ON \
-DCMAKE_UNITY_BUILD=ON -DCURL_TEST_BUNDLES=ON -DCURL_WERROR=ON \
${{ matrix.build.generate }}
else
mkdir bld && cd bld && \
${{ matrix.build.configure-prefix }} \
../configure --enable-unity --enable-test-bundles --enable-warnings --enable-werror \
--disable-dependency-tracking \
./configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-warnings --enable-werror \
${{ matrix.build.configure }}
fi
- name: 'configure log'
if: ${{ !cancelled() }}
run: cat bld/config.log bld/CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true
run: cat config.log CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true
- name: 'curl_config.h'
run: |
echo '::group::raw'; cat bld/lib/curl_config.h || true; echo '::endgroup::'
grep -F '#define' bld/lib/curl_config.h | sort || true
echo '::group::raw'; cat lib/curl_config.h || true; echo '::endgroup::'
grep -F '#define' lib/curl_config.h | sort || true
- name: 'test configs'
run: grep -H -v '^#' bld/tests/config bld/tests/http/config.ini || true
run: |
cat tests/config || true
cat tests/http/config.ini || true
- name: 'build'
run: |
if [ -n '${{ matrix.build.generate }}' ]; then
${{ matrix.build.make-prefix }} cmake --build bld --verbose
${{ matrix.build.make-prefix }} cmake --build . --verbose
else
${{ matrix.build.make-prefix }} make -C bld V=1 ${{ matrix.build.make-custom-target }}
${{ matrix.build.make-prefix }} make V=1 ${{ matrix.build.make-custom-target }}
fi
- name: 'single-use function check'
@ -627,27 +631,27 @@ jobs:
run: |
git config --global --add safe.directory "*"
if [ -n '${{ matrix.build.generate }}' ]; then
libcurla=bld/lib/libcurl.a
libcurla=lib/libcurl.a
else
libcurla=bld/lib/.libs/libcurl.a
libcurla=lib/.libs/libcurl.a
fi
./scripts/singleuse.pl --unit ${libcurla}
- name: 'check curl -V output'
if: ${{ matrix.build.make-custom-target != 'tidy' }}
run: bld/src/curl -V
run: ./src/curl -V
- name: 'cmake install'
if: ${{ matrix.build.generate }}
run: cmake --install bld --strip
run: cmake --install . --strip
- name: 'build tests'
if: ${{ matrix.build.install_steps != 'skipall' }}
run: |
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld --verbose --target testdeps
cmake --build . --verbose --target testdeps
else
make -C bld V=1 -C tests
make V=1 -C tests
fi
- name: 'install test prereqs'
@ -674,9 +678,9 @@ jobs:
fi
[ -x "$HOME/venv/bin/activate" ] && source $HOME/venv/bin/activate
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld --verbose --target ${{ matrix.build.torture && 'test-torture' || 'test-ci' }}
cmake --build . --verbose --target ${{ matrix.build.torture && 'test-torture' || 'test-ci' }}
else
make -C bld V=1 ${{ matrix.build.torture && 'test-torture' || 'test-ci' }}
make V=1 ${{ matrix.build.torture && 'test-torture' || 'test-ci' }}
fi
- name: 'install pytest prereqs'
@ -688,21 +692,22 @@ jobs:
- name: 'run pytest'
if: contains(matrix.build.install_steps, 'pytest')
env:
TFLAGS: '${{ matrix.build.tflags }}'
CURL_CI: github
PYTEST_ADDOPTS: '--color=yes'
run: |
[ -x "$HOME/venv/bin/activate" ] && source $HOME/venv/bin/activate
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld --verbose --target curl-pytest-ci
cmake --build . --verbose --target curl-pytest-ci
else
make -C bld V=1 pytest-ci
make V=1 pytest-ci
fi
- name: 'build examples'
if: ${{ matrix.build.make-custom-target != 'tidy' }}
run: |
if [ -n '${{ matrix.build.generate }}' ]; then
${{ matrix.build.make-prefix }} cmake --build bld --verbose --target curl-examples
${{ matrix.build.make-prefix }} cmake --build . --verbose --target curl-examples
else
${{ matrix.build.make-prefix }} make -C bld V=1 examples
${{ matrix.build.make-prefix }} make V=1 examples
fi

View File

@ -47,8 +47,8 @@ permissions: {}
# newer than the 10.8 required by `CFURLCreateDataAndPropertiesFromResource`.
env:
MAKEFLAGS: -j 4
LDFLAGS: -w # suppress 'object file was built for newer macOS version than being linked' warnings
MAKEFLAGS: -j 4
jobs:
macos:
@ -123,10 +123,9 @@ jobs:
compiler: clang
configure: --enable-debug --with-openssl=$(brew --prefix openssl)
tflags: --test-event
- name: 'quictls libssh2 !ldap 10.15'
- name: 'OpenSSL libssh2 !ldap 10.15'
compiler: clang
install: quictls
configure: --enable-debug --disable-ldap --with-openssl=$(brew --prefix quictls) LDFLAGS="${LDFLAGS} -L$(brew --prefix quictls)/lib"
configure: --enable-debug --disable-ldap --with-openssl=$(brew --prefix openssl)
macos-version-min: '10.15'
# cmake
- name: 'OpenSSL gsasl rtmp AppleIDN'
@ -137,9 +136,9 @@ jobs:
generate: -DOPENSSL_ROOT_DIR=$(brew --prefix openssl) -DUSE_APPLE_IDN=ON -DCURL_CLANG_TIDY=ON -DCLANG_TIDY=$(brew --prefix llvm)/bin/clang-tidy
clang-tidy: true
chkprefill: _chkprefill
- name: 'quictls +static libssh +examples'
install: quictls libssh
generate: -DOPENSSL_ROOT_DIR=$(brew --prefix quictls) -DBUILD_STATIC_LIBS=ON -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON
- name: 'OpenSSL +static libssh +examples'
install: libssh
generate: -DOPENSSL_ROOT_DIR=$(brew --prefix openssl) -DBUILD_STATIC_LIBS=ON -DCURL_USE_LIBSSH2=OFF -DCURL_USE_LIBSSH=ON
- name: 'SecureTransport debug'
generate: -DCURL_USE_SECTRANSP=ON -DENABLE_DEBUG=ON
macos-version-min: '10.8'
@ -185,12 +184,11 @@ jobs:
run: |
echo ${{ matrix.build.generate && 'ninja' || 'automake libtool' }} \
pkgconf libpsl libssh2 \
${{ !matrix.build.clang-tidy && 'libnghttp2 stunnel' || '' }} \
${{ !matrix.build.clang-tidy && 'nghttp2 stunnel' || '' }} \
${{ matrix.build.install }} | xargs -Ix -n1 echo brew '"x"' > /tmp/Brewfile
while [[ $? == 0 ]]; do for i in 1 2 3; do brew update && brew bundle install --no-lock --file /tmp/Brewfile && break 2 || { echo Error: wait to try again; sleep 10; } done; false Too many retries; done
- name: 'brew unlink openssl'
if: ${{ contains(matrix.build.install, 'libressl') || contains(matrix.build.install, 'quictls') }}
run: |
if test -d $(brew --prefix)/include/openssl; then
brew unlink openssl
@ -315,6 +313,7 @@ jobs:
if [ -z '${{ matrix.build.torture }}' ]; then
TFLAGS+=' ~2037 ~2041' # flaky
if [[ '${{ matrix.compiler }}' = 'gcc'* ]]; then
TFLAGS+=' ~RTSP' # 567 568 569 570 571 572 577 689 3100
TFLAGS+=' ~1156 ~1539' # HTTP Content-Range, Content-Length
if [[ -n '${{ matrix.build.configure }}' || \
'${{ matrix.build.generate }}' = *'-DCURL_USE_SECTRANSP=ON'* ]]; then
@ -345,7 +344,7 @@ jobs:
if: ${{ contains(matrix.build.name, '+examples') }}
run: |
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld --verbose --target curl-examples
cmake --build bld --target curl-examples --verbose
else
make -C bld examples V=1
fi

View File

@ -59,21 +59,21 @@ jobs:
time cmake -B bld -G Ninja \
-DCMAKE_UNITY_BUILD=ON -DCURL_TEST_BUNDLES=ON \
-DCURL_WERROR=ON \
-DENABLE_DEBUG=ON -DCMAKE_BUILD_TYPE=Debug \
-DENABLE_DEBUG=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG= \
-DCURL_USE_OPENSSL=ON \
-DCURL_USE_GSSAPI=ON \
|| { cat bld/CMakeFiles/CMake*.yaml; false; }
echo '::group::curl_config.h (raw)'; cat bld/lib/curl_config.h || true; echo '::endgroup::'
echo '::group::curl_config.h'; grep -F '#define' bld/lib/curl_config.h | sort || true; echo '::endgroup::'
time cmake --build bld
time cmake --build bld --config Debug
bld/src/curl --disable --version
if [ '${{ matrix.arch }}' = 'x86_64' ]; then # Slow on emulated CPU
time cmake --build bld --target testdeps
time cmake --build bld --config Debug --target testdeps
export TFLAGS='-j4'
time cmake --build bld --target test-ci
time cmake --build bld --config Debug --target test-ci
fi
echo '::group::build examples'
time cmake --build bld --target curl-examples
time cmake --build bld --config Debug --target curl-examples
echo '::endgroup::'
openbsd:
@ -100,20 +100,20 @@ jobs:
time cmake -B bld -G Ninja \
-DCMAKE_UNITY_BUILD=ON -DCURL_TEST_BUNDLES=ON \
-DCURL_WERROR=ON \
-DENABLE_DEBUG=ON -DCMAKE_BUILD_TYPE=Debug \
-DENABLE_DEBUG=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG= \
-DCURL_USE_OPENSSL=ON \
|| { cat bld/CMakeFiles/CMake*.yaml; false; }
echo '::group::curl_config.h (raw)'; cat bld/lib/curl_config.h || true; echo '::endgroup::'
echo '::group::curl_config.h'; grep -F '#define' bld/lib/curl_config.h | sort || true; echo '::endgroup::'
time cmake --build bld
time cmake --build bld --config Debug
bld/src/curl --disable --version
if [ '${{ matrix.arch }}' = 'x86_64' ]; then # Slow on emulated CPU
time cmake --build bld --target testdeps
time cmake --build bld --config Debug --target testdeps
export TFLAGS='-j8 ~3017 ~TFTP ~FTP' # FIXME: TFTP requests executed twice? Related: `curl: (69) TFTP: Access Violation`?
time cmake --build bld --target test-ci
time cmake --build bld --config Debug --target test-ci
fi
echo '::group::build examples'
time cmake --build bld --target curl-examples
time cmake --build bld --config Debug --target curl-examples
echo '::endgroup::'
freebsd:
@ -140,7 +140,6 @@ jobs:
version: '14.1'
architecture: ${{ matrix.arch }}
run: |
export MAKEFLAGS=-j3
# https://ports.freebsd.org/
time sudo pkg install -y autoconf automake libtool \
pkgconf brotli openldap26-client libidn2 libnghttp2 stunnel py311-impacket
@ -155,18 +154,18 @@ jobs:
|| { tail -n 1000 config.log; false; }
echo '::group::curl_config.h (raw)'; cat lib/curl_config.h || true; echo '::endgroup::'
echo '::group::curl_config.h'; grep -F '#define' lib/curl_config.h | sort || true; echo '::endgroup::'
time make install
time make -j3 install
src/curl --disable --version
desc='${{ matrix.desc }}'
if [ '${{ matrix.arch }}' = 'x86_64' ]; then # Slow on emulated CPU
time make -C tests
time make -j3 -C tests
if [ "${desc#*!runtests*}" = "${desc}" ]; then
time make test-ci V=1 TFLAGS='-j4'
fi
fi
if [ "${desc#*!examples*}" = "${desc}" ]; then
echo '::group::build examples'
time make examples
time make -j3 examples
echo '::endgroup::'
fi
@ -185,25 +184,25 @@ jobs:
-DCMAKE_C_COMPILER='${{ matrix.compiler }}' \
-DCMAKE_UNITY_BUILD=ON -DCURL_TEST_BUNDLES=ON \
-DCURL_WERROR=ON \
-DENABLE_DEBUG=ON -DCMAKE_BUILD_TYPE=Debug \
-DENABLE_DEBUG=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG= \
-DCURL_USE_OPENSSL=ON \
-DCURL_USE_GSSAPI=ON \
${{ matrix.options }} \
|| { cat bld/CMakeFiles/CMake*.yaml; false; }
echo '::group::curl_config.h (raw)'; cat bld/lib/curl_config.h || true; echo '::endgroup::'
echo '::group::curl_config.h'; grep -F '#define' bld/lib/curl_config.h | sort || true; echo '::endgroup::'
time cmake --build bld
time cmake --build bld --config Debug
bld/src/curl --disable --version
desc='${{ matrix.desc }}'
if [ '${{ matrix.arch }}' = 'x86_64' ]; then # Slow on emulated CPU
time cmake --build bld --target testdeps
time cmake --build bld --config Debug --target testdeps
if [ "${desc#*!runtests*}" = "${desc}" ]; then
time cmake --build bld --target test-ci
time cmake --build bld --config Debug --target test-ci
fi
fi
if [ "${desc#*!examples*}" = "${desc}" ]; then
echo '::group::build examples'
time cmake --build bld --target curl-examples
time cmake --build bld --config Debug --target curl-examples
echo '::endgroup::'
fi
@ -224,7 +223,6 @@ jobs:
run: |
set -e
ln -s /usr/bin/gcpp /usr/bin/cpp # Some tests expect `cpp`, which is named `gcpp` in this env.
export MAKEFLAGS=-j3
time autoreconf -fi
mkdir bld && cd bld && time ../configure --enable-unity --enable-test-bundles --enable-debug --enable-warnings --enable-werror \
--prefix="${HOME}"/install \
@ -233,12 +231,12 @@ jobs:
|| { tail -n 1000 config.log; false; }
echo '::group::curl_config.h (raw)'; cat lib/curl_config.h || true; echo '::endgroup::'
echo '::group::curl_config.h'; grep -F '#define' lib/curl_config.h | sort || true; echo '::endgroup::'
time gmake install
time gmake -j3 install
src/curl --disable --version
time gmake -C tests
time gmake -j3 -C tests
time gmake test-ci V=1
echo '::group::build examples'
time gmake examples
time gmake -j3 examples
echo '::endgroup::'
ios:
@ -246,9 +244,9 @@ jobs:
runs-on: 'macos-latest'
timeout-minutes: 10
env:
MAKEFLAGS: -j 4
DEVELOPER_DIR: "/Applications/Xcode${{ matrix.build.xcode && format('_{0}', matrix.build.xcode) || '' }}.app/Contents/Developer"
CC: ${{ matrix.build.compiler || 'clang' }}
MAKEFLAGS: -j 4
# renovate: datasource=github-tags depName=libressl-portable/portable versioning=semver registryUrl=https://github.com
libressl-version: 4.0.0
strategy:
@ -263,7 +261,6 @@ jobs:
install_steps: libressl
# FIXME: Could not make OPENSSL_ROOT_DIR work. CMake seems to prepend sysroot to it.
generate: >-
-DCMAKE_BUILD_TYPE=Release -DCMAKE_UNITY_BUILD_BATCH_SIZE=50
-DOPENSSL_INCLUDE_DIR="$HOME/libressl/include"
-DOPENSSL_SSL_LIBRARY="$HOME/libressl/lib/libssl.a"
-DOPENSSL_CRYPTO_LIBRARY="$HOME/libressl/lib/libcrypto.a"
@ -272,7 +269,6 @@ jobs:
- name: 'libressl'
install_steps: libressl
generator: Xcode
options: --config Debug
generate: >-
-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=OFF
-DMACOSX_BUNDLE_GUI_IDENTIFIER=se.curl
@ -365,7 +361,7 @@ jobs:
- name: 'build'
run: |
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld ${{ matrix.build.options }} --parallel 4 --verbose
cmake --build bld --verbose
else
make -C bld V=1
fi
@ -376,7 +372,7 @@ jobs:
- name: 'build tests'
run: |
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld ${{ matrix.build.options }} --parallel 4 --target testdeps --verbose
cmake --build bld --target testdeps --verbose
else
make -C bld V=1 -C tests
fi
@ -384,7 +380,7 @@ jobs:
- name: 'build examples'
run: |
if [ -n '${{ matrix.build.generate }}' ]; then
cmake --build bld ${{ matrix.build.options }} --parallel 4 --target curl-examples --verbose
cmake --build bld --target curl-examples --verbose
else
make -C bld examples V=1
fi
@ -394,9 +390,9 @@ jobs:
runs-on: 'ubuntu-latest'
timeout-minutes: 25
env:
MAKEFLAGS: -j 5
VCPKG_BINARY_SOURCES: 'clear;x-gha,readwrite'
VCPKG_DISABLE_METRICS: '1'
MAKEFLAGS: -j 5
strategy:
matrix:
include:
@ -494,7 +490,7 @@ jobs:
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --verbose
else
make -C bld V=1
make -j5 -C bld V=1
fi
- name: 'curl info'
@ -505,7 +501,7 @@ jobs:
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target testdeps
else
make -C bld -C tests
make -j5 -C bld -C tests
fi
- name: 'build examples'
@ -513,7 +509,7 @@ jobs:
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target curl-examples
else
make -C bld examples
make -j5 -C bld examples
fi
amiga:
@ -521,7 +517,6 @@ jobs:
runs-on: 'ubuntu-latest'
timeout-minutes: 5
env:
MAKEFLAGS: -j 5
amissl-version: 5.18
strategy:
matrix:
@ -589,9 +584,9 @@ jobs:
- name: 'build'
run: |
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld
cmake --build bld --parallel 5
else
make -C bld
make -j5 -C bld
fi
- name: 'curl info'
@ -601,18 +596,18 @@ jobs:
if: ${{ matrix.build == 'cmake' }} # skip for autotools to save time
run: |
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target testdeps
cmake --build bld --parallel 5 --target testdeps
else
make -C bld -C tests
make -j5 -C bld -C tests
fi
- name: 'build examples'
if: ${{ matrix.build == 'cmake' }} # skip for autotools to save time
run: |
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target curl-examples
cmake --build bld --parallel 5 --target curl-examples
else
make -C bld examples
make -j5 -C bld examples
fi
msdos:
@ -620,7 +615,6 @@ jobs:
runs-on: 'ubuntu-latest'
timeout-minutes: 5
env:
MAKEFLAGS: -j 5
toolchain-version: '3.4'
strategy:
matrix:
@ -700,7 +694,7 @@ jobs:
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld
else
make -C bld
make -j5 -C bld
fi
- name: 'curl info'
@ -712,7 +706,7 @@ jobs:
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target testdeps
else
make -C bld -C tests
make -j5 -C bld -C tests
fi
- name: 'build examples'
@ -721,5 +715,5 @@ jobs:
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target curl-examples
else
make -C bld examples
make -j5 -C bld examples
fi

View File

@ -44,7 +44,6 @@ jobs:
run:
shell: C:\cygwin\bin\bash.exe '{0}'
env:
MAKEFLAGS: -j 5
SHELLOPTS: 'igncr'
strategy:
matrix:
@ -84,13 +83,14 @@ jobs:
- name: 'configure'
timeout-minutes: 5
run: |
PATH=/usr/bin
if [ '${{ matrix.build }}' = 'cmake' ]; then
PATH="/usr/bin:$(cygpath "${SYSTEMROOT}")/System32"
cmake -B bld -G Ninja -D_CURL_PREFILL=ON ${options} \
-DCMAKE_UNITY_BUILD=ON -DCMAKE_UNITY_BUILD_BATCH_SIZE=30 -DCURL_TEST_BUNDLES=ON \
-DCURL_WERROR=ON \
${{ matrix.config }}
else
PATH="/usr/bin:$(cygpath "${SYSTEMROOT}")/System32"
mkdir bld && cd bld && ../configure --enable-unity --enable-test-bundles --enable-warnings --enable-werror \
--prefix="${HOME}"/install \
--with-openssl \
@ -112,9 +112,9 @@ jobs:
timeout-minutes: 10
run: |
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld
cmake --build bld --config '${{ matrix.type }}'
else
make -C bld V=1 install
make -C bld -j5 V=1 install
fi
- name: 'curl version'
@ -131,9 +131,9 @@ jobs:
timeout-minutes: 15
run: |
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target testdeps
cmake --build bld --config '${{ matrix.type }}' --target testdeps
else
make -C bld V=1 -C tests
make -C bld -j5 V=1 -C tests
fi
- name: 'run tests'
@ -146,9 +146,9 @@ jobs:
fi
if [ '${{ matrix.build }}' = 'cmake' ]; then
PATH="$PWD/bld/lib:$PATH"
cmake --build bld --target test-ci
cmake --build bld --config '${{ matrix.type }}' --target test-ci
else
make -C bld V=1 test-ci
make -C bld -j5 V=1 test-ci
fi
- name: 'build examples'
@ -156,9 +156,9 @@ jobs:
timeout-minutes: 5
run: |
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target curl-examples
cmake --build bld --config '${{ matrix.type }}' --target curl-examples
else
make -C bld V=1 examples
make -C bld -j5 V=1 examples
fi
msys2: # both msys and mingw-w64
@ -168,8 +168,6 @@ jobs:
defaults:
run:
shell: msys2 {0}
env:
MAKEFLAGS: -j 5
strategy:
matrix:
include:
@ -207,7 +205,6 @@ jobs:
libnghttp2-devel
libpsl-devel
libssh2-devel
${{ matrix.chkprefill == '_chkprefill' && 'diffutils' || '' }}
- uses: msys2/setup-msys2@d44ca8e88d8b43d56cf5670f91747359d5537f97 # v2
if: ${{ matrix.sys != 'msys' }}
@ -253,6 +250,8 @@ jobs:
fi
[ '${{ matrix.sys }}' = 'msys' ] && options+=' -D_CURL_PREFILL=ON'
[ '${{ matrix.test }}' = 'uwp' ] && options+=' -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0'
[ '${{ matrix.type }}' = 'Debug' ] && options+=' -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG='
[ '${{ matrix.type }}' = 'Release' ] && options+=' -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE='
[ "${_chkprefill}" = '_chkprefill' ] && options+=' -D_CURL_PREFILL=OFF'
cmake -B "bld${_chkprefill}" -G Ninja ${options} \
-DCMAKE_C_FLAGS="${{ matrix.cflags }} ${CFLAGS_CMAKE} ${CPPFLAGS}" \
@ -287,9 +286,9 @@ jobs:
timeout-minutes: 10
run: |
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld
cmake --build bld --config '${{ matrix.type }}'
else
make -C bld V=1 install
make -C bld -j5 V=1 install
fi
- name: 'curl version'
@ -312,9 +311,9 @@ jobs:
timeout-minutes: 10
run: |
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target testdeps
cmake --build bld --config '${{ matrix.type }}' --target testdeps
else
make -C bld V=1 -C tests
make -C bld -j5 V=1 -C tests
fi
if [ '${{ matrix.build }}' != 'cmake' ]; then
# avoid libtool's .exe wrappers
@ -348,10 +347,10 @@ jobs:
PATH="$PATH:/c/Program Files (x86)/stunnel/bin"
if [ '${{ matrix.build }}' = 'cmake' ]; then
PATH="$PWD/bld/lib:$PATH"
cmake --build bld --target test-ci
cmake --build bld --config '${{ matrix.type }}' --target test-ci
else
PATH="$PWD/bld/lib/.libs:$PATH"
make -C bld V=1 test-ci
make -C bld -j5 V=1 test-ci
fi
- name: 'build examples'
@ -359,9 +358,9 @@ jobs:
timeout-minutes: 5
run: |
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target curl-examples
cmake --build bld --config '${{ matrix.type }}' --target curl-examples
else
make -C bld V=1 examples
make -C bld -j5 V=1 examples
fi
mingw-w64-standalone-downloads:
@ -371,8 +370,6 @@ jobs:
defaults:
run:
shell: C:\msys64\usr\bin\bash.exe {0}
env:
MAKEFLAGS: -j 5
strategy:
matrix:
include:
@ -429,21 +426,15 @@ jobs:
timeout-minutes: 5
run: |
PATH="$(cygpath "${USERPROFILE}")/my-cache/${{ matrix.dir }}/bin:/c/msys64/usr/bin:$PATH"
for _chkprefill in '' ${{ matrix.chkprefill }}; do
options=''
[ "${_chkprefill}" = '_chkprefill' ] && options+=' -D_CURL_PREFILL=OFF'
cmake -B "bld${_chkprefill}" -G 'MSYS Makefiles' ${options} \
-DCMAKE_C_COMPILER=gcc \
-DCMAKE_BUILD_TYPE='${{ matrix.type }}' \
-DCMAKE_UNITY_BUILD=ON -DCMAKE_UNITY_BUILD_BATCH_SIZE=30 -DCURL_TEST_BUNDLES=ON \
-DCURL_WERROR=ON \
-DCURL_USE_LIBPSL=OFF \
${{ matrix.config }}
done
if [ -d bld_chkprefill ] && ! diff -u bld/lib/curl_config.h bld_chkprefill/lib/curl_config.h; then
echo '::group::reference configure log'; cat bld_chkprefill/CMakeFiles/CMake*.yaml 2>/dev/null || true; echo '::endgroup::'
false
fi
[ '${{ matrix.type }}' = 'Debug' ] && options+=' -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG='
[ '${{ matrix.type }}' = 'Release' ] && options+=' -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE='
cmake -B bld -G 'MSYS Makefiles' ${options} \
-DCMAKE_C_COMPILER=gcc \
-DCMAKE_BUILD_TYPE='${{ matrix.type }}' \
-DCMAKE_UNITY_BUILD=ON -DCMAKE_UNITY_BUILD_BATCH_SIZE=30 -DCURL_TEST_BUNDLES=ON \
-DCURL_WERROR=ON \
-DCURL_USE_LIBPSL=OFF \
${{ matrix.config }}
- name: 'configure log'
if: ${{ !cancelled() }}
@ -458,7 +449,7 @@ jobs:
timeout-minutes: 5
run: |
PATH="$(cygpath "${USERPROFILE}")/my-cache/${{ matrix.dir }}/bin:/c/msys64/usr/bin:$PATH"
cmake --build bld
cmake --build bld --config '${{ matrix.type }}' --parallel 5
- name: 'curl version'
timeout-minutes: 1
@ -472,7 +463,7 @@ jobs:
timeout-minutes: 10
run: |
PATH="$(cygpath "${USERPROFILE}")/my-cache/${{ matrix.dir }}/bin:/c/msys64/usr/bin:$PATH"
cmake --build bld --target testdeps
cmake --build bld --config '${{ matrix.type }}' --parallel 5 --target testdeps
- name: 'install test prereqs'
if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }}
@ -501,29 +492,27 @@ jobs:
TFLAGS+=" -ac $(cygpath "${SYSTEMROOT}/System32/curl.exe")"
fi
PATH="$PWD/bld/lib:$PATH:/c/Program Files (x86)/stunnel/bin"
cmake --build bld --target test-ci
cmake --build bld --config '${{ matrix.type }}' --target test-ci
- name: 'build examples'
timeout-minutes: 5
run: |
PATH="$(cygpath "${USERPROFILE}")/my-cache/${{ matrix.dir }}/bin:/c/msys64/usr/bin:$PATH"
cmake --build bld --target curl-examples
cmake --build bld --config '${{ matrix.type }}' --parallel 5 --target curl-examples
linux-cross-mingw-w64:
name: "linux-mingw, ${{ matrix.build == 'cmake' && 'CM' || 'AM' }} ${{ matrix.compiler }}"
runs-on: ubuntu-latest
timeout-minutes: 15
env:
MAKEFLAGS: -j 5
TRIPLET: 'x86_64-w64-mingw32'
strategy:
fail-fast: false
matrix:
build: [autotools, cmake]
compiler: [gcc]
env:
TRIPLET: 'x86_64-w64-mingw32'
steps:
- name: 'install packages'
timeout-minutes: 5
run: sudo apt-get -o Dpkg::Use-Pty=0 install mingw-w64 ${{ matrix.build == 'cmake' && 'ninja-build' || '' }}
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
@ -567,7 +556,7 @@ jobs:
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld
else
make -C bld
make -C bld -j5
fi
- name: 'curl info'
@ -579,7 +568,7 @@ jobs:
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target testdeps
else
make -C bld -C tests
make -C bld -j5 -C tests
fi
- name: 'build examples'
@ -587,7 +576,7 @@ jobs:
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target curl-examples
else
make -C bld examples
make -C bld -j5 examples
fi
wince:
@ -595,7 +584,6 @@ jobs:
runs-on: 'macos-latest'
timeout-minutes: 10
env:
MAKEFLAGS: -j 4
toolchain-version: '0.59.1'
strategy:
matrix:
@ -604,7 +592,6 @@ jobs:
steps:
- name: 'install packages'
if: ${{ matrix.build == 'autotools' }}
timeout-minutes: 5
run: |
echo automake libtool | xargs -Ix -n1 echo brew '"x"' > /tmp/Brewfile
while [[ $? == 0 ]]; do for i in 1 2 3; do brew update && brew bundle install --no-lock --file /tmp/Brewfile && break 2 || { echo Error: wait to try again; sleep 10; } done; false Too many retries; done
@ -618,7 +605,6 @@ jobs:
- name: 'install compiler (mingw32ce)'
if: ${{ steps.cache-compiler.outputs.cache-hit != 'true' }}
timeout-minutes: 5
run: |
cd "${HOME}" || exit 1
curl --disable --fail --silent --show-error --connect-timeout 15 --max-time 120 --retry 3 --retry-connrefused --proto-redir =https \
@ -629,19 +615,18 @@ jobs:
- name: 'configure'
run: |
PATH="$HOME/opt/mingw32ce/bin:$PATH"
MINGW32CE_ROOT="${HOME}/opt/mingw32ce"
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake -B bld \
-DCMAKE_SYSTEM_NAME=WindowsCE \
-DCMAKE_SYSTEM_VERSION=8.0 \
-DCMAKE_SYSTEM_PROCESSOR=arm \
-DCMAKE_C_FLAGS='-O3 -DNDEBUG' \
-DCMAKE_C_COMPILER_TARGET=arm-mingw32ce \
-DCMAKE_C_COMPILER=arm-mingw32ce-gcc \
-DCMAKE_RC_COMPILER=arm-mingw32ce-windres \
-DMINGW32CE_LIBRARY_DIR="$HOME/opt/mingw32ce/arm-mingw32ce/lib" \
-DCMAKE_C_COMPILER_TARGET=arm-wince-mingw32ce \
-DCMAKE_C_COMPILER="${MINGW32CE_ROOT}/bin/arm-mingw32ce-gcc" \
-DCMAKE_RC_COMPILER="${MINGW32CE_ROOT}/bin/arm-mingw32ce-windres" \
-DMINGW32CE_LIBRARY_DIR="${MINGW32CE_ROOT}/arm-mingw32ce/lib" \
-DCMAKE_IGNORE_PREFIX_PATH="$(brew --prefix)" \
-DCMAKE_UNITY_BUILD=ON -DCMAKE_UNITY_BUILD_BATCH_SIZE=50 -DCURL_TEST_BUNDLES=ON \
-DCMAKE_UNITY_BUILD=ON -DCURL_TEST_BUNDLES=ON \
-DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=ON -DBUILD_STATIC_CURL=OFF \
-DCURL_WERROR=ON \
-DCURL_USE_SCHANNEL=ON \
@ -649,7 +634,12 @@ jobs:
else
autoreconf -fi
mkdir bld && cd bld && ../configure --disable-dependency-tracking --enable-unity --enable-test-bundles --enable-warnings --enable-werror \
--host=arm-mingw32ce \
ac_cv_prog_cc_c99=no \
CC="${MINGW32CE_ROOT}/bin/arm-mingw32ce-gcc" \
AR="${MINGW32CE_ROOT}/bin/arm-mingw32ce-ar" \
RANLIB="${MINGW32CE_ROOT}/bin/arm-mingw32ce-ranlib" \
RC="${MINGW32CE_ROOT}/bin/arm-mingw32ce-windres" \
--host=arm-wince-mingw32ce \
--with-schannel \
--without-libpsl \
--disable-shared
@ -666,11 +656,10 @@ jobs:
- name: 'build'
run: |
PATH="$HOME/opt/mingw32ce/bin:$PATH"
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld
else
make -C bld
make -j5 -C bld
fi
- name: 'curl info'
@ -680,21 +669,19 @@ jobs:
- name: 'build tests'
if: ${{ matrix.build == 'cmake' }} # skip for autotools to save time
run: |
PATH="$HOME/opt/mingw32ce/bin:$PATH"
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target testdeps
else
make -C bld -C tests
make -j5 -C bld -C tests
fi
- name: 'build examples'
if: ${{ matrix.build == 'cmake' }} # skip for autotools to save time
run: |
PATH="$HOME/opt/mingw32ce/bin:$PATH"
if [ '${{ matrix.build }}' = 'cmake' ]; then
cmake --build bld --target curl-examples
else
make -C bld examples
make -j5 -C bld examples
fi
msvc:
@ -710,16 +697,16 @@ jobs:
strategy:
matrix:
include:
- name: 'openssl'
install: 'brotli zlib zstd nghttp2 nghttp3 openssl libssh2'
- name: 'schannel MultiSSL U'
install: 'brotli zlib zstd libpsl nghttp2 libssh2[core,zlib] pkgconf gsasl openssl mbedtls wolfssl'
arch: 'x64'
plat: 'uwp'
plat: 'windows'
type: 'Debug'
tflags: 'skiprun'
tflags: '~1516 ~2301 ~2302 ~2303 ~2307 ~2310'
config: >-
-DCURL_USE_LIBSSH2=ON
-DCURL_USE_SCHANNEL=OFF -DCURL_USE_OPENSSL=ON -DUSE_OPENSSL_QUIC=ON
-DCURL_USE_LIBPSL=OFF
-DCURL_USE_SCHANNEL=ON -DCURL_USE_OPENSSL=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_WOLFSSL=ON -DCURL_DEFAULT_SSL_BACKEND=schannel
-DCURL_USE_GSASL=ON -DUSE_WIN32_IDN=ON -DENABLE_UNICODE=ON -DUSE_SSLS_EXPORT=ON
- name: 'openssl'
install: 'brotli zlib zstd libpsl nghttp2 nghttp3 openssl libssh2 pkgconf gsasl c-ares libuv krb5'
@ -732,16 +719,16 @@ jobs:
-DCURL_USE_SCHANNEL=OFF -DCURL_USE_OPENSSL=ON -DUSE_OPENSSL_QUIC=ON
-DCURL_USE_GSASL=ON -DENABLE_ARES=ON -DCURL_USE_LIBUV=ON -DCURL_USE_GSSAPI=ON
- name: 'schannel MultiSSL U'
install: 'brotli zlib zstd libpsl nghttp2 libssh2[core,zlib] pkgconf gsasl openssl mbedtls wolfssl'
- name: 'openssl'
install: 'brotli zlib zstd nghttp2 nghttp3 openssl libssh2'
arch: 'x64'
plat: 'windows'
plat: 'uwp'
type: 'Debug'
tflags: '~1516 ~2301 ~2302 ~2303 ~2307 ~2310'
tflags: 'skiprun'
config: >-
-DCURL_USE_LIBSSH2=ON
-DCURL_USE_SCHANNEL=ON -DCURL_USE_OPENSSL=ON -DCURL_USE_MBEDTLS=ON -DCURL_USE_WOLFSSL=ON -DCURL_DEFAULT_SSL_BACKEND=schannel
-DCURL_USE_GSASL=ON -DUSE_WIN32_IDN=ON -DENABLE_UNICODE=ON -DUSE_SSLS_EXPORT=ON
-DCURL_USE_SCHANNEL=OFF -DCURL_USE_OPENSSL=ON -DUSE_OPENSSL_QUIC=ON
-DCURL_USE_LIBPSL=OFF
- name: 'libressl'
install: 'brotli zlib zstd libpsl nghttp2 libressl libssh2[core,zlib] pkgconf ngtcp2[libressl] nghttp3'
@ -840,6 +827,8 @@ jobs:
-DCMAKE_EXE_LINKER_FLAGS="-INCREMENTAL:NO ${ldflags}" \
-DCMAKE_SHARED_LINKER_FLAGS="-INCREMENTAL:NO ${ldflags}" \
-DCMAKE_VS_GLOBALS="TrackFileAccess=false${vsglobals}" \
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG= \
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE= \
-DCMAKE_UNITY_BUILD=ON -DCURL_TEST_BUNDLES=ON \
-DCURL_WERROR=ON \
-DBUILD_SHARED_LIBS=OFF \
@ -869,10 +858,10 @@ jobs:
- name: 'curl version'
timeout-minutes: 1
run: |
PATH=/usr/bin find . \( -name '*.exe' -o -name '*.dll' -o -name '*.lib' -o -name '*.pdb' \) -exec file '{}' \;
PATH=/usr/bin find . \( -name '*.exe' -o -name '*.dll' -o -name '*.lib' \) -exec file '{}' \;
if [ '${{ matrix.plat }}' != 'uwp' ]; then # Missing: ucrtbased.dll, VCRUNTIME140D.dll, VCRUNTIME140D_APP.dll
PATH="$PWD/bld/lib/${{ matrix.type }}:$PATH"
'bld/src/${{ matrix.type }}/curl.exe' --disable --version
PATH="$PWD/bld/lib:$PATH"
bld/src/curl.exe --disable --version
fi
- name: 'build tests'
@ -907,14 +896,13 @@ jobs:
if: ${{ matrix.tflags != 'skipall' && matrix.tflags != 'skiprun' }}
timeout-minutes: 10
run: |
export CURL_DIRSUFFIX='${{ matrix.type }}'
export TFLAGS='-j8 ~WebSockets ~SCP ~612 ${{ matrix.tflags }}'
if [[ '${{ matrix.install }}' = *'libssh2[core,zlib]'* ]]; then
TFLAGS+=' ~SFTP'
elif [[ '${{ matrix.install }}' = *'libssh '* ]]; then
TFLAGS+=' ~614' # 'SFTP pre-quote chmod' SFTP, pre-quote, directory
fi
PATH="$PWD/bld/lib/${{ matrix.type }}:$PATH:/c/Program Files (x86)/stunnel/bin:/c/Program Files/OpenSSH-Win64"
PATH="$PWD/bld/lib:$PATH:/c/Program Files (x86)/stunnel/bin:/c/Program Files/OpenSSH-Win64"
PATH="/c/msys64/usr/bin:$PATH"
cmake --build bld --config '${{ matrix.type }}' --target test-ci

View File

@ -87,10 +87,3 @@ macro(curl_required_libpaths _libpaths_arg)
list(APPEND CMAKE_REQUIRED_LINK_DIRECTORIES "${_libpaths_arg}")
endif()
endmacro()
# Pre-fill variables set by a check_type_size() call.
macro(curl_prefill_type_size _type _size)
set(HAVE_SIZEOF_${_type} TRUE)
set(SIZEOF_${_type} ${_size})
set(SIZEOF_${_type}_CODE "#define SIZEOF_${_type} ${_size}")
endmacro()

View File

@ -182,7 +182,6 @@ if(PICKY_COMPILER)
-Wold-style-declaration # gcc 4.3
-Wpragmas # clang 3.5 gcc 4.1 appleclang 6.0
-Wstrict-aliasing=3 # gcc 4.0
-ftree-vrp # gcc 4.3 (required for -Warray-bounds, included in -Wall)
)
endif()
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5)
@ -205,7 +204,7 @@ if(PICKY_COMPILER)
endif()
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
list(APPEND _picky_enable
-Warray-bounds=2 # clang 3.0 gcc 5.0 (clang default: -Warray-bounds)
-Warray-bounds=2 -ftree-vrp # clang 3.0 gcc 5.0 (clang default: -Warray-bounds)
)
endif()
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.0)

View File

@ -44,6 +44,10 @@ if(MINGW)
set(HAVE_UTIME_H 1) # wrapper to sys/utime.h
set(HAVE_DIRENT_H 1)
set(HAVE_OPENDIR 1)
if(MINGW32CE)
set(HAVE_STRTOK_R 0)
set(HAVE_FILE_OFFSET_BITS 0)
endif()
else()
set(HAVE_LIBGEN_H 0)
set(HAVE_FTRUNCATE 0)
@ -74,6 +78,7 @@ else()
set(HAVE_SNPRINTF 0)
endif()
set(HAVE_BASENAME 0)
set(HAVE_FILE_OFFSET_BITS 0)
endif()
endif()
@ -191,37 +196,6 @@ set(STDC_HEADERS 1)
set(HAVE_SIZEOF_SUSECONDS_T 0)
set(HAVE_SIZEOF_SA_FAMILY_T 0)
if(MINGW OR MSVC)
curl_prefill_type_size("INT" 4)
curl_prefill_type_size("LONG" 4)
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
# 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.
if(MSVC)
set(HAVE_SIZEOF_SSIZE_T 0)
set(HAVE_FILE_OFFSET_BITS 0)
curl_prefill_type_size("OFF_T" 4)
curl_prefill_type_size("ADDRESS_FAMILY" 2)
else()
# SSIZE_T: 8 for _WIN64, 4 otherwise
if(MINGW64_VERSION)
if(NOT MINGW64_VERSION VERSION_LESS 3.0)
set(HAVE_FILE_OFFSET_BITS 1)
curl_prefill_type_size("OFF_T" 8)
endif()
if(NOT MINGW64_VERSION VERSION_LESS 2.0)
curl_prefill_type_size("ADDRESS_FAMILY" 2)
else()
set(HAVE_SIZEOF_ADDRESS_FAMILY 0)
endif()
endif()
endif()
endif()
if(WINCE) # Windows CE exceptions
set(HAVE_LOCALE_H 0)
set(HAVE_GETADDRINFO 0)
@ -230,15 +204,7 @@ if(WINCE) # Windows CE exceptions
set(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 0)
set(HAVE_SIGNAL 0)
set(HAVE_SETMODE 0)
curl_prefill_type_size("CURL_SOCKET_T" 4)
curl_prefill_type_size("TIME_T" 4)
curl_prefill_type_size("SIZE_T" 4)
if(MINGW32CE)
set(HAVE_STRTOK_R 0)
set(HAVE__SETMODE 0)
set(HAVE_FILE_OFFSET_BITS 0)
set(HAVE_SIZEOF_ADDRESS_FAMILY 0)
curl_prefill_type_size("SSIZE_T" 4)
curl_prefill_type_size("OFF_T" 4)
endif()
endif()

View File

@ -217,6 +217,13 @@ option(ENABLE_ARES "Enable c-ares support" OFF)
option(CURL_DISABLE_INSTALL "Disable installation targets" OFF)
if(WIN32)
option(CURL_STATIC_CRT "Build libcurl with static CRT with MSVC (/MT)" OFF)
if(CURL_STATIC_CRT AND MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
string(APPEND CMAKE_C_FLAGS_RELEASE " -MT")
string(APPEND CMAKE_C_FLAGS_DEBUG " -MTd")
endif()
option(ENABLE_UNICODE "Use the Unicode version of the Windows API functions" OFF)
if(WINDOWS_STORE OR WINCE)
set(ENABLE_UNICODE ON)
@ -257,9 +264,7 @@ if(WIN32)
if(MINGW64_VERSION)
string(REGEX MATCH "MINGW64_VERSION=[0-9]+\.[0-9]+" CURL_TEST_OUTPUT "${CURL_TEST_OUTPUT}")
string(REGEX REPLACE "MINGW64_VERSION=" "" MINGW64_VERSION "${CURL_TEST_OUTPUT}")
if(MINGW64_VERSION)
message(STATUS "Found MINGW64_VERSION=${MINGW64_VERSION}")
endif()
message(STATUS "Found MINGW64_VERSION=${MINGW64_VERSION}")
endif()
unset(MINGW64_VERSION CACHE) # Avoid storing in CMake cache
endif()
@ -349,19 +354,6 @@ else()
set(LIB_SELECTED ${LIB_STATIC})
endif()
if(WIN32)
option(CURL_STATIC_CRT "Build libcurl with static CRT with MSVC (/MT)" OFF)
if(CURL_STATIC_CRT AND MSVC)
if(BUILD_STATIC_CURL OR NOT BUILD_CURL_EXE)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
string(APPEND CMAKE_C_FLAGS_RELEASE " -MT")
string(APPEND CMAKE_C_FLAGS_DEBUG " -MTd")
else()
message(WARNING "Static CRT requires static or no curl executable.")
endif()
endif()
endif()
# Override to force-disable or force-enable the use of pkg-config.
if((UNIX AND NOT ANDROID AND (NOT APPLE OR CMAKE_SYSTEM_NAME MATCHES "Darwin")) OR
VCPKG_TOOLCHAIN OR
@ -827,6 +819,9 @@ if(CURL_USE_OPENSSL)
set(_openssl "AmiSSL")
else()
set(_openssl "OpenSSL")
if(OPENSSL_VERSION VERSION_LESS 1.1.1)
message(WARNING "OpenSSL ${OPENSSL_VERSION} does not support TLS 1.3.")
endif()
endif()
endif()
@ -1953,6 +1948,22 @@ endif()
# Some other minor tests
if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
include(CheckCCompilerFlag)
check_c_compiler_flag("-Wno-long-double" HAVE_C_FLAG_Wno_long_double)
if(HAVE_C_FLAG_Wno_long_double)
# The Mac version of GCC warns about use of long double. Disable it.
get_source_file_property(_mprintf_compile_flags "mprintf.c" COMPILE_FLAGS)
if(_mprintf_compile_flags)
string(APPEND _mprintf_compile_flags " -Wno-long-double")
else()
set(_mprintf_compile_flags "-Wno-long-double")
endif()
set_source_files_properties("mprintf.c" PROPERTIES
COMPILE_FLAGS ${_mprintf_compile_flags})
endif()
endif()
if(_cmake_try_compile_target_type_save)
set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_cmake_try_compile_target_type_save})
unset(_cmake_try_compile_target_type_save)
@ -1972,6 +1983,9 @@ if(WIN32)
set(USE_WIN32_LARGE_FILES ON)
endif()
# Use the manifest embedded in the Windows Resource
string(APPEND CMAKE_RC_FLAGS " -DCURL_EMBED_MANIFEST")
# We use crypto functions that are not available for UWP apps
if(NOT WINDOWS_STORE)
set(USE_WIN32_CRYPTO ON)
@ -1987,6 +2001,9 @@ if(WIN32)
endif()
if(MSVC)
# Disable default manifest added by CMake
string(APPEND CMAKE_EXE_LINKER_FLAGS " -MANIFEST:NO")
string(APPEND CMAKE_C_FLAGS " -MP") # Parallel compilation
endif()
@ -2166,7 +2183,7 @@ curl_add_if("TLS-SRP" USE_TLS_SRP)
curl_add_if("HTTP2" USE_NGHTTP2)
curl_add_if("HTTP3" USE_NGTCP2 OR USE_QUICHE OR USE_MSH3 OR USE_OPENSSL_QUIC)
curl_add_if("MultiSSL" CURL_WITH_MULTI_SSL)
curl_add_if("HTTPS-proxy" NOT CURL_DISABLE_PROXY AND _ssl_enabled AND (USE_OPENSSL OR USE_GNUTLS
curl_add_if("HTTPS-proxy" _ssl_enabled AND (USE_OPENSSL OR USE_GNUTLS
OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
USE_MBEDTLS OR USE_SECTRANSP OR
(USE_WOLFSSL AND HAVE_WOLFSSL_BIO)))

View File

@ -4,15 +4,10 @@ curl and libcurl 8.13.0
Command line options: 267
curl_easy_setopt() options: 306
Public functions in libcurl: 96
Contributors: 3354
Contributors: 3349
This release includes the following changes:
o curl: add write-out variable 'tls_earlydata' [79]
o rustls: add support for CERTINFO [106]
o tool_getparam: make --url support a file with URLs [104]
o var: add a '64dec' function that can base64 decode a string [78]
o wolfssl: tls early data support [50]
This release includes the following bugfixes:
@ -21,111 +16,67 @@ This release includes the following bugfixes:
o asyn-thread: avoid the separate curl_mutex_t alloc [6]
o asyn-thread: do not allocate thread_data separately [21]
o asyn-thread: remove 'status' from struct Curl_async [36]
o build: add Windows CE / CeGCC support, with CI jobs [87]
o build: drop unused `getpart` tool [107]
o build: enable -Wjump-misses-init for GCC 4.5+ [62]
o build: fix compiler warnings in feature detections [39]
o build: set `HAVE_WRITABLE_ARGV` for Apple cross-builds [8]
o build: silence bogus `-Wconversion` warnings with gcc 5.1-5.4 [68]
o c-ares: error out for unsupported versions, drop unused macros [85]
o ca-native.md: sync with CURLSSLOPT_NATIVE_CA [72]
o cf-socket: deduplicate Windows Vista detection [11]
o client writer: handle pause before deocding [61]
o cmake: `SHARE_LIB_OBJECT=ON` requires CMake 3.12 or newer [46]
o cmake: add pre-fill for Unix, enable in GHA/macos, verify pre-fills [42]
o cmake: allow empty `IMPORT_LIB_SUFFIX`, add suffix collision detection [41]
o cmake: avoid `-Wnonnull` warning in `HAVE_FSETXATTR_5` detection [81]
o cmake: disable HTTPS-proxy as a feature if proxy is disabled [77]
o cmake: drop `CURL_DISABLE_TESTS` option [94]
o cmake: allow empty custom `IMPORT_LIB_SUFFIX`, add suffix collision detection [41]
o cmake: drop `HAVE_IN_ADDR_T` from pre-fill too
o cmake: drop two stray TLS feature checks for wolfSSL [9]
o cmake: fix `HAVE_ATOMIC`/`HAVE_STDATOMIC` pre-fill for clang-cl [28]
o cmake: fix ECH detection in custom-patched OpenSSL [32]
o cmake: hide empty `MINGW64_VERSION` output for mingw32ce [114]
o cmake: mention 'insecure' in the debug build warning [15]
o cmake: misc tidy-ups [38]
o cmake: pre-fill known type sizes for Windows OSes [100]
o cmake: restrict static CRT builds to static curl exe, test in CI [113]
o cmake: sync cutoff version with autotools for picky option `-ftree-vrp` [99]
o cmake: sync OpenSSL(-fork) feature checks with `./configure` [49]
o CODE_STYLE: readability and banned functions [35]
o configure: silence compiler warnings in feature checks, drop duplicates [86]
o configure: use `curl_cv_apple` variable [40]
o conn: fix connection reuse when SSL is optional [54]
o contributors.sh: lowercase 'github' for consistency [52]
o contrithanks.sh: update docs/THANKS in place [119]
o cookie: do prefix matching case-sensitively [82]
o cookie: minor parser simplification [58]
o cookie: simplify invalid_octets() [24]
o curl.h: change some enums to defines with L suffix [84]
o curl_msh3: remove verify bypass from DEBUGBUILDs [43]
o curl_trc: fix build with CURL_DISABLE_VERBOSE_STRINGS [109]
o CURLMOPT_SOCKETFUNCTION.md: add advice for socket callback invocation[69]
o CURLOPT_HTTPHEADER.md: add comments to the example [90]
o CURLOPT_HTTPHEADER.md: rephrases [108]
o docs: add FD_ZERO to curl_multi_fdset example [19]
o docs: bump `rustls` to 0.14.1 [111]
o docs: correct argument names & URL redirection [4]
o eventfd: allow use on all CPUs [93]
o gnutls: fix connection state check on handshake [80]
o hash: use single linked list for entries [57]
o hostip: make CURLOPT_RESOLVE support replacing IPv6 addresses [47]
o HTTP3.md: only speak about minimal versions [18]
o http: convert parsers to strparse [48]
o http: fix NTLM info message typo [22]
o http: fix the auth check [88]
o http: make the RTSP version check stricter [73]
o http: negotiation and room for alt-svc/https rr to navigate [64]
o http: version negotiation [45]
o http_aws_sigv4: use strparse more for parsing [55]
o https-rr: implementation improvements [44]
o httpsrr: fix port detection [51]
o httpsrr: fix the HTTPS-RR threaded-resolver build combo [67]
o INSTALL-CMAKE.md: CMake usage updates [101]
o INSTALL-CMAKE.md: mention `ZLIB_USE_STATIC_LIBS` [112]
o lib: better optimized casecompare() and ncasecompare() [3]
o lib: simplify more white space loops [60]
o lib: strtoofft.h header cleanup [17]
o lib: use Curl_str_* instead of strtok_r() [59]
o lib: use Curl_str_number() for parsing decimal numbers [13]
o libtest/libprereq.c: set CURLOPT_FOLLOWLOCATION with a long [89]
o managen: correct the warning for un-escaped '<' and '>' [1]
o msvc: drop support for VS2005 and older [96]
o multi: event based rework [74]
o openssl: check return value of X509_get0_pubkey [105]
o openssl: drop support for old OpenSSL/LibreSSL versions [95]
o openssl: remove bad `goto`s into other scope [63]
o runtests: drop recognizing 'winssl' as Schannel [102]
o runtests: drop ref to unused external function
o runtests: recognize AWS-LC as OpenSSL [103]
o runtests: support multi-target cmake, drop workarounds from CI [116]
o schannel: deduplicate Windows Vista detection [98]
o schannel: enable ALPN support under WINE 6.0+ [92]
o schannel: enable ALPN with MinGW, fix ALPN for UWP builds [71]
o schannel: guard ALPN init code to ALPN builds [91]
o scripts/managen: fix option 'single' [31]
o scripts/managen: fix parsing of markdown code sections [30]
o setopt: remove unnecesary void pointer typecasts [76]
o ssh: consider sftp quote commands case sensitive [33]
o ssl session cache: add exportable flag [56]
o strparse: make Curl_str_number() return error for no digits [14]
o strparse: switch the API to work on 'const char *' [2]
o strparse: switch to curl_off_t as base data type [7]
o tests: fix enum/int confusion, fix autotools `CFLAGS` for `servers` [27]
o tidy-up: align MSYS2/Cygwin codepaths, follow Cygwin `MAX_PID` bump [97]
o tests: fix enum/int confusion (Intel C), fix autotools `CFLAGS` for `servers` [27]
o tidy-up: delete, comment or scope C macros reported unused [16]
o tidy-up: drop unused `CURL_INADDR_NONE` macro and `in_addr_t` type [26]
o tidy-up: use `CURL_ARRAYSIZE()` [37]
o timediff: fix comment for curlx_mstotv() [25]
o timediff: remove unnecessary double typecast [53]
o tool_getparam: clear sensitive arguments better [66]
o tool_operate: fail SSH transfers without server auth [70]
o urlapi: simplify junkscan [23]
o variable.md: clarify 'trim' example [12]
o windows: drop code and curl manifest targeting W2K and older [115]
o wolfssh: retrieve the error using wolfSSH_get_error [5]
o wolfssl: fix CA certificate multiple location import [34]
o wolfssl: warn if CA native import option is ignored [65]
o wolfssl: when using PQ KEM, use ML-KEM, not Kyber [10]
This release includes the following known bugs:
@ -147,13 +98,12 @@ Planned upcoming removals include:
This release would not have looked like this without help, code, reports and
advice from friends like these:
Anthony Hu, Dan Fandrich, Daniel Stenberg, dependabot[bot], Derek Huang,
Dexter Gerig, Harry Sintonen, Jeremy Drake, John Bampton, Joseph Chen,
kayrus on github, kriztalz, Laurențiu Nicola, lf- on github, Marcel Raad,
Mark Phillips, qhill on github, Ray Satiro, renovate[bot], rmg-x on github,
RubisetCie on github, Sergey, Stefan Eissing, Tianyi Song, Timo Tijhof,
Viktor Szakats, Yedaya Katsman, Zenju on github
(28 contributors)
Anthony Hu, Daniel Stenberg, dependabot[bot], Dexter Gerig, Harry Sintonen,
John Bampton, Joseph Chen, kayrus on github, kriztalz, lf- on github,
Marcel Raad, Mark Phillips, Ray Satiro, rmg-x on github,
RubisetCie on Github, Sergey, Stefan Eissing, Viktor Szakats,
Zenju on github
(19 contributors)
References to bug reports and discussions on issues:
@ -204,11 +154,8 @@ References to bug reports and discussions on issues:
[45] = https://curl.se/bug/?i=16100
[46] = https://curl.se/bug/?i=16375
[47] = https://curl.se/bug/?i=16357
[48] = https://curl.se/bug/?i=16436
[49] = https://curl.se/bug/?i=16352
[50] = https://curl.se/bug/?i=16167
[51] = https://curl.se/bug/?i=16409
[52] = https://curl.se/bug/?i=16443
[53] = https://curl.se/bug/?i=16367
[54] = https://curl.se/bug/?i=16384
[55] = https://curl.se/bug/?i=16366
@ -221,53 +168,8 @@ References to bug reports and discussions on issues:
[62] = https://curl.se/bug/?i=16252
[63] = https://curl.se/bug/?i=16356
[64] = https://curl.se/bug/?i=16117
[65] = https://curl.se/bug/?i=16417
[66] = https://curl.se/bug/?i=16396
[67] = https://curl.se/bug/?i=16399
[68] = https://curl.se/bug/?i=16398
[69] = https://curl.se/bug/?i=16441
[70] = https://curl.se/bug/?i=16205
[71] = https://curl.se/bug/?i=16385
[72] = https://curl.se/bug/?i=16373
[73] = https://curl.se/bug/?i=16435
[74] = https://curl.se/bug/?i=16308
[76] = https://curl.se/bug/?i=16426
[77] = https://curl.se/bug/?i=16434
[78] = https://curl.se/bug/?i=16330
[79] = https://curl.se/bug/?i=15956
[80] = https://curl.se/bug/?i=16423
[81] = https://curl.se/bug/?i=16427
[82] = https://curl.se/bug/?i=16494
[84] = https://curl.se/bug/?i=16482
[85] = https://curl.se/bug/?i=16407
[86] = https://curl.se/bug/?i=16377
[87] = https://curl.se/bug/?i=15975
[88] = https://curl.se/bug/?i=16419
[89] = https://curl.se/bug/?i=16487
[90] = https://curl.se/bug/?i=16488
[91] = https://curl.se/bug/?i=16420
[92] = https://curl.se/bug/?i=16393
[93] = https://curl.se/bug/?i=16277
[94] = https://curl.se/bug/?i=16134
[95] = https://curl.se/bug/?i=16104
[96] = https://curl.se/bug/?i=16004
[97] = https://curl.se/bug/?i=16217
[98] = https://curl.se/bug/?i=16408
[99] = https://curl.se/bug/?i=16478
[100] = https://curl.se/bug/?i=16464
[101] = https://curl.se/bug/?i=16329
[102] = https://curl.se/bug/?i=16467
[103] = https://curl.se/bug/?i=16466
[104] = https://curl.se/bug/?i=16099
[105] = https://curl.se/bug/?i=16468
[106] = https://curl.se/bug/?i=16459
[107] = https://curl.se/bug/?i=16460
[108] = https://curl.se/bug/?i=16461
[109] = https://curl.se/bug/?i=16462
[111] = https://curl.se/bug/?i=16446
[112] = https://curl.se/bug/?i=16457
[113] = https://curl.se/bug/?i=16456
[114] = https://curl.se/bug/?i=16455
[115] = https://curl.se/bug/?i=16453
[116] = https://curl.se/bug/?i=16452
[119] = https://curl.se/bug/?i=16448

View File

@ -36,8 +36,6 @@ esac
if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = 'Visual Studio 2022' ]; then
openssl_root_win="C:/OpenSSL-v34${openssl_suffix}"
elif [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = 'Visual Studio 2019' ]; then
openssl_root_win="C:/OpenSSL-v11${openssl_suffix}"
elif [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = 'Visual Studio 2013' ]; then
openssl_root_win="C:/OpenSSL${openssl_suffix}"
else
openssl_root_win="C:/OpenSSL-v111${openssl_suffix}"
@ -54,49 +52,35 @@ if [ "${BUILD_SYSTEM}" = 'CMake' ]; then
[ -n "${TOOLSET:-}" ] && options+=" -T ${TOOLSET}"
[ "${OPENSSL}" = 'ON' ] && options+=" -DOPENSSL_ROOT_DIR=${openssl_root_win}"
[ -n "${CURLDEBUG:-}" ] && options+=" -DENABLE_CURLDEBUG=${CURLDEBUG}"
if [ "${APPVEYOR_BUILD_WORKER_IMAGE}" = 'Visual Studio 2013' ]; then
mkdir "_bld${_chkprefill}"
cd "_bld${_chkprefill}"
options+=' ..'
root='..'
else
options+=" -B _bld${_chkprefill}"
options+=' -DCMAKE_VS_GLOBALS=TrackFileAccess=false'
options+=" -DCMAKE_UNITY_BUILD=${UNITY}"
root='.'
fi
# shellcheck disable=SC2086
time cmake -G "${PRJ_GEN}" ${TARGET} \
-DCURL_TEST_BUNDLES=ON \
cmake -B "_bld${_chkprefill}" -G "${PRJ_GEN}" ${TARGET} \
-DCMAKE_VS_GLOBALS=TrackFileAccess=false \
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG= \
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE= \
-DCMAKE_UNITY_BUILD="${UNITY}" -DCURL_TEST_BUNDLES=ON \
-DCURL_WERROR=ON \
-DBUILD_SHARED_LIBS="${SHARED}" \
-DCURL_STATIC_CRT=ON \
-DENABLE_DEBUG="${DEBUG}" \
-DENABLE_UNICODE="${ENABLE_UNICODE}" \
-DHTTP_ONLY="${HTTP_ONLY}" \
-DCURL_USE_SCHANNEL="${SCHANNEL}" \
-DCURL_USE_OPENSSL="${OPENSSL}" \
-DCURL_USE_LIBPSL=OFF \
${options} \
|| { cat ${root}/_bld/CMakeFiles/CMake* 2>/dev/null; false; }
[ "${APPVEYOR_BUILD_WORKER_IMAGE}" = 'Visual Studio 2013' ] && cd ..
${options}
done
if [ -d _bld_chkprefill ] && ! diff -u _bld/lib/curl_config.h _bld_chkprefill/lib/curl_config.h; then
cat _bld_chkprefill/CMakeFiles/CMake* 2>/dev/null || true
cat _bld_chkprefill/CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true
false
fi
if false; then
cat _bld/CMakeFiles/CMakeConfigureLog.yaml 2>/dev/null || true
fi
echo 'curl_config.h'; grep -F '#define' _bld/lib/curl_config.h | sort || true
# shellcheck disable=SC2086
if ! time cmake --build _bld --config "${PRJ_CFG}" --parallel 2 -- ${BUILD_OPT:-}; then
if [ "${PRJ_GEN}" = 'Visual Studio 9 2008' ]; then
find . -name BuildLog.htm -exec dos2unix '{}' +
find . -name BuildLog.htm -exec cat '{}' +
fi
false
fi
[ "${SHARED}" = 'ON' ] && PATH="$PWD/_bld/lib/${PRJ_CFG}:$PATH"
[ "${OPENSSL}" = 'ON' ] && { PATH="${openssl_root}:$PATH"; cp "${openssl_root}"/*.dll "_bld/src/${PRJ_CFG}"; }
curl="_bld/src/${PRJ_CFG}/curl.exe"
cmake --build _bld --config "${PRJ_CFG}" --parallel 2 -- ${BUILD_OPT:-}
[ "${SHARED}" = 'ON' ] && PATH="$PWD/_bld/lib:$PATH"
[ "${OPENSSL}" = 'ON' ] && PATH="${openssl_root}:$PATH"
curl='_bld/src/curl.exe'
elif [ "${BUILD_SYSTEM}" = 'VisualStudioSolution' ]; then
(
cd projects
@ -129,7 +113,7 @@ EOF
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 '{}' \;
find . \( -name '*.exe' -o -name '*.dll' -o -name '*.lib' \) -exec file '{}' \;
if [ -z "${SKIP_RUN:-}" ]; then
"${curl}" --disable --version
else
@ -140,14 +124,13 @@ fi
if [ "${TFLAGS}" != 'skipall' ] && \
[ "${BUILD_SYSTEM}" = 'CMake' ]; then
time cmake --build _bld --config "${PRJ_CFG}" --parallel 2 --target testdeps
cmake --build _bld --config "${PRJ_CFG}" --parallel 2 --target testdeps
fi
# run tests
if [ "${TFLAGS}" != 'skipall' ] && \
[ "${TFLAGS}" != 'skiprun' ]; then
export CURL_DIRSUFFIX="${PRJ_CFG}"
if [ -x "$(cygpath "${SYSTEMROOT}/System32/curl.exe")" ]; then
TFLAGS+=" -ac $(cygpath "${SYSTEMROOT}/System32/curl.exe")"
elif [ -x "$(cygpath 'C:/msys64/usr/bin/curl.exe')" ]; then
@ -155,12 +138,12 @@ if [ "${TFLAGS}" != 'skipall' ] && \
fi
TFLAGS+=' -j0'
if [ "${BUILD_SYSTEM}" = 'CMake' ]; then
time cmake --build _bld --config "${PRJ_CFG}" --target test-ci
cmake --build _bld --config "${PRJ_CFG}" --target test-ci
else
(
TFLAGS="-a -p !flaky -r -rm ${TFLAGS}"
cd _bld/tests
time ./runtests.pl
./runtests.pl
)
fi
fi
@ -169,5 +152,5 @@ fi
if [ "${EXAMPLES}" = 'ON' ] && \
[ "${BUILD_SYSTEM}" = 'CMake' ]; then
time cmake --build _bld --config "${PRJ_CFG}" --parallel 2 --target curl-examples
cmake --build _bld --config "${PRJ_CFG}" --parallel 2 --target curl-examples
fi

View File

@ -31,11 +31,8 @@
version: 7.50.0.{build}
environment:
BUILD_SYSTEM: CMake
UNITY: 'ON'
OPENSSL: 'OFF'
SCHANNEL: 'OFF'
ENABLE_UNICODE: 'OFF'
DEBUG: 'ON'
SHARED: 'OFF'
HTTP_ONLY: 'OFF'
@ -48,77 +45,89 @@ environment:
- job_name: 'CMake, VS2022, Release, x64, OpenSSL 3.4, Shared, Build-tests'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 17 2022'
TARGET: '-A x64'
PRJ_CFG: Release
OPENSSL: 'ON'
SCHANNEL: 'OFF'
ENABLE_UNICODE: 'OFF'
SHARED: 'ON'
- job_name: 'CMake, VS2022, Release, arm64, Schannel, Static, Build-tests'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 17 2022'
TARGET: '-A ARM64'
PRJ_CFG: Release
SCHANNEL: 'ON'
ENABLE_UNICODE: 'OFF'
DEBUG: 'OFF'
CURLDEBUG: 'ON'
- job_name: 'CMake, VS2008, Debug, x86, OpenSSL 1.0.2 + Schannel, Shared, Build-tests & examples'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2013'
PRJ_GEN: 'Visual Studio 9 2008'
TARGET: '-A Win32'
PRJ_CFG: Debug
OPENSSL: 'ON'
SCHANNEL: 'ON'
SHARED: 'ON'
EXAMPLES: 'ON'
- job_name: 'CMake, VS2010, Debug, x64, Schannel, Shared, Build-tests & examples'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 10 2010'
TARGET: '-A x64'
PRJ_CFG: Debug
SCHANNEL: 'ON'
ENABLE_UNICODE: 'OFF'
SHARED: 'ON'
EXAMPLES: 'ON'
- job_name: 'CMake, VS2012, Release, x86, OpenSSL 1.1.1 + Schannel, Shared, Build-tests'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 11 2012'
TARGET: '-A Win32'
PRJ_CFG: Release
OPENSSL: 'ON'
SCHANNEL: 'ON'
ENABLE_UNICODE: 'OFF'
SHARED: 'ON'
- job_name: 'CMake, VS2013, Debug, x64, OpenSSL 1.1.1, Shared, Build-only'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 12 2013'
TARGET: '-A x64'
PRJ_CFG: Debug
OPENSSL: 'ON'
SCHANNEL: 'OFF'
ENABLE_UNICODE: 'OFF'
SHARED: 'ON'
TFLAGS: 'skipall'
- job_name: 'CMake, VS2015, Debug, x64, OpenSSL 1.1.1, Static, Build-only'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 14 2015'
TARGET: '-A x64'
PRJ_CFG: Debug
OPENSSL: 'ON'
SCHANNEL: 'OFF'
ENABLE_UNICODE: 'OFF'
TFLAGS: 'skipall'
- job_name: 'CMake, VS2017, Debug, x64, OpenSSL 1.1.1, Shared, Build-only'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 15 2017'
TARGET: '-A x64'
PRJ_CFG: Debug
OPENSSL: 'ON'
SCHANNEL: 'OFF'
ENABLE_UNICODE: 'OFF'
SHARED: 'ON'
TFLAGS: 'skipall'
- job_name: 'CMake, VS2019, Debug, x64, OpenSSL 1.1.0 + Schannel, Shared, Build-tests'
- job_name: 'CMake, VS2019, Debug, x64, OpenSSL 1.0.2 + Schannel, Shared, Build-tests'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2019'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 16 2019'
TARGET: '-A x64'
PRJ_CFG: Debug
OPENSSL: 'ON'
SCHANNEL: 'ON'
ENABLE_UNICODE: 'OFF'
SHARED: 'ON'
- job_name: 'CMake, VS2022, Debug, x64, Schannel, Static, Unicode, Build-tests & examples, clang-cl'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 17 2022'
TARGET: '-A x64'
PRJ_CFG: Debug
@ -128,6 +137,7 @@ environment:
TOOLSET: 'ClangCl'
- job_name: 'CMake, VS2022, Debug, x64, Schannel, Static, Unicode, Build-tests'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 17 2022'
TARGET: '-A x64'
PRJ_CFG: Debug
@ -135,6 +145,7 @@ environment:
ENABLE_UNICODE: 'ON'
- job_name: 'CMake, VS2022, Release, x64, Schannel, Shared, Unicode, DEBUGBUILD, no-CURLDEBUG, Build-tests'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 17 2022'
TARGET: '-A x64'
PRJ_CFG: Release
@ -144,14 +155,20 @@ environment:
CURLDEBUG: 'OFF'
- job_name: 'CMake, VS2022, Debug, x64, no SSL, Static, Build-tests'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 17 2022'
TARGET: '-A x64'
PRJ_CFG: Debug
SCHANNEL: 'OFF'
ENABLE_UNICODE: 'OFF'
- job_name: 'CMake, VS2022, Debug, x64, no SSL, Static, HTTP only, Build-tests'
APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2022'
BUILD_SYSTEM: CMake
PRJ_GEN: 'Visual Studio 17 2022'
TARGET: '-A x64'
PRJ_CFG: Debug
SCHANNEL: 'OFF'
ENABLE_UNICODE: 'OFF'
HTTP_ONLY: 'ON'
# winbuild-based builds
@ -237,5 +254,5 @@ skip_commits:
#artifacts:
# - path: '**/curl.exe'
# name: curl
# - path: '**/*.dll'
# - path: '**/*curl*.dll'
# name: libcurl dll

View File

@ -21,12 +21,6 @@ CMake's GUIs.
A CMake configuration of curl is similar to the autotools build of curl.
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).
## Using `cmake`
You can configure for in source tree builds or for a build tree
@ -37,14 +31,10 @@ that is apart from the source tree.
$ cmake -B .
- Build in a separate directory (parallel to the curl source tree in this
example). The build directory is created for you. This is recommended over
building in the source tree to separate source and build artifacts.
example). The build directory is created for you.
$ cmake -B ../curl-build
For the full list of CMake build configuration variables see
[the corresponding section](#cmake-build-options).
### Fallback for CMake before version 3.13
CMake before version 3.13 does not support the `-B` option. In that case,
@ -139,12 +129,6 @@ Install to default location (you have to specify the build directory).
$ cmake --install ../curl-build
Do not use `--prefix` to change the installation prefix as the output produced
by the `curl-config` script is determined at CMake configure time. If you want
to set a custom install prefix for curl, set
[`CMAKE_INSTALL_PREFIX`](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
when configuring the CMake build.
### Fallback for CMake before version 3.15
CMake before version 3.15 does not support the `--install` option. In that
@ -155,68 +139,6 @@ assumes that CMake generates `Makefile`:
$ cd ../curl-build
$ make install
# CMake usage
Just as curl can be built and installed using CMake, it can also be used from
CMake.
## Using `find_package`
To locate libcurl from CMake, one can use the standard
[`find_package`](https://cmake.org/cmake/help/latest/command/find_package.html)
command in the typical fashion:
```cmake
find_package(CURL 8.12.0 REQUIRED) # FATAL_ERROR if CURL is not found
```
This invokes the CMake-provided
[FindCURL](https://cmake.org/cmake/help/latest/module/FindCURL.html) find module,
which first performs a search using the `find_package`
[config mode](https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-search-procedure).
This is supported by the `CURLConfig.cmake` CMake config script which is
available if the given CURL was built and installed using CMake.
### Detecting CURL features/protocols
Since version 8.12.0, `CURLConfig.cmake` publishes the supported CURL features
and protocols (see [release notes](https://curl.se/ch/8.12.0.html)). These can
be specified using the `find_package` keywords `COMPONENTS` and
`OPTIONAL_COMPONENTS`, with protocols in all caps, e.g. `HTTPS`, `LDAP`, while
features should be in their original sentence case, e.g. `AsynchDNS`,
`UnixSockets`. If any of the `COMPONENTS` are missing, then CURL is considered
as *not* found.
Here is an example of using `COMPONENTS` and `OPTIONAL_COMPONENTS` in
`find_package` with CURL:
```cmake
# CURL_FOUND is FALSE if no HTTPS but brotli and zstd can be missing
find_package(CURL 8.12.0 COMPONENTS HTTPS OPTIONAL_COMPONENTS brotli zstd)
```
One can also check the defined `CURL_SUPPORTS_<feature-or-protocol>` variables
if a particular feature/protocol is supported. For example:
```cmake
# check HTTPS
if(CURL_SUPPORTS_HTTPS)
message(STATUS "CURL supports HTTPS")
else()
message(STATUS "CURL does NOT support HTTPS")
endif()
```
### Linking against libcurl
To link a CMake target against libcurl one can use
[`target_link_libraries`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)
as usual:
```cmake
target_link_libraries(my_target PRIVATE CURL::libcurl)
```
# CMake build options
- `BUILD_CURL_EXE`: Build curl executable. Default: `ON`
@ -238,7 +160,7 @@ target_link_libraries(my_target PRIVATE CURL::libcurl)
- `CURL_LIBCURL_VERSIONED_SYMBOLS`: Enable libcurl versioned symbols. Default: `OFF`
- `CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX`: Override default versioned symbol prefix. Default: `<TLS-BACKEND>_` or `MULTISSL_`
- `CURL_LTO`: Enable compiler Link Time Optimizations. Default: `OFF`
- `CURL_STATIC_CRT`: Build libcurl with static CRT with MSVC (`/MT`) (requires static or no curl executable). Default: `OFF`
- `CURL_STATIC_CRT`: Build libcurl with static CRT with MSVC (`/MT`). Default: `OFF`
- `CURL_TARGET_WINDOWS_VERSION`: Minimum target Windows version as hex string.
- `CURL_TEST_BUNDLES`: Bundle `libtest` and `unittest` tests into single binaries. Default: `OFF`
- `CURL_WERROR`: Turn compiler warnings into errors. Default: `OFF`
@ -384,7 +306,6 @@ Details via CMake
- `OPENSSL_USE_STATIC_LIBS`: Look for static OpenSSL libraries.
- `ZLIB_INCLUDE_DIR`: The zlib include directory.
- `ZLIB_LIBRARY`: Path to `zlib` library.
- `ZLIB_USE_STATIC_LIBS`: Look for static ZLIB library (requires CMake v3.24).
## Dependency options
@ -458,7 +379,7 @@ Details via CMake
# Migrating from Visual Studio IDE Project Files
We recommend using CMake to build curl with MSVC.
We recommend CMake to build curl with MSVC.
The project build files reside in project/Windows/VC\* for VS2010, VS2010 and
VS2013 respectively.
@ -478,8 +399,8 @@ Configuration element | Equivalent CMake options
`Win32` | `-A Win32`
`DLL` | `BUILD_SHARED_LIBS=ON`, `BUILD_STATIC_LIBS=OFF`, (default)
`LIB` | `BUILD_SHARED_LIBS=OFF`, `BUILD_STATIC_LIBS=ON`
`Debug` | `CMAKE_BUILD_TYPE=Debug` (`-G "NMake Makefiles"` only)
`Release` | `CMAKE_BUILD_TYPE=Release` (`-G "NMake Makefiles"` only)
`Debug` | `CMAKE_BUILD_TYPE=Debug`
`Release` | `CMAKE_BUILD_TYPE=Release`
`DLL Windows SSPI` | `CURL_USE_SCHANNEL=ON` (with SSPI enabled by default)
`DLL OpenSSL` | `CURL_USE_OPENSSL=ON`, optional: `OPENSSL_ROOT_DIR`, `OPENSSL_USE_STATIC_LIBS=ON`
`DLL libssh2` | `CURL_USE_LIBSSH2=ON`, optional: `LIBSSH2_INCLUDE_DIR`, `LIBSSH2_LIBRARY`
@ -493,13 +414,7 @@ For example these commands:
translate to:
> cmake . -G "Visual Studio 12 2013" -A x64 -DCURL_USE_SCHANNEL=ON -DUSE_WIN32_IDN=ON -DCURL_USE_LIBPSL=OFF
> cmake --build . --config Debug --parallel
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`.
> cmake . -G "Visual Studio 12 2013" -A x64 -DCMAKE_BUILD_TYPE=Debug -DCURL_USE_SCHANNEL=ON -DUSE_WIN32_IDN=ON -DCURL_USE_LIBPSL=OFF
# Migrating from winbuild builds
@ -522,7 +437,7 @@ winbuild options | Equivalent CMake options
`DEBUG` | `CMAKE_BUILD_TYPE=Debug`
`GEN_PDB` | `CMAKE_EXE_LINKER_FLAGS=/Fd<path>`, `CMAKE_SHARED_LINKER_FLAGS=/Fd<path>`
`LIB_NAME_DLL`, `LIB_NAME_STATIC` | `IMPORT_LIB_SUFFIX`, `LIBCURL_OUTPUT_NAME`, `STATIC_LIB_SUFFIX`
`VC`: `<N>` | see the CMake [Visual Studio generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators)
`VC` | see CMake `-G` [options](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html)
`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`
@ -552,8 +467,4 @@ For example this command-line:
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`.
> cmake . -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON -DOPENSSL_ROOT_DIR=C:\OpenSSL -DCURL_USE_OPENSSL=ON -DENABLE_UNICODE=ON -DCURL_USE_LIBPSL=OFF

View File

@ -52,7 +52,6 @@ INTERNALDOCS = \
internals/HASH.md \
internals/LLIST.md \
internals/MQTT.md \
internals/MULTI-EV.md \
internals/NEW-PROTOCOL.md \
internals/README.md \
internals/SPLAY.md \

View File

@ -9,7 +9,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
version of curl is compatible with `rustls-ffi` v0.14.x.
version of curl depends on version v0.14.0 of rustls-ffi.
# Building with Rustls
@ -17,7 +17,7 @@ First, [install Rust](https://rustup.rs/).
Next, check out, build, and install the appropriate version of rustls-ffi:
% git clone https://github.com/rustls/rustls-ffi -b v0.14.1
% git clone https://github.com/rustls/rustls-ffi -b v0.14.0
% cd rustls-ffi
% make
% make DESTDIR=${HOME}/rustls-ffi-built/ install

View File

@ -157,4 +157,3 @@ s/edmcln\z/edmcln on github/
s/andrewkirillov-ibm/Andrew Kirillov/
s/\(.*\) via #[0-9]*//
s/jethrogb$/jethrogb on github/
s/on github/on github/i

View File

@ -247,11 +247,11 @@ local system or network, the bar is raised. If a local user wrongfully has
elevated rights on your system enough to attack curl, they can probably
already do much worse harm and the problem is not really in curl.
## Debug & Experiments
## Experiments
Vulnerabilities in features which are off by default (in the build) and
documented as experimental, or exist only in debug mode, are not eligible for a
reward and we do not consider them security problems.
documented as experimental, are not eligible for a reward and we do not
consider them security problems.
## URL inconsistencies

View File

@ -27,10 +27,10 @@ set:
When expanding variables, curl supports a set of functions that can make the
variable contents more convenient to use. It can trim leading and trailing
white space with `trim`, it can output the contents as a JSON quoted string
with `json`, URL encode the string with `url`, base64 encode it with `b64` and
base64 decode it with `64dec`. To apply functions to a variable expansion, add
them colon separated to the right side of the variable. Variable content
holding null bytes that are not encoded when expanded cause error.
with `json`, URL encode the string with `url` or base64 encode it with `b64`.
To apply functions to a variable expansion, add them colon separated to the
right side of the variable. Variable content holding null bytes that are not
encoded when expanded cause error.
Example: get the contents of a file called $HOME/.secret into a variable
called "fix". Make sure that the content is trimmed and percent-encoded when

View File

@ -59,4 +59,4 @@ used.
Doing FTP over an HTTP proxy without --proxytunnel makes curl do HTTP with an
FTP URL over the proxy. For such transfers, common FTP specific options do not
work, including --ssl-reqd and --ftp-ssl-control.
work, including --ftp-ssl-reqd and --ftp-ssl-control.

View File

@ -38,8 +38,5 @@ for you, it is probably not a good idea to use early data for it. curl
cannot deduce what the security implications of your requests actually
are and make this decision for you.
The amount of early data sent can be inspected by using the `--write-out`
variable `tls_earlydata`.
**WARNING**: this option has security implications. See above for more
details.

View File

@ -2,19 +2,16 @@
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: url
Arg: <url/file>
Help: URL(s) to work with
Arg: <url>
Help: URL to work with
Category: curl
Added: 7.5
Multi: append
See-also:
- next
- config
- path-as-is
- disallow-username-in-url
Example:
- --url $URL
- --url @file
---
# `--url`
@ -35,15 +32,3 @@ destination option unless --remote-name-all is used.
On Windows, `file://` accesses can be converted to network accesses by the
operating system.
Starting in curl 8.13.0, curl can be told to download URLs provided in a text
file, one URL per line. It is done by with `--url @filename`: so instead of a
URL, you specify a filename prefixed with the `@` symbol. It can be told to
load the list of URLs from stdin by providing an argument like `@-`.
When downloading URLs given in a file, it implies using --remote-name for each
provided URL. The URLs are full, there is no globbing applied or done on
these. Features such as --skip-existing work fine in combination with this.
Lines in the URL file that start with `#` are treated as comments and are
skipped.

View File

@ -66,45 +66,30 @@ error.
Available functions:
## `trim`
## trim
removes all leading and trailing white space.
Example:
curl --expand-url https://example.com/{{var:trim}}
## `json`
## json
outputs the content using JSON string quoting rules.
Example:
curl --expand-data {{data:json}} https://example.com
## `url`
## url
shows the content URL (percent) encoded.
Example:
curl --expand-url https://example.com/{{path:url}}
## `b64`
## b64
expands the variable base64 encoded
Example:
curl --expand-url https://example.com/{{var:b64}}
## `64dec`
decodes a base64 encoded character sequence. If the sequence is not possible
to decode, it instead outputs `[64dec-fail]`
Example:
curl --expand-url https://example.com/{{var:64dec}}
(Added in 8.13.0)

View File

@ -62,7 +62,7 @@ The variables available are:
## `certs`
Output the certificate chain with details. Supported only by the OpenSSL,
GnuTLS, Schannel, Rustls, and Secure Transport backends. (Added in 7.88.0)
GnuTLS, Schannel and Secure Transport backends. (Added in 7.88.0)
## `conn_id`
The connection identifier last used by the transfer. The connection id is
@ -128,7 +128,7 @@ The http method used in the most recent HTTP request. (Added in 7.72.0)
## `num_certs`
Number of server certificates received in the TLS handshake. Supported only by
the OpenSSL, GnuTLS, Schannel, Rustls and Secure Transport backends.
the OpenSSL, GnuTLS, Schannel and Secure Transport backends.
(Added in 7.88.0)
## `num_connects`
@ -262,12 +262,6 @@ the result.
## `time_total`
The total time, in seconds, that the full operation lasted.
## `tls_earlydata`
The amount of bytes that were sent as TLSv1.3 early data. This is 0
if this TLS feature was not used and negative if the data sent had
been rejected by the server. The use of early data is enabled via
the command line option `--tls-earlydata`. (Added in 8.12.0)
## `url`
The URL that was fetched. (Added in 7.75.0)

View File

@ -24,53 +24,53 @@ displays information about the curl and libcurl installation.
# OPTIONS
## `--ca`
## --ca
Displays the built-in path to the CA cert bundle this libcurl uses.
## `--cc`
## --cc
Displays the compiler used to build libcurl.
## `--cflags`
## --cflags
Set of compiler options (CFLAGS) to use when compiling files that use
libcurl. Currently that is only the include path to the curl include files.
## `--checkfor [version]`
## --checkfor [version]
Specify the oldest possible libcurl version string you want, and this script
returns 0 if the current installation is new enough or it returns 1 and
outputs a text saying that the current version is not new enough. (Added in
7.15.4)
## `--configure`
## --configure
Displays the arguments given to configure when building curl.
## `--feature`
## --feature
Lists what particular main features the installed libcurl was built with. At
the time of writing, this list may include SSL, KRB4 or IPv6. Do not assume
any particular order. The keywords are separated by newlines. There may be
none, one, or several keywords in the list.
## `--help`
## --help
Displays the available options.
## `--libs`
## --libs
Shows the complete set of libs and other linker options you need in order to
link your application with libcurl.
## `--prefix`
## --prefix
This is the prefix used when libcurl was installed. libcurl is then installed
in $prefix/lib and its header files are installed in $prefix/include and so
on. The prefix is set with `configure --prefix`.
on. The prefix is set with "configure --prefix".
## `--protocols`
## --protocols
Lists what particular protocols the installed libcurl was built to support. At
the time of writing, this list may include HTTP, HTTPS, FTP, FTPS, FILE,
@ -78,22 +78,22 @@ TELNET, LDAP, DICT and many more. Do not assume any particular order. The
protocols are listed using uppercase and are separated by newlines. There may
be none, one, or several protocols in the list. (Added in 7.13.0)
## `--ssl-backends`
## --ssl-backends
Lists the SSL backends that were enabled when libcurl was built. It might be
no, one or several names. If more than one name, they appear comma-separated.
(Added in 7.58.0)
## `--static-libs`
## --static-libs
Shows the complete set of libs and other linker options you need in order to
link your application with libcurl statically. (Added in 7.17.1)
## `--version`
## --version
Outputs version information about the installed libcurl.
## `--vernum`
## --vernum
Outputs version information about the installed libcurl, in numerical mode.
This shows the version number, in hexadecimal, using 8 bits for each part:
@ -104,21 +104,22 @@ omitted. (This option was broken in the 7.15.0 release.)
# EXAMPLES
What linker options do I need when I link with libcurl?
$ curl-config --libs
~~~
$ curl-config --libs
~~~
What compiler options do I need when I compile using libcurl functions?
$ curl-config --cflags
~~~
$ curl-config --cflags
~~~
How do I know if libcurl was built with SSL support?
$ curl-config --feature | grep SSL
~~~
$ curl-config --feature | grep SSL
~~~
What's the installed libcurl version?
$ curl-config --version
~~~
$ curl-config --version
~~~
How do I build a single file with a one-line command?
$ `curl-config --cc --cflags` -o example source.c `curl-config --libs`
~~~
$ `curl-config --cc --cflags` -o example source.c `curl-config --libs`
~~~

View File

@ -298,19 +298,14 @@ int main(void)
filter = (struct connection_filter *)calloc(1, sizeof(*filter));
if(!filter)
return 1;
exit(1);
if(curl_global_init(CURL_GLOBAL_DEFAULT)) {
free(filter);
return 1;
}
if(curl_global_init(CURL_GLOBAL_DEFAULT))
exit(1);
curl = curl_easy_init();
if(!curl) {
curl_global_cleanup();
free(filter);
return 1;
}
if(!curl)
exit(1);
/* Set the target URL */
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost");

View File

@ -79,12 +79,12 @@ int main(int argc, char *argv[])
fprintf(stderr,
"\rUsage: %s [-m=1|2|5|10|20|50|100] [-t] [-x] [url]\n",
appname);
return 1;
exit(1);
case 'v':
case 'V':
fprintf(stderr, "\r%s %s - %s\n",
appname, CHKSPEED_VERSION, curl_version());
return 1;
exit(1);
case 'a':
case 'A':
prtall = 1;

View File

@ -34,7 +34,8 @@
#include <curl/curl.h>
#include <curl/mprintf.h>
static int print_cookies(CURL *curl)
static void
print_cookies(CURL *curl)
{
CURLcode res;
struct curl_slist *cookies;
@ -46,7 +47,7 @@ static int print_cookies(CURL *curl)
if(res != CURLE_OK) {
fprintf(stderr, "Curl curl_easy_getinfo failed: %s\n",
curl_easy_strerror(res));
return 1;
exit(1);
}
nc = cookies;
i = 1;
@ -59,8 +60,6 @@ static int print_cookies(CURL *curl)
printf("(none)\n");
}
curl_slist_free_all(cookies);
return 0;
}
int

View File

@ -418,22 +418,22 @@ static int init_fifo(GlobalInfo *g)
struct epoll_event epev;
fprintf(MSG_OUT, "Creating named pipe \"%s\"\n", fifo);
if(lstat(fifo, &st) == 0) {
if(lstat (fifo, &st) == 0) {
if((st.st_mode & S_IFMT) == S_IFREG) {
errno = EEXIST;
perror("lstat");
return 1;
exit(1);
}
}
unlink(fifo);
if(mkfifo(fifo, 0600) == -1) {
if(mkfifo (fifo, 0600) == -1) {
perror("mkfifo");
return 1;
exit(1);
}
sockfd = open(fifo, O_RDWR | O_NONBLOCK, 0);
if(sockfd == -1) {
perror("open");
return 1;
exit(1);
}
g->fifofd = sockfd;
@ -449,9 +449,9 @@ static int init_fifo(GlobalInfo *g)
static void clean_fifo(GlobalInfo *g)
{
epoll_ctl(g->epfd, EPOLL_CTL_DEL, g->fifofd, NULL);
fclose(g->input);
unlink(fifo);
epoll_ctl(g->epfd, EPOLL_CTL_DEL, g->fifofd, NULL);
fclose(g->input);
unlink(fifo);
}
@ -478,13 +478,13 @@ int main(int argc, char **argv)
g.epfd = epoll_create1(EPOLL_CLOEXEC);
if(g.epfd == -1) {
perror("epoll_create1 failed");
return 1;
exit(1);
}
g.tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if(g.tfd == -1) {
perror("timerfd_create failed");
return 1;
exit(1);
}
memset(&its, 0, sizeof(struct itimerspec));
@ -496,8 +496,7 @@ 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))
return 1;
init_fifo(&g);
g.multi = curl_multi_init();
/* setup the generic multi interface options we want */
@ -522,7 +521,7 @@ int main(int argc, char **argv)
}
else {
perror("epoll_wait");
return 1;
exit(1);
}
}

View File

@ -402,22 +402,22 @@ static int init_fifo(GlobalInfo *g)
curl_socket_t sockfd;
fprintf(MSG_OUT, "Creating named pipe \"%s\"\n", fifo);
if(lstat(fifo, &st) == 0) {
if(lstat (fifo, &st) == 0) {
if((st.st_mode & S_IFMT) == S_IFREG) {
errno = EEXIST;
perror("lstat");
return 1;
exit(1);
}
}
unlink(fifo);
if(mkfifo(fifo, 0600) == -1) {
if(mkfifo (fifo, 0600) == -1) {
perror("mkfifo");
return 1;
exit(1);
}
sockfd = open(fifo, O_RDWR | O_NONBLOCK, 0);
if(sockfd == -1) {
perror("open");
return 1;
exit(1);
}
g->input = fdopen(sockfd, "r");
@ -436,8 +436,7 @@ int main(int argc, char **argv)
memset(&g, 0, sizeof(GlobalInfo));
g.loop = ev_default_loop(0);
if(init_fifo(&g))
return 1;
init_fifo(&g);
g.multi = curl_multi_init();
ev_timer_init(&g.timer_event, timer_cb, 0., 0.);

View File

@ -392,21 +392,21 @@ int init_fifo(void)
if((st.st_mode & S_IFMT) == S_IFREG) {
errno = EEXIST;
perror("lstat");
return CURL_SOCKET_BAD;
exit(1);
}
}
unlink(fifo);
if(mkfifo(fifo, 0600) == -1) {
if(mkfifo (fifo, 0600) == -1) {
perror("mkfifo");
return CURL_SOCKET_BAD;
exit(1);
}
socket = open(fifo, O_RDWR | O_NONBLOCK, 0);
if(socket == CURL_SOCKET_BAD) {
if(socket == -1) {
perror("open");
return socket;
exit(1);
}
MSG_OUT("Now, pipe some URL's into > %s\n", fifo);
@ -421,8 +421,6 @@ int main(void)
GIOChannel* ch;
fd = init_fifo();
if(fd == CURL_SOCKET_BAD)
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);

View File

@ -399,22 +399,22 @@ static int init_fifo(GlobalInfo *g)
curl_socket_t sockfd;
fprintf(MSG_OUT, "Creating named pipe \"%s\"\n", fifo);
if(lstat(fifo, &st) == 0) {
if(lstat (fifo, &st) == 0) {
if((st.st_mode & S_IFMT) == S_IFREG) {
errno = EEXIST;
perror("lstat");
return 1;
exit(1);
}
}
unlink(fifo);
if(mkfifo (fifo, 0600) == -1) {
perror("mkfifo");
return 1;
exit(1);
}
sockfd = open(fifo, O_RDWR | O_NONBLOCK, 0);
if(sockfd == -1) {
perror("open");
return 1;
exit(1);
}
g->input = fdopen(sockfd, "r");
@ -440,8 +440,7 @@ int main(int argc, char **argv)
memset(&g, 0, sizeof(GlobalInfo));
g.evbase = event_base_new();
if(init_fifo(&g))
return 1;
init_fifo(&g);
g.multi = curl_multi_init();
evtimer_assign(&g.timer_event, g.evbase, timer_cb, &g);

View File

@ -94,7 +94,7 @@ static bool init(CURL *&conn, const char *url)
if(conn == NULL) {
fprintf(stderr, "Failed to create CURL connection\n");
return false;
exit(EXIT_FAILURE);
}
code = curl_easy_setopt(conn, CURLOPT_ERRORBUFFER, errorBuffer);
@ -270,7 +270,7 @@ int main(int argc, char *argv[])
if(argc != 2) {
fprintf(stderr, "Usage: %s <url>\n", argv[0]);
return EXIT_FAILURE;
exit(EXIT_FAILURE);
}
curl_global_init(CURL_GLOBAL_DEFAULT);
@ -279,7 +279,7 @@ int main(int argc, char *argv[])
if(!init(conn, argv[1])) {
fprintf(stderr, "Connection initialization failed\n");
return EXIT_FAILURE;
exit(EXIT_FAILURE);
}
// Retrieve content for the URL
@ -289,7 +289,7 @@ int main(int argc, char *argv[])
if(code != CURLE_OK) {
fprintf(stderr, "Failed to get '%s' [%s]\n", argv[1], errorBuffer);
return EXIT_FAILURE;
exit(EXIT_FAILURE);
}
// Parse the (assumed) HTML code

View File

@ -142,7 +142,7 @@ int my_trace(CURL *handle, curl_infotype type,
return 0;
}
static int setup(struct transfer *t, int num)
static void setup(struct transfer *t, int num)
{
char filename[128];
CURL *hnd;
@ -155,7 +155,7 @@ static int setup(struct transfer *t, int num)
if(!t->out) {
fprintf(stderr, "error: could not open file %s for writing: %s\n",
filename, strerror(errno));
return 1;
exit(1);
}
/* write to this file */
@ -179,7 +179,6 @@ static int setup(struct transfer *t, int num)
/* wait for pipe connection to confirm */
curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L);
#endif
return 0;
}
/*
@ -205,8 +204,7 @@ int main(int argc, char **argv)
multi_handle = curl_multi_init();
for(i = 0; i < num_transfers; i++) {
if(setup(&trans[i], i))
return 1;
setup(&trans[i], i);
/* add the individual transfer */
curl_multi_add_handle(multi_handle, trans[i].easy);

View File

@ -200,7 +200,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp)
return retcode;
}
static int setup(struct input *i, int num, const char *upload)
static void setup(struct input *i, int num, const char *upload)
{
FILE *out;
char url[256];
@ -209,15 +209,14 @@ static int setup(struct input *i, int num, const char *upload)
curl_off_t uploadsize;
CURL *hnd;
hnd = i->hnd = NULL;
hnd = i->hnd = curl_easy_init();
i->num = num;
curl_msnprintf(filename, 128, "dl-%d", num);
out = fopen(filename, "wb");
if(!out) {
fprintf(stderr, "error: could not open file %s for writing: %s\n", upload,
strerror(errno));
return 1;
exit(1);
}
curl_msnprintf(url, 256, "https://localhost:8443/upload-%d", num);
@ -226,8 +225,7 @@ static int setup(struct input *i, int num, const char *upload)
if(stat(upload, &file_info)) {
fprintf(stderr, "error: could not stat file %s: %s\n", upload,
strerror(errno));
fclose(out);
return 1;
exit(1);
}
uploadsize = file_info.st_size;
@ -236,12 +234,9 @@ static int setup(struct input *i, int num, const char *upload)
if(!i->in) {
fprintf(stderr, "error: could not open file %s for reading: %s\n", upload,
strerror(errno));
fclose(out);
return 1;
exit(1);
}
hnd = i->hnd = curl_easy_init();
/* write to this file */
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out);
@ -274,7 +269,6 @@ static int setup(struct input *i, int num, const char *upload)
/* wait for pipe connection to confirm */
curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L);
#endif
return 0;
}
/*
@ -307,8 +301,7 @@ int main(int argc, char **argv)
multi_handle = curl_multi_init();
for(i = 0; i < num_transfers; i++) {
if(setup(&trans[i], i, filename))
return 1;
setup(&trans[i], i, filename);
/* add the individual transfer */
curl_multi_add_handle(multi_handle, trans[i].hnd);

View File

@ -1,127 +0,0 @@
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
-->
# Multi Event Based
A libcurl multi is operating "event based" when the application uses
and event library like `libuv` to monitor the sockets and file descriptors
libcurl uses to trigger transfer operations. How that works from the
applications point of view is described in libcurl-multi(3).
This documents is about the internal handling.
## Source Locations
All code related to event based handling is found in `lib/multi_ev.c`
and `lib/multi_ev.h`. The header defines a set of internal functions
and `struct curl_multi_ev` that is embedded in each multi handle.
There is `Curl_multi_ev_init()` and `Curl_multi_ev_cleanup()` to manage
the overall life cycle, call on creation and destruction of the multi
handle.
## Tracking Events
First, the various functions in `lib/multi_ev.h` only ever really do
something when the libcurl application has registered its callback
in `multi->socket_cb`.
This is important as this callback gets informed about *changes* to sockets.
When a new socket is added, an existing is removed, or the `POLLIN/OUT`
flags change, `multi->socket_cb` needs to be invoked. `multi_ev` has to
track what it already reported to detect changes.
Most applications are expected to go "event based" right from the start,
but the libcurl API does not prohibit an application to start another
way and then go for events later on, even in the middle of a transfer.
### Transfer Events
Most event that happen are in connection with a transfer. A transfer
opens a connection, which opens a socket, and waits for this socket
to become writable (`POLLOUT`) when using TCP, for example.
The multi then calls `Curl_multi_ev_assess_xfer(multi, data)` to
let the multi event code detect what sockets the transfer is interested in.
If indeed a `multi->socket_cb` is set, the *current* transfer pollset is
retrieved via `Curl_multi_getsock()`. This current pollset is then
compared to the *previous* pollset. If relevant changes are detected,
`multi->socket_cb` gets informed about those. These can be:
* a socket is in the current set, but not the previous one
* a socket was also in the previous one, but IN/OUT flags changed
* a socket in the previous one is no longer part of the current
`multi_ev.c` keeps a `struct mev_sh_entry` for each sockets in a hash
with the socket as key. It tracks in each entry which transfers are
interested in this particular socket. How many transfer want to read
and/or write and what the summarized `POLLIN/POLLOUT` action, that
had been reported to `multi->socket_cb` was.
This is necessary as a socket may be in use by several transfers
at the same time (think HTTP/2 on the same connection). When a transfer
is done and gets removed from the socket entry, it decrements
the reader and/or writer count (depending on what it was last
interested in). This *may* result in the entry's summarized action
to change, or not.
### Connection Events
There are also events not connected to any transfer that need to be tracked.
The multi connection cache, concerned with clean shutdowns of connections,
is interested in socket events during the shutdown.
To allow use of the libcurl infrastructure, the connection cache operates
using an *internal* easy handle that is not a transfer as such. The
internal handle is used for all connection shutdown operations, being tied
to a particular connection only for a short time. This means tracking
the last pollset for an internal handle is useless.
Instead, the connection cache uses `Curl_multi_ev_assess_conn()` to have
multi event handling check the connection and track a "last pollset"
for the connection alone.
## Event Processing
When the libcurl application is informed by the event library that
a particular socket has an event, it calls `curl_multi_socket_action()`
to make libcurl react to it. This internally invokes
`Curl_multi_ev_expire_xfers()` which expires all transfers that
are interested in the given socket, so the multi handle runs them.
In addition `Curl_multi_ev_expire_xfers()` returns a `bool` to let
the multi know that connections are also interested in the socket, so
the connection pool should be informed as well.
## All Things Pass
When a transfer is done, e.g. removed from its multi handle, the
multi calls `Curl_multi_ev_xfer_done()`. This cleans up the pollset
tracking for the transfer.
When a connection is done, and before it is destroyed,
`Curl_multi_ev_conn_done()` is called. This cleans up the pollset
tracking for this connection.
When a socket is about to be closed, `Curl_multi_ev_socket_done()`
is called to cleanup the socket entry and all information kept there.
These calls do not have to happen in any particular order. A transfer's
socket may be around while the transfer is ongoing. Or it might disappear
in the middle of things. Also, a transfer might be interested in several
sockets at the same time (resolving, eye balling, ftp are all examples of
those).
### And Come Again
While transfer and connection identifier are practically unique in a
libcurl application, sockets are not. Operating systems are keen on reusing
their resources, and the next socket may get the same identifier as
one just having been closed with high likelihood.
This means that multi event handling needs to be informed *before* a close,
clean up all its tracking and be ready to see that same socket identifier
again right after.

View File

@ -151,15 +151,6 @@ int Curl_str_casecompare(struct Curl_str *str, const char *check);
Returns true if the provided string in the `str` argument matches the `check`
string case insensitively.
## `Curl_str_cmp`
~~~c
int Curl_str_cmp(struct Curl_str *str, const char *check);
~~~
Returns true if the provided string in the `str` argument matches the `check`
string case sensitively. This is *not* the same return code as `strcmp`.
## `Curl_str_nudge`
~~~c

View File

@ -28,10 +28,11 @@ const struct curl_easyoption *curl_easy_option_by_id(CURLoption id);
# DESCRIPTION
Given a *CURLoption* **id**, this function returns a pointer to the
*curl_easyoption* struct, holding information about the curl_easy_setopt(3)
option using that id. The option id is the `CURLOPT_` prefixed ones provided
in the standard curl/curl.h header file. This function returns the non-alias
version of the cases where there is an alias function as well.
*curl_easyoption* struct, holding information about the
curl_easy_setopt(3) option using that id. The option id is the CURLOPT_
prefix ones provided in the standard curl/curl.h header file. This function
returns the non-alias version of the cases where there is an alias function as
well.
If libcurl has no option with the given id, this function returns NULL.

View File

@ -27,10 +27,11 @@ const struct curl_easyoption *curl_easy_option_by_name(const char *name);
# DESCRIPTION
Given a **name**, this function returns a pointer to the *curl_easyoption*
struct, holding information about the curl_easy_setopt(3) option using that
name. The name should be specified without the `CURLOPT_` prefix and the name
comparison is made case insensitive.
Given a **name**, this function returns a pointer to the
*curl_easyoption* struct, holding information about the
curl_easy_setopt(3) option using that name. The name should be specified
without the "CURLOPT_" prefix and the name comparison is made case
insensitive.
If libcurl has no option with the given name, this function returns NULL.

View File

@ -316,4 +316,4 @@ filenames are now escaped before transmission.
# RETURN VALUE
0 means everything was OK, non-zero means an error occurred corresponding to a
`CURL_FORMADD_*` constant defined in *\<curl/curl.h\>*.
CURL_FORMADD_* constant defined in *\<curl/curl.h\>*.

View File

@ -38,9 +38,9 @@ first argument to the curl_formget_callback function.
size_t len);"
~~~
The *curl_formget_callback* is invoked for each part of the HTTP POST chain.
The character buffer passed to the callback must not be freed. The callback
should return the buffer length passed to it on success.
The curl_formget_callback is invoked for each part of the HTTP POST chain. The
character buffer passed to the callback must not be freed. The callback should
return the buffer length passed to it on success.
If the **CURLFORM_STREAM** option is used in the formpost, it prevents
curl_formget(3) from working until you have performed the actual HTTP request.

View File

@ -101,34 +101,13 @@ trace.
Tracing of DNS operations to resolve hostnames and HTTPS records.
## `lib-ids`
Adds transfer and connection identifiers as prefix to every call to
CURLOPT_DEBUGFUNCTION(3). The format is `[n-m]` where `n` is the identifier
of the transfer and `m` is the identifier of the connection. A literal `x`
is used for internal transfers or when no connection is assigned.
For example, `[5-x]` is the prefix for transfer 5 that has no
connection. The command line tool `curl`uses the same format for its
`--trace-ids` option.
`lib-ids` is intended for libcurl applications that handle multiple
transfers but have no own way to identify in trace output which transfer
a trace event is connected to.
## `doh`
Former name for DNS-over-HTTP operations. Now an alias for `dns`.
## `multi`
Traces multi operations managing transfers' state changes and sockets poll
states.
## `read`
Traces reading of upload data from the application in order to send it to the
server.
Traces reading of upload data from the application in order to send it to the server.
## `ssls`

View File

@ -376,8 +376,9 @@ 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.)
libcurl was built with support for character conversions, as provided by the
CURLOPT_CONV_* callbacks. Always 0 since 7.82.0. (Added in 7.15.4,
deprecated.)
## no name

View File

@ -23,16 +23,16 @@ These variables are intended for internal use only, subject to change and have
many effects on the behavior of libcurl. Refer to the source code to determine
how exactly they are being used.
## `CURL_ALTSVC_HTTP`
## CURL_ALTSVC_HTTP
Bypass the AltSvc HTTPS protocol restriction if this variable exists.
## `CURL_DBG_SOCK_RBLOCK`
## CURL_DBG_SOCK_RBLOCK
The percentage of recv() calls that should be answered with a EAGAIN at random.
For TCP/UNIX sockets.
## `CURL_DBG_SOCK_RMAX`
## CURL_DBG_SOCK_RMAX
The maximum data that shall be received from the network in one recv() call.
For TCP/UNIX sockets. This is applied to every recv.
@ -40,12 +40,12 @@ For TCP/UNIX sockets. This is applied to every recv.
Example: **CURL_DBG_SOCK_RMAX=400** means recv buffer size is limited to a
maximum of 400 bytes.
## `CURL_DBG_SOCK_WBLOCK`
## CURL_DBG_SOCK_WBLOCK
The percentage of send() calls that should be answered with a EAGAIN at random.
For TCP/UNIX sockets.
## `CURL_DBG_SOCK_WPARTIAL`
## CURL_DBG_SOCK_WPARTIAL
The percentage of data that shall be written to the network. For TCP/UNIX
sockets. This is applied to every send.
@ -53,12 +53,12 @@ sockets. This is applied to every send.
Example: **CURL_DBG_SOCK_WPARTIAL=80** means a send with 1000 bytes would
only send 800.
## `CURL_DBG_QUIC_WBLOCK`
## CURL_DBG_QUIC_WBLOCK
The percentage of send() calls that should be answered with EAGAIN at random.
QUIC only.
## `CURL_DEBUG`
## CURL_DEBUG
Trace logging behavior as an alternative to calling curl_global_trace(3).
@ -73,39 +73,39 @@ Example: **CURL_DEBUG=tcp,-http/2 curl -vv url** means trace protocol details,
triggered by `-vv`, add tracing of TCP in addition and remove tracing of
HTTP/2.
## `CURL_DEBUG_SIZE`
## CURL_DEBUG_SIZE
Fake the size returned by CURLINFO_HEADER_SIZE and CURLINFO_REQUEST_SIZE.
## `CURL_GETHOSTNAME`
## CURL_GETHOSTNAME
Fake the local machine's unqualified hostname for NTLM and SMTP.
## `CURL_HSTS_HTTP`
## CURL_HSTS_HTTP
Bypass the HSTS HTTPS protocol restriction if this variable exists.
## `CURL_FORCETIME`
## CURL_FORCETIME
A time of 0 is used for AWS signatures and NTLM if this variable exists.
## `CURL_ENTROPY`
## CURL_ENTROPY
A fixed faked value to use instead of a proper random number so that functions
in libcurl that are otherwise getting random outputs can be tested for what
they generate.
## `CURL_SMALLREQSEND`
## CURL_SMALLREQSEND
An alternative size of HTTP data to be sent at a time only if smaller than the
current.
## `CURL_SMALLSENDS`
## CURL_SMALLSENDS
An alternative size of socket data to be sent at a time only if smaller than
the current.
## `CURL_TIME`
## CURL_TIME
Fake Unix timestamp to use for AltSvc, HSTS and CURLINFO variables that are
time related.
@ -114,34 +114,34 @@ This variable can also be used to fake the data returned by some CURLINFO
variables that are not time-related (such as CURLINFO_LOCAL_PORT), and in that
case the value is not a timestamp.
## `CURL_TRACE`
## CURL_TRACE
LDAP tracing is enabled if this variable exists and its value is 1 or greater.
OpenLDAP tracing is separate. Refer to CURL_OPENLDAP_TRACE.
## `CURL_OPENLDAP_TRACE`
## CURL_OPENLDAP_TRACE
OpenLDAP tracing is enabled if this variable exists and its value is 1 or
greater. There is a number of debug levels, refer to *openldap.c* comments.
## `CURL_WS_CHUNK_SIZE`
## CURL_WS_CHUNK_SIZE
Used to influence the buffer chunk size used for WebSocket encoding and
decoding.
## `CURL_WS_CHUNK_EAGAIN`
## CURL_WS_CHUNK_EAGAIN
Used to simulate blocking sends after this chunk size for WebSocket
connections.
## `CURL_FORBID_REUSE`
## CURL_FORBID_REUSE
Used to set the CURLOPT_FORBID_REUSE flag on each transfer initiated
by the curl command line tool. The value of the environment variable
does not matter.
## `CURL_GRACEFUL_SHUTDOWN`
## CURL_GRACEFUL_SHUTDOWN
Make a blocking, graceful shutdown of all remaining connections when
a multi handle is destroyed. This implicitly triggers for easy handles

View File

@ -15,7 +15,6 @@ TLS-backend:
- GnuTLS
- Schannel
- Secure Transport
- rustls
Added-in: 7.19.1
---

View File

@ -32,7 +32,7 @@ CURLINFO_SCHEME(3) instead, because this option cannot return all
possible protocols.
Pass a pointer to a long to receive the version used in the last http
connection. The returned value is set to one of these values:
connection. The returned value is set to one of the CURLPROTO_* values:
~~~c
CURLPROTO_DICT, CURLPROTO_FILE, CURLPROTO_FTP, CURLPROTO_FTPS,

View File

@ -58,11 +58,12 @@ struct curl_tlssessioninfo {
};
~~~
The *backend* struct member is one of these defines: CURLSSLBACKEND_NONE (when
built without TLS support), CURLSSLBACKEND_WOLFSSL,
CURLSSLBACKEND_SECURETRANSPORT, CURLSSLBACKEND_GNUTLS, CURLSSLBACKEND_MBEDTLS,
CURLSSLBACKEND_NSS, CURLSSLBACKEND_OPENSSL or CURLSSLBACKEND_SCHANNEL. (Note
that the OpenSSL forks are all reported as just OpenSSL here.)
The *backend* struct member is one of the defines in the CURLSSLBACKEND_*
series: CURLSSLBACKEND_NONE (when built without TLS support),
CURLSSLBACKEND_WOLFSSL, CURLSSLBACKEND_SECURETRANSPORT, CURLSSLBACKEND_GNUTLS,
CURLSSLBACKEND_MBEDTLS, CURLSSLBACKEND_NSS, CURLSSLBACKEND_OPENSSL or
CURLSSLBACKEND_SCHANNEL. (Note that the OpenSSL
forks are all reported as just OpenSSL here.)
The *internals* struct member points to a TLS library specific pointer for
the active ("in use") SSL connection, with the following underlying types:

View File

@ -47,11 +47,6 @@ libcurl then expects the application to monitor the sockets for the specific
activities and tell libcurl again when something happens on one of them. Tell
libcurl by calling curl_multi_socket_action(3).
This callback may get invoked at any time when interacting with libcurl.
This may even happen after all transfers are done and is *likely* to
happen *during* a call to curl_multi_cleanup(3) when cached connections
are shut down.
# CALLBACK ARGUMENTS
*easy* identifies the specific transfer for which this update is related.

View File

@ -17,7 +17,6 @@ TLS-backend:
- GnuTLS
- Schannel
- Secure Transport
- rustls
Added-in: 7.19.1
---

View File

@ -42,24 +42,21 @@ header list establishes the document-level MIME headers to prepend to the
uploaded document described by CURLOPT_MIMEPOST(3). This does not affect raw
mail uploads.
When used with HTTP, this option can add new headers, replace internal headers
and remove internal headers.
The linked list should be a valid list of **struct curl_slist** entries
The linked list should be a fully valid list of **struct curl_slist** structs
properly filled in. Use curl_slist_append(3) to create the list and
curl_slist_free_all(3) to free it again after use.
curl_slist_free_all(3) to clean up an entire list. If you add a header that is
otherwise generated and used by libcurl internally, your added header is used
instead. If you add a header with no content as in 'Accept:' (no data on the
right side of the colon), the internally used header is disabled/removed. With
this option you can add new headers, replace internal headers and remove
internal headers. To add a header with no content (nothing to the right side
of the colon), use the form 'name;' (note the ending semicolon).
If you provide a header that is otherwise generated and used by libcurl
internally, your header alternative is used instead. If you provide a header
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).
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
give it, without any filter or other safe guards. That includes white space
and control characters.
The headers included in the linked list **must not** be CRLF-terminated,
because 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 give it, without any filter or other safe guards. That includes
white space and control characters.
The first line in an HTTP request (containing the method, usually a GET or
POST) is not a header and cannot be replaced using this option. Only the lines
@ -167,15 +164,9 @@ int main(void)
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
/* add this header */
list = curl_slist_append(list, "Shoesize: 10");
/* remove this header */
list = curl_slist_append(list, "Accept:");
/* change this header */
list = curl_slist_append(list, "Host: example.net");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_perform(curl);

View File

@ -28,8 +28,8 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MIME_OPTIONS, long options);
# DESCRIPTION
Pass a long that holds a bitmask of options. Each bit is a boolean flag used
while encoding a MIME tree or multipart form data.
Pass a long that holds a bitmask of CURLMIMEOPT_* defines. Each bit is a
Boolean flag used while encoding a MIME tree or multipart form data.
Available bits are:

View File

@ -31,7 +31,7 @@ This option is deprecated. We strongly recommend using
CURLOPT_PROTOCOLS_STR(3) instead because this option cannot control all
available protocols.
Pass a long that holds a bitmask of protocol bits. If used, this bitmask
Pass a long that holds a bitmask of CURLPROTO_* defines. If used, this bitmask
limits what protocols libcurl may use in the transfer. This allows you to have
a libcurl built to support a wide range of protocols but still limit specific
transfers to only be allowed to use a subset of them. By default libcurl

View File

@ -32,10 +32,10 @@ This option is deprecated. We strongly recommend using
CURLOPT_REDIR_PROTOCOLS_STR(3) instead because this option cannot
control all available protocols.
Pass a long that holds a bitmask of protocol bits. If used, this bitmask
Pass a long that holds a bitmask of CURLPROTO_* defines. If used, this bitmask
limits what protocols libcurl may use in a transfer that it follows to in a
redirect when CURLOPT_FOLLOWLOCATION(3) is enabled. This allows you to limit
specific transfers to only be allowed to use a subset of protocols in
redirect when CURLOPT_FOLLOWLOCATION(3) is enabled. This allows you to
limit specific transfers to only be allowed to use a subset of protocols in
redirections.
Protocols denied by CURLOPT_PROTOCOLS(3) are not overridden by this

View File

@ -89,11 +89,11 @@ could be a privacy violation and unexpected.
## CURLSSLOPT_EARLYDATA
Tell libcurl to try sending application data as TLS1.3 early data. This option
is supported for GnuTLS and wolfSSL. This option works on a best effort basis,
is only supported for GnuTLS. This option works on a best effort basis,
in cases when it wasn't possible to send early data the request is resent
normally post-handshake.
This option does not work when using QUIC.
(Added in 8.11.0 for GnuTLS and 8.13.0 for wolfSSL)
(Added in 8.11.0)
# DEFAULT

View File

@ -71,7 +71,7 @@ int main(void)
~~~
If you are on Linux and somehow have a need for paths larger than 107 bytes,
you can use the *proc* filesystem to bypass the limitation:
you can use the proc filesystem to bypass the limitation:
~~~c
int dirfd = open(long_directory_path_to_socket, O_DIRECTORY | O_RDONLY);

View File

@ -81,8 +81,9 @@ int main(void)
# HISTORY
This option was known as CURLOPT_FTP_SSL up to 7.16.4. Supported by LDAP since
7.81.0. Fully supported by the OpenLDAP backend only.
This option was known as CURLOPT_FTP_SSL up to 7.16.4, and the constants were
known as CURLFTPSSL_* Handled by LDAP since 7.81.0. Fully supported by the
OpenLDAP backend only.
# %AVAILABILITY%

View File

@ -51,7 +51,7 @@ stdout
A common technique is to use the write callback to store the incoming data
into a dynamically growing allocated buffer, and then this
CURLOPT_WRITEDATA(3) is used to point to a struct or the buffer to store data
in. Like in the *getinmemory* example:
in. Like in the getinmemory example:
https://curl.se/libcurl/c/getinmemory.html
# HISTORY

View File

@ -45,7 +45,6 @@ CURL_GLOBAL_DEFAULT 7.8
CURL_GLOBAL_NOTHING 7.8
CURL_GLOBAL_SSL 7.8
CURL_GLOBAL_WIN32 7.8.1
CURL_HAS_DECLSPEC_ATTRIBUTE 8.13.0
CURL_HET_DEFAULT 7.59.0
CURL_HTTP_VERSION_1_0 7.9.1
CURL_HTTP_VERSION_1_1 7.9.1

View File

@ -102,6 +102,11 @@
#include <sys/time.h>
#endif
/* Compatibility for non-Clang compilers */
#ifndef __has_declspec_attribute
# define __has_declspec_attribute(x) 0
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -113,17 +118,11 @@ typedef void CURLSH;
* libcurl external API function linkage decorations.
*/
#ifdef __has_declspec_attribute
#define CURL_HAS_DECLSPEC_ATTRIBUTE(x) __has_declspec_attribute(x)
#else
#define CURL_HAS_DECLSPEC_ATTRIBUTE(x) 0
#endif
#ifdef CURL_STATICLIB
# define CURL_EXTERN
#elif defined(_WIN32) || \
(CURL_HAS_DECLSPEC_ATTRIBUTE(dllexport) && \
CURL_HAS_DECLSPEC_ATTRIBUTE(dllimport))
(__has_declspec_attribute(dllexport) && \
__has_declspec_attribute(dllimport))
# if defined(BUILDING_LIBCURL)
# define CURL_EXTERN __declspec(dllexport)
# else
@ -2303,33 +2302,32 @@ enum {
/*
* Public API enums for RTSP requests
*/
#define CURL_RTSPREQ_NONE 0L
#define CURL_RTSPREQ_OPTIONS 1L
#define CURL_RTSPREQ_DESCRIBE 2L
#define CURL_RTSPREQ_ANNOUNCE 3L
#define CURL_RTSPREQ_SETUP 4L
#define CURL_RTSPREQ_PLAY 5L
#define CURL_RTSPREQ_PAUSE 6L
#define CURL_RTSPREQ_TEARDOWN 7L
#define CURL_RTSPREQ_GET_PARAMETER 8L
#define CURL_RTSPREQ_SET_PARAMETER 9L
#define CURL_RTSPREQ_RECORD 10L
#define CURL_RTSPREQ_RECEIVE 11L
#define CURL_RTSPREQ_LAST 12L /* not used */
enum {
CURL_RTSPREQ_NONE, /* first in list */
CURL_RTSPREQ_OPTIONS,
CURL_RTSPREQ_DESCRIBE,
CURL_RTSPREQ_ANNOUNCE,
CURL_RTSPREQ_SETUP,
CURL_RTSPREQ_PLAY,
CURL_RTSPREQ_PAUSE,
CURL_RTSPREQ_TEARDOWN,
CURL_RTSPREQ_GET_PARAMETER,
CURL_RTSPREQ_SET_PARAMETER,
CURL_RTSPREQ_RECORD,
CURL_RTSPREQ_RECEIVE,
CURL_RTSPREQ_LAST /* last in list */
};
/* These enums are for use with the CURLOPT_NETRC option. */
#define CURL_NETRC_IGNORED 0L /* The .netrc will never be read.
This is the default. */
#define CURL_NETRC_OPTIONAL 1L /* A user:password in the URL will be preferred
to one in the .netrc. */
#define CURL_NETRC_REQUIRED 2L /* A user:password in the URL will be ignored.
Unless one is set programmatically, the
.netrc will be queried. */
enum CURL_NETRC_OPTION {
/* we set a single member here, just to make sure we still provide the enum,
but the values to use are defined above with L suffixes */
CURL_NETRC_LAST = 3
CURL_NETRC_IGNORED, /* The .netrc will never be read.
* This is the default. */
CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred
* to one in the .netrc. */
CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored.
* Unless one is set programmatically, the .netrc
* will be queried. */
CURL_NETRC_LAST
};
#define CURL_SSLVERSION_DEFAULT 0
@ -2353,13 +2351,10 @@ enum CURL_NETRC_OPTION {
/* never use, keep last */
#define CURL_SSLVERSION_MAX_LAST (CURL_SSLVERSION_LAST << 16)
#define CURL_TLSAUTH_NONE 0L
#define CURL_TLSAUTH_SRP 1L
enum CURL_TLSAUTH {
/* we set a single member here, just to make sure we still provide the enum,
but the values to use are defined above with L suffixes */
CURL_TLSAUTH_LAST = 2
CURL_TLSAUTH_NONE,
CURL_TLSAUTH_SRP,
CURL_TLSAUTH_LAST /* never use, keep last */
};
/* symbols to use with CURLOPT_POSTREDIR.
@ -2374,16 +2369,14 @@ enum CURL_TLSAUTH {
#define CURL_REDIR_POST_ALL \
(CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303)
#define CURL_TIMECOND_NONE 0L
#define CURL_TIMECOND_IFMODSINCE 1L
#define CURL_TIMECOND_IFUNMODSINCE 2L
#define CURL_TIMECOND_LASTMOD 3L
typedef enum {
/* we set a single member here, just to make sure we still provide
the enum typedef, but the values to use are defined above with L
suffixes */
CURL_TIMECOND_LAST = 4
CURL_TIMECOND_NONE,
CURL_TIMECOND_IFMODSINCE,
CURL_TIMECOND_IFUNMODSINCE,
CURL_TIMECOND_LASTMOD,
CURL_TIMECOND_LAST
} curl_TimeCond;
/* Special size_t value signaling a null-terminated string. */

View File

@ -162,8 +162,7 @@ endif
TIDY := clang-tidy
tidy:
(_csources=`echo ' $(CSOURCES)' | sed -e 's/ +/ /g' -e 's| | $(srcdir)/|g'`; \
$(TIDY) $$_csources $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H)
$(TIDY) $(CSOURCES) $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H
optiontable:
perl optiontable.pl < $(top_srcdir)/include/curl/curl.h > easyoptions.c

View File

@ -198,7 +198,6 @@ LIB_CFILES = \
mprintf.c \
mqtt.c \
multi.c \
multi_ev.c \
netrc.c \
nonblock.c \
noproxy.c \
@ -336,7 +335,6 @@ LIB_HFILES = \
mime.h \
mqtt.h \
multihandle.h \
multi_ev.h \
multiif.h \
netrc.h \
nonblock.h \

View File

@ -407,6 +407,26 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data,
return result;
}
static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen)
{
size_t len;
const char *protop;
const char *p = *ptr;
while(ISBLANK(*p))
p++;
protop = p;
while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '='))
p++;
len = p - protop;
*ptr = p;
if(!len || (len >= buflen))
return CURLE_BAD_FUNCTION_ARGUMENT;
memcpy(alpnbuf, protop, len);
alpnbuf[len] = 0;
return CURLE_OK;
}
/* hostcompare() returns true if 'host' matches 'check'. The first host
* argument may have a trailing dot present that will be ignored.
*/
@ -477,124 +497,144 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
unsigned short srcport)
{
const char *p = value;
char alpnbuf[MAX_ALTSVC_ALPNLEN] = "";
struct altsvc *as;
unsigned short dstport = srcport; /* the same by default */
CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
size_t entries = 0;
struct Curl_str alpn;
const char *sp;
time_t maxage = 24 * 3600; /* default is 24 hours */
bool persist = FALSE;
size_t alpnlen = strlen(alpnbuf);
size_t srchostlen = strlen(srchost);
#ifdef CURL_DISABLE_VERBOSE_STRINGS
(void)data;
#endif
if(result) {
infof(data, "Excessive alt-svc header, ignoring.");
return CURLE_OK;
}
DEBUGASSERT(asi);
/* initial check for "clear" */
if(!Curl_str_until(&p, &alpn, MAX_ALTSVC_LINE, ';') &&
!Curl_str_single(&p, ';')) {
Curl_str_trimblanks(&alpn);
/* "clear" is a magic keyword */
if(Curl_str_casecompare(&alpn, "clear")) {
/* Flush cached alternatives for this source origin */
altsvc_flush(asi, srcalpnid, srchost, srcport);
return CURLE_OK;
}
}
p = value;
if(Curl_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
return CURLE_OK; /* strange line */
Curl_str_trimblanks(&alpn);
/* Handle the optional 'ma' and 'persist' flags once first, as they need to
be known for each alternative service. Unknown flags are skipped. */
sp = strchr(p, ';');
if(sp) {
sp++; /* pass the semicolon */
for(;;) {
struct Curl_str name;
struct Curl_str val;
const char *vp;
curl_off_t num;
bool quoted;
/* allow some extra whitespaces around name and value */
if(Curl_str_until(&sp, &name, 20, '=') ||
Curl_str_single(&sp, '=') ||
Curl_str_until(&sp, &val, 80, ';'))
break;
Curl_str_trimblanks(&name);
Curl_str_trimblanks(&val);
/* the value might be quoted */
vp = Curl_str(&val);
quoted = (*vp == '\"');
if(quoted)
vp++;
if(!Curl_str_number(&vp, &num, TIME_T_MAX)) {
if(Curl_str_casecompare(&name, "ma"))
maxage = (time_t)num;
else if(Curl_str_casecompare(&name, "persist") && (num == 1))
persist = TRUE;
}
if(quoted && Curl_str_single(&sp, '\"'))
break;
if(Curl_str_single(&sp, ';'))
break;
}
/* "clear" is a magic keyword */
if(strcasecompare(alpnbuf, "clear")) {
/* Flush cached alternatives for this source origin */
altsvc_flush(asi, srcalpnid, srchost, srcport);
return CURLE_OK;
}
do {
if(!Curl_str_single(&p, '=')) {
/* [protocol]="[host][:port], [protocol]="[host][:port]" */
enum alpnid dstalpnid =
Curl_alpn2alpnid(Curl_str(&alpn), Curl_strlen(&alpn));
if(!Curl_str_single(&p, '\"')) {
struct Curl_str dsthost;
curl_off_t port = 0;
if(Curl_str_single(&p, ':')) {
if(*p == '=') {
/* [protocol]="[host][:port]" */
enum alpnid dstalpnid = Curl_alpn2alpnid(alpnbuf, alpnlen);
p++;
if(*p == '\"') {
const char *dsthost = "";
size_t dstlen = 0; /* destination hostname length */
const char *value_ptr;
char option[32];
curl_off_t num;
bool quoted = FALSE;
time_t maxage = 24 * 3600; /* default is 24 hours */
bool persist = FALSE;
bool valid = TRUE;
p++;
if(*p != ':') {
/* hostname starts here */
if(Curl_str_single(&p, '[')) {
if(Curl_str_until(&p, &dsthost, MAX_ALTSVC_HOSTLEN, ':')) {
infof(data, "Bad alt-svc hostname, ignoring.");
const char *hostp = p;
if(*p == '[') {
/* pass all valid IPv6 letters - does not handle zone id */
dstlen = strspn(++p, "0123456789abcdefABCDEF:.");
if(p[dstlen] != ']')
/* invalid host syntax, bail out */
break;
}
/* we store the IPv6 numerical address *with* brackets */
dstlen += 2;
p = &p[dstlen-1];
}
else {
/* IPv6 host name */
if(Curl_str_until(&p, &dsthost, MAX_IPADR_LEN, ']') ||
Curl_str_single(&p, ']')) {
infof(data, "Bad alt-svc IPv6 hostname, ignoring.");
break;
}
while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
p++;
dstlen = p - hostp;
}
if(!dstlen || (dstlen >= MAX_ALTSVC_HOSTLEN)) {
infof(data, "Excessive alt-svc hostname, ignoring.");
valid = FALSE;
}
else {
dsthost = hostp;
}
if(Curl_str_single(&p, ':'))
break;
}
else
else {
/* no destination name, use source host */
Curl_str_assign(&dsthost, srchost, strlen(srchost));
if(Curl_str_number(&p, &port, 0xffff)) {
infof(data, "Unknown alt-svc port number, ignoring.");
break;
dsthost = srchost;
dstlen = strlen(srchost);
}
dstport = (unsigned short)port;
if(Curl_str_single(&p, '\"'))
if(*p == ':') {
curl_off_t port = 0;
p++;
if(Curl_str_number(&p, &port, 0xffff) || (*p != '\"')) {
infof(data, "Unknown alt-svc port number, ignoring.");
valid = FALSE;
}
else
dstport = (unsigned short)port;
}
if(*p++ != '\"')
break;
if(dstalpnid) {
/* Handle the optional 'ma' and 'persist' flags. Unknown flags
are skipped. */
for(;;) {
while(ISBLANK(*p))
p++;
if(*p != ';')
break;
p++; /* pass the semicolon */
if(!*p || ISNEWLINE(*p))
break;
result = getalnum(&p, option, sizeof(option));
if(result) {
/* skip option if name is too long */
option[0] = '\0';
}
while(ISBLANK(*p))
p++;
if(*p != '=')
return CURLE_OK;
p++;
while(ISBLANK(*p))
p++;
if(!*p)
return CURLE_OK;
if(*p == '\"') {
/* quoted value */
p++;
quoted = TRUE;
}
value_ptr = p;
if(quoted) {
while(*p && *p != '\"')
p++;
if(!*p++)
return CURLE_OK;
}
else {
while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
p++;
}
if(!Curl_str_number(&value_ptr, &num, TIME_T_MAX)) {
if(strcasecompare("ma", option))
maxage = (time_t)num;
else if(strcasecompare("persist", option) && (num == 1))
persist = TRUE;
}
}
if(dstalpnid && valid) {
if(!entries++)
/* Flush cached alternatives for this source origin, if any - when
this is the first entry of the line. */
altsvc_flush(asi, srcalpnid, srchost, srcport);
as = altsvc_createid(srchost, strlen(srchost),
Curl_str(&dsthost),
Curl_strlen(&dsthost),
as = altsvc_createid(srchost, srchostlen,
dsthost, dstlen,
srcalpnid, dstalpnid,
srcport, dstport);
if(as) {
@ -607,28 +647,26 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
as->expires = maxage + secs;
as->persist = persist;
Curl_llist_append(&asi->list, as, &as->node);
infof(data, "Added alt-svc: %.*s:%d over %s",
(int)Curl_strlen(&dsthost), Curl_str(&dsthost),
dstport, Curl_alpnid2str(dstalpnid));
infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
Curl_alpnid2str(dstalpnid));
}
}
}
else
break;
/* after the double quote there can be a comma if there is another
string or a semicolon if no more */
if(Curl_str_single(&p, ','))
break;
/* comma means another alternative is present */
if(Curl_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
break;
Curl_str_trimblanks(&alpn);
if(*p == ',') {
/* comma means another alternative is presented */
p++;
result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
if(result)
break;
}
}
else
break;
} while(1);
} while(*p && (*p != ';') && (*p != '\n') && (*p != '\r'));
return CURLE_OK;
}

View File

@ -245,7 +245,7 @@ static void sock_state_cb(void *data, ares_socket_t socket_fd,
struct Curl_easy *easy = data;
if(!readable && !writable) {
DEBUGASSERT(easy);
Curl_multi_will_close(easy, socket_fd);
Curl_multi_closed(easy, socket_fd);
}
}
@ -592,7 +592,7 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
res->num_pending--;
if(CURL_ASYNC_SUCCESS == status) {
struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->conn->remote_port);
struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
if(ai) {
compound_results(res, ai);
}
@ -774,6 +774,8 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
if(!res->hostname)
return NULL;
data->state.async.hostname = res->hostname;
data->state.async.port = port;
data->state.async.done = FALSE; /* not done */
data->state.async.dns = NULL; /* clear */
@ -809,7 +811,6 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
service, &hints, addrinfo_cb, data);
}
#else
(void)port;
#ifdef HAVE_CARES_IPV6
if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {

View File

@ -394,13 +394,13 @@ static void destroy_async_data(struct Curl_easy *data)
* ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
* before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
*/
Curl_multi_will_close(data, sock_rd);
Curl_multi_closed(data, sock_rd);
wakeup_close(sock_rd);
#endif
td->init = FALSE;
}
Curl_safefree(async->hostname);
}
#ifdef USE_HTTPSRR_ARES
@ -414,7 +414,7 @@ static CURLcode resolve_httpsrr(struct Curl_easy *data,
memset(&async->thdata.hinfo, 0, sizeof(struct Curl_https_rrinfo));
async->thdata.hinfo.port = -1;
ares_query_dnsrec(async->thdata.channel,
data->conn->host.name, ARES_CLASS_IN,
async->hostname, ARES_CLASS_IN,
ARES_REC_TYPE_HTTPS,
Curl_dnsrec_done_cb, data, NULL);
@ -436,6 +436,7 @@ static bool init_resolve_thread(struct Curl_easy *data,
int err = ENOMEM;
struct Curl_async *async = &data->state.async;
async->port = port;
async->done = FALSE;
async->dns = NULL;
td->thread_hnd = curl_thread_t_null;
@ -446,6 +447,11 @@ static bool init_resolve_thread(struct Curl_easy *data,
goto errno_exit;
}
free(async->hostname);
async->hostname = strdup(hostname);
if(!async->hostname)
goto err_exit;
/* The thread will set this TRUE when complete. */
td->tsd.done = FALSE;

View File

@ -177,7 +177,7 @@ void Curl_resolver_kill(struct Curl_easy *data);
/* Curl_resolver_getsock()
*
* This function is called from the Curl_multi_getsock() function. 'sock' is a
* This function is called from the multi_getsock() function. 'sock' is a
* pointer to an array to hold the file descriptors, with 'numsock' being the
* size of that array (in number of entries). This function is supposed to
* return bitmask indicating what file descriptors (referring to array indexes

View File

@ -422,7 +422,7 @@ static int socket_close(struct Curl_easy *data, struct connectdata *conn,
if(use_callback && conn && conn->fclosesocket) {
int rc;
Curl_multi_will_close(data, sock);
Curl_multi_closed(data, sock);
Curl_set_in_callback(data, TRUE);
rc = conn->fclosesocket(conn->closesocket_client, sock);
Curl_set_in_callback(data, FALSE);
@ -431,7 +431,7 @@ static int socket_close(struct Curl_easy *data, struct connectdata *conn,
if(conn)
/* tell the multi-socket code about this */
Curl_multi_will_close(data, sock);
Curl_multi_closed(data, sock);
sclose(sock);
@ -997,7 +997,7 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
struct cf_socket_ctx *ctx = cf->ctx;
if(ctx && CURL_SOCKET_BAD != ctx->sock) {
CURL_TRC_CF(data, cf, "cf_socket_close, fd=%" FMT_SOCKET_T, ctx->sock);
CURL_TRC_CF(data, cf, "cf_socket_close(%" FMT_SOCKET_T ")", ctx->sock);
if(ctx->sock == cf->conn->sock[cf->sockindex])
cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
@ -1019,7 +1019,7 @@ static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
if(cf->connected) {
struct cf_socket_ctx *ctx = cf->ctx;
CURL_TRC_CF(data, cf, "cf_socket_shutdown, fd=%" FMT_SOCKET_T, ctx->sock);
CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" FMT_SOCKET_T ")", ctx->sock);
/* On TCP, and when the socket looks well and non-blocking mode
* can be enabled, receive dangling bytes before close to avoid
* entering RST states unnecessarily. */

View File

@ -200,8 +200,8 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
*done = FALSE;
now = Curl_now();
if(!Curl_shutdown_started(data, sockindex)) {
CURL_TRC_M(data, "shutdown start on%s connection",
sockindex ? " secondary" : "");
DEBUGF(infof(data, "shutdown start on%s connection",
sockindex ? " secondary" : ""));
Curl_shutdown_start(data, sockindex, &now);
}
else {
@ -476,7 +476,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
/* In general, we want to send after connect, wait on that. */
if(sockfd != CURL_SOCKET_BAD)
Curl_pollset_set_out_only(data, &ps, sockfd);
Curl_conn_adjust_pollset(data, data->conn, &ps);
Curl_conn_adjust_pollset(data, &ps);
result = Curl_pollfds_add_ps(&cpfds, &ps);
if(result)
goto out;
@ -626,15 +626,14 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
}
void Curl_conn_adjust_pollset(struct Curl_easy *data,
struct connectdata *conn,
struct easy_pollset *ps)
struct easy_pollset *ps)
{
int i;
DEBUGASSERT(data);
DEBUGASSERT(conn);
DEBUGASSERT(data->conn);
for(i = 0; i < 2; ++i) {
Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
}
}

View File

@ -455,8 +455,7 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
* Adjust pollset from filters installed at transfer's connection.
*/
void Curl_conn_adjust_pollset(struct Curl_easy *data,
struct connectdata *conn,
struct easy_pollset *ps);
struct easy_pollset *ps);
/**
* Curl_poll() the filter chain at `cf` with timeout `timeout_ms`.

View File

@ -32,7 +32,6 @@
#include "cfilters.h"
#include "progress.h"
#include "multiif.h"
#include "multi_ev.h"
#include "sendf.h"
#include "conncache.h"
#include "http_negotiate.h"
@ -95,8 +94,8 @@ static void cpool_run_conn_shutdown(struct Curl_easy *data,
bool *done);
static void cpool_run_conn_shutdown_handler(struct Curl_easy *data,
struct connectdata *conn);
static CURLMcode cpool_update_shutdown_ev(struct cpool *cpool,
struct Curl_multi *multi,
static CURLMcode cpool_update_shutdown_ev(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn);
static void cpool_shutdown_all(struct cpool *cpool,
struct Curl_easy *data, int timeout_ms);
@ -149,10 +148,10 @@ static void cpool_bundle_free_entry(void *freethis)
}
int Curl_cpool_init(struct cpool *cpool,
Curl_cpool_disconnect_cb *disconnect_cb,
struct Curl_multi *multi,
struct Curl_share *share,
size_t size)
Curl_cpool_disconnect_cb *disconnect_cb,
struct Curl_multi *multi,
struct Curl_share *share,
size_t size)
{
DEBUGASSERT(!!multi != !!share); /* either one */
Curl_hash_init(&cpool->dest2bundle, size, Curl_hash_str,
@ -318,10 +317,10 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
CURL_TRC_M(data, "Discarding connection #%"
DEBUGF(infof(data, "Discarding connection #%"
FMT_OFF_T " from %zu to reach destination "
"limit of %zu", oldest_idle->connection_id,
Curl_llist_count(&bundle->conns), dest_limit);
Curl_llist_count(&bundle->conns), dest_limit));
Curl_cpool_disconnect(data, oldest_idle, FALSE);
/* in case the bundle was destroyed in disconnect, look it up again */
@ -342,10 +341,10 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
CURL_TRC_M(data, "Discarding connection #%"
FMT_OFF_T " from %zu to reach total "
"limit of %zu",
oldest_idle->connection_id, cpool->num_conn, total_limit);
DEBUGF(infof(data, "Discarding connection #%"
FMT_OFF_T " from %zu to reach total "
"limit of %zu",
oldest_idle->connection_id, cpool->num_conn, total_limit));
Curl_cpool_disconnect(data, oldest_idle, FALSE);
shutdowns = Curl_llist_count(&cpool->shutdowns);
}
@ -653,6 +652,8 @@ static void cpool_shutdown_discard_all(struct cpool *cpool)
while(e) {
conn = Curl_node_elem(e);
Curl_node_remove(e);
DEBUGF(infof(cpool->idata, "discard connection #%" FMT_OFF_T,
conn->connection_id));
cpool_close_and_destroy(cpool, conn, NULL, FALSE);
e = Curl_llist_head(&cpool->shutdowns);
}
@ -734,9 +735,9 @@ static void cpool_discard_conn(struct cpool *cpool,
* are other users of it
*/
if(CONN_INUSE(conn) && !aborted) {
CURL_TRC_M(data, "[CPOOL] not discarding #%" FMT_OFF_T
" still in use by %zu transfers", conn->connection_id,
CONN_INUSE(conn));
DEBUGF(infof(data, "[CCACHE] not discarding #%" FMT_OFF_T
" still in use by %zu transfers", conn->connection_id,
CONN_INUSE(conn)));
return;
}
@ -757,7 +758,8 @@ static void cpool_discard_conn(struct cpool *cpool,
/* Attempt to shutdown the connection right away. */
Curl_attach_connection(data, conn);
cpool_run_conn_shutdown(data, conn, &done);
CURL_TRC_M(data, "[CPOOL] shutdown, done=%d", done);
DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
conn->connection_id, done));
Curl_detach_connection(data);
}
@ -771,26 +773,30 @@ static void cpool_discard_conn(struct cpool *cpool,
if(data->multi && data->multi->max_total_connections > 0 &&
(data->multi->max_total_connections <=
(long)(cpool->num_conn + Curl_llist_count(&cpool->shutdowns)))) {
CURL_TRC_M(data, "[CPOOL] discarding oldest shutdown connection "
"due to connection limit of %ld",
data->multi->max_total_connections);
DEBUGF(infof(data, "[CCACHE] discarding oldest shutdown connection "
"due to connection limit of %ld",
data->multi->max_total_connections));
cpool_shutdown_destroy_oldest(cpool);
}
if(data->multi && data->multi->socket_cb) {
DEBUGASSERT(cpool == &data->multi->cpool);
if(cpool_update_shutdown_ev(cpool, data->multi, conn)) {
CURL_TRC_M(data, "[CPOOL] update events failed, discarding #%"
FMT_OFF_T, conn->connection_id);
/* Start with an empty shutdown pollset, so out internal closure handle
* is added to the sockets. */
memset(&conn->shutdown_poll, 0, sizeof(conn->shutdown_poll));
if(cpool_update_shutdown_ev(data->multi, cpool->idata, conn)) {
DEBUGF(infof(data, "[CCACHE] update events for shutdown failed, "
"discarding #%" FMT_OFF_T,
conn->connection_id));
cpool_close_and_destroy(cpool, conn, data, FALSE);
return;
}
}
Curl_llist_append(&cpool->shutdowns, conn, &conn->cpool_node);
CURL_TRC_M(data, "[CPOOL] added #%" FMT_OFF_T
" to shutdowns, now %zu conns in shutdown",
conn->connection_id, Curl_llist_count(&cpool->shutdowns));
DEBUGF(infof(data, "[CCACHE] added #%" FMT_OFF_T
" to shutdowns, now %zu conns in shutdown",
conn->connection_id, Curl_llist_count(&cpool->shutdowns)));
}
void Curl_cpool_disconnect(struct Curl_easy *data,
@ -924,7 +930,7 @@ static CURLcode cpool_add_pollfds(struct cpool *cpool,
conn = Curl_node_elem(e);
memset(&ps, 0, sizeof(ps));
Curl_attach_connection(cpool->idata, conn);
Curl_conn_adjust_pollset(cpool->idata, conn, &ps);
Curl_conn_adjust_pollset(cpool->idata, &ps);
Curl_detach_connection(cpool->idata);
result = Curl_pollfds_add_ps(cpfds, &ps);
@ -965,7 +971,7 @@ unsigned int Curl_cpool_add_waitfds(struct cpool *cpool,
conn = Curl_node_elem(e);
memset(&ps, 0, sizeof(ps));
Curl_attach_connection(cpool->idata, conn);
Curl_conn_adjust_pollset(cpool->idata, conn, &ps);
Curl_conn_adjust_pollset(cpool->idata, &ps);
Curl_detach_connection(cpool->idata);
need += Curl_waitfds_add_ps(cwfds, &ps);
@ -991,7 +997,7 @@ void Curl_cpool_setfds(struct cpool *cpool,
struct connectdata *conn = Curl_node_elem(e);
memset(&ps, 0, sizeof(ps));
Curl_attach_connection(cpool->idata, conn);
Curl_conn_adjust_pollset(cpool->idata, conn, &ps);
Curl_conn_adjust_pollset(cpool->idata, &ps);
Curl_detach_connection(cpool->idata);
for(i = 0; i < ps.num; i++) {
@ -1030,14 +1036,15 @@ static void cpool_perform(struct cpool *cpool)
return;
DEBUGASSERT(data);
CURL_TRC_M(data, "[CPOOL] perform, %zu connections being shutdown",
Curl_llist_count(&cpool->shutdowns));
DEBUGF(infof(data, "[CCACHE] perform, %zu connections being shutdown",
Curl_llist_count(&cpool->shutdowns)));
while(e) {
enext = Curl_node_next(e);
conn = Curl_node_elem(e);
Curl_attach_connection(data, conn);
cpool_run_conn_shutdown(data, conn, &done);
CURL_TRC_M(data, "[CPOOL] shutdown, done=%d", done);
DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
conn->connection_id, done));
Curl_detach_connection(data);
if(done) {
Curl_node_remove(e);
@ -1060,6 +1067,14 @@ static void cpool_perform(struct cpool *cpool)
Curl_expire(data, next_from_now_ms, EXPIRE_RUN_NOW);
}
void Curl_cpool_multi_perform(struct Curl_multi *multi)
{
CPOOL_LOCK(&multi->cpool);
cpool_perform(&multi->cpool);
CPOOL_UNLOCK(&multi->cpool);
}
/*
* Close and destroy the connection. Run the shutdown sequence once,
* of so requested.
@ -1093,7 +1108,8 @@ static void cpool_close_and_destroy(struct cpool *cpool,
}
if(cpool)
CURL_TRC_M(data, "[CPOOL] closing connection");
DEBUGF(infof(data, "[CCACHE] closing #%" FMT_OFF_T,
conn->connection_id));
else
DEBUGF(infof(data, "closing connection #%" FMT_OFF_T,
conn->connection_id));
@ -1101,54 +1117,60 @@ static void cpool_close_and_destroy(struct cpool *cpool,
Curl_conn_close(data, FIRSTSOCKET);
Curl_detach_connection(data);
if(cpool && cpool->multi)
Curl_multi_ev_conn_done(cpool->multi, data, conn);
else if(data->multi)
Curl_multi_ev_conn_done(data->multi, data, conn);
Curl_conn_free(data, conn);
if(cpool && cpool->multi) {
CURL_TRC_M(data, "[CPOOL] trigger multi connchanged");
DEBUGF(infof(data, "[CCACHE] trigger multi connchanged"));
Curl_multi_connchanged(cpool->multi);
}
}
static CURLMcode cpool_update_shutdown_ev(struct cpool *cpool,
struct Curl_multi *multi,
static CURLMcode cpool_update_shutdown_ev(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn)
{
struct easy_pollset ps;
CURLMcode mresult;
DEBUGASSERT(cpool);
DEBUGASSERT(data);
DEBUGASSERT(multi);
DEBUGASSERT(multi->socket_cb);
Curl_attach_connection(cpool->idata, conn);
mresult = Curl_multi_ev_assess_conn(multi, cpool->idata, conn);
Curl_detach_connection(cpool->idata);
memset(&ps, 0, sizeof(ps));
Curl_attach_connection(data, conn);
Curl_conn_adjust_pollset(data, &ps);
Curl_detach_connection(data);
mresult = Curl_multi_pollset_ev(multi, data, &ps, &conn->shutdown_poll);
if(!mresult) /* Remember for next time */
memcpy(&conn->shutdown_poll, &ps, sizeof(ps));
return mresult;
}
static void cpool_multi_socket(struct Curl_multi *multi, curl_socket_t s)
void Curl_cpool_multi_socket(struct Curl_multi *multi,
curl_socket_t s, int ev_bitmask)
{
struct cpool *cpool = &multi->cpool;
struct Curl_easy *data = cpool->idata;
struct Curl_llist_node *e;
struct connectdata *conn;
bool done;
(void)ev_bitmask;
DEBUGASSERT(multi->socket_cb);
CPOOL_LOCK(cpool);
e = Curl_llist_head(&cpool->shutdowns);
while(e) {
conn = Curl_node_elem(e);
if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
Curl_attach_connection(cpool->idata, conn);
cpool_run_conn_shutdown(cpool->idata, conn, &done);
CURL_TRC_M(cpool->idata, "[CPOOL] shutdown, done=%d", done);
Curl_detach_connection(cpool->idata);
if(done || cpool_update_shutdown_ev(cpool, multi, conn)) {
Curl_attach_connection(data, conn);
cpool_run_conn_shutdown(data, conn, &done);
DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
conn->connection_id, done));
Curl_detach_connection(data);
if(done || cpool_update_shutdown_ev(multi, data, conn)) {
Curl_node_remove(e);
cpool_close_and_destroy(cpool, conn, NULL, FALSE);
}
@ -1159,17 +1181,6 @@ static void cpool_multi_socket(struct Curl_multi *multi, curl_socket_t s)
CPOOL_UNLOCK(cpool);
}
void Curl_cpool_multi_perform(struct Curl_multi *multi, curl_socket_t s)
{
CPOOL_LOCK(&multi->cpool);
if((s == CURL_SOCKET_TIMEOUT) || (!multi->socket_cb))
cpool_perform(&multi->cpool);
else
cpool_multi_socket(multi, s);
CPOOL_UNLOCK(&multi->cpool);
}
#define NUM_POLLS_ON_STACK 10
static CURLcode cpool_shutdown_wait(struct cpool *cpool, int timeout_ms)
@ -1201,13 +1212,14 @@ static void cpool_shutdown_all(struct cpool *cpool,
return;
(void)data;
CURL_TRC_M(data, "[CPOOL] shutdown all");
DEBUGF(infof(data, "cpool shutdown all"));
/* Move all connections into the shutdown queue */
for(conn = cpool_get_live_conn(cpool); conn;
conn = cpool_get_live_conn(cpool)) {
/* Move conn from live set to shutdown or destroy right away */
CURL_TRC_M(data, "[CPOOL] moving connection to shutdown queue");
DEBUGF(infof(data, "moving connection #%" FMT_OFF_T
" to shutdown queue", conn->connection_id));
cpool_remove_conn(cpool, conn);
cpool_discard_conn(cpool, data, conn, FALSE);
}
@ -1219,21 +1231,21 @@ static void cpool_shutdown_all(struct cpool *cpool,
cpool_perform(cpool);
if(!Curl_llist_head(&cpool->shutdowns)) {
CURL_TRC_M(data, "[CPOOL] shutdown finished cleanly");
DEBUGF(infof(data, "cpool shutdown ok"));
break;
}
/* wait for activity, timeout or "nothing" */
timespent = Curl_timediff(Curl_now(), started);
if(timespent >= (timediff_t)timeout_ms) {
CURL_TRC_M(data, "[CPOOL] shutdown finished, %s",
(timeout_ms > 0) ? "timeout" : "best effort done");
DEBUGF(infof(data, "cpool shutdown %s",
(timeout_ms > 0) ? "timeout" : "best effort done"));
break;
}
remain_ms = timeout_ms - (int)timespent;
if(cpool_shutdown_wait(cpool, remain_ms)) {
CURL_TRC_M(data, "[CPOOL] shutdown finished, aborted");
DEBUGF(infof(data, "cpool shutdown all, abort"));
break;
}
}

View File

@ -191,9 +191,13 @@ void Curl_cpool_setfds(struct cpool *cpool,
int *maxfd);
/**
* Run connections on socket. If socket is CURL_SOCKET_TIMEOUT, run
* maintenance on all connections.
* Perform maintenance on connections in the pool. Specifically,
* progress the shutdown of connections in the queue.
*/
void Curl_cpool_multi_perform(struct Curl_multi *multi, curl_socket_t s);
void Curl_cpool_multi_perform(struct Curl_multi *multi);
void Curl_cpool_multi_socket(struct Curl_multi *multi,
curl_socket_t s, int ev_bitmask);
#endif /* HEADER_CURL_CONNCACHE_H */

View File

@ -536,9 +536,9 @@ parse_cookie_header(struct Curl_easy *data,
* "the rest". Prefixes must start with '__' and end with a '-', so
* only test for names where that can possibly be true.
*/
if(!strncmp("__Secure-", Curl_str(&name), 9))
if(strncasecompare("__Secure-", Curl_str(&name), 9))
co->prefix_secure = TRUE;
else if(!strncmp("__Host-", Curl_str(&name), 7))
else if(strncasecompare("__Host-", Curl_str(&name), 7))
co->prefix_host = TRUE;
/*

View File

@ -34,9 +34,15 @@
#endif
#else /* HAVE_MEMRCHR */
#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) || \
defined(USE_OPENSSL) || \
defined(USE_SCHANNEL)
void *Curl_memrchr(const void *s, int c, size_t n);
#define memrchr(x,y,z) Curl_memrchr((x),(y),(z))
#endif
#endif /* HAVE_MEMRCHR */
#endif /* HEADER_CURL_MEMRCHR_H */

View File

@ -120,14 +120,6 @@
# endif
#endif
/* Avoid bogus format check warnings with mingw32ce gcc 4.4.0 in
C99 (-std=gnu99) mode */
#if defined(__MINGW32CE__) && !defined(CURL_NO_FMT_CHECKS) && \
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) && \
(defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 4))
#define CURL_NO_FMT_CHECKS
#endif
/* Compatibility */
#ifdef ENABLE_IPV6
#define USE_IPV6 1

View File

@ -53,10 +53,12 @@
#include "curl_memory.h"
#include "memdebug.h"
static void trc_write(struct Curl_easy *data, curl_infotype type,
char *ptr, size_t size)
void Curl_debug(struct Curl_easy *data, curl_infotype type,
char *ptr, size_t size)
{
if(data->set.verbose) {
static const char s_infotype[CURLINFO_END][3] = {
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
if(data->set.fdebug) {
bool inCallback = Curl_is_in_callback(data);
Curl_set_in_callback(data, TRUE);
@ -64,8 +66,6 @@ static void trc_write(struct Curl_easy *data, curl_infotype type,
Curl_set_in_callback(data, inCallback);
}
else {
static const char s_infotype[CURLINFO_END][3] = {
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
switch(type) {
case CURLINFO_TEXT:
case CURLINFO_HEADER_OUT:
@ -80,100 +80,6 @@ static void trc_write(struct Curl_easy *data, curl_infotype type,
}
}
/* max length we trace before ending in '...' */
#define TRC_LINE_MAX 2048
#define CURL_TRC_FMT_IDSC "[x-%" CURL_FORMAT_CURL_OFF_T "] "
#define CURL_TRC_FMT_IDSD "[%" CURL_FORMAT_CURL_OFF_T "-x] "
#define CURL_TRC_FMT_IDSDC "[%" CURL_FORMAT_CURL_OFF_T "-%" \
CURL_FORMAT_CURL_OFF_T "] "
static struct curl_trc_feat Curl_trc_feat_ids = {
"LIB-IDS",
CURL_LOG_LVL_NONE,
};
#define CURL_TRC_IDS(data) \
(Curl_trc_is_verbose(data) && \
Curl_trc_feat_ids.log_level >= CURL_LOG_LVL_INFO)
static size_t trc_print_ids(struct Curl_easy *data, char *buf, size_t maxlen)
{
curl_off_t cid = data->conn ?
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);
else
return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSD, data->id);
}
else if(cid >= 0)
return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSC, cid);
else {
return msnprintf(buf, maxlen, "[x-x] ");
}
}
static size_t trc_end_buf(char *buf, size_t len, size_t maxlen, bool addnl)
{
/* make sure we end the trace line in `buf` properly. It needs
* to end with a terminating '\0' or '\n\0' */
if(len >= (maxlen - (addnl ? 2 : 1))) {
len = maxlen - 5;
buf[len++] = '.';
buf[len++] = '.';
buf[len++] = '.';
buf[len++] = '\n';
}
else if(addnl)
buf[len++] = '\n';
buf[len] = '\0';
return len;
}
void Curl_debug(struct Curl_easy *data, curl_infotype type,
char *ptr, size_t size)
{
if(data->set.verbose) {
static const char s_infotype[CURLINFO_END][3] = {
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
char buf[TRC_LINE_MAX];
size_t len;
if(data->set.fdebug) {
bool inCallback = Curl_is_in_callback(data);
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 = 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);
Curl_set_in_callback(data, inCallback);
}
else {
Curl_set_in_callback(data, TRUE);
(void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
Curl_set_in_callback(data, inCallback);
}
}
else {
switch(type) {
case CURLINFO_TEXT:
case CURLINFO_HEADER_OUT:
case CURLINFO_HEADER_IN:
if(CURL_TRC_IDS(data)) {
len = trc_print_ids(data, buf, TRC_LINE_MAX);
fwrite(buf, len, 1, data->set.err);
}
fwrite(s_infotype[type], 2, 1, data->set.err);
fwrite(ptr, size, 1, data->set.err);
break;
default: /* nada */
break;
}
}
}
}
/* Curl_failf() is for messages stating why we failed.
* The message SHALL NOT include any LF or CR.
@ -183,7 +89,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
DEBUGASSERT(!strchr(fmt, '\n'));
if(data->set.verbose || data->set.errorbuffer) {
va_list ap;
size_t len;
int len;
char error[CURL_ERROR_SIZE + 2];
va_start(ap, fmt);
len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
@ -194,41 +100,36 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
}
error[len++] = '\n';
error[len] = '\0';
trc_write(data, CURLINFO_TEXT, error, len);
Curl_debug(data, CURLINFO_TEXT, error, len);
va_end(ap);
}
}
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* Curl_infof() is for info message along the way */
#define MAXINFO 2048
static void trc_infof(struct Curl_easy *data,
struct curl_trc_feat *feat,
const char *opt_id, int opt_id_idx,
const char * const fmt, va_list ap) CURL_PRINTF(5, 0);
static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
const char * const fmt, va_list ap) CURL_PRINTF(3, 0);
static void trc_infof(struct Curl_easy *data,
struct curl_trc_feat *feat,
const char *opt_id, int opt_id_idx,
static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
const char * const fmt, va_list ap)
{
size_t len = 0;
char buf[TRC_LINE_MAX];
if(CURL_TRC_IDS(data))
len += trc_print_ids(data, buf + len, TRC_LINE_MAX - len);
int len = 0;
char buffer[MAXINFO + 5];
if(feat)
len += 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);
else
len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", opt_id);
len = msnprintf(buffer, (MAXINFO + 1), "[%s] ", feat->name);
len += mvsnprintf(buffer + len, (MAXINFO + 1) - len, fmt, ap);
if(len >= MAXINFO) { /* too long, shorten with '...' */
--len;
buffer[len++] = '.';
buffer[len++] = '.';
buffer[len++] = '.';
}
len += 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);
buffer[len++] = '\n';
buffer[len] = '\0';
Curl_debug(data, CURLINFO_TEXT, buffer, len);
}
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
@ -237,7 +138,7 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_is_verbose(data)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, data->state.feat, NULL, 0, fmt, ap);
trc_infof(data, data->state.feat, fmt, ap);
va_end(ap);
}
}
@ -248,16 +149,25 @@ void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
DEBUGASSERT(cf);
if(Curl_trc_cf_is_verbose(cf, data)) {
va_list ap;
int len = 0;
char buffer[MAXINFO + 2];
if(data->state.feat)
len += msnprintf(buffer + len, MAXINFO - len, "[%s] ",
data->state.feat->name);
if(cf->sockindex)
len += msnprintf(buffer + len, MAXINFO - len, "[%s-%d] ",
cf->cft->name, cf->sockindex);
else
len += msnprintf(buffer + len, MAXINFO - len, "[%s] ", cf->cft->name);
va_start(ap, fmt);
trc_infof(data, data->state.feat, cf->cft->name, cf->sockindex, fmt, ap);
len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
va_end(ap);
buffer[len++] = '\n';
buffer[len] = '\0';
Curl_debug(data, CURLINFO_TEXT, buffer, len);
}
}
struct curl_trc_feat Curl_trc_feat_multi = {
"MULTI",
CURL_LOG_LVL_NONE,
};
struct curl_trc_feat Curl_trc_feat_read = {
"READ",
CURL_LOG_LVL_NONE,
@ -272,54 +182,13 @@ struct curl_trc_feat Curl_trc_feat_dns = {
};
static const char * const Curl_trc_mstate_names[]={
"INIT",
"PENDING",
"SETUP",
"CONNECT",
"RESOLVING",
"CONNECTING",
"TUNNELING",
"PROTOCONNECT",
"PROTOCONNECTING",
"DO",
"DOING",
"DOING_MORE",
"DID",
"PERFORMING",
"RATELIMITING",
"DONE",
"COMPLETED",
"MSGSENT",
};
const char *Curl_trc_mstate_name(int state)
{
if((state >= 0) && ((size_t)state < CURL_ARRAYSIZE(Curl_trc_mstate_names)))
return Curl_trc_mstate_names[(size_t)state];
return "?";
}
void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
{
DEBUGASSERT(!strchr(fmt, '\n'));
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) {
const char *sname = (data->id >= 0) ?
Curl_trc_mstate_name(data->mstate) : NULL;
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_multi, sname, 0, fmt, ap);
va_end(ap);
}
}
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
{
DEBUGASSERT(!strchr(fmt, '\n'));
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_read, NULL, 0, fmt, ap);
trc_infof(data, &Curl_trc_feat_read, fmt, ap);
va_end(ap);
}
}
@ -330,7 +199,7 @@ void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_write, NULL, 0, fmt, ap);
trc_infof(data, &Curl_trc_feat_write, fmt, ap);
va_end(ap);
}
}
@ -341,7 +210,7 @@ void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_dns, NULL, 0, fmt, ap);
trc_infof(data, &Curl_trc_feat_dns, fmt, ap);
va_end(ap);
}
}
@ -358,7 +227,7 @@ void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_ftp, NULL, 0, fmt, ap);
trc_infof(data, &Curl_trc_feat_ftp, fmt, ap);
va_end(ap);
}
}
@ -376,7 +245,7 @@ void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_smtp, NULL, 0, fmt, ap);
trc_infof(data, &Curl_trc_feat_smtp, fmt, ap);
va_end(ap);
}
}
@ -394,7 +263,7 @@ void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_ssls, NULL, 0, fmt, ap);
trc_infof(data, &Curl_trc_feat_ssls, fmt, ap);
va_end(ap);
}
}
@ -412,7 +281,7 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_ws, NULL, 0, fmt, ap);
trc_infof(data, &Curl_trc_feat_ws, fmt, ap);
va_end(ap);
}
}
@ -422,7 +291,6 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
#define TRC_CT_PROTOCOL (1<<(0))
#define TRC_CT_NETWORK (1<<(1))
#define TRC_CT_PROXY (1<<(2))
#define TRC_CT_INTERNALS (1<<(3))
struct trc_feat_def {
struct curl_trc_feat *feat;
@ -430,8 +298,6 @@ struct trc_feat_def {
};
static struct trc_feat_def trc_feats[] = {
{ &Curl_trc_feat_ids, TRC_CT_INTERNALS },
{ &Curl_trc_feat_multi, TRC_CT_NETWORK },
{ &Curl_trc_feat_read, TRC_CT_NONE },
{ &Curl_trc_feat_write, TRC_CT_NONE },
{ &Curl_trc_feat_dns, TRC_CT_NETWORK },
@ -602,11 +468,6 @@ void Curl_trc_cf_infof(struct Curl_easy *data,
struct curl_trc_feat;
void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
{
(void)data; (void)fmt;
}
void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
{
(void)data; (void)fmt;

View File

@ -82,9 +82,6 @@ void Curl_infof(struct Curl_easy *data,
*/
void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
const char *fmt, ...) CURL_PRINTF(3, 4);
void Curl_trc_multi(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);
const char *Curl_trc_mstate_name(int state);
void Curl_trc_write(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);
void Curl_trc_read(struct Curl_easy *data,
@ -117,9 +114,6 @@ void Curl_trc_ws(struct Curl_easy *data,
#define infof(data, ...) \
do { if(Curl_trc_is_verbose(data)) \
Curl_infof(data, __VA_ARGS__); } while(0)
#define CURL_TRC_M(data, ...) \
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) \
Curl_trc_multi(data, __VA_ARGS__); } while(0)
#define CURL_TRC_CF(data, cf, ...) \
do { if(Curl_trc_cf_is_verbose(cf, data)) \
Curl_trc_cf_infof(data, cf, __VA_ARGS__); } while(0)
@ -157,7 +151,6 @@ void Curl_trc_ws(struct Curl_easy *data,
#else /* CURL_HAVE_C99 */
#define infof Curl_infof
#define CURL_TRC_M Curl_trc_multi
#define CURL_TRC_CF Curl_trc_cf_infof
#define CURL_TRC_WRITE Curl_trc_write
#define CURL_TRC_READ Curl_trc_read
@ -178,15 +171,13 @@ void Curl_trc_ws(struct Curl_easy *data,
#endif /* !CURL_HAVE_C99 */
#ifndef CURL_DISABLE_VERBOSE_STRINGS
/* informational messages enabled */
struct curl_trc_feat {
const char *name;
int log_level;
};
#ifndef CURL_DISABLE_VERBOSE_STRINGS
/* informational messages enabled */
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;
@ -201,7 +192,6 @@ extern struct curl_trc_feat Curl_trc_feat_dns;
#define Curl_trc_ft_is_verbose(data, ft) \
(Curl_trc_is_verbose(data) && \
(ft)->log_level >= CURL_LOG_LVL_INFO)
#define CURL_MSTATE_NAME(s) Curl_trc_mstate_name((int)(s))
#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
/* All informational messages are not compiled in for size savings */
@ -209,7 +199,6 @@ extern struct curl_trc_feat Curl_trc_feat_dns;
#define Curl_trc_is_verbose(d) (FALSE)
#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), "-")
#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */

View File

@ -1181,7 +1181,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
if(dohp->probe[DOH_SLOT_IPV4].easy_mid < 0 &&
dohp->probe[DOH_SLOT_IPV6].easy_mid < 0) {
failf(data, "Could not DoH-resolve: %s", dohp->host);
failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
return CONN_IS_PROXIED(data->conn) ? CURLE_COULDNT_RESOLVE_PROXY :
CURLE_COULDNT_RESOLVE_HOST;
}

View File

@ -1195,10 +1195,10 @@ CURLcode curl_easy_pause(CURL *d, int action)
}
out:
if(!result && !data->state.done && keep_changed && data->multi)
/* pause/unpausing may result in multi event changes */
if(Curl_multi_ev_assess_xfer(data->multi, data))
result = CURLE_ABORTED_BY_CALLBACK;
if(!result && !data->state.done && keep_changed)
/* This transfer may have been moved in or out of the bundle, update the
corresponding socket callback, if used */
result = Curl_updatesocket(data);
if(recursive)
/* this might have called a callback recursively which might have set this

View File

@ -76,8 +76,8 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns = Curl_cache_addr(data, ai,
data->conn->host.dispname, 0,
data->conn->localport, FALSE);
data->state.async.hostname, 0,
data->state.async.port, FALSE);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

View File

@ -1480,7 +1480,7 @@ CURLcode Curl_resolver_error(struct Curl_easy *data)
}
failf(data, "Could not resolve %s: %s", host_or_proxy,
data->conn->host.dispname);
data->state.async.hostname);
return result;
}

View File

@ -273,28 +273,46 @@ char *Curl_checkProxyheaders(struct Curl_easy *data,
#endif
/*
* 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
* allocation failure or bad input. Returns an empty string if the header
* value consists entirely of whitespace.
*
* If the header is provided as "name;", ending with a semicolon, it must
* return a blank string.
* Strip off leading and trailing whitespace from the value in the
* given HTTP header line and return a strdupped copy. Returns NULL in
* case of allocation failure. Returns an empty string if the header value
* consists entirely of whitespace.
*/
char *Curl_copy_header_value(const char *header)
{
struct Curl_str out;
const char *start;
const char *end;
size_t len;
/* find the end of the header name */
if(!Curl_str_cspn(&header, &out, ";:") &&
(!Curl_str_single(&header, ':') || !Curl_str_single(&header, ';'))) {
Curl_str_untilnl(&header, &out, MAX_HTTP_RESP_HEADER_SIZE);
Curl_str_trimblanks(&out);
/* Find the end of the header name */
while(*header && (*header != ':'))
++header;
return Curl_memdup0(Curl_str(&out), Curl_strlen(&out));
}
/* bad input */
return NULL;
if(*header)
/* Skip over colon */
++header;
/* Find the first non-space letter */
start = header;
while(ISSPACE(*start))
start++;
end = strchr(start, '\r');
if(!end)
end = strchr(start, '\n');
if(!end)
end = strchr(start, '\0');
if(!end)
return NULL;
/* skip all trailing space letters */
while((end > start) && ISSPACE(*end))
end--;
/* get length of the type */
len = end - start + 1;
return Curl_memdup0(start, len);
}
#ifndef CURL_DISABLE_HTTP_AUTH
@ -996,8 +1014,6 @@ static CURLcode auth_bearer(struct Curl_easy *data,
* Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
* headers. They are dealt with both in the transfer.c main loop and in the
* proxy CONNECT loop.
*
* The 'auth' line ends with a null byte without CR or LF present.
*/
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
const char *auth) /* the first non-space */
@ -1450,8 +1466,9 @@ Curl_compareheader(const char *headerline, /* line to check */
* The field value MAY be preceded by any amount of LWS, though a single SP
* is preferred." */
const char *p;
struct Curl_str val;
size_t len;
const char *start;
const char *end;
DEBUGASSERT(hlen);
DEBUGASSERT(clen);
DEBUGASSERT(header);
@ -1461,21 +1478,31 @@ Curl_compareheader(const char *headerline, /* line to check */
return FALSE; /* does not start with header */
/* pass the header */
p = &headerline[hlen];
start = &headerline[hlen];
if(Curl_str_untilnl(&p, &val, MAX_HTTP_RESP_HEADER_SIZE))
return FALSE;
Curl_str_trimblanks(&val);
/* pass all whitespace */
while(ISSPACE(*start))
start++;
/* find the end of the header line */
end = strchr(start, '\r'); /* lines end with CRLF */
if(!end) {
/* in case there is a non-standard compliant line here */
end = strchr(start, '\n');
if(!end)
/* hm, there is no line ending here, use the zero byte! */
end = strchr(start, '\0');
}
len = end-start; /* length of the content part of the input line */
/* find the content string in the rest of the line */
if(Curl_strlen(&val) >= clen) {
size_t len;
p = Curl_str(&val);
for(len = Curl_strlen(&val); len >= Curl_strlen(&val); len--, p++) {
if(strncasecompare(p, content, clen))
return TRUE; /* match! */
}
for(; len >= clen; len--, start++) {
if(strncasecompare(start, content, clen))
return TRUE; /* match! */
}
return FALSE; /* no match */
}
@ -1594,6 +1621,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
bool is_connect, int httpversion,
struct dynbuf *req)
{
char *ptr;
struct curl_slist *h[2];
struct curl_slist *headers;
int numlists = 1; /* by default */
@ -1633,81 +1661,98 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
/* loop through one or two lists */
for(i = 0; i < numlists; i++) {
for(headers = h[i]; headers; headers = headers->next) {
CURLcode result = CURLE_OK;
bool blankheader = FALSE;
struct Curl_str name;
const char *p = headers->data;
const char *origp = p;
headers = h[i];
/* explicitly asked to send header without content is done by a header
that ends with a semicolon, but there must be no colon present in the
name */
if(!Curl_str_until(&p, &name, MAX_HTTP_RESP_HEADER_SIZE, ';') &&
!Curl_str_single(&p, ';') &&
!Curl_str_single(&p, '\0') &&
!memchr(Curl_str(&name), ':', Curl_strlen(&name)))
blankheader = TRUE;
else {
p = origp;
if(!Curl_str_until(&p, &name, MAX_HTTP_RESP_HEADER_SIZE, ':') &&
!Curl_str_single(&p, ':')) {
struct Curl_str val;
Curl_str_untilnl(&p, &val, MAX_HTTP_RESP_HEADER_SIZE);
Curl_str_trimblanks(&val);
if(!Curl_strlen(&val))
/* no content, don't send this */
continue;
while(headers) {
char *semicolonp = NULL;
ptr = strchr(headers->data, ':');
if(!ptr) {
char *optr;
/* no colon, semicolon? */
ptr = strchr(headers->data, ';');
if(ptr) {
optr = ptr;
ptr++; /* pass the semicolon */
while(ISSPACE(*ptr))
ptr++;
if(*ptr) {
/* this may be used for something else in the future */
optr = NULL;
}
else {
if(*(--ptr) == ';') {
/* copy the source */
semicolonp = strdup(headers->data);
if(!semicolonp) {
Curl_dyn_free(req);
return CURLE_OUT_OF_MEMORY;
}
/* put a colon where the semicolon is */
semicolonp[ptr - headers->data] = ':';
/* point at the colon */
optr = &semicolonp [ptr - headers->data];
}
}
ptr = optr;
}
else
/* no colon */
continue;
}
if(ptr && (ptr != headers->data)) {
/* we require a colon for this to be a true header */
/* only send this if the contents was non-blank or done special */
ptr++; /* pass the colon */
while(ISSPACE(*ptr))
ptr++;
if(data->state.aptr.host &&
/* a Host: header was sent already, do not pass on any custom
Host: header as that will produce *two* in the same
request! */
Curl_str_casecompare(&name, "Host"))
;
else if(data->state.httpreq == HTTPREQ_POST_FORM &&
/* this header (extended by formdata.c) is sent later */
Curl_str_casecompare(&name, "Content-Type"))
;
else if(data->state.httpreq == HTTPREQ_POST_MIME &&
/* this header is sent later */
Curl_str_casecompare(&name, "Content-Type"))
;
else if(data->req.authneg &&
/* while doing auth neg, do not allow the custom length since
we will force length zero then */
Curl_str_casecompare(&name, "Content-Length"))
;
else if(data->state.aptr.te &&
/* when asking for Transfer-Encoding, do not pass on a custom
Connection: */
Curl_str_casecompare(&name, "Connection"))
;
else if((httpversion >= 20) &&
Curl_str_casecompare(&name, "Transfer-Encoding"))
/* HTTP/2 does not support chunked requests */
;
else if((Curl_str_casecompare(&name, "Authorization") ||
Curl_str_casecompare(&name, "Cookie")) &&
/* be careful of sending this potentially sensitive header to
other hosts */
!Curl_auth_allowed_to_host(data))
;
else if(blankheader)
result = Curl_dyn_addf(req, "%.*s:\r\n", (int)Curl_strlen(&name),
Curl_str(&name));
else
result = Curl_dyn_addf(req, "%s\r\n", origp);
if(*ptr || semicolonp) {
/* only send this if the contents was non-blank or done special */
CURLcode result = CURLE_OK;
char *compare = semicolonp ? semicolonp : headers->data;
if(result)
return result;
if(data->state.aptr.host &&
/* a Host: header was sent already, do not pass on any custom
Host: header as that will produce *two* in the same
request! */
checkprefix("Host:", compare))
;
else if(data->state.httpreq == HTTPREQ_POST_FORM &&
/* this header (extended by formdata.c) is sent later */
checkprefix("Content-Type:", compare))
;
else if(data->state.httpreq == HTTPREQ_POST_MIME &&
/* this header is sent later */
checkprefix("Content-Type:", compare))
;
else if(data->req.authneg &&
/* while doing auth neg, do not allow the custom length since
we will force length zero then */
checkprefix("Content-Length:", compare))
;
else if(data->state.aptr.te &&
/* when asking for Transfer-Encoding, do not pass on a custom
Connection: */
checkprefix("Connection:", compare))
;
else if((httpversion >= 20) &&
checkprefix("Transfer-Encoding:", compare))
/* HTTP/2 does not support chunked requests */
;
else if((checkprefix("Authorization:", compare) ||
checkprefix("Cookie:", compare)) &&
/* be careful of sending this potentially sensitive header to
other hosts */
!Curl_auth_allowed_to_host(data))
;
else {
result = Curl_dyn_addf(req, "%s\r\n", compare);
}
if(semicolonp)
free(semicolonp);
if(result)
return result;
}
}
headers = headers->next;
}
}
@ -3940,22 +3985,30 @@ static CURLcode http_rw_hd(struct Curl_easy *data,
}
else if(data->conn->handler->protocol & CURLPROTO_RTSP) {
const char *p = hd;
struct Curl_str ver;
curl_off_t status;
/* we set the max string a little excessive to forgive some leading
spaces */
if(!Curl_str_until(&p, &ver, 32, ' ') &&
!Curl_str_single(&p, ' ') &&
!Curl_str_number(&p, &status, 999)) {
Curl_str_trimblanks(&ver);
if(Curl_str_cmp(&ver, "RTSP/1.0")) {
k->httpcode = (int)status;
fine_statusline = TRUE;
k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
while(ISBLANK(*p))
p++;
if(!strncmp(p, "RTSP/", 5)) {
p += 5;
if(ISDIGIT(*p)) {
p++;
if((p[0] == '.') && ISDIGIT(p[1])) {
if(ISBLANK(p[2])) {
p += 3;
if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
(p[2] - '0');
p += 3;
if(ISSPACE(*p)) {
fine_statusline = TRUE;
k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
}
}
}
}
}
if(!fine_statusline)
return CURLE_WEIRD_SERVER_REPLY;
}
if(!fine_statusline)
return CURLE_WEIRD_SERVER_REPLY;
}
if(fine_statusline) {

View File

@ -36,7 +36,6 @@
#include "share.h"
#include "psl.h"
#include "multiif.h"
#include "multi_ev.h"
#include "sendf.h"
#include "timeval.h"
#include "http.h"
@ -95,6 +94,8 @@
static void move_pending_to_connect(struct Curl_multi *multi,
struct Curl_easy *data);
static CURLMcode singlesocket(struct Curl_multi *multi,
struct Curl_easy *data);
static CURLMcode add_next_timeout(struct curltime now,
struct Curl_multi *multi,
struct Curl_easy *d);
@ -103,6 +104,31 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
long *timeout_ms);
static void process_pending_handles(struct Curl_multi *multi);
static void multi_xfer_bufs_free(struct Curl_multi *multi);
static void expire_ex(struct Curl_easy *data, const struct curltime *nowp,
timediff_t milli, expire_id id);
#if defined( DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
static const char * const multi_statename[]={
"INIT",
"PENDING",
"SETUP",
"CONNECT",
"RESOLVING",
"CONNECTING",
"TUNNELING",
"PROTOCONNECT",
"PROTOCONNECTING",
"DO",
"DOING",
"DOING_MORE",
"DID",
"PERFORMING",
"RATELIMITING",
"DONE",
"COMPLETED",
"MSGSENT",
};
#endif
/* function pointer called once when switching TO a state */
typedef void (*init_multistate_func)(struct Curl_easy *data);
@ -153,18 +179,26 @@ static void mstate(struct Curl_easy *data, CURLMstate state
NULL /* MSGSENT */
};
#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) lineno;
#endif
if(oldstate == state)
/* do not bother when the new state is the same as the old state */
return;
#ifdef DEBUGBUILD
CURL_TRC_M(data, "-> [%s] (line %d)", CURL_MSTATE_NAME(state), lineno);
#else
CURL_TRC_M(data, "-> [%s]", CURL_MSTATE_NAME(state));
#endif
data->mstate = state;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
if(data->mstate >= MSTATE_PENDING &&
data->mstate < MSTATE_COMPLETED) {
infof(data,
"STATE: %s => %s handle %p; line %d",
multi_statename[oldstate], multi_statename[data->mstate],
(void *)data, lineno);
}
#endif
if(state == MSTATE_COMPLETED) {
/* changing to COMPLETED means there is one less easy handle 'alive' */
DEBUGASSERT(data->multi->num_alive > 0);
@ -186,6 +220,163 @@ static void mstate(struct Curl_easy *data, CURLMstate state
#define multistate(x,y) mstate(x,y, __LINE__)
#endif
/*
* We add one of these structs to the sockhash for each socket
*/
struct Curl_sh_entry {
struct Curl_hash transfers; /* hash of transfers using this socket */
unsigned int action; /* what combined action READ/WRITE this socket waits
for */
unsigned int users; /* number of transfers using this */
void *socketp; /* settable by users with curl_multi_assign() */
unsigned int readers; /* this many transfers want to read */
unsigned int writers; /* this many transfers want to write */
};
/* look up a given socket in the socket hash, skip invalid sockets */
static struct Curl_sh_entry *sh_getentry(struct Curl_hash *sh,
curl_socket_t s)
{
if(s != CURL_SOCKET_BAD) {
/* only look for proper sockets */
return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
}
return NULL;
}
#define TRHASH_SIZE 13
/* the given key here is a struct Curl_easy pointer */
static size_t trhash(void *key, size_t key_length, size_t slots_num)
{
unsigned char bytes = ((unsigned char *)key)[key_length - 1] ^
((unsigned char *)key)[0];
return (bytes % slots_num);
}
static size_t trhash_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
{
(void)k2_len;
return !memcmp(k1, k2, k1_len);
}
static void trhash_dtor(void *nada)
{
(void)nada;
}
/*
* The sockhash has its own separate subhash in each entry that need to be
* safely destroyed first.
*/
static void sockhash_destroy(struct Curl_hash *h)
{
struct Curl_hash_iterator iter;
struct Curl_hash_element *he;
DEBUGASSERT(h);
Curl_hash_start_iterate(h, &iter);
he = Curl_hash_next_element(&iter);
while(he) {
struct Curl_sh_entry *sh = (struct Curl_sh_entry *)he->ptr;
Curl_hash_destroy(&sh->transfers);
he = Curl_hash_next_element(&iter);
}
Curl_hash_destroy(h);
}
/* make sure this socket is present in the hash for this handle */
static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh,
curl_socket_t s)
{
struct Curl_sh_entry *there = sh_getentry(sh, s);
struct Curl_sh_entry *check;
if(there) {
/* it is present, return fine */
return there;
}
/* not present, add it */
check = calloc(1, sizeof(struct Curl_sh_entry));
if(!check)
return NULL; /* major failure */
Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare,
trhash_dtor);
/* make/add new hash entry */
if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
Curl_hash_destroy(&check->transfers);
free(check);
return NULL; /* major failure */
}
return check; /* things are good in sockhash land */
}
/* delete the given socket + handle from the hash */
static void sh_delentry(struct Curl_sh_entry *entry,
struct Curl_hash *sh, curl_socket_t s)
{
Curl_hash_destroy(&entry->transfers);
/* We remove the hash entry. This will end up in a call to
sh_freeentry(). */
Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
}
/*
* free a sockhash entry
*/
static void sh_freeentry(void *freethis)
{
struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
free(p);
}
static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
{
(void) k1_len; (void) k2_len;
return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2));
}
static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
{
curl_socket_t fd = *((curl_socket_t *) key);
(void) key_length;
return (fd % (curl_socket_t)slots_num);
}
/*
* sh_init() creates a new socket hash and returns the handle for it.
*
* Quote from README.multi_socket:
*
* "Some tests at 7000 and 9000 connections showed that the socket hash lookup
* is somewhat of a bottle neck. Its current implementation may be a bit too
* limiting. It simply has a fixed-size array, and on each entry in the array
* it has a linked list with entries. The hash only checks which list to scan
* through. The code I had used so for used a list with merely 7 slots (as
* that is what the DNS hash uses) but with 7000 connections that would make
* an average of 1000 nodes in each list to run through. I upped that to 97
* slots (I believe a prime is suitable) and noticed a significant speed
* increase. I need to reconsider the hash implementation or use a rather
* large default value like this. At 9000 connections I was still below 10us
* per call."
*
*/
static void sh_init(struct Curl_hash *hash, size_t hashsize)
{
Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
sh_freeentry);
}
/* multi->proto_hash destructor. Should never be called as elements
* MUST be added with their own destructor */
@ -209,7 +400,7 @@ static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg)
Curl_llist_append(&multi->msglist, msg, &msg->list);
}
struct Curl_multi *Curl_multi_handle(size_t ev_hashsize, /* event hash */
struct Curl_multi *Curl_multi_handle(size_t hashsize, /* socket hash */
size_t chashsize, /* connection hash */
size_t dnssize, /* dns hash */
size_t sesssize) /* TLS session cache */
@ -222,7 +413,8 @@ struct Curl_multi *Curl_multi_handle(size_t ev_hashsize, /* event hash */
multi->magic = CURL_MULTI_HANDLE;
Curl_init_dnscache(&multi->hostcache, dnssize);
Curl_multi_ev_init(multi, ev_hashsize);
sh_init(&multi->sockhash, hashsize);
Curl_hash_init(&multi->proto_hash, 23,
Curl_hash_str, Curl_str_key_compare, ph_freeentry);
@ -260,7 +452,7 @@ struct Curl_multi *Curl_multi_handle(size_t ev_hashsize, /* event hash */
error:
Curl_multi_ev_cleanup(multi);
sockhash_destroy(&multi->sockhash);
Curl_hash_destroy(&multi->proto_hash);
Curl_hash_destroy(&multi->hostcache);
Curl_cpool_destroy(&multi->cpool);
@ -396,7 +588,6 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *d)
Curl_cpool_xfer_init(data);
multi_warn_debug(multi, data);
CURL_TRC_M(data, "added, transfers=%u", multi->num_easy);
return CURLM_OK;
}
@ -430,8 +621,9 @@ static void multi_done_locked(struct connectdata *conn,
if(CONN_INUSE(conn)) {
/* Stop if still used. */
CURL_TRC_M(data, "Connection still in use %zu, no more multi_done now!",
Curl_llist_count(&conn->easyq));
DEBUGF(infof(data, "Connection still in use %zu, "
"no more multi_done now!",
Curl_llist_count(&conn->easyq)));
return;
}
@ -468,12 +660,12 @@ static void multi_done_locked(struct connectdata *conn,
#endif
) || conn->bits.close
|| (mdctx->premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) {
CURL_TRC_M(data, "multi_done, not reusing connection=%"
FMT_OFF_T ", forbid=%d"
", close=%d, premature=%d, conn_multiplex=%d",
conn->connection_id, data->set.reuse_forbid,
conn->bits.close, mdctx->premature,
Curl_conn_is_multiplex(conn, FIRSTSOCKET));
DEBUGF(infof(data, "multi_done, not reusing connection=%"
FMT_OFF_T ", forbid=%d"
", close=%d, premature=%d, conn_multiplex=%d",
conn->connection_id, data->set.reuse_forbid,
conn->bits.close, mdctx->premature,
Curl_conn_is_multiplex(conn, FIRSTSOCKET)));
connclose(conn, "disconnecting");
Curl_cpool_disconnect(data, conn, mdctx->premature);
}
@ -511,8 +703,14 @@ static CURLcode multi_done(struct Curl_easy *data,
memset(&mdctx, 0, sizeof(mdctx));
CURL_TRC_M(data, "multi_done: status: %d prem: %d done: %d",
(int)status, (int)premature, data->state.done);
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
DEBUGF(infof(data, "multi_done[%s]: status: %d prem: %d done: %d",
multi_statename[data->mstate],
(int)status, (int)premature, data->state.done));
#else
DEBUGF(infof(data, "multi_done: status: %d prem: %d done: %d",
(int)status, (int)premature, data->state.done));
#endif
if(data->state.done)
/* Stop if multi_done() has already been called */
@ -663,14 +861,18 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d)
Curl_wildcard_dtor(&data->wildcard);
/* change state without using multistate(), only to make singlesocket() do
what we want */
data->mstate = MSTATE_COMPLETED;
/* This ignores the return code even in case of problems because there is
nothing more to do about that, here */
(void)singlesocket(multi, data); /* to let the application know what sockets
that vanish with this handle */
/* Remove the association between the connection and the handle */
Curl_detach_connection(data);
/* Tell event handling that this transfer is definitely going away */
Curl_multi_ev_xfer_done(multi, data);
if(data->set.connect_only && !data->multi_easy) {
/* This removes a handle that was part the multi interface that used
CONNECT_ONLY, that connection is now left alive but since this handle
@ -725,8 +927,6 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d)
if(rc)
return rc;
}
CURL_TRC_M(data, "removed, transfers=%u", multi->num_easy);
return CURLM_OK;
}
@ -868,15 +1068,13 @@ static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
/* Initializes `poll_set` with the current socket poll actions needed
* for transfer `data`. */
void Curl_multi_getsock(struct Curl_easy *data,
struct easy_pollset *ps,
const char *caller)
static void multi_getsock(struct Curl_easy *data,
struct easy_pollset *ps)
{
bool expect_sockets = TRUE;
/* If the transfer has no connection, this is fine. Happens when
called via curl_multi_remove_handle() => Curl_multi_ev_assess() =>
Curl_multi_getsock(). */
/* The no connection case can happen when this is called from
curl_multi_remove_handle() => singlesocket() => multi_getsock().
*/
Curl_pollset_reset(data, ps);
if(!data->conn)
return;
@ -900,30 +1098,30 @@ void Curl_multi_getsock(struct Curl_easy *data,
case MSTATE_CONNECTING:
case MSTATE_TUNNELING:
Curl_pollset_add_socks(data, ps, connecting_getsock);
Curl_conn_adjust_pollset(data, data->conn, ps);
Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_PROTOCONNECT:
case MSTATE_PROTOCONNECTING:
Curl_pollset_add_socks(data, ps, protocol_getsock);
Curl_conn_adjust_pollset(data, data->conn, ps);
Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_DO:
case MSTATE_DOING:
Curl_pollset_add_socks(data, ps, doing_getsock);
Curl_conn_adjust_pollset(data, data->conn, ps);
Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_DOING_MORE:
Curl_pollset_add_socks(data, ps, domore_getsock);
Curl_conn_adjust_pollset(data, data->conn, ps);
Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_DID: /* same as PERFORMING in regard to polling */
case MSTATE_PERFORMING:
Curl_pollset_add_socks(data, ps, perform_getsock);
Curl_conn_adjust_pollset(data, data->conn, ps);
Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_RATELIMITING:
@ -945,35 +1143,6 @@ void Curl_multi_getsock(struct Curl_easy *data,
break;
}
switch(ps->num) {
case 0:
CURL_TRC_M(data, "%s pollset[], timeouts=%zu, paused %d/%d (r/w)",
caller, Curl_llist_count(&data->state.timeoutlist),
Curl_creader_is_paused(data), Curl_cwriter_is_paused(data));
break;
case 1:
CURL_TRC_M(data, "%s pollset[fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu",
caller, ps->sockets[0],
(ps->actions[0] & CURL_POLL_IN) ? "IN" : "",
(ps->actions[0] & CURL_POLL_OUT) ? "OUT" : "",
Curl_llist_count(&data->state.timeoutlist));
break;
case 2:
CURL_TRC_M(data, "%s pollset[fd=%" FMT_SOCKET_T " %s%s, "
"fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu",
caller, ps->sockets[0],
(ps->actions[0] & CURL_POLL_IN) ? "IN" : "",
(ps->actions[0] & CURL_POLL_OUT) ? "OUT" : "",
ps->sockets[1],
(ps->actions[1] & CURL_POLL_IN) ? "IN" : "",
(ps->actions[1] & CURL_POLL_OUT) ? "OUT" : "",
Curl_llist_count(&data->state.timeoutlist));
break;
default:
CURL_TRC_M(data, "%s pollset[fds=%u], timeouts=%zu",
caller, ps->num, Curl_llist_count(&data->state.timeoutlist));
break;
}
if(expect_sockets && !ps->num &&
!Curl_llist_count(&data->state.timeoutlist) &&
!Curl_cwriter_is_paused(data) && !Curl_creader_is_paused(data) &&
@ -1008,27 +1177,26 @@ CURLMcode curl_multi_fdset(CURLM *m,
for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
struct easy_pollset ps;
Curl_multi_getsock(data, &ps, "curl_multi_fdset");
multi_getsock(data, &data->last_poll);
for(i = 0; i < ps.num; i++) {
if(!FDSET_SOCK(ps.sockets[i]))
for(i = 0; i < data->last_poll.num; i++) {
if(!FDSET_SOCK(data->last_poll.sockets[i]))
/* pretend it does not exist */
continue;
#if defined(__DJGPP__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warith-conversion"
#endif
if(ps.actions[i] & CURL_POLL_IN)
FD_SET(ps.sockets[i], read_fd_set);
if(ps.actions[i] & CURL_POLL_OUT)
FD_SET(ps.sockets[i], write_fd_set);
if(data->last_poll.actions[i] & CURL_POLL_IN)
FD_SET(data->last_poll.sockets[i], read_fd_set);
if(data->last_poll.actions[i] & CURL_POLL_OUT)
FD_SET(data->last_poll.sockets[i], write_fd_set);
#if defined(__DJGPP__)
#pragma GCC diagnostic pop
#endif
if((int)ps.sockets[i] > this_max_fd)
this_max_fd = (int)ps.sockets[i];
if((int)data->last_poll.sockets[i] > this_max_fd)
this_max_fd = (int)data->last_poll.sockets[i];
}
}
@ -1062,10 +1230,8 @@ CURLMcode curl_multi_waitfds(CURLM *m,
Curl_waitfds_init(&cwfds, ufds, size);
for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
struct easy_pollset ps;
Curl_multi_getsock(data, &ps, "curl_multi_waitfds");
need += Curl_waitfds_add_ps(&cwfds, &ps);
multi_getsock(data, &data->last_poll);
need += Curl_waitfds_add_ps(&cwfds, &data->last_poll);
}
need += Curl_cpool_add_waitfds(&multi->cpool, &cwfds);
@ -1137,10 +1303,9 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
/* Add the curl handles to our pollfds first */
for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
struct easy_pollset ps;
Curl_multi_getsock(data, &ps, "multi_wait");
if(Curl_pollfds_add_ps(&cpfds, &ps)) {
multi_getsock(data, &data->last_poll);
if(Curl_pollfds_add_ps(&cpfds, &data->last_poll)) {
result = CURLM_OUT_OF_MEMORY;
goto out;
}
@ -1275,14 +1440,23 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
#ifdef USE_WINSOCK
/* Count up all our own sockets that had activity,
and remove them from the event. */
for(i = 0; i < curl_nfds; ++i) {
wsa_events.lNetworkEvents = 0;
if(WSAEnumNetworkEvents(cpfds.pfds[i].fd, NULL, &wsa_events) == 0) {
if(ret && !pollrc && wsa_events.lNetworkEvents)
retcode++;
if(curl_nfds) {
for(e = Curl_llist_head(&multi->process); e && !result;
e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
for(i = 0; i < data->last_poll.num; i++) {
wsa_events.lNetworkEvents = 0;
if(WSAEnumNetworkEvents(data->last_poll.sockets[i], NULL,
&wsa_events) == 0) {
if(ret && !pollrc && wsa_events.lNetworkEvents)
retcode++;
}
WSAEventSelect(data->last_poll.sockets[i], multi->wsa_event, 0);
}
}
WSAEventSelect(cpfds.pfds[i].fd, multi->wsa_event, 0);
}
WSAResetEvent(multi->wsa_event);
#else
#ifdef ENABLE_WAKEUP
@ -2072,7 +2246,7 @@ static CURLMcode state_resolving(struct Curl_multi *multi,
socket(s) will again be used further down. If the name has not yet been
resolved, it is likely that new sockets have been opened in an attempt to
contact another resolver. */
rc = Curl_multi_ev_assess_xfer(multi, data);
rc = singlesocket(multi, data);
if(rc)
return rc;
@ -2191,7 +2365,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_OK;
if(multi_ischanged(multi, TRUE)) {
CURL_TRC_M(data, "multi changed, check CONNECT_PEND queue");
DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue"));
process_pending_handles(multi); /* multiplexed */
}
@ -2557,7 +2731,6 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
struct Curl_llist_node *e;
struct Curl_llist_node *n = NULL;
struct Curl_multi *multi = m;
bool first = TRUE;
SIGPIPE_VARIABLE(pipe_st);
if(!GOOD_MULTI_HANDLE(multi))
@ -2572,16 +2745,12 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
CURLMcode result;
/* Do the loop and only alter the signal ignore state if the next handle
has a different NO_SIGNAL state than the previous */
if(first) {
CURL_TRC_M(data, "multi_perform(running=%u)", multi->num_alive);
first = FALSE;
}
/* the current node might be unlinked in multi_runsingle(), get the next
pointer now */
n = Curl_node_next(e);
if(data && data != multi->cpool.idata) {
if(data != multi->cpool.idata) {
/* connection pool handle is processed below */
sigpipe_apply(data, &pipe_st);
result = multi_runsingle(multi, &now, data);
@ -2591,7 +2760,7 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
}
sigpipe_apply(multi->cpool.idata, &pipe_st);
Curl_cpool_multi_perform(multi, CURL_SOCKET_TIMEOUT);
Curl_cpool_multi_perform(multi);
sigpipe_restore(&pipe_st);
if(multi_ischanged(m, TRUE))
@ -2693,7 +2862,7 @@ CURLMcode curl_multi_cleanup(CURLM *m)
multi->magic = 0; /* not good anymore */
Curl_multi_ev_cleanup(multi);
sockhash_destroy(&multi->sockhash);
Curl_hash_destroy(&multi->proto_hash);
Curl_hash_destroy(&multi->hostcache);
Curl_psl_destroy(&multi->psl);
@ -2756,14 +2925,233 @@ CURLMsg *curl_multi_info_read(CURLM *m, int *msgs_in_queue)
return NULL;
}
/*
* singlesocket() checks what sockets we deal with and their "action state"
* and if we have a different state in any of those sockets from last time we
* call the callback accordingly.
*/
static CURLMcode singlesocket(struct Curl_multi *multi,
struct Curl_easy *data)
{
struct easy_pollset cur_poll;
CURLMcode mresult;
void Curl_multi_will_close(struct Curl_easy *data, curl_socket_t s)
/* Fill in the 'current' struct with the state as it is now: what sockets to
supervise and for what actions */
multi_getsock(data, &cur_poll);
mresult = Curl_multi_pollset_ev(multi, data, &cur_poll, &data->last_poll);
if(!mresult) /* Remember for next time */
memcpy(&data->last_poll, &cur_poll, sizeof(cur_poll));
return mresult;
}
CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
struct Curl_easy *data,
struct easy_pollset *ps,
struct easy_pollset *last_ps)
{
unsigned int i;
struct Curl_sh_entry *entry;
curl_socket_t s;
int rc;
/* We have 0 .. N sockets already and we get to know about the 0 .. M
sockets we should have from now on. Detect the differences, remove no
longer supervised ones and add new ones */
/* walk over the sockets we got right now */
for(i = 0; i < ps->num; i++) {
unsigned char cur_action = ps->actions[i];
unsigned char last_action = 0;
int comboaction;
s = ps->sockets[i];
/* get it from the hash */
entry = sh_getentry(&multi->sockhash, s);
if(entry) {
/* check if new for this transfer */
unsigned int j;
for(j = 0; j < last_ps->num; j++) {
if(s == last_ps->sockets[j]) {
last_action = last_ps->actions[j];
break;
}
}
}
else {
/* this is a socket we did not have before, add it to the hash! */
entry = sh_addentry(&multi->sockhash, s);
if(!entry)
/* fatal */
return CURLM_OUT_OF_MEMORY;
}
if(last_action && (last_action != cur_action)) {
/* Socket was used already, but different action now */
if(last_action & CURL_POLL_IN) {
DEBUGASSERT(entry->readers);
entry->readers--;
}
if(last_action & CURL_POLL_OUT) {
DEBUGASSERT(entry->writers);
entry->writers--;
}
if(cur_action & CURL_POLL_IN) {
entry->readers++;
}
if(cur_action & CURL_POLL_OUT)
entry->writers++;
}
else if(!last_action &&
!Curl_hash_pick(&entry->transfers, (char *)&data, /* hash key */
sizeof(struct Curl_easy *))) {
DEBUGASSERT(entry->users < 100000); /* detect weird values */
/* a new transfer using this socket */
entry->users++;
if(cur_action & CURL_POLL_IN)
entry->readers++;
if(cur_action & CURL_POLL_OUT)
entry->writers++;
/* add 'data' to the transfer hash on this socket! */
if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
sizeof(struct Curl_easy *), data)) {
Curl_hash_destroy(&entry->transfers);
return CURLM_OUT_OF_MEMORY;
}
}
comboaction = (entry->writers ? CURL_POLL_OUT : 0) |
(entry->readers ? CURL_POLL_IN : 0);
/* socket existed before and has the same action set as before */
if(last_action && ((int)entry->action == comboaction))
/* same, continue */
continue;
if(multi->socket_cb) {
set_in_callback(multi, TRUE);
rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
entry->socketp);
set_in_callback(multi, FALSE);
if(rc == -1) {
multi->dead = TRUE;
return CURLM_ABORTED_BY_CALLBACK;
}
}
/* store the current action state */
entry->action = (unsigned int)comboaction;
}
/* Check for last_poll.sockets that no longer appear in ps->sockets.
* Need to remove the easy handle from the multi->sockhash->transfers and
* remove multi->sockhash entry when this was the last transfer */
for(i = 0; i < last_ps->num; i++) {
unsigned int j;
bool stillused = FALSE;
s = last_ps->sockets[i];
for(j = 0; j < ps->num; j++) {
if(s == ps->sockets[j]) {
/* this is still supervised */
stillused = TRUE;
break;
}
}
if(stillused)
continue;
entry = sh_getentry(&multi->sockhash, s);
/* if this is NULL here, the socket has been closed and notified so
already by Curl_multi_closed() */
if(entry) {
unsigned char oldactions = last_ps->actions[i];
/* this socket has been removed. Decrease user count */
DEBUGASSERT(entry->users);
entry->users--;
if(oldactions & CURL_POLL_OUT)
entry->writers--;
if(oldactions & CURL_POLL_IN)
entry->readers--;
if(!entry->users) {
bool dead = FALSE;
if(multi->socket_cb) {
set_in_callback(multi, TRUE);
rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
multi->socket_userp, entry->socketp);
set_in_callback(multi, FALSE);
if(rc == -1)
dead = TRUE;
}
sh_delentry(entry, &multi->sockhash, s);
if(dead) {
multi->dead = TRUE;
return CURLM_ABORTED_BY_CALLBACK;
}
}
else {
/* still users, but remove this handle as a user of this socket */
if(Curl_hash_delete(&entry->transfers, (char *)&data,
sizeof(struct Curl_easy *))) {
DEBUGASSERT(NULL);
}
}
}
} /* for loop over num */
return CURLM_OK;
}
CURLcode Curl_updatesocket(struct Curl_easy *data)
{
if(singlesocket(data->multi, data))
return CURLE_ABORTED_BY_CALLBACK;
return CURLE_OK;
}
/*
* Curl_multi_closed()
*
* Used by the connect code to tell the multi_socket code that one of the
* sockets we were using is about to be closed. This function will then
* remove it from the sockethash for this handle to make the multi_socket API
* behave properly, especially for the case when libcurl will create another
* socket again and it gets the same file descriptor number.
*/
void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s)
{
if(data) {
/* if there is still an easy handle associated with this connection */
struct Curl_multi *multi = data->multi;
DEBUGF(infof(data, "Curl_multi_closed, fd=%" FMT_SOCKET_T
" multi is %p", s, (void *)multi));
if(multi) {
CURL_TRC_M(data, "Curl_multi_will_close fd=%" FMT_SOCKET_T, s);
Curl_multi_ev_socket_done(multi, data, s);
/* this is set if this connection is part of a handle that is added to
a multi handle, and only then this is necessary */
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
DEBUGF(infof(data, "Curl_multi_closed, fd=%" FMT_SOCKET_T
" entry is %p", s, (void *)entry));
if(entry) {
int rc = 0;
if(multi->socket_cb) {
set_in_callback(multi, TRUE);
rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
multi->socket_userp, entry->socketp);
set_in_callback(multi, FALSE);
}
/* now remove it from the socket hash */
sh_delentry(entry, &multi->sockhash, s);
if(rc == -1)
/* This just marks the multi handle as "dead" without returning an
error code primarily because this function is used from many
places where propagating an error back is tricky. */
multi->dead = TRUE;
}
}
}
}
@ -2865,8 +3253,9 @@ static CURLMcode multi_run_expired(struct multi_run_ctx *mrc)
result = multi_runsingle(multi, &mrc->now, data);
if(CURLM_OK >= result) {
/* reassess event handling of data */
result = Curl_multi_ev_assess_xfer(multi, data);
/* get the socket(s) and check if the state has been changed since
last */
result = singlesocket(multi, data);
if(result)
goto out;
}
@ -2882,6 +3271,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
int *running_handles)
{
CURLMcode result = CURLM_OK;
struct Curl_easy *data = NULL;
struct multi_run_ctx mrc;
(void)ev_bitmask;
@ -2891,19 +3281,56 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
sigpipe_init(&mrc.pipe_st);
if(checkall) {
struct Curl_llist_node *e;
/* *perform() deals with running_handles on its own */
result = curl_multi_perform(multi, running_handles);
/* walk through each easy handle and do the socket state change magic
and callbacks */
if(result != CURLM_BAD_HANDLE) {
/* Reassess event status of all active transfers */
result = Curl_multi_ev_assess_xfer_list(multi, &multi->process);
for(e = Curl_llist_head(&multi->process); e && !result;
e = Curl_node_next(e)) {
result = singlesocket(multi, Curl_node_elem(e));
}
}
mrc.run_cpool = TRUE;
goto out;
}
if(s != CURL_SOCKET_TIMEOUT) {
Curl_multi_ev_expire_xfers(multi, s, &mrc.now, &mrc.run_cpool);
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
if(!entry) {
/* Unmatched socket, we cannot act on it but we ignore this fact. In
real-world tests it has been proved that libevent can in fact give
the application actions even though the socket was just previously
asked to get removed, so thus we better survive stray socket actions
and just move on. */
/* The socket might come from a connection that is being shut down
* by the multi's connection pool. */
Curl_cpool_multi_socket(multi, s, ev_bitmask);
}
else {
struct Curl_hash_iterator iter;
struct Curl_hash_element *he;
/* the socket can be shared by many transfers, iterate */
Curl_hash_start_iterate(&entry->transfers, &iter);
for(he = Curl_hash_next_element(&iter); he;
he = Curl_hash_next_element(&iter)) {
data = (struct Curl_easy *)he->ptr;
DEBUGASSERT(data);
DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
if(data == multi->cpool.idata)
mrc.run_cpool = TRUE;
else {
/* Expire with out current now, so we will get it below when
* asking the splaytree for expired transfers. */
expire_ex(data, &mrc.now, 0, EXPIRE_RUN_NOW);
}
}
}
}
else {
/* Asked to run due to time-out. Clear the 'last_expire_ts' variable to
@ -2912,7 +3339,6 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
handles the case when the application asks libcurl to run the timeout
prematurely. */
memset(&multi->last_expire_ts, 0, sizeof(multi->last_expire_ts));
mrc.run_cpool = TRUE;
}
result = multi_run_expired(&mrc);
@ -2932,7 +3358,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
out:
if(mrc.run_cpool) {
sigpipe_apply(multi->cpool.idata, &mrc.pipe_st);
Curl_cpool_multi_perform(multi, s);
Curl_cpool_multi_perform(multi);
}
sigpipe_restore(&mrc.pipe_st);
@ -3249,9 +3675,9 @@ multi_addtimeout(struct Curl_easy *data,
return CURLM_OK;
}
void Curl_expire_ex(struct Curl_easy *data,
const struct curltime *nowp,
timediff_t milli, expire_id id)
static void expire_ex(struct Curl_easy *data,
const struct curltime *nowp,
timediff_t milli, expire_id id)
{
struct Curl_multi *multi = data->multi;
struct curltime *curr_expire = &data->state.expiretime;
@ -3323,7 +3749,7 @@ void Curl_expire_ex(struct Curl_easy *data,
void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
{
struct curltime now = Curl_now();
Curl_expire_ex(data, &now, milli, id);
expire_ex(data, &now, milli, id);
}
/*
@ -3367,7 +3793,9 @@ bool Curl_expire_clear(struct Curl_easy *data)
/* clear the timeout list too */
Curl_llist_destroy(list, NULL);
CURL_TRC_M(data, "Expire cleared");
#ifdef DEBUGBUILD
infof(data, "Expire cleared");
#endif
nowp->tv_sec = 0;
nowp->tv_usec = 0;
return TRUE;
@ -3378,11 +3806,19 @@ bool Curl_expire_clear(struct Curl_easy *data)
CURLMcode curl_multi_assign(CURLM *m, curl_socket_t s,
void *hashp)
{
struct Curl_sh_entry *there = NULL;
struct Curl_multi *multi = m;
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
return Curl_multi_ev_assign(multi, s, hashp);
there = sh_getentry(&multi->sockhash, s);
if(!there)
return CURLM_BAD_SOCKET;
there->socketp = hashp;
return CURLM_OK;
}
static void move_pending_to_connect(struct Curl_multi *multi,

View File

@ -1,610 +0,0 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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 <curl/curl.h>
#include "urldata.h"
#include "cfilters.h"
#include "curl_trc.h"
#include "multiif.h"
#include "timeval.h"
#include "multi_ev.h"
#include "select.h"
#include "warnless.h"
#include "multihandle.h"
#include "socks.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
static void mev_in_callback(struct Curl_multi *multi, bool value)
{
multi->in_callback = value;
}
#define CURL_MEV_XFER_HASH_SIZE 13
#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)
*/
struct mev_sh_entry {
struct Curl_hash xfers; /* hash of transfers using this socket */
struct Curl_hash conns; /* hash of connections using this socket */
void *user_data; /* libcurl app data via curl_multi_assign() */
unsigned int action; /* CURL_POLL_IN/CURL_POLL_OUT we last told the
* libcurl application to watch out for */
unsigned int readers; /* this many transfers want to read */
unsigned int writers; /* this many transfers want to write */
};
static size_t mev_sh_entry_hash(void *key, size_t key_length, size_t slots_num)
{
curl_socket_t fd = *((curl_socket_t *) key);
(void) key_length;
return (fd % (curl_socket_t)slots_num);
}
static size_t mev_sh_entry_compare(void *k1, size_t k1_len,
void *k2, size_t k2_len)
{
(void) k1_len; (void) k2_len;
return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2));
}
/* sockhash entry destructor callback */
static void mev_sh_entry_dtor(void *freethis)
{
struct mev_sh_entry *entry = (struct mev_sh_entry *)freethis;
Curl_hash_destroy(&entry->xfers);
Curl_hash_destroy(&entry->conns);
free(entry);
}
/* look up a given socket in the socket hash, skip invalid sockets */
static struct mev_sh_entry *
mev_sh_entry_get(struct Curl_hash *sh, curl_socket_t s)
{
if(s != CURL_SOCKET_BAD) {
/* only look for proper sockets */
return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
}
return NULL;
}
static void mev_nop_dtor(void *e)
{
(void)e; /* does nothing */
}
/* make sure this socket is present in the hash for this handle */
static struct mev_sh_entry *
mev_sh_entry_add(struct Curl_hash *sh, curl_socket_t s)
{
struct mev_sh_entry *there = mev_sh_entry_get(sh, s);
struct mev_sh_entry *check;
if(there) {
/* it is present, return fine */
return there;
}
/* not present, add it */
check = calloc(1, sizeof(struct mev_sh_entry));
if(!check)
return NULL; /* major failure */
Curl_hash_offt_init(&check->xfers, CURL_MEV_XFER_HASH_SIZE, mev_nop_dtor);
Curl_hash_offt_init(&check->conns, CURL_MEV_CONN_HASH_SIZE, mev_nop_dtor);
/* make/add new hash entry */
if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
mev_sh_entry_dtor(check);
return NULL; /* major failure */
}
return check; /* things are good in sockhash land */
}
/* delete the given socket entry from the hash */
static void mev_sh_entry_kill(struct Curl_multi *multi, curl_socket_t s)
{
Curl_hash_delete(&multi->ev.sh_entries, (char *)&s, sizeof(curl_socket_t));
}
static size_t mev_sh_entry_user_count(struct mev_sh_entry *e)
{
return Curl_hash_count(&e->xfers) + Curl_hash_count(&e->conns);
}
static bool mev_sh_entry_xfer_known(struct mev_sh_entry *e,
struct Curl_easy *data)
{
return !!Curl_hash_offt_get(&e->xfers, data->id);
}
static bool mev_sh_entry_conn_known(struct mev_sh_entry *e,
struct connectdata *conn)
{
return !!Curl_hash_offt_get(&e->conns, conn->connection_id);
}
static bool mev_sh_entry_xfer_add(struct mev_sh_entry *e,
struct Curl_easy *data)
{
/* detect weird values */
DEBUGASSERT(mev_sh_entry_user_count(e) < 100000);
return !!Curl_hash_offt_set(&e->xfers, data->id, data);
}
static bool mev_sh_entry_conn_add(struct mev_sh_entry *e,
struct connectdata *conn)
{
/* detect weird values */
DEBUGASSERT(mev_sh_entry_user_count(e) < 100000);
return !!Curl_hash_offt_set(&e->conns, conn->connection_id, conn);
}
static bool mev_sh_entry_xfer_remove(struct mev_sh_entry *e,
struct Curl_easy *data)
{
return !Curl_hash_offt_remove(&e->xfers, data->id);
}
/* Purge any information about socket `s`.
* Let the socket callback know as well when necessary */
static CURLMcode mev_forget_socket(struct Curl_multi *multi,
struct Curl_easy *data,
curl_socket_t s,
const char *cause)
{
struct mev_sh_entry *entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
int rc = 0;
if(!entry) /* we never knew or already forgot about this socket */
return CURLM_OK;
/* We managed this socket before, tell the socket callback to forget it. */
if(multi->socket_cb) {
CURL_TRC_M(data, "ev %s, call(fd=%" FMT_SOCKET_T ", ev=REMOVE)",
cause, s);
mev_in_callback(multi, TRUE);
rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
multi->socket_userp, entry->user_data);
mev_in_callback(multi, FALSE);
}
mev_sh_entry_kill(multi, s);
if(rc == -1) {
multi->dead = TRUE;
return CURLM_ABORTED_BY_CALLBACK;
}
return CURLM_OK;
}
static CURLMcode mev_sh_entry_update(struct Curl_multi *multi,
struct Curl_easy *data,
struct mev_sh_entry *entry,
curl_socket_t s,
unsigned char last_action,
unsigned char cur_action)
{
int rc, comboaction;
/* we should only be called when the callback exists */
DEBUGASSERT(multi->socket_cb);
if(!multi->socket_cb)
return CURLM_OK;
/* Transfer `data` goes from `last_action` to `cur_action` on socket `s`
* with `multi->ev.sh_entries` entry `entry`. Update `entry` and trigger
* `multi->socket_cb` on change, if the callback is set. */
if(last_action == cur_action) /* nothing from `data` changed */
return CURLM_OK;
if(last_action & CURL_POLL_IN) {
DEBUGASSERT(entry->readers);
if(!(cur_action & CURL_POLL_IN))
entry->readers--;
}
else if(cur_action & CURL_POLL_IN)
entry->readers++;
if(last_action & CURL_POLL_OUT) {
DEBUGASSERT(entry->writers);
if(!(cur_action & CURL_POLL_OUT))
entry->writers--;
}
else if(cur_action & CURL_POLL_OUT)
entry->writers++;
DEBUGASSERT(entry->readers <= mev_sh_entry_user_count(entry));
DEBUGASSERT(entry->writers <= mev_sh_entry_user_count(entry));
DEBUGASSERT(entry->writers + entry->readers);
CURL_TRC_M(data, "ev update fd=%" FMT_SOCKET_T ", action '%s%s' -> '%s%s'"
" (%d/%d r/w)", s,
(last_action & CURL_POLL_IN) ? "IN" : "",
(last_action & CURL_POLL_OUT) ? "OUT" : "",
(cur_action & CURL_POLL_IN) ? "IN" : "",
(cur_action & CURL_POLL_OUT) ? "OUT" : "",
entry->readers, entry->writers);
comboaction = (entry->writers ? CURL_POLL_OUT : 0) |
(entry->readers ? CURL_POLL_IN : 0);
if(((int)entry->action == comboaction)) /* nothing for socket changed */
return CURLM_OK;
CURL_TRC_M(data, "ev update call(fd=%" FMT_SOCKET_T ", ev=%s%s)",
s, (comboaction & CURL_POLL_IN) ? "IN" : "",
(comboaction & CURL_POLL_OUT) ? "OUT" : "");
mev_in_callback(multi, TRUE);
rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
entry->user_data);
mev_in_callback(multi, FALSE);
if(rc == -1) {
multi->dead = TRUE;
return CURLM_ABORTED_BY_CALLBACK;
}
entry->action = (unsigned int)comboaction;
return CURLM_OK;
}
static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn,
struct easy_pollset *ps,
struct easy_pollset *prev_ps)
{
struct mev_sh_entry *entry;
curl_socket_t s;
unsigned int i, j;
CURLMcode mresult;
/* The transfer `data` reports in `ps` the sockets it is interested
* in and which combinatino of CURL_POLL_IN/CURL_POLL_OUT it wants
* to have monitored for events.
* There can be more than 1 transfer interested in the same socket
* and 1 transfer might be interested in more than 1 socket.
* `prev_ps` is the pollset copy from the previous call here. On
* the 1st call it will be empty.
*/
DEBUGASSERT(ps);
DEBUGASSERT(prev_ps);
/* Handle changes to sockets the transfer is interested in. */
for(i = 0; i < ps->num; i++) {
unsigned char last_action;
bool first_time = FALSE; /* data/conn appears first time on socket */
s = ps->sockets[i];
/* Have we handled this socket before? */
entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
if(!entry) {
/* new socket, add new entry */
first_time = TRUE;
entry = mev_sh_entry_add(&multi->ev.sh_entries, s);
if(!entry) /* fatal */
return CURLM_OUT_OF_MEMORY;
CURL_TRC_M(data, "ev new entry fd=%" FMT_SOCKET_T, s);
}
else if(conn) {
first_time = !mev_sh_entry_conn_known(entry, data->conn);
}
else {
first_time = !mev_sh_entry_xfer_known(entry, data);
}
/* What was the previous action the transfer had regarding this socket?
* If the transfer is new to the socket, disregard the information
* in `last_poll`, because the socket might have been destroyed and
* reopened. We'd have cleared the sh_entry for that, but the socket
* might still be mentioned in the hashed pollsets. */
last_action = 0;
if(first_time) {
if(conn) {
if(!mev_sh_entry_conn_add(entry, data->conn))
return CURLM_OUT_OF_MEMORY;
}
else {
if(!mev_sh_entry_xfer_add(entry, data))
return CURLM_OUT_OF_MEMORY;
}
CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", added %s #%" FMT_OFF_T
", total=%zu/%zu (xfer/conn)", s,
conn ? "connection" : "transfer",
conn ? conn->connection_id : data->id,
Curl_hash_count(&entry->xfers),
Curl_hash_count(&entry->conns));
}
else {
for(j = 0; j < prev_ps->num; j++) {
if(s == prev_ps->sockets[j]) {
last_action = prev_ps->actions[j];
break;
}
}
}
/* track readers/writers changes and report to socket callback */
mresult = mev_sh_entry_update(multi, data, entry, s,
last_action, ps->actions[i]);
if(mresult)
return mresult;
}
/* Handle changes to sockets the transfer is NO LONGER interested in. */
for(i = 0; i < prev_ps->num; i++) {
bool stillused = FALSE;
s = prev_ps->sockets[i];
for(j = 0; j < ps->num; j++) {
if(s == ps->sockets[j]) {
/* socket is still supervised */
stillused = TRUE;
break;
}
}
if(stillused)
continue;
entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
/* if entry does not exist, we were either never told about it or
* have already cleaned up this socket via Curl_multi_ev_socket_done().
* In other words: this is perfectly normal */
if(!entry)
continue;
if(!mev_sh_entry_xfer_remove(entry, data)) {
/* `data` says in `prev_ps` that it had been using a socket,
* but `data` has not been registered for it.
* This should not happen if our book-keeping is correct? */
CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", transfer lost "
"interest but is not registered", s);
DEBUGASSERT(NULL);
continue;
}
if(mev_sh_entry_user_count(entry)) {
/* track readers/writers changes and report to socket callback */
mresult = mev_sh_entry_update(multi, data, entry, s,
prev_ps->actions[i], 0);
if(mresult)
return mresult;
CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", removed transfer, "
"total=%zu/%zu (xfer/conn)", s,
Curl_hash_count(&entry->xfers),
Curl_hash_count(&entry->conns));
}
else {
mresult = mev_forget_socket(multi, data, s, "last user gone");
if(mresult)
return mresult;
}
} /* for loop over num */
/* Remember for next time */
memcpy(prev_ps, ps, sizeof(*prev_ps));
return CURLM_OK;
}
static struct easy_pollset*
mev_add_new_pollset(struct Curl_hash *h, curl_off_t id)
{
struct easy_pollset *ps;
ps = calloc(1, sizeof(*ps));
if(!ps)
return NULL;
if(!Curl_hash_offt_set(h, id, ps)) {
free(ps);
return NULL;
}
return ps;
}
static struct easy_pollset *
mev_get_last_pollset(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn)
{
if(data) {
if(conn)
return Curl_hash_offt_get(&multi->ev.conn_pollsets,
conn->connection_id);
else if(data)
return Curl_hash_offt_get(&multi->ev.xfer_pollsets, data->id);
}
return NULL;
}
static void mev_init_cur_pollset(struct easy_pollset *ps,
struct Curl_easy *data,
struct connectdata *conn)
{
memset(ps, 0, sizeof(*ps));
if(conn)
Curl_conn_adjust_pollset(data, conn, ps);
else if(data)
Curl_multi_getsock(data, ps, "ev assess");
}
static CURLMcode mev_assess(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn)
{
if(multi && multi->socket_cb) {
struct easy_pollset ps, *last_ps;
mev_init_cur_pollset(&ps, data, conn);
last_ps = mev_get_last_pollset(multi, data, conn);
if(!last_ps && ps.num) {
if(conn)
last_ps = mev_add_new_pollset(&multi->ev.conn_pollsets,
data->conn->connection_id);
else
last_ps = mev_add_new_pollset(&multi->ev.xfer_pollsets, data->id);
if(!last_ps)
return CURLM_OUT_OF_MEMORY;
}
if(last_ps)
return mev_pollset_diff(multi, data, conn, &ps, last_ps);
else
DEBUGASSERT(!ps.num);
}
return CURLM_OK;
}
CURLMcode Curl_multi_ev_assess_xfer(struct Curl_multi *multi,
struct Curl_easy *data)
{
return mev_assess(multi, data, NULL);
}
CURLMcode Curl_multi_ev_assess_conn(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn)
{
return mev_assess(multi, data, conn);
}
CURLMcode Curl_multi_ev_assess_xfer_list(struct Curl_multi *multi,
struct Curl_llist *list)
{
struct Curl_llist_node *e;
CURLMcode result = CURLM_OK;
if(multi && multi->socket_cb) {
for(e = Curl_llist_head(list); e && !result; e = Curl_node_next(e)) {
result = Curl_multi_ev_assess_xfer(multi, Curl_node_elem(e));
}
}
return result;
}
CURLMcode Curl_multi_ev_assign(struct Curl_multi *multi,
curl_socket_t s,
void *user_data)
{
struct mev_sh_entry *e = mev_sh_entry_get(&multi->ev.sh_entries, s);
if(!e)
return CURLM_BAD_SOCKET;
e->user_data = user_data;
return CURLM_OK;
}
void Curl_multi_ev_expire_xfers(struct Curl_multi *multi,
curl_socket_t s,
const struct curltime *nowp,
bool *run_cpool)
{
struct mev_sh_entry *entry;
DEBUGASSERT(s != CURL_SOCKET_TIMEOUT);
entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
/* Unmatched socket, we cannot act on it but we ignore this fact. In
real-world tests it has been proved that libevent can in fact give
the application actions even though the socket was just previously
asked to get removed, so thus we better survive stray socket actions
and just move on. */
if(entry) {
struct Curl_hash_iterator iter;
struct Curl_hash_element *he;
/* the socket can be shared by many transfers, iterate */
Curl_hash_start_iterate(&entry->xfers, &iter);
for(he = Curl_hash_next_element(&iter); he;
he = Curl_hash_next_element(&iter)) {
struct Curl_easy *data = (struct Curl_easy *)he->ptr;
DEBUGASSERT(data);
DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
DEBUGASSERT(data->id >= 0); /* we should not track internal handles */
/* Expire with out current now, so we will get it below when
* asking the splaytree for expired transfers. */
Curl_expire_ex(data, nowp, 0, EXPIRE_RUN_NOW);
}
if(Curl_hash_count(&entry->conns))
*run_cpool = TRUE;
}
}
void Curl_multi_ev_socket_done(struct Curl_multi *multi,
struct Curl_easy *data, curl_socket_t s)
{
mev_forget_socket(multi, data, s, "socket done");
}
void Curl_multi_ev_xfer_done(struct Curl_multi *multi,
struct Curl_easy *data)
{
DEBUGASSERT(!data->conn); /* transfer should have been detached */
if(data->id >= 0) {
(void)mev_assess(multi, data, NULL);
Curl_hash_offt_remove(&multi->ev.xfer_pollsets, data->id);
}
}
void Curl_multi_ev_conn_done(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn)
{
(void)mev_assess(multi, data, conn);
Curl_hash_offt_remove(&multi->ev.conn_pollsets, conn->connection_id);
}
#define CURL_MEV_PS_HASH_SLOTS (991) /* nice prime */
static void mev_hash_pollset_free(void *entry)
{
free(entry);
}
void Curl_multi_ev_init(struct Curl_multi *multi, size_t hashsize)
{
Curl_hash_init(&multi->ev.sh_entries, hashsize, mev_sh_entry_hash,
mev_sh_entry_compare, mev_sh_entry_dtor);
Curl_hash_offt_init(&multi->ev.xfer_pollsets,
CURL_MEV_PS_HASH_SLOTS, mev_hash_pollset_free);
Curl_hash_offt_init(&multi->ev.conn_pollsets,
CURL_MEV_PS_HASH_SLOTS, mev_hash_pollset_free);
}
void Curl_multi_ev_cleanup(struct Curl_multi *multi)
{
Curl_hash_destroy(&multi->ev.sh_entries);
Curl_hash_destroy(&multi->ev.xfer_pollsets);
Curl_hash_destroy(&multi->ev.conn_pollsets);
}

View File

@ -1,79 +0,0 @@
#ifndef HEADER_CURL_MULTI_EV_H
#define HEADER_CURL_MULTI_EV_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
struct Curl_easy;
struct Curl_multi;
struct easy_pollset;
struct curl_multi_ev {
struct Curl_hash sh_entries;
struct Curl_hash xfer_pollsets;
struct Curl_hash conn_pollsets;
};
/* Setup/teardown of multi event book-keeping. */
void Curl_multi_ev_init(struct Curl_multi *multi, size_t hashsize);
void Curl_multi_ev_cleanup(struct Curl_multi *multi);
/* Assign a 'user_data' to be passed to the socket callback when
* invoked with the given socket. This will fail if this socket
* is not active, e.g. the application has not been told to monitor it. */
CURLMcode Curl_multi_ev_assign(struct Curl_multi *multi, curl_socket_t s,
void *user_data);
/* Assess the transfer by getting its current pollset, compute
* any changes to the last one and inform the application's socket
* callback if things have changed. */
CURLMcode Curl_multi_ev_assess_xfer(struct Curl_multi *multi,
struct Curl_easy *data);
/* Assess all easy handles on the list */
CURLMcode Curl_multi_ev_assess_xfer_list(struct Curl_multi *multi,
struct Curl_llist *list);
/* Assess the connection by getting its current pollset */
CURLMcode Curl_multi_ev_assess_conn(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn);
/* Expire all transfers tied to the given socket */
void Curl_multi_ev_expire_xfers(struct Curl_multi *multi,
curl_socket_t s,
const struct curltime *nowp,
bool *run_cpool);
/* Socket will be closed, forget anything we know about it. */
void Curl_multi_ev_socket_done(struct Curl_multi *multi,
struct Curl_easy *data, curl_socket_t s);
/* Transfer is removed from the multi */
void Curl_multi_ev_xfer_done(struct Curl_multi *multi,
struct Curl_easy *data);
/* Connection is being destroyed */
void Curl_multi_ev_conn_done(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn);
#endif /* HEADER_CURL_MULTI_EV_H */

View File

@ -27,7 +27,6 @@
#include "llist.h"
#include "hash.h"
#include "conncache.h"
#include "multi_ev.h"
#include "psl.h"
#include "socketpair.h"
@ -39,9 +38,9 @@ struct Curl_message {
struct CURLMsg extmsg;
};
/* NOTE: if you add a state here, add the name to the statenames[] array
* in curl_trc.c as well!
*/
/* NOTE: if you add a state here, add the name to the statename[] array as
well!
*/
typedef enum {
MSTATE_INIT, /* 0 - start in this state */
MSTATE_PENDING, /* 1 - no connections, waiting for one */
@ -129,9 +128,10 @@ struct Curl_multi {
char *xfer_sockbuf; /* the actual buffer */
size_t xfer_sockbuf_len; /* the allocated length */
/* multi event related things */
struct curl_multi_ev ev;
/* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
the pluralis form, there can be more than one easy handle waiting on the
same actual socket) */
struct Curl_hash sockhash;
/* `proto_hash` is a general key-value store for protocol implementations
* with the lifetime of the multi handle. The number of elements kept here
* should be in the order of supported protocols (and sub-protocols like

View File

@ -28,10 +28,8 @@
* Prototypes for library-wide functions provided by multi.c
*/
CURLcode Curl_updatesocket(struct Curl_easy *data);
void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id);
void Curl_expire_ex(struct Curl_easy *data,
const struct curltime *nowp,
timediff_t milli, expire_id id);
bool Curl_expire_clear(struct Curl_easy *data);
void Curl_expire_done(struct Curl_easy *data, expire_id id);
CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT;
@ -66,13 +64,26 @@ struct Curl_multi *Curl_multi_handle(size_t hashsize,
/* mask for checking if read and/or write is set for index x */
#define GETSOCK_MASK_RW(x) (GETSOCK_READSOCK(x)|GETSOCK_WRITESOCK(x))
/**
* Let the multi handle know that the socket is about to be closed.
* The multi will then remove anything it knows about the socket, so
* when the OS is using this socket (number) again subsequently,
* the internal book keeping will not get confused.
/*
* Curl_multi_closed()
*
* Used by the connect code to tell the multi_socket code that one of the
* sockets we were using is about to be closed. This function will then
* remove it from the sockethash for this handle to make the multi_socket API
* behave properly, especially for the case when libcurl will create another
* socket again and it gets the same file descriptor number.
*/
void Curl_multi_will_close(struct Curl_easy *data, curl_socket_t s);
void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s);
/* Compare the two pollsets to notify the multi_socket API of changes
* in socket polling, e.g calling multi->socket_cb() with the changes if
* differences are seen.
*/
CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
struct Curl_easy *data,
struct easy_pollset *ps,
struct easy_pollset *last_ps);
/*
* Add a handle and move it into PERFORM state at once. For pushed streams.
@ -85,10 +96,6 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
/* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */
unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi);
void Curl_multi_getsock(struct Curl_easy *data,
struct easy_pollset *ps,
const char *caller);
/**
* Borrow the transfer buffer from the multi, suitable
* for the given transfer `data`. The buffer may only be used in one

View File

@ -438,7 +438,7 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option,
*/
if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST))
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.timecondition = (unsigned char)arg;
data->set.timecondition = (unsigned char)(curl_TimeCond)arg;
break;
case CURLOPT_TIMEVALUE:
/*
@ -1970,46 +1970,46 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
/*
* Custom pointer to pass the header write callback function
*/
data->set.writeheader = ptr;
data->set.writeheader = (void *)ptr;
break;
case CURLOPT_READDATA:
/*
* FILE pointer to read the file to be uploaded from. Or possibly used as
* argument to the read callback.
*/
data->set.in_set = ptr;
data->set.in_set = (void *)ptr;
break;
case CURLOPT_WRITEDATA:
/*
* FILE pointer to write to. Or possibly used as argument to the write
* callback.
*/
data->set.out = ptr;
data->set.out = (void *)ptr;
break;
case CURLOPT_DEBUGDATA:
/*
* Set to a void * that should receive all error writes. This
* defaults to CURLOPT_STDERR for normal operations.
*/
data->set.debugdata = ptr;
data->set.debugdata = (void *)ptr;
break;
case CURLOPT_PROGRESSDATA:
/*
* Custom client data to pass to the progress callback
*/
data->set.progress_client = ptr;
data->set.progress_client = (void *)ptr;
break;
case CURLOPT_SEEKDATA:
/*
* Seek control callback. Might be NULL.
*/
data->set.seek_client = ptr;
data->set.seek_client = (void *)ptr;
break;
case CURLOPT_IOCTLDATA:
/*
* I/O control data pointer. Might be NULL.
*/
data->set.ioctl_client = ptr;
data->set.ioctl_client = (void *)ptr;
break;
case CURLOPT_SSL_CTX_DATA:
/*
@ -2017,7 +2017,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
*/
#ifdef USE_SSL
if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
data->set.ssl.fsslctxp = ptr;
data->set.ssl.fsslctxp = (void *)ptr;
else
#endif
return CURLE_NOT_BUILT_IN;
@ -2026,33 +2026,33 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
/*
* socket callback data pointer. Might be NULL.
*/
data->set.sockopt_client = ptr;
data->set.sockopt_client = (void *)ptr;
break;
case CURLOPT_OPENSOCKETDATA:
/*
* socket callback data pointer. Might be NULL.
*/
data->set.opensocket_client = ptr;
data->set.opensocket_client = (void *)ptr;
break;
case CURLOPT_RESOLVER_START_DATA:
/*
* resolver start callback data pointer. Might be NULL.
*/
data->set.resolver_start_client = ptr;
data->set.resolver_start_client = (void *)ptr;
break;
case CURLOPT_CLOSESOCKETDATA:
/*
* socket callback data pointer. Might be NULL.
*/
data->set.closesocket_client = ptr;
data->set.closesocket_client = (void *)ptr;
break;
case CURLOPT_TRAILERDATA:
#ifndef CURL_DISABLE_HTTP
data->set.trailer_data = ptr;
data->set.trailer_data = (void *)ptr;
#endif
break;
case CURLOPT_PREREQDATA:
data->set.prereq_userp = ptr;
data->set.prereq_userp = (void *)ptr;
break;
case CURLOPT_ERRORBUFFER:
@ -2388,7 +2388,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
/*
* Set private data pointer.
*/
data->set.private_data = ptr;
data->set.private_data = (void *)ptr;
break;
#ifdef USE_SSL
@ -2430,7 +2430,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
/*
* Custom client data to pass to the SSH keyfunc callback
*/
data->set.ssh_keyfunc_userp = ptr;
data->set.ssh_keyfunc_userp = (void *)ptr;
break;
#ifdef USE_LIBSSH2
case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
@ -2445,7 +2445,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
/*
* Custom client data to pass to the SSH keyfunc callback
*/
data->set.ssh_hostkeyfunc_userp = ptr;
data->set.ssh_hostkeyfunc_userp = (void *)ptr;
break;
#endif /* USE_LIBSSH2 */
#endif /* USE_SSH */
@ -2504,15 +2504,15 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
return Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT], ptr);
case CURLOPT_INTERLEAVEDATA:
data->set.rtp_out = ptr;
data->set.rtp_out = (void *)ptr;
break;
#endif /* ! CURL_DISABLE_RTSP */
#ifndef CURL_DISABLE_FTP
case CURLOPT_CHUNK_DATA:
data->set.wildcardptr = ptr;
data->set.wildcardptr = (void *)ptr;
break;
case CURLOPT_FNMATCH_DATA:
data->set.fnmatch_data = ptr;
data->set.fnmatch_data = (void *)ptr;
break;
#endif
#ifdef USE_TLS_SRP
@ -2587,10 +2587,10 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
#endif
#ifndef CURL_DISABLE_HSTS
case CURLOPT_HSTSREADDATA:
data->set.hsts_read_userp = ptr;
data->set.hsts_read_userp = (void *)ptr;
break;
case CURLOPT_HSTSWRITEDATA:
data->set.hsts_write_userp = ptr;
data->set.hsts_write_userp = (void *)ptr;
break;
case CURLOPT_HSTS: {
struct curl_slist *h;

View File

@ -93,6 +93,12 @@
* newer symbols.
*/
#ifndef _WIN32_WINNT_NT4
#define _WIN32_WINNT_NT4 0x0400 /* Windows NT 4.0 */
#endif
#ifndef _WIN32_WINNT_WIN2K
#define _WIN32_WINNT_WIN2K 0x0500 /* Windows 2000 */
#endif
#ifndef _WIN32_WINNT_WINXP
#define _WIN32_WINNT_WINXP 0x0501 /* Windows XP */
#endif

View File

@ -114,10 +114,7 @@ void *Curl_memdup0(const char *src, size_t length)
char *buf = malloc(length + 1);
if(!buf)
return NULL;
if(length) {
DEBUGASSERT(src); /* must never be NULL */
memcpy(buf, src, length);
}
memcpy(buf, src, length);
buf[length] = 0;
return buf;
}

View File

@ -31,12 +31,6 @@ void Curl_str_init(struct Curl_str *out)
out->len = 0;
}
void Curl_str_assign(struct Curl_str *out, const char *str, size_t len)
{
out->str = str;
out->len = len;
}
/* Get a word until the first DELIM or end of string. At least one byte long.
return non-zero on error */
int Curl_str_until(const char **linep, struct Curl_str *out,
@ -69,29 +63,6 @@ int Curl_str_word(const char **linep, struct Curl_str *out,
return Curl_str_until(linep, out, max, ' ');
}
/* Get a word until a newline byte or end of string. At least one byte long.
return non-zero on error */
int Curl_str_untilnl(const char **linep, struct Curl_str *out,
const size_t max)
{
const char *s = *linep;
size_t len = 0;
DEBUGASSERT(linep && *linep && out && max);
Curl_str_init(out);
while(*s && !ISNEWLINE(*s)) {
s++;
if(++len > max)
return STRE_BIG;
}
if(!len)
return STRE_SHORT;
out->str = *linep;
out->len = len;
*linep = s; /* point to the first byte after the word */
return STRE_OK;
}
/* Get a "quoted" word. No escaping possible.
return non-zero on error */
@ -232,16 +203,6 @@ int Curl_str_casecompare(struct Curl_str *str, const char *check)
return ((str->len == clen) && strncasecompare(str->str, check, clen));
}
/* case sensitive string compare. Returns non-zero on match. */
int Curl_str_cmp(struct Curl_str *str, const char *check)
{
if(check) {
size_t clen = strlen(check);
return ((str->len == clen) && !strncmp(str->str, check, clen));
}
return !!(str->len);
}
/* Trim off 'num' number of bytes from the beginning (left side) of the
string. If 'num' is larger than the string, return error. */
int Curl_str_nudge(struct Curl_str *str, size_t num)

View File

@ -43,7 +43,6 @@ struct Curl_str {
};
void Curl_str_init(struct Curl_str *out);
void Curl_str_assign(struct Curl_str *out, const char *str, size_t len);
#define Curl_str(x) ((x)->str)
#define Curl_strlen(x) ((x)->len)
@ -57,11 +56,6 @@ int Curl_str_word(const char **linep, struct Curl_str *out, const size_t max);
int Curl_str_until(const char **linep, struct Curl_str *out, const size_t max,
char delim);
/* Get a word until a newline byte or end of string. At least one byte long.
return non-zero on error */
int Curl_str_untilnl(const char **linep, struct Curl_str *out,
const size_t max);
/* Get a "quoted" word. No escaping possible.
return non-zero on error */
int Curl_str_quotedword(const char **linep, struct Curl_str *out,
@ -91,7 +85,6 @@ int Curl_str_newline(const char **linep);
/* case insensitive compare that the parsed string matches the
given string. */
int Curl_str_casecompare(struct Curl_str *str, const char *check);
int Curl_str_cmp(struct Curl_str *str, const char *check);
int Curl_str_nudge(struct Curl_str *str, size_t num);

View File

@ -35,7 +35,6 @@
#include "strdup.h"
#include "idn.h"
#include "strparse.h"
#include "curl_memrchr.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -111,18 +110,26 @@ static void free_urlhandle(struct Curl_URL *u)
*/
static const char *find_host_sep(const char *url)
{
const char *sep;
const char *query;
/* Find the start of the hostname */
const char *sep = strstr(url, "//");
sep = strstr(url, "//");
if(!sep)
sep = url;
else
sep += 2;
/* Find first / or ? */
while(*sep && *sep != '/' && *sep != '?')
sep++;
query = strchr(sep, '?');
sep = strchr(sep, '/');
return sep;
if(!sep)
sep = url + strlen(url);
if(!query)
query = url + strlen(url);
return sep < query ? sep : query;
}
/* convert CURLcode to CURLUcode */
@ -148,40 +155,46 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
bool left = !query;
const unsigned char *iptr;
const unsigned char *host_sep = (const unsigned char *) url;
CURLcode result = CURLE_OK;
CURLcode result;
if(!relative) {
size_t n;
if(!relative)
host_sep = (const unsigned char *) find_host_sep(url);
/* output the first piece as-is */
n = (const char *)host_sep - url;
result = Curl_dyn_addn(o, url, n);
len -= n;
}
for(iptr = (unsigned char *)url; /* read from here */
len; iptr++, len--) {
if(iptr < host_sep) {
result = Curl_dyn_addn(o, iptr, 1);
if(result)
return cc2cu(result);
continue;
}
for(iptr = host_sep; len && !result; iptr++, len--) {
if(*iptr == ' ') {
if(left)
result = Curl_dyn_addn(o, "%20", 3);
else
result = Curl_dyn_addn(o, "+", 1);
if(result)
return cc2cu(result);
continue;
}
else if(urlchar_needs_escaping(*iptr)) {
if(*iptr == '?')
left = FALSE;
if(urlchar_needs_escaping(*iptr)) {
char out[3]={'%'};
out[1] = hexdigits[*iptr >> 4];
out[2] = hexdigits[*iptr & 0xf];
result = Curl_dyn_addn(o, out, 3);
}
else {
else
result = Curl_dyn_addn(o, iptr, 1);
if(*iptr == '?')
left = FALSE;
}
if(result)
return cc2cu(result);
}
if(result)
return cc2cu(result);
return CURLUE_OK;
}
@ -234,76 +247,87 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
}
/*
* Concatenate a relative URL onto a base URL making it absolute.
* Concatenate a relative URL to a base URL making it absolute.
*
* Note that this function destroys the 'base' string.
*/
static CURLUcode redirect_url(const char *base, const char *relurl,
static CURLUcode redirect_url(char *base, const char *relurl,
CURLU *u, unsigned int flags)
{
struct dynbuf urlbuf;
bool host_changed = FALSE;
const char *useurl = relurl;
const char *cutoff = NULL;
size_t prelen;
CURLcode result = CURLE_OK;
CURLUcode uc;
/* protsep points to the start of the hostname */
char *protsep = strstr(base, "//");
DEBUGASSERT(protsep);
if(!protsep)
protsep = base;
else
protsep += 2; /* pass the slashes */
/* protsep points to the start of the hostname, after [scheme]:// */
const char *protsep = base + strlen(u->scheme) + 3;
DEBUGASSERT(base && relurl && u); /* all set here */
if(!base)
return CURLUE_MALFORMED_INPUT; /* should never happen */
if(('/' != relurl[0]) && ('#' != relurl[0])) {
/* First we need to find out if there is a ?-letter in the original URL,
and cut it and the right-side of that off */
char *pathsep = strchr(protsep, '?');
if(pathsep)
*pathsep = 0;
else {
/* if not, cut off the potential fragment */
pathsep = strchr(protsep, '#');
if(pathsep)
*pathsep = 0;
}
/* if the redirect-to piece is not just a query, cut the path after the
last slash */
if(useurl[0] != '?') {
pathsep = strrchr(protsep, '/');
if(pathsep)
pathsep[1] = 0; /* leave the slash */
}
}
else if('/' == relurl[0]) {
/* We got a new absolute path for this server */
/* handle different relative URL types */
switch(relurl[0]) {
case '/':
if(relurl[1] == '/') {
/* protocol-relative URL: //example.com/path */
cutoff = protsep;
useurl = &relurl[2];
/* the new URL starts with //, just keep the protocol part from the
original one */
*protsep = 0;
useurl = &relurl[2]; /* we keep the slashes from the original, so we
skip the new ones */
host_changed = TRUE;
}
else
/* absolute /path */
cutoff = strchr(protsep, '/');
break;
case '#':
/* fragment-only change */
if(u->fragment)
cutoff = strchr(protsep, '#');
break;
default:
/* path or query-only change */
if(u->query && u->query[0])
/* remove existing query */
cutoff = strchr(protsep, '?');
else if(u->fragment && u->fragment[0])
/* Remove existing fragment */
cutoff = strchr(protsep, '#');
if(relurl[0] != '?') {
/* append a relative path after the last slash */
cutoff = memrchr(protsep, '/',
cutoff ? (size_t)(cutoff - protsep) : strlen(protsep));
if(cutoff)
cutoff++; /* truncate after last slash */
else {
/* cut the original URL at first slash */
char *pathsep = strchr(protsep, '/');
if(pathsep)
*pathsep = 0;
}
break;
}
else {
/* the relative piece starts with '#' */
/* If there is a fragment in the original URL, cut it off */
char *pathsep = strchr(protsep, '#');
if(pathsep)
*pathsep = 0;
}
prelen = cutoff ? (size_t)(cutoff - base) : strlen(base);
/* build new URL */
Curl_dyn_init(&urlbuf, CURL_MAX_INPUT_LENGTH);
if(!Curl_dyn_addn(&urlbuf, base, prelen) &&
!urlencode_str(&urlbuf, useurl, strlen(useurl), !host_changed, FALSE)) {
uc = parseurl_and_replace(Curl_dyn_ptr(&urlbuf), u,
flags & ~CURLU_PATH_AS_IS);
}
else
uc = CURLUE_OUT_OF_MEMORY;
/* copy over the root URL part */
result = Curl_dyn_add(&urlbuf, base);
if(result)
return cc2cu(result);
/* then append the new piece on the right side */
uc = urlencode_str(&urlbuf, useurl, strlen(useurl), !host_changed,
FALSE);
if(!uc)
uc = parseurl_and_replace(Curl_dyn_ptr(&urlbuf), u,
flags&~CURLU_PATH_AS_IS);
Curl_dyn_free(&urlbuf);
return uc;
}
@ -1416,10 +1440,8 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
punycode = (flags & CURLU_PUNYCODE) ? 1 : 0;
depunyfy = (flags & CURLU_PUNY2IDN) ? 1 : 0;
if(u->scheme && strcasecompare("file", u->scheme)) {
url = aprintf("file://%s%s%s%s%s",
url = aprintf("file://%s%s%s",
u->path,
show_query ? "?": "",
u->query ? u->query : "",
show_fragment ? "#": "",
u->fragment ? u->fragment : "");
}
@ -1773,7 +1795,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|| curl_url_get(u, CURLUPART_URL, &oldurl, flags)) {
return parseurl_and_replace(part, u, flags);
}
DEBUGASSERT(oldurl); /* it is set here */
/* apply the relative part to create a new URL */
uc = redirect_url(oldurl, part, u, flags);
free(oldurl);

View File

@ -565,12 +565,14 @@ struct hostname {
#if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH)
#define USE_CURL_ASYNC
struct Curl_async {
char *hostname;
struct Curl_dns_entry *dns;
#ifdef CURLRES_ASYNCH
struct thread_data thdata;
#endif
void *resolver; /* resolver state, if it is used in the URL state -
ares_channel e.g. */
int port;
BIT(done); /* set TRUE when the lookup is complete */
};
@ -813,6 +815,9 @@ struct connectdata {
struct curltime start[2]; /* when filter shutdown started */
unsigned int timeout_ms; /* 0 means no timeout */
} shutdown;
/* Last pollset used in connection shutdown. Used to detect changes
* for multi_socket API. */
struct easy_pollset shutdown_poll;
struct ssl_primary_config ssl_config;
#ifndef CURL_DISABLE_PROXY
@ -1688,9 +1693,6 @@ struct UserDefined {
struct curl_slist *mail_rcpt; /* linked list of mail recipients */
#endif
unsigned int maxconnects; /* Max idle connections in the connection cache */
#ifdef USE_ECH
int tls_ech; /* TLS ECH configuration */
#endif
unsigned short use_port; /* which port to use (when not using default) */
#ifndef CURL_DISABLE_BINDLOCAL
unsigned short localport; /* local port number to bind to */
@ -1828,6 +1830,9 @@ struct UserDefined {
#ifndef CURL_DISABLE_WEBSOCKETS
BIT(ws_raw_mode);
#endif
#ifdef USE_ECH
int tls_ech; /* TLS ECH configuration */
#endif
};
#ifndef CURL_DISABLE_MIME
@ -1880,6 +1885,12 @@ struct Curl_easy {
struct Curl_message msg; /* A single posted message. */
/* Array with the plain socket numbers this handle takes care of, in no
particular order. Note that all sockets are added to the sockhash, where
the state etc are also kept. This array is mostly used to detect when a
socket is to be removed from the hash. See singlesocket(). */
struct easy_pollset last_poll;
struct Names dns;
struct Curl_multi *multi; /* if non-NULL, points to the multi handle
struct to which this "belongs" when used by

View File

@ -113,12 +113,88 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
/* we are always running on PLATFORM_WINNT */
matched = FALSE;
}
#elif defined(UNDER_CE)
(void)majorVersion;
(void)minorVersion;
(void)buildVersion;
(void)platform;
(void)condition;
#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
(_WIN32_WINNT < _WIN32_WINNT_WIN2K)
OSVERSIONINFO osver;
memset(&osver, 0, sizeof(osver));
osver.dwOSVersionInfoSize = sizeof(osver);
/* Find out Windows version */
if(GetVersionEx(&osver)) {
/* Verify the Operating System version number */
switch(condition) {
case VERSION_LESS_THAN:
if(osver.dwMajorVersion < majorVersion ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion < minorVersion) ||
(buildVersion != 0 &&
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion == minorVersion &&
osver.dwBuildNumber < buildVersion)))
matched = TRUE;
break;
case VERSION_LESS_THAN_EQUAL:
if(osver.dwMajorVersion < majorVersion ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion < minorVersion) ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion == minorVersion &&
(buildVersion == 0 ||
osver.dwBuildNumber <= buildVersion)))
matched = TRUE;
break;
case VERSION_EQUAL:
if(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion == minorVersion &&
(buildVersion == 0 ||
osver.dwBuildNumber == buildVersion))
matched = TRUE;
break;
case VERSION_GREATER_THAN_EQUAL:
if(osver.dwMajorVersion > majorVersion ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion > minorVersion) ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion == minorVersion &&
(buildVersion == 0 ||
osver.dwBuildNumber >= buildVersion)))
matched = TRUE;
break;
case VERSION_GREATER_THAN:
if(osver.dwMajorVersion > majorVersion ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion > minorVersion) ||
(buildVersion != 0 &&
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion == minorVersion &&
osver.dwBuildNumber > buildVersion)))
matched = TRUE;
break;
}
/* Verify the platform identifier (if necessary) */
if(matched) {
switch(platform) {
case PLATFORM_WINDOWS:
if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
matched = FALSE;
break;
case PLATFORM_WINNT:
if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
matched = FALSE;
break;
default: /* like platform == PLATFORM_DONT_CARE */
break;
}
}
}
#else
ULONGLONG cm = 0;
struct OUR_OSVERSIONINFOEXW osver;

View File

@ -481,27 +481,17 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data)
* the handshake time when we really did connect */
if(ctx->use_earlydata)
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
if(ctx->use_earlydata) {
#ifdef USE_GNUTLS
if(ctx->use_earlydata) {
int flags = gnutls_session_get_flags(ctx->tls.gtls.session);
ctx->earlydata_accepted = !!(flags & GNUTLS_SFLAGS_EARLY_DATA);
#endif
#ifdef USE_WOLFSSL
#ifdef WOLFSSL_EARLY_DATA
ctx->earlydata_accepted =
(wolfSSL_get_early_data_status(ctx->tls.wssl.ssl) !=
WOLFSSL_EARLY_DATA_REJECTED);
#else
DEBUGASSERT(0); /* should not come here if ED is disabled. */
ctx->earlydata_accepted = FALSE;
#endif /* WOLFSSL_EARLY_DATA */
#endif
CURL_TRC_CF(data, cf, "server did%s accept %zu bytes of early data",
ctx->earlydata_accepted ? "" : " not", ctx->earlydata_skip);
Curl_pgrsEarlyData(data, ctx->earlydata_accepted ?
(curl_off_t)ctx->earlydata_skip :
-(curl_off_t)ctx->earlydata_skip);
}
#endif
return 0;
}
@ -2267,23 +2257,8 @@ static int wssl_quic_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
struct Curl_easy *data = CF_DATA_CURRENT(cf);
DEBUGASSERT(data);
if(data && ctx) {
ngtcp2_ssize tplen;
uint8_t tpbuf[256];
unsigned char *quic_tp = NULL;
size_t quic_tp_len = 0;
tplen = ngtcp2_conn_encode_0rtt_transport_params(ctx->qconn, tpbuf,
sizeof(tpbuf));
if(tplen < 0)
CURL_TRC_CF(data, cf, "error encoding 0RTT transport data: %s",
ngtcp2_strerror((int)tplen));
else {
quic_tp = (unsigned char *)tpbuf;
quic_tp_len = (size_t)tplen;
}
(void)Curl_wssl_cache_session(cf, data, ctx->peer.scache_key,
session, wolfSSL_version(ssl),
"h3", quic_tp, quic_tp_len);
session, wolfSSL_version(ssl), "h3");
}
}
return 0;
@ -2333,13 +2308,13 @@ static CURLcode cf_ngtcp2_tls_ctx_setup(struct Curl_cfilter *cf,
}
#elif defined(USE_WOLFSSL)
if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ssl_ctx) != 0) {
if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ctx) != 0) {
failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
return CURLE_FAILED_INIT;
}
if(ssl_config->primary.cache_session) {
/* Register to get notified when a new session is received */
wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ssl_ctx, wssl_quic_new_session_cb);
wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ctx, wssl_quic_new_session_cb);
}
#endif
return CURLE_OK;
@ -2347,7 +2322,6 @@ static CURLcode cf_ngtcp2_tls_ctx_setup(struct Curl_cfilter *cf,
static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct alpn_spec *alpns,
struct Curl_ssl_session *scs,
bool *do_early_data)
{
@ -2358,19 +2332,10 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
#ifdef USE_GNUTLS
ctx->earlydata_max =
gnutls_record_get_max_early_data_size(ctx->tls.gtls.session);
#endif
#ifdef USE_WOLFSSL
#ifdef WOLFSSL_EARLY_DATA
ctx->earlydata_max = scs->earlydata_max;
#else
ctx->earlydata_max = 0;
#endif /* WOLFSSL_EARLY_DATA */
#endif
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL)
if((!ctx->earlydata_max)) {
CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
}
else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
else if(strcmp("h3", scs->alpn)) {
CURL_TRC_CF(data, cf, "SSL session from different ALPN, no early data");
}
else if(!scs->quic_tp || !scs->quic_tp_len) {
@ -2398,7 +2363,6 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
(void)data;
(void)ctx;
(void)scs;
(void)alpns;
#endif
return result;
}
@ -2416,9 +2380,6 @@ 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
};
DEBUGASSERT(ctx->initialized);
ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
@ -2462,7 +2423,9 @@ static const struct alpn_spec ALPN_SPEC_H3 = {
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, &ALPN_SPEC_H3,
#define H3_ALPN "\x2h3\x5h3-29"
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
H3_ALPN, sizeof(H3_ALPN) - 1,
cf_ngtcp2_tls_ctx_setup, &ctx->tls,
&ctx->conn_ref,
cf_ngtcp2_on_session_reuse);
@ -2475,7 +2438,7 @@ static const struct alpn_spec ALPN_SPEC_H3 = {
#elif defined(USE_GNUTLS)
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
#elif defined(USE_WOLFSSL)
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.ssl);
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.handle);
#else
#error "ngtcp2 TLS backend not defined"
#endif

View File

@ -1163,15 +1163,13 @@ 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
};
DEBUGASSERT(ctx->initialized);
#define H3_ALPN "\x2h3"
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
&ALPN_SPEC_H3, NULL, NULL, NULL, NULL);
H3_ALPN, sizeof(H3_ALPN) - 1,
NULL, NULL, NULL, NULL);
if(result)
goto out;

Some files were not shown because too many files have changed in this diff Show More