summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2024-05-24 23:43:03 +0300
committerdartraiden <wowemuh@gmail.com>2024-05-24 23:43:03 +0300
commitff76fe6c8f1e3b34c5571437612a038077f29860 (patch)
tree0ae912a13465fa5658253185d4eeab21d6ecdfde
parent174bf88b63eaf4b49c00894a3f14fbf9194cae02 (diff)
libcurl: update to 8.8.0
-rw-r--r--libs/libcurl/docs/CHANGES7549
-rw-r--r--libs/libcurl/docs/THANKS41
-rw-r--r--libs/libcurl/include/curl/curl.h75
-rw-r--r--libs/libcurl/include/curl/curlver.h10
-rw-r--r--libs/libcurl/include/curl/multi.h14
-rw-r--r--libs/libcurl/include/curl/typecheck-gcc.h1
-rw-r--r--libs/libcurl/include/curl/urlapi.h3
-rw-r--r--libs/libcurl/libcurl.vcxproj10
-rw-r--r--libs/libcurl/libcurl.vcxproj.filters12
-rw-r--r--libs/libcurl/src/CMakeLists.txt41
-rw-r--r--libs/libcurl/src/Makefile.am9
-rw-r--r--libs/libcurl/src/Makefile.in236
-rw-r--r--libs/libcurl/src/Makefile.inc5
-rw-r--r--libs/libcurl/src/altsvc.c8
-rw-r--r--libs/libcurl/src/asyn-ares.c6
-rw-r--r--libs/libcurl/src/asyn-thread.c25
-rw-r--r--libs/libcurl/src/base64.c2
-rw-r--r--libs/libcurl/src/bufq.h2
-rw-r--r--libs/libcurl/src/c-hyper.c6
-rw-r--r--libs/libcurl/src/cf-h1-proxy.c32
-rw-r--r--libs/libcurl/src/cf-h2-proxy.c2
-rw-r--r--libs/libcurl/src/cf-haproxy.c2
-rw-r--r--libs/libcurl/src/cf-https-connect.c4
-rw-r--r--libs/libcurl/src/cf-socket.c47
-rw-r--r--libs/libcurl/src/cfilters.c15
-rw-r--r--libs/libcurl/src/cfilters.h11
-rw-r--r--libs/libcurl/src/config-os400.h4
-rw-r--r--libs/libcurl/src/config-plan9.h2
-rw-r--r--libs/libcurl/src/config-riscos.h5
-rw-r--r--libs/libcurl/src/config-win32.h11
-rw-r--r--libs/libcurl/src/conncache.c7
-rw-r--r--libs/libcurl/src/conncache.h2
-rw-r--r--libs/libcurl/src/connect.c12
-rw-r--r--libs/libcurl/src/content_encoding.c41
-rw-r--r--libs/libcurl/src/cookie.c3
-rw-r--r--libs/libcurl/src/curl_addrinfo.c18
-rw-r--r--libs/libcurl/src/curl_config.h.cmake26
-rw-r--r--libs/libcurl/src/curl_config.h.in40
-rw-r--r--libs/libcurl/src/curl_gethostname.c2
-rw-r--r--libs/libcurl/src/curl_multibyte.c17
-rw-r--r--libs/libcurl/src/curl_ntlm_wb.c500
-rw-r--r--libs/libcurl/src/curl_path.c68
-rw-r--r--libs/libcurl/src/curl_path.h2
-rw-r--r--libs/libcurl/src/curl_rtmp.c38
-rw-r--r--libs/libcurl/src/curl_rtmp.h2
-rw-r--r--libs/libcurl/src/curl_sasl.c10
-rw-r--r--libs/libcurl/src/curl_setup.h71
-rw-r--r--libs/libcurl/src/curl_setup_once.h8
-rw-r--r--libs/libcurl/src/curl_sha512_256.c52
-rw-r--r--libs/libcurl/src/curl_threads.c3
-rw-r--r--libs/libcurl/src/curl_trc.c81
-rw-r--r--libs/libcurl/src/curl_trc.h75
-rw-r--r--libs/libcurl/src/curlx.h1
-rw-r--r--libs/libcurl/src/cw-out.c67
-rw-r--r--libs/libcurl/src/cw-out.h2
-rw-r--r--libs/libcurl/src/dict.c3
-rw-r--r--libs/libcurl/src/dllmain.c81
-rw-r--r--libs/libcurl/src/doh.c409
-rw-r--r--libs/libcurl/src/doh.h41
-rw-r--r--libs/libcurl/src/dynbuf.c2
-rw-r--r--libs/libcurl/src/easy.c78
-rw-r--r--libs/libcurl/src/easyoptions.c3
-rw-r--r--libs/libcurl/src/file.c110
-rw-r--r--libs/libcurl/src/ftp.c223
-rw-r--r--libs/libcurl/src/ftplistparser.c2
-rw-r--r--libs/libcurl/src/getinfo.c4
-rw-r--r--libs/libcurl/src/gopher.c6
-rw-r--r--libs/libcurl/src/hash.c57
-rw-r--r--libs/libcurl/src/hash.h16
-rw-r--r--libs/libcurl/src/headers.c10
-rw-r--r--libs/libcurl/src/hostip.c54
-rw-r--r--libs/libcurl/src/hostip.h41
-rw-r--r--libs/libcurl/src/hsts.c16
-rw-r--r--libs/libcurl/src/http.c776
-rw-r--r--libs/libcurl/src/http.h15
-rw-r--r--libs/libcurl/src/http2.c281
-rw-r--r--libs/libcurl/src/http_aws_sigv4.c5
-rw-r--r--libs/libcurl/src/http_chunks.c17
-rw-r--r--libs/libcurl/src/http_negotiate.c25
-rw-r--r--libs/libcurl/src/http_ntlm.c5
-rw-r--r--libs/libcurl/src/http_proxy.c2
-rw-r--r--libs/libcurl/src/idn.c86
-rw-r--r--libs/libcurl/src/idn.h7
-rw-r--r--libs/libcurl/src/if2ip.c22
-rw-r--r--libs/libcurl/src/if2ip.h6
-rw-r--r--libs/libcurl/src/imap.c6
-rw-r--r--libs/libcurl/src/inet_ntop.c4
-rw-r--r--libs/libcurl/src/inet_pton.c4
-rw-r--r--libs/libcurl/src/krb5.c56
-rw-r--r--libs/libcurl/src/ldap.c11
-rw-r--r--libs/libcurl/src/libcurl.plist35
-rw-r--r--libs/libcurl/src/libcurl.plist.in35
-rw-r--r--libs/libcurl/src/llist.c16
-rw-r--r--libs/libcurl/src/llist.h2
-rw-r--r--libs/libcurl/src/md4.c3
-rw-r--r--libs/libcurl/src/mime.c55
-rw-r--r--libs/libcurl/src/mprintf.c40
-rw-r--r--libs/libcurl/src/mqtt.c7
-rw-r--r--libs/libcurl/src/multi.c422
-rw-r--r--libs/libcurl/src/multihandle.h37
-rw-r--r--libs/libcurl/src/multiif.h7
-rw-r--r--libs/libcurl/src/noproxy.c2
-rw-r--r--libs/libcurl/src/openldap.c15
-rw-r--r--libs/libcurl/src/pop3.c8
-rw-r--r--libs/libcurl/src/pop3.h3
-rw-r--r--libs/libcurl/src/request.c6
-rw-r--r--libs/libcurl/src/request.h2
-rw-r--r--libs/libcurl/src/rtsp.c23
-rw-r--r--libs/libcurl/src/rtsp.h2
-rw-r--r--libs/libcurl/src/sendf.c86
-rw-r--r--libs/libcurl/src/sendf.h16
-rw-r--r--libs/libcurl/src/setopt.c154
-rw-r--r--libs/libcurl/src/setopt.h7
-rw-r--r--libs/libcurl/src/setup-vms.h4
-rw-r--r--libs/libcurl/src/smb.c6
-rw-r--r--libs/libcurl/src/smtp.c8
-rw-r--r--libs/libcurl/src/sockaddr.h2
-rw-r--r--libs/libcurl/src/socketpair.c21
-rw-r--r--libs/libcurl/src/socketpair.h28
-rw-r--r--libs/libcurl/src/socks.c8
-rw-r--r--libs/libcurl/src/strcase.c4
-rw-r--r--libs/libcurl/src/strerror.c3
-rw-r--r--libs/libcurl/src/telnet.c8
-rw-r--r--libs/libcurl/src/tftp.c5
-rw-r--r--libs/libcurl/src/transfer.c35
-rw-r--r--libs/libcurl/src/transfer.h12
-rw-r--r--libs/libcurl/src/url.c238
-rw-r--r--libs/libcurl/src/urlapi-int.h3
-rw-r--r--libs/libcurl/src/urlapi.c181
-rw-r--r--libs/libcurl/src/urldata.h171
-rw-r--r--libs/libcurl/src/vauth/cleartext.c11
-rw-r--r--libs/libcurl/src/vauth/digest.c2
-rw-r--r--libs/libcurl/src/vauth/vauth.h6
-rw-r--r--libs/libcurl/src/version.c60
-rw-r--r--libs/libcurl/src/vquic/curl_msh3.c100
-rw-r--r--libs/libcurl/src/vquic/curl_ngtcp2.c606
-rw-r--r--libs/libcurl/src/vquic/curl_osslq.c315
-rw-r--r--libs/libcurl/src/vquic/curl_quiche.c316
-rw-r--r--libs/libcurl/src/vquic/vquic-tls.c387
-rw-r--r--libs/libcurl/src/vquic/vquic-tls.h37
-rw-r--r--libs/libcurl/src/vquic/vquic.c6
-rw-r--r--libs/libcurl/src/vquic/vquic.h6
-rw-r--r--libs/libcurl/src/vquic/vquic_int.h4
-rw-r--r--libs/libcurl/src/vssh/libssh.c2
-rw-r--r--libs/libcurl/src/vssh/libssh2.c16
-rw-r--r--libs/libcurl/src/vssh/wolfssh.c2
-rw-r--r--libs/libcurl/src/vtls/bearssl.c298
-rw-r--r--libs/libcurl/src/vtls/cipher_suite.c716
-rw-r--r--libs/libcurl/src/vtls/cipher_suite.h (renamed from libs/libcurl/src/curl_ntlm_wb.h)33
-rw-r--r--libs/libcurl/src/vtls/gtls.c477
-rw-r--r--libs/libcurl/src/vtls/gtls.h40
-rw-r--r--libs/libcurl/src/vtls/keylog.c1
-rw-r--r--libs/libcurl/src/vtls/mbedtls.c237
-rw-r--r--libs/libcurl/src/vtls/openssl.c907
-rw-r--r--libs/libcurl/src/vtls/openssl.h51
-rw-r--r--libs/libcurl/src/vtls/rustls.c238
-rw-r--r--libs/libcurl/src/vtls/schannel.c82
-rw-r--r--libs/libcurl/src/vtls/schannel_int.h10
-rw-r--r--libs/libcurl/src/vtls/sectransp.c47
-rw-r--r--libs/libcurl/src/vtls/vtls.c106
-rw-r--r--libs/libcurl/src/vtls/vtls.h4
-rw-r--r--libs/libcurl/src/vtls/vtls_int.h9
-rw-r--r--libs/libcurl/src/vtls/wolfssl.c174
-rw-r--r--libs/libcurl/src/vtls/x509asn1.c3
-rw-r--r--libs/libcurl/src/warnless.h14
-rw-r--r--libs/libcurl/src/ws.c43
166 files changed, 10557 insertions, 8351 deletions
diff --git a/libs/libcurl/docs/CHANGES b/libs/libcurl/docs/CHANGES
index 80d1cc84b5..5553b0a845 100644
--- a/libs/libcurl/docs/CHANGES
+++ b/libs/libcurl/docs/CHANGES
@@ -6,6 +6,3623 @@
Changelog
+Version 8.8.0 (22 May 2024)
+
+Daniel Stenberg (22 May 2024)
+
+- RELEASE-NOTES: synced
+
+- THANKS: add contributors from 8.8.0
+
+Nathan Moinvaziri (21 May 2024)
+
+- url: remove duplicate call to Curl_conncache_remove_conn when pruning
+
+ - remove unnecessary prunedead struct from prune_dead_connections
+ - rename extract_if_dead to prune_if_dead for clarity
+
+ Closes #13710
+
+Joseph Chen (21 May 2024)
+
+- curl_setup.h: add support for IAR compiler
+
+ Closes #13728
+
+Stephen Farrell (21 May 2024)
+
+- docs/ECH: typo/clarification
+
+ Closes #13727
+
+Viktor Szakats (21 May 2024)
+
+- hash: delete unused debug function
+
+ It had no use in the curl codebase and was also protected by the macro
+ `AGGRESSIVE_TEST` (renamed in 2020), also with no local reference.
+
+ Added in ca6e77083768858aa34207f8c5dce38b3c05336d (2002-11-11)
+
+ Closes #13729
+
+Stefan Eissing (21 May 2024)
+
+- content_encoding: reject transfer-encoding after chunked
+
+ reject a response that applies a transfer-encoding after a 'chunked'
+ encoding. RFC 9112 ch. 6.1 required chunked to be the final encoding.
+
+ Closes #13733
+
+- http: HEAD response body tolerance
+
+ - as reported in #13725, some servers wrongly send body bytes in
+ responses to a HEAD request. This used to be tolerated in curl
+ 8.4 and before and leads to failed transfers in newer versions.
+ - restore previous behaviour for HTTP/1.1 and HTTP/2:
+ * 1.1: do not add 'Transfer-Encoding' writers from HEAD
+ responses. RFC 9112 says they do not apply.
+ * 2: when the transfer expects 'no_body', to not report stream
+ resets as error when all response headers have been received.
+
+ Reported-by: Jeroen Ooms
+ Fixes #13725
+ Closes #13732
+
+Viktor Szakats (20 May 2024)
+
+- tests: fix TFTP test 2305 on Windows
+
+ Ref: #13692
+ Closes #13724
+
+Jay Satiro (20 May 2024)
+
+- openssl: revert keylog_callback support for LibreSSL
+
+ - Revert to the legacy TLS 1.2 key logging code for LibreSSL.
+
+ - Document SSLKEYLOGFILE for LibreSSL is TLS 1.2 max.
+
+ Prior to this change if the user specified a filename in the
+ SSLKEYLOGFILE environment variable and was using LibreSSL 3.5.0+ then
+ an empty file would be created and no keys would be logged.
+
+ This is effectively a revert of e43474b4 which changed openssl.c to use
+ SSL_CTX_set_keylog_callback for LibreSSL 3.5.0+. Unfortunately LibreSSL
+ added that function only as a stub that doesn't actually do anything.
+
+ Reported-by: Gonçalo Carvalho
+
+ Fixes https://github.com/curl/curl/issues/13672
+ Closes https://github.com/curl/curl/pull/13682
+
+renovate[bot] (19 May 2024)
+
+- GHA: pin dependencies
+
+ Closes #13712
+
+Viktor Szakats (19 May 2024)
+
+- appveyor: drop unnecessary `--clean-first` cmake option
+
+ In CI all machines are fresh on startup, making the `clean` operation
+ unnecessary. This can save some time/energy for each job run.
+
+ Closes #13707
+
+- cmake: merge two `if(BUILD_TESTING)` branches
+
+ Closes #13708
+
+Tatsuhiro Tsujikawa (19 May 2024)
+
+- GHA: bump nghttp2 to v1.62.1
+
+ Use gcc-12 explicitly to compile C++20 source files.
+
+ Closes #13702
+
+Viktor Szakats (19 May 2024)
+
+- GHA: add NetBSD, OpenBSD, FreeBSD/arm64 and OmniOS jobs
+
+ Add these jobs to GHA:
+ - NetBSD, cmake-unity, clang, OpenSSL, x86_64, with tests, w/o python,
+ no parallelism (was flaky sometimes)
+ - OpenBSD, cmake-unity, clang, LibreSSL, x86_64, with tests,
+ with python, -j8, TFTP results ignored due to #13623.
+ - FreeBSD, cmake-unity and autotools, clang, OpenSSL, arm64
+ (Tests disabled for arm64, because they are slow. It's available for
+ x86_64 with python, -j12.)
+ Configuration matches our existing Cirrus CI one.
+ - OmniOS, autotools, gcc, OpenSSL, x86_64, with tests, -j12.
+
+ All build with websockets and examples.
+
+ Closes #13583
+
+- GHA: disable TFTP test on native Windows
+
+ Some TFTP tests seem to enter into a loop and maybe hang?
+
+ E.g. 1007, 1009, 1238
+
+ Try fixing it by skipping all TFTP tests.
+
+ Ref: https://github.com/curl/curl/actions/runs/9141987545/job/25137038249?pr=
+ 13698
+
+ Also drop mingw-w64 test exclusions copy-pasted from MSYS jobs.
+
+ Possibly related: cffbcc3110c1eda2e333f9cfe2e269154618793a #5364
+
+ Close #13699
+
+renovate[bot] (18 May 2024)
+
+- GHA: pin dependencies
+
+ Closes #13691
+
+Viktor Szakats (18 May 2024)
+
+- cmake: do not pass linker flags to the static library tool
+
+ Do not add linker flags to the global CMake static library tool (aka
+ "static linker") (e.g. `ar`) flags list. They don't mix well. This was
+ only done after successfully detecting GSSAPI.
+
+ Linker flags seen on Old Linux CI:
+ ```
+ -- |GSS_LINKER_FLAGS|-Wl,--enable-new-dtags -Wl,-rpath -Wl,/usr/lib/x86_64-li
+ nux-gnu/heimdal|
+ -- |CMAKE_STATIC_LINKER_FLAGS| -Wl,--enable-new-dtags -Wl,-rpath -Wl,/usr/lib
+ /x86_64-linux-gnu/heimdal|
+ ```
+ Ref: https://github.com/curl/curl/actions/runs/9138988036/job/25130791712#ste
+ p:6:85
+
+ Causing:
+ ```
+ /usr/bin/ar qc libcurltool.a -Wl,--enable-new-dtags -Wl,-rpath -Wl,/usr/lib/
+ x86_64-linux-gnu/heimdal
+ CMakeFiles/curltool.dir/slist_wc.c.o CMakeFiles/curltool.dir/tool_binmode.c
+ .o CMakeFiles/curltool.dir/tool_bname.c.o
+ [...]
+ CMakeFiles/curltool.dir/tool_writeout_json.c.o CMakeFiles/curltool.dir/tool
+ _xattr.c.o CMakeFiles/curltool.dir/var.c.o
+ CMakeFiles/curltool.dir/__/lib/base64.c.o CMakeFiles/curltool.dir/__/lib/dy
+ nbuf.c.o
+ /usr/bin/ar: invalid option -- 'W'
+ Usage: /usr/bin/ar [emulation options] [-]{dmpqrstx}[abcDfilMNoPsSTuvV] [--pl
+ ugin <name>] [member-name] [count] archive-file file...
+ /usr/bin/ar -M [<mri-script]
+ ```
+ Ref: https://github.com/curl/curl/actions/runs/9138988036/job/25130791712#ste
+ p:9:125
+
+ This problem is invisible at the moment because of another bug (#13698)
+ that misses building unit tests when not using either the
+ `ENABLE_DEBUG=ON` or `ENABLE_CURLDEBUG=ON` options (to set
+ `-DCURLDEBUG`):
+ ```
+ test 1300 SKIPPED: curl lacks unittest support
+ ```
+ Ref: https://github.com/curl/curl/actions/runs/9135571781/job/25123104557#ste
+ p:9:2883
+
+ With that fixed, this becomes the next issue.
+
+ It's possible this bug also required an older CMake version and/or
+ a specific OS environment which uses linker flags in GSSAPI that are not
+ playing well with `ar` options, to reproduce.
+
+ Follow-up to 558814e16d84aa202c5ccc0c8108a9d728e77a58 (2014-09-25)
+ Ref: #13698
+ Closes #13697
+
+- GHA: ignore flaky test2302 results on Windows
+
+ WebSockets:
+ ```
+ TESTFAIL: These test cases failed: 2302
+ ```
+ Ref: https://github.com/curl/curl/actions/runs/9139155361/job/25131144383?pr=
+ 13689#step:14:9892
+
+ Follow-up to 36fd2dd6ee874726c628e67fcf6415a2e52bfe29 #13599
+ Ref: #13692
+ Closes #13696
+
+- GHA: add MSYS, mingw-w64, Cygwin jobs
+
+ - re-implement autotools MSYS and Cygwin AppVeyor jobs in GHA.
+ Now build with SSL and PSL to improve test coverage.
+ - re-implement MSYS2 mingw-w64 gcc 13 AppVeyor job in GHA.
+ `CMake, mingw-w64, gcc 13, Debug, x64, Schannel, Static, Unicode`
+ - add new cmake Cygwin job (build-only).
+ - enable `-j14` parallelism when running tests.
+ - delete the 5 migrated jobs from AppVeyor CI.
+ - add 2 build-only mingw-w64 builds, gcc Release and clang OpenSSL.
+ - also enable brotli, libssh2, nghttp2 for more test coverage.
+
+ These jobs offer better performance, more flexibility and
+ parallelization compared to the AppVeyor ones they replace. It also
+ offloads AppVeyor, allowing to iterate faster. They also appear more
+ reliable than e.g. Azure Windows jobs, where runners are prone to fail
+ [1].
+
+ Closes #13599
+
+ [1]:
+ `Exit code 143 returned from process: file name 'C:\Windows\system32\docker.E
+ XE',
+ arguments 'exec -i 6b13a669c6dfe7fb9f59414369872fd64d61c7182f880c3d39c135cb
+ 4c115c8f
+ C:\__a\externals\node\bin\node.exe C:\__w\_temp\containerHandlerInvoker.js'.`
+
+Stefan Eissing (17 May 2024)
+
+- pytest: fixes for recent python, add FTP tests
+
+ Fixes:
+ - in uds tests, abort also silently on os errors
+ - be conservative on the h3 goaway duration
+ - detect curl debug build and use in checks
+ - fix caddy version check for slight difference under linux
+ - set caddy default path fitting for linux
+ - fix deprecation warnings in valid time checks
+
+ FTP tests:
+ - add '--with-test-vsftpd=path' to configure
+ - use vsftpd default path suitable for linux
+ - add test_30 with plain FTP tests
+ - add test_31 with --ssl-reqd FTP tests
+ - add vsftpd to linux GHA for pytest workflows
+
+ Closes #13661
+
+- rustls: fix handshake done handling
+
+ - rustls report it has finished the TLS handshake *before*
+ all relevant data has been sent off, e.g. it FINISHED message
+ - On connections the send data immediately, this was never noticed
+ as the FINISHED in rustls buffers was send with the app data
+ - On passive FTP connections, curl does not send any data after
+ the handshake, leaving FINISHED unsent and the server never
+ responded as it was waiting on this.
+
+ Closes #13686
+
+Daniel Stenberg (17 May 2024)
+
+- x509asn1: return error on missing OID
+
+ to avoid crash when dereferencing a NULL pointer.
+
+ Reported-by: Trzik on github
+ Patch-by: Trzik on github
+ Fixes #13684
+ Closes #13685
+
+- CURLOPT_WRITEFUNCTION.md: fix the callback proto in the example
+
+ Reported-by: Michael Litwak
+ Fixes #13681
+ Closes #13687
+
+Viktor Szakats (17 May 2024)
+
+- src: tidy up types, add necessary casts
+
+ Cherry-picked from #13489
+ Closes #13614
+
+- lib: fix compiler warnings (gcc)
+
+ Seen when setting `ENABLE_DEBUG=ON` and `-DDEBUGBUILD` for mingw-w64
+ gcc 13.2.0 CMake unity builds in 'Release' configurations.
+
+ ```
+ curl/lib/curl_gethostname.c:71:5: error: 'strncpy' specified bound 1025 equal
+ s destination size [-Werror=stringop-truncation]
+ 71 | strncpy(name, force_hostname, namelen);
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ In file included from curl/_bld/lib/CMakeFiles/libcurl_object.dir/Unity/unity
+ _0_c.c:175:
+ In function 'hostcache_timestamp_remove',
+ inlined from 'Curl_hash_clean_with_criterium' at curl/lib/hash.c:265:19,
+ inlined from 'Curl_hash_clean_with_criterium' at curl/lib/hash.c:247:1,
+ inlined from 'hostcache_prune' at curl/lib/hostip.c:228:3,
+ inlined from 'Curl_hostcache_prune' at curl/lib/hostip.c:256:21:
+ curl/lib/hostip.c:205:12: error: 'now' may be used uninitialized [-Werror=may
+ be-uninitialized]
+ 205 | time_t age = prune->now - c->timestamp;
+ | ^~~
+ curl/lib/hostip.c: In function 'Curl_hostcache_prune':
+ curl/lib/hostip.c:241:10: note: 'now' was declared here
+ 241 | time_t now;
+ | ^~~
+ In function 'hostcache_timestamp_remove',
+ inlined from 'fetch_addr' at curl/lib/hostip.c:310:8:
+ curl/lib/hostip.c:205:23: error: 'user.now' may be used uninitialized [-Werro
+ r=maybe-uninitialized]
+ 205 | time_t age = prune->now - c->timestamp;
+ | ~~~~~^~~~~
+ curl/lib/hostip.c: In function 'fetch_addr':
+ curl/lib/hostip.c:304:33: note: 'user' declared here
+ 304 | struct hostcache_prune_data user;
+ | ^~~~
+ In file included from curl/_bld/lib/CMakeFiles/libcurl_object.dir/Unity/unity
+ _0_c.c:40:
+ curl/lib/cf-socket.c: In function 'cf_socket_send':
+ curl/lib/cf-socket.c:1294:10: error: 'c' may be used uninitialized [-Werror=m
+ aybe-uninitialized]
+ 1294 | if(c >= ((100-ctx->wblock_percent)*256/100)) {
+ | ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ curl/lib/cf-socket.c:1292:19: note: 'c' was declared here
+ 1292 | unsigned char c;
+ | ^
+ In file included from curl/_bld/lib/CMakeFiles/libcurl_object.dir/Unity/unity
+ _0_c.c:364:
+ In function 'tftp_state_timeout',
+ inlined from 'tftp_multi_statemach' at curl/lib/tftp.c:1230:27:
+ curl/lib/tftp.c:1208:5: error: 'current' may be used uninitialized [-Werror=m
+ aybe-uninitialized]
+ 1208 | if(current > state->rx_time + state->retry_time) {
+ | ^
+ curl/lib/tftp.c: In function 'tftp_multi_statemach':
+ curl/lib/tftp.c:1192:10: note: 'current' was declared here
+ 1192 | time_t current;
+ | ^~~~~~~
+ ```
+ Ref: https://ci.appveyor.com/project/curlorg/curl/builds/49792835/job/91c8dj5
+ qb36spfe0#L112
+ Ref: https://github.com/curl/curl/actions/runs/9082968838/job/24960616145#ste
+ p:12:62
+
+ Ref: #13592
+ Closes #13643
+
+Andrew (16 May 2024)
+
+- wakeup_create: use FD_CLOEXEC/SOCK_CLOEXEC
+
+ for `pipe()`/`socketpair()`
+
+ Fixes #13618
+ Closes #13625
+
+Stefan Eissing (16 May 2024)
+
+- rustls: fix partial send handling
+
+ When TLS bytes could not completely sent off, the amount of plain bytes
+ already added to rustls were forgotten. This lead to send those byte
+ duplicate, corrupting the request send to the server.
+
+ Closes #13676
+
+- pytest: add DELETE tests, check server version
+
+ - add tests for DELETE working
+ - check apache version in keepalive test
+ - fix some comments
+
+ Closes #13679
+
+Juliusz Sosinowicz (16 May 2024)
+
+- vquic-tls: use correct cert name check API for wolfSSL
+
+ wolfSSL_X509_check_host checks the peer name against the alt names and
+ the common name.
+
+ Fixes #13487
+ Closes #13680
+
+Viktor Szakats (16 May 2024)
+
+- cmake: initialize `BUILD_TESTING` before first use
+
+ Before this patch `BUILD_TESTING` was used once, then initialized, then
+ used again. This caused the `curlu` library not being built when relying
+ on an implicit `BUILD_TESTING=ON` setting, and ending up with a link
+ error when building the `testdeps` target.
+
+ It did not cause issues when `BUILD_TESTING` was explicitly set.
+
+ Move the initialization before the first use to fix it.
+
+ Regression from aace27b0965c10394544d1dacc9c2cb2fe0de3d3 #12287
+ Closes #13668
+
+Daniel Stenberg (16 May 2024)
+
+- libtest: 2308 verifies CURLE_WRITE_ERROR after write callback error
+
+ Verifies that the issue in #13669 actually is fixed. This return code is
+ what the CURLOPT_WRITEFUNCTION manpage documents should be returned.
+
+ This code is mostly from the
+ Source-written-by: Trumeet on github
+ Closes #13671
+
+Antoine Bollengier (16 May 2024)
+
+- socketpair: fix compilation when USE_UNIX_SOCKETS is not defined
+
+ Closes #13666
+
+Stefan Eissing (16 May 2024)
+
+- rustsls: fix error code on receive
+
+ - use CURLE_RECV_ERROR instead of CURLE_READ_ERROR when receiving
+ data fails.
+
+ Closes #13670
+
+Max Dymond (16 May 2024)
+
+- ci: disable Renovate dashboard
+
+ The Renovate dashboard insists on an open issue,
+ which is a problem. Disable the dashboard. Status
+ can still be seen at https://developer.mend.io/github/curl/curl.
+
+ Fixes #13630
+ Closes #13673
+
+Daniel Stenberg (16 May 2024)
+
+- RELEASE-NOTES: synced
+
+renovate[bot] (16 May 2024)
+
+- GHA: update awslabs/aws-lc to v1.27.0
+
+ Closes #13667
+
+Daniel Stenberg (15 May 2024)
+
+- curl_easy_pause.md: use correct defines in example
+
+ Spotted-by: Harry Sintonen
+ Closes #13664
+
+Viktor Szakats (15 May 2024)
+
+- appveyor: more tidy-ups
+
+ - use `--disable` when calling `curl --version`. Just in case.
+
+ - use single-quotes for a constant.
+
+ Closes #13662
+
+- reuse: migrate standalone license file to dep5
+
+ Follow-up to 73a36021207284ad2b4340ffde34a51b0ba4d47a
+ Closes #13660
+
+- appveyor: guard against crash-build with VS2008
+
+ The combination of `-DDEBUGBUILD`, a shared `curl.exe`, and the VS2008
+ compiler creates a `curl.exe` segfaulting on startup:
+
+ ```
+ + _bld/src/curl.exe --version
+ ./appveyor.sh: line 122: 793 Segmentation fault "${curl}" --version
+ Command exited with code 139
+ ```
+ Ref: https://ci.appveyor.com/project/curlorg/curl/builds/49817266/job/651iy6q
+ n1e238pqj#L191
+
+ Add job that triggers the issue and add the necessary logic to skip
+ running the affected `curl.exe`.
+
+ Ref: #13592
+ Closes #13654
+
+renovate[bot] (15 May 2024)
+
+- GHA: pin dependencies
+
+ Closes #13628
+
+Orgad Shaneh (15 May 2024)
+
+- socket: remove redundant call to getsockname
+
+ The result "add" is unused.
+
+ Closes #13655
+
+renovate[bot] (15 May 2024)
+
+- CI: renovate updates
+
+ - GHA: update actions/checkout action to v4
+ - GHA: update wolfSSL/wolfssh to v1.4.17
+ - GHA: update wolfSSL/wolfssl to v5.7.0
+ - Update the regex config in renovate.json
+
+ Closes #13632
+ Closes #13641
+ Closes #13658
+ Closes #13659
+
+Max Dymond (15 May 2024)
+
+- ci: fix renovate config for WolfSSL/WolfSSH tagging scheme
+
+ WolfSSL/WolfSSH use a different versioning scheme;
+ stable builds end with `-stable`. Renovate requires
+ some extra configuration to extract the version
+ from these types of tags.
+
+ Closes #13644
+
+- ci: set semantic type as CI and include digests as CI operations
+
+ Replace "chore" with "ci" for renovate's semantic
+ type, and include digests with "pin" and
+ "pinDigest" as ci operations.
+
+ Closes #13644
+
+Daniel Stenberg (15 May 2024)
+
+- DEPRECATE.md: TLS libraries without 1.3 support
+
+ curl drops support for TLS libraries without TLS 1.3 capability after
+ May 2025.
+
+ It requires that a curl build using the library should be able to
+ negotiate and use TLS 1.3, or else it is not good enough. We support a
+ vast amount of other TLS libraries that are likely to satisfy users
+ better.
+
+ Closes #13544
+
+- Revert "ci: update nghttp2/nghttp2 to v1.62.0"
+
+ This reverts commit 14f2c767555b7598d7783ccd9093670b84d28488.
+
+ We need to also upgrade the C++ compiler for that bump to work.
+
+ Closes #13656
+
+renovate[bot] (15 May 2024)
+
+- Dockerfile: update debian digest to 911821c
+
+ Closes #13629
+
+- ci: update gnutls/gnutls to v3.8.5
+
+ Closes #13640
+
+- ci: update awslabs/aws-lc to v1.26.0
+
+ Closes #13647
+
+- ci: update cloudflare/quiche to v0.21.0
+
+ Closes #13648
+
+- ci: update libressl-portable/portable to v3.9.2
+
+ Closes #13649
+
+- ci: update nghttp2/nghttp2 to v1.62.0
+
+ Closes #13650
+
+- ci: update ngtcp2/nghttp3 to v1.3.0
+
+ Closes #13651
+
+- ci: update ngtcp2/ngtcp2 to v1.5.0
+
+ Closes #13652
+
+Max Dymond (14 May 2024)
+
+- ci: handle git submodules for mbedTLS
+
+- ci: reconfigure renovate
+
+ - set prefix for github actions updates to be gha:
+ - set prefix for other renovate actions to be ci:
+ - disable debian updates in linux-old.yml
+
+Viktor Szakats (14 May 2024)
+
+- tidy-up: whitespace [ci skip]
+
+- warnless: delete orphan declarations
+
+ Follow-up to 358f7e757781857c4b498a68634726609fa3884a #11932
+ Closes #13639
+
+Daniel Stenberg (14 May 2024)
+
+- BUG-BOUNTY.md: clarify the third party situation
+
+ We do not pay bounties for problems in other libraries.
+
+ Closes #13560
+
+Stefan Eissing (14 May 2024)
+
+- http tests: in CI skip test_02_23* for quiche
+
+ For unknown reasons, these tests fail in CI often, but run fine locally.
+ Skip them in CI to avoid unrelated PRs to have failures.
+
+ Closes #13638
+
+Daniel Gustafsson (14 May 2024)
+
+- hsts: explicitly skip blank lines
+
+ Keep blank lines or lines containing only whitespace to make it all
+ the way to the more expensive sscanf call in hsts_add.
+
+ Closes: #13603
+ Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+
+- autotools: Only probe for SGI MIPS compilers on IRIX
+
+ MIPSPro and the predecessor compiler which was part of the IDO (IRIS
+ Development Option) were only ever shipped on the SGI IRIX operating
+ system (with MIPSPro on 6.0+ which was released in 1994). Limit the
+ autoconf check to IRIX when probing for these compilers to save some
+ cycles on other platforms.
+
+ Closes: #13611
+ Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+
+Viktor Szakats (14 May 2024)
+
+- tests: fix test 1167 to skip digit-only symbols
+
+ This avoids mistaking symbols with their numeric value when using
+ certain C preprocessors which output these numeric values at the
+ beginning of the line as part of an expression.
+
+ Seen on OpenBSD 7.5 + clang.
+
+ Example `test1167.pl -v` output, before this patch:
+ ```
+ Source: cpp /home/runner/work/curl/curl/tests/../include/curl/curl.h
+ Symbol: 20000
+ Line #3835: 20000 + 142,
+ [...]
+ Bad symbols in public header files:
+ 20000
+ [...]
+ ```
+ Ref: https://github.com/curl/curl/actions/runs/9069136530/job/24918015357#ste
+ p:3:7513
+
+ Ref: #13583
+ Closes #13634
+
+Daniel Stenberg (14 May 2024)
+
+- lib: call Curl_strntolower instead of doing crafted loops
+
+ Closes #13627
+
+- setopt: acknowledge errors proper for CURLOPT_COOKIEJAR
+
+ Error out on error, do not continue.
+
+ Closes #13624
+
+- vtls: remove duplicate assign
+
+ Curl_ssl_peer_cleanup() already clears the ->sni field, no point in
+ assigning it again.
+
+ Spotted by CodeSonar
+
+ Closes #13626
+
+Max Dymond (13 May 2024)
+
+- Group all non-major updates together to reduce PR spam
+
+- Add the remainder of the workflows
+
+- Add some basic versioning for some workflows to check whether this is detecte
+ d properly
+
+renovate[bot] (13 May 2024)
+
+- Add renovate.json
+
+Daniel Stenberg (13 May 2024)
+
+- vauth: make two functions void that always just returned OK
+
+ Removes the need to check return values when they can never fail.
+
+ Pointed out by CodeSonar
+
+ Closes #13621
+
+- setopt: remove check for 'option' that is always true
+
+ - make sure that passing in option set to NULL clears the fields
+ correctly
+
+ - remove the weird second take if Curl_parse_login_details() returns
+ error
+
+ Follow-up to 7333faf00bf25db7cd1e0012d6b140
+
+ Spotted by CodeSonar
+
+ Closes #13619
+
+Viktor Szakats (13 May 2024)
+
+- tests: tidy up types in server code
+
+ Cherry-picked from #13489
+ Closes #13610
+
+Daniel Stenberg (13 May 2024)
+
+- setopt: make the setstropt_userpwd args compulsory
+
+ They were always used so no point in allowing them to be optional.
+
+ follow-up to 0e37b42dc956bd8a
+
+ Closes #13608
+ Reviewed-by: Daniel Gustafsson
+
+- RELEASE-NOTES: synced
+
+Daniel Gustafsson (13 May 2024)
+
+- websocket: Avoid memory leak in error path
+
+ In the errorpath for randstr being too long to copy into the buffer
+ we leak the randstr when returning CURLE_FAILED_INIT. Fix by using
+ an explicit free on randstr in the errorpath.
+
+ Closes: #13602
+ Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+
+- hsts: Remove single-use single-line function
+
+ The hsts_entry() function contains of a single line and is only
+ used in a single place in the code, so move the allocation into
+ hsts_create instead to improve code readability. C code usually
+ don't use the factory abstraction for object creation, and this
+ small example wasn't following our usual code style.
+
+ Closes: #13604
+ Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+
+Viktor Szakats (12 May 2024)
+
+- lib: bump hash sizes to `size_t`
+
+ Follow-up to cc907e80a2498c0599253271a6f657f614b52a4e #13502
+ Cherry-picked from #13489
+ Closes #13601
+
+- tests: make the unit test result type `CURLcode`
+
+ Before this patch, the result code was a mixture of `int` and
+ `CURLcode`.
+
+ Also adjust casts and fix a couple of minor issues found along the way.
+
+ Cherry-picked from #13489
+ Closes #13600
+
+- appveyor: tidy-ups
+
+ - delete a duplicate line.
+ - simplify a `make` call.
+ - merge two `if` branches.
+ - reorder autotools options for clarity.
+ - add `--enable-warnings` where missing (it's also the default.)
+ - add empty lines to YAML for readability.
+ - use lowercase install prefix/directory.
+
+ Closes #13598
+
+Daniel Stenberg (12 May 2024)
+
+- docs/cmdline-opts: mention STARTTLS for --ssl and --ssl-reqd
+
+ ... since users might look for those terms in the manpage.
+
+ Closes #13590
+
+- setopt: warn on Curl_set*opt() uses not using the return value
+
+ And switch the invokes that would "set" NULL to instead just plainly
+ free the pointer, as those were otherwise the invokes that would ignore
+ the return code. And possibly confuse static code analyzers.
+
+ Closes #13591
+
+Orgad Shaneh (12 May 2024)
+
+- autotools: delete unused functions
+
+ Closes #13605
+
+Viktor Szakats (11 May 2024)
+
+- examples: fix/silence `-Wsign-conversion`
+
+ - extend `FD_SET()` hack to all platforms (was only Cygwin).
+ Warnings may also happen in other envs, e.g. OmniOS.
+ Ref: https://github.com/libssh2/libssh2/actions/runs/8854199687/job/2431676
+ 2831#step:3:2021
+
+ - tidy-up `CURLcode` vs `int` use.
+
+ - cast an unsigned to `long` before passing to `curl_easy_setopt()`.
+
+ Cherry-picked from #13489
+ Follow-up to 3829759bd042c03225ae862062560f568ba1a231 #12489
+ Closes #13501
+
+Orgad Shaneh (11 May 2024)
+
+- cmake: fix `HAVE_IOCTLSOCKET_FIONBIO` test with gcc 14
+
+ The function signature has had u_long flags since ever. This is how it
+ is defined in the documentation, and implemented in MinGW.
+
+ The code that uses ioctlsocket in nonblock.c also has unsigned long.
+
+ Error:
+ CurlTests.c:275:41: error: passing argument 3 of 'ioctlsocket' from incompati
+ ble pointer type [-Wincompatible-pointer-types]
+ 275 | if(0 != ioctlsocket(0, FIONBIO, &flags))
+ | ^~~~~~
+ | |
+ | int *
+ In file included from CurlTests.c:266:
+ /opt/mxe/usr/i686-w64-mingw32.static/include/winsock2.h:1007:76: note: expect
+ ed 'u_long *' {aka 'long unsigned int *'} but argument is of type 'int *'
+ 1007 | WINSOCK_API_LINKAGE int WSAAPI ioctlsocket(SOCKET s,__LONG32 cmd,u_
+ long *argp);
+ | ~~
+ ~~~~~~^~~~
+
+ Closes #13578
+
+Jay Satiro (10 May 2024)
+
+- ftp: fix build for CURL_DISABLE_VERBOSE_STRINGS
+
+ This is a follow-up to b7c7dffe which changed the FTP state change
+ verbose debug text (aka infof) to tracing debug text (aka trc).
+
+ Prior to this change if libcurl was without DEBUGBUILD and built with
+ CURL_DISABLE_VERBOSE_STRINGS (ie --disable-verbose) the build would
+ error.
+
+ Caught by Circle CI job openssl-no-verbose.
+
+- lib: clear the easy handle's saved errno before transfer
+
+ - Clear data->state.os_errno before transfer.
+
+ - Explain the change in behavior in the CURLINFO_OS_ERRNO doc.
+
+ - Add to the CURLINFO_OS_ERRNO doc the list of libcurl network-related
+ errors that may cause the errno to be saved.
+
+ data->state.os_errno is saved before libcurl returns a network-related
+ failure such as connection failure. It is accessible to the user via
+ CURLINFO_OS_ERRNO so they can get more information about the failure.
+
+ Prior to this change it wasn't cleared before transfer, so if a user
+ retrieved the saved errno it could be from a previous transfer. That is
+ because an errno is not always saved for network-related errors.
+
+ Closes https://github.com/curl/curl/pull/13574
+
+Stefan Eissing (10 May 2024)
+
+- ftp: add tracing support
+
+ - add `Curl_trc_feat_ftp` for tracing via trace config
+ - add macro CURL_TRC_FTP(data, fmt, ...)
+ - replace DEBUGF(infof()) statements in ftp.c by CURL_TRC_FTP()
+ - always trace FTP connection state
+
+ Closes #13580
+
+Daniel Stenberg (10 May 2024)
+
+- http: remove redundant check
+
+ Spotted by CodeSonar
+
+ Closes #13582
+
+Viktor Szakats (10 May 2024)
+
+- ldap: fix unused variables (seen on OmniOS)
+
+ ```
+ ../../lib/ldap.c: In function 'ldap_do':
+ ../../lib/ldap.c:380:11: error: unused variable 'ldap_ca' [-Werror=unused-v
+ ariable]
+ 380 | char *ldap_ca = conn->ssl_config.CAfile;
+ | ^~~~~~~
+ ../../lib/ldap.c:379:9: error: unused variable 'ldap_option' [-Werror=unuse
+ d-variable]
+ 379 | int ldap_option;
+ | ^~~~~~~~~~~
+ ```
+ Ref: https://github.com/curl/curl/actions/runs/9033564377/job/24824192730#ste
+ p:3:6059
+
+ Ref: #13583
+ Closes #13588
+
+Daniel Stenberg (10 May 2024)
+
+- url: make parse_login_details use memdup0
+
+ Also make the user and password arguments mandatory, since all code
+ paths in libcurl used them anyway.
+
+ Adapted unit test case 1620 to the new rules.
+
+ Closes #13584
+
+Orgad Shaneh (10 May 2024)
+
+- digest: replace strcpy for empty string with simple assignment
+
+ Closes #13586
+
+Viktor Szakats (10 May 2024)
+
+- autotools: fix `HAVE_IOCTLSOCKET_FIONBIO` test for gcc 14
+
+ ```
+ conftest.c:152:41: error: passing argument 3 of 'ioctlsocket' from incompatib
+ le pointer type [-Wincompatible-pointer-types]
+ 152 | if(0 != ioctlsocket(0, FIONBIO, &flags))
+ | ^~~~~~
+ | |
+ | int *
+ ```
+
+ Reported-by: LigH
+ Fixes #13579
+ Closes #13587
+
+- CI: ignore test 286 on Appveyor gcc 7 build
+
+ Disabled earlier for gcc 9 builds. gcc 7 uses the same runner and
+ prone to similar intermittent failures.
+
+ Follow-up to f1e05a6e6e7225fa09952abb2c935ae1abe44f45 #12106 #12040
+ Closes #13575
+
+Daniel Stenberg (10 May 2024)
+
+- cf-socket: don't try getting local IP without socket
+
+ In cf_tcp_connect(), it might fail and not get a socket assigned to
+ ctx->sock but set_local_ip() is still called which would make
+ getsockname() get invoked with a negative file desriptor and fail.
+
+ By adding this check, set_local_ip() will now instead blank out the
+ fields correctly.
+
+ Spotted by CodeSonar
+
+ Closes #13577
+
+- tool_getparam: remove two redundant conditions
+
+ When getstr() does not return error, it returns a valid pointer.
+
+ Spotted by CodeSonar
+
+ Closes #13576
+
+Stefan Eissing (10 May 2024)
+
+- quiche: trust its timeout handling
+
+ - set the idle timeout transport parameter
+ in milliseconds as documented by quiche
+ - do not calculate the idle timeout, rely on
+ quiche handling it
+
+ Closes #13581
+
+Daniel Stenberg (10 May 2024)
+
+- dmaketgz: accept a SOURCE_DATE_EPOCH as an second argument
+
+ to make it easier to reproduce a tarball
+
+ Closes #13573
+
+- RELEASE-NOTES: synced
+
+Stefan Eissing (10 May 2024)
+
+- h3/ngtcp2: improve error handling
+
+ - identify ngtcp2 and nghttp3 error codes that are fatal
+ - close quic connection on fatal errors
+ - refuse further filter operations once connection is closed
+ - confusion about the nghttp3 API. We should close the QUIC stream on
+ cancel and not use the nghttp3 calls intended to be invoked when the
+ QUIC stream was closed by the peer.
+
+ Closes #13562
+
+Jay Satiro (10 May 2024)
+
+- docs: fix some CURLINFO examples
+
+ - improve getinfo result check for example sections:
+ CURLINFO_ACTIVESOCKET, CURLINFO_LASTSOCKET, CURLINFO_SSL_VERIFYRESULT,
+ CURLINFO_PROXY_SSL_VERIFYRESULT
+
+ - fix getinfo result check for example sections:
+ CURLINFO_NUM_CONNECTS, CURLINFO_OS_ERRNO
+
+ - fix verify result check for example sections:
+ CURLINFO_PROXY_SSL_VERIFYRESULT
+
+ Bug: https://github.com/curl/curl/discussions/13557#discussion-6625507
+ Reported-by: farazrbx@users.noreply.github.com
+
+ Closes https://github.com/curl/curl/pull/13559
+
+Daniel Stenberg (9 May 2024)
+
+- KNOWN_BUGS: gssapi library name + version is missing in curl_version_info()
+
+ Closes #13492
+ Closes #13570
+
+- krb5: use dynbuf
+
+ Closes #13568
+
+- managen: fix the option sort order
+
+ ... it used to strip off the .d file extension to sort correctly but
+ ever since the extension changed to .md the operation failed and the
+ sort got wrong.
+
+ Follow-up to 2494b8dd5175cee7f2e
+
+ Closes #13567
+
+Stefan Eissing (8 May 2024)
+
+- GHA: repair the linux-old job
+
+ package libc6_2.28-10+deb10u2_amd64.deb changed to
+ libc6_2.28-10+deb10u3_amd64.deb
+
+ Closes #13564
+
+Viktor Szakats (8 May 2024)
+
+- appveyor: make gcc 6 mingw64 job build-only
+
+ This job has proven to be the flakiest of all, and it's also the oldest
+ Windows runner we had tests running on: 'Visual Studio 2015', that is
+ running on Windows Server 2012 R2:
+ https://www.appveyor.com/docs/windows-images-software/
+
+ Turn off tests on this job to help stabilizing CI runs.
+
+ This was also one of the slowest running job amongst the AppVeyor CI ones.
+
+ Flakiness data:
+ https://testclutch.curl.se/static/reports/summary.html
+ Entries:
+ Appveyor / CMake, mingw-w64, gcc 6, Debug, x86, Schannel, Static, no-unity
+ (curl) [current]
+ Appveyor / CMake, mingw-w64, gcc 6, Debug, x86, Schannel, Static (curl) [fo
+ rmer]
+
+ Closes #13566
+
+Stefan Eissing (8 May 2024)
+
+- unit2604: use alloc instead of overlong string const
+
+ Closes #13563
+
+Daniel Gustafsson (8 May 2024)
+
+- bufq: remove duplicate word in comment
+
+ Inspired by 13552.
+
+ Closes: #13554
+ Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+
+Viktor Szakats (8 May 2024)
+
+- lib/cf-h1-proxy: silence compiler warnings (gcc 14)
+
+ They came up ealier with gcc 12 (Windows), but apparently gcc 14 is
+ still reporting them, also under Linux.
+
+ ```
+ /home/runner/work/curl-for-win/curl-for-win/curl/lib/cf-h1-proxy.c: In functi
+ on 'cf_h1_proxy_close':
+ /home/runner/work/curl-for-win/curl-for-win/curl/lib/cf-h1-proxy.c:1060:17: w
+ arning: null pointer dereference [-Wnull-dereference]
+ 1060 | cf->connected = FALSE;
+ /home/runner/work/curl-for-win/curl-for-win/curl/lib/cf-h1-proxy.c:1061:8: wa
+ rning: null pointer dereference [-Wnull-dereference]
+ 1061 | if(cf->ctx) {
+ | ~~^~~~~
+ In function 'tunnel_free',
+ inlined from 'cf_h1_proxy_destroy' at /home/runner/work/curl-for-win/curl
+ -for-win/curl/lib/cf-h1-proxy.c:1053:3:
+ /home/runner/work/curl-for-win/curl-for-win/curl/lib/cf-h1-proxy.c:198:27: wa
+ rning: null pointer dereference [-Wnull-dereference]
+ 198 | struct h1_tunnel_state *ts = cf->ctx;
+ | ^~
+ ```
+ Ref: https://github.com/curl/curl-for-win/actions/runs/8985369476/job/2467921
+ 9528#step:3:6320
+
+ Fixes #13237
+ Closes #13555
+
+Michał Antoniak (8 May 2024)
+
+- mbedtls: support TLS 1.3
+
+ Closes #13539
+
+Daniel Stenberg (8 May 2024)
+
+- version: use msnprintf instead of strncpy
+
+ - to ensure a terminating null byte
+ - to avoid zero-padding the target
+
+ debug code only
+
+ Closes #13549
+
+- curl_path: make Curl_get_pathname use dynbuf
+
+ ... instead of malloc and memcpy
+
+ - unit test 2604 verifies Curl_get_pathname()
+
+ Closes #13550
+
+- lib: make protocol handlers store scheme name lowercase
+
+ - saves a lowercase operation when the "[scheme]_proxy" name is
+ generated
+ - appears less "shouting"
+ - update test 970, 972, 1438 and 1536
+
+ Closes #13553
+
+- lib: remove two instances of "only only" messages
+
+ Fixes #13551
+ Reported-by: Lucas Nussbaum
+ Closes #13552
+
+Pavel Pavlov (7 May 2024)
+
+- asyn-thread: fix curl_global_cleanup crash in Windows
+
+ - Make sure that asynchronous resolves handled by Winsock are stopped
+ before WSACleanup is called.
+
+ This is implemented by ensuring that when Curl_resolver_kill is called
+ (eg via multi_done) it will cancel the Winsock asynchronous resolve and
+ wait for the cancellation to complete. Winsock runs the asynchronous
+ completion routine immediately when a resolve is canceled.
+
+ Prior to this change it was possible that during curl_global_cleanup
+ "a DNS resolver thread created by GetAddrInfoExW did not terminate yet,
+ however curl is already shutting down, deinitializing Winsock with
+ WSACleanup() leading to an access violation."
+
+ Background:
+
+ If libcurl is built with the asynchronous threaded resolver option for
+ Windows then it resolves in one of two ways. For Windows 8.1 and later,
+ libcurl resolves by using the Winsock asynchronous resolver which does
+ its own thread management. For older versions of Windows, libcurl
+ resolves by creating a separate thread that calls getaddrinfo. This
+ change only affects the former and it's already handled for the latter.
+
+ Reported-by: Ch40zz@users.noreply.github.com
+
+ Fixes https://github.com/curl/curl/issues/13509
+ Closes https://github.com/curl/curl/pull/13518
+
+Jay Satiro (7 May 2024)
+
+- asyn-thread: fix Curl_thread_create result check
+
+ - Compare to curl_thread_t_null instead of 0 for error.
+
+ Currently for both supported thread libraries (pthreads and Windows)
+ curl_thread_t_null is defined as 0. However, the pattern throughout the
+ code is to check against curl_thread_t_null and not 0 since for
+ posterity some thread library may not use 0 for error.
+
+ Closes https://github.com/curl/curl/pull/13542
+
+- curl_multibyte: remove access() function wrapper for Windows
+
+ - Remove curlx_win32_access() which was a wrapper to use access() in
+ Windows.
+
+ This is a follow-up to 602fc213, one of two commits which removed
+ access() calls from the codebase and banned use of the function.
+
+ Closes https://github.com/curl/curl/pull/13529
+
+Daniel Gustafsson (6 May 2024)
+
+- tls: Remove EXAMPLEs from deprecated options
+
+ CURLOPT_EGDSOCKET and CURLOPT_RANDOM_FILE are both completely dead
+ so remove their example sections since the code there is useless.
+ There is still a way to inject a random file for OpenSSL older than
+ 1.1.0 but it's not what the example showed (and it's not even done
+ with this option) so we refrain from documenting it here.
+
+ Closes: #13540
+ Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+
+- tests: Only require EXAMPLE for non-deprecated options
+
+ Manpages which document deprecated CURLOPT_ or CURLINFO_ are not
+ required to have an EXAMPLE section since they might effectively
+ be dead no-ops which we don't want to trick users into believing
+ they can use by copying example code.
+
+ Closes: #13540
+ Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+
+Daniel Stenberg (6 May 2024)
+
+- EXPERIMENTAL: add graduation requirements for each feature
+
+ Starting now, experimental features should have a set of documentated
+ requirements of what is needed for the feature to graduate.
+
+ This adds requirements to all existing experiments.
+
+ Closes #13541
+
+Ivan (6 May 2024)
+
+- misc: fix typos, quoting and spelling
+
+ Fix wording of comments, and misquotings where `' is markdown parsed
+ where it shouldn't be, and remove a misspelled preprocessor comment
+ which really isn't needed (and removing it makes it match surrounding
+ code better).
+
+ Closes: #13538
+ Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
+
+Daniel Gustafsson (6 May 2024)
+
+- tests: Mark tftpd timer function as noreturn
+
+ This avoids the below compiler warning:
+
+ tftpd.c:280:1: warning: function 'timer' could be declared with
+ attribute 'noreturn' [-Wmissing-noreturn]
+
+ Closes: #13534
+ Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+
+- doh: Remove unused function prototype
+
+ Closes: #13536
+ Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+
+Daniel Stenberg (6 May 2024)
+
+- doh: cleanups in ECH related functions
+
+ - make local_decode_rdata_name use dynbuf instead of calloc + memcpy
+ - avoid extra memdup in local_decode_rdata_alpn
+ - no need to if() before free()
+ - use memdup instead of calloc + memcpy in Curl_doh_decode_httpsrr
+
+ Reviewed-by: Stephen Farrell
+ Closes #13526
+
+Viktor Szakats (5 May 2024)
+
+- libssh2: delete redundant feature guard
+
+ Delete `HAVE_LIBSSH2_VERSION` (equivalent to
+ `LIBSSH2_VERSION_NUM` > 0x010100) guard surrounding
+ a `LIBSSH2_VERSION_NUM` > 0x010B00 one.
+
+ Reviewed-by: Daniel Gustafsson
+ Closes #13537
+
+Jan Venekamp (5 May 2024)
+
+- tool_cfgable: free {proxy_}cipher13_list on exit
+
+ Author: Jan Venekamp
+ Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
+ Closes: #13531
+
+RainRat (4 May 2024)
+
+- doh: Fix typo in comment
+
+ Closes: #13504
+ Author: RainRat on Github
+ Reviewed-by: Daniel Stenberg <daniel@haxx.se>
+ Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
+
+Christian Schmitz (4 May 2024)
+
+- dynbuf: Fix returncode on memory error
+
+ Curl_dyn_vaddf should return a proper error code in case allocating
+ memory failed.
+
+ Closes: #13533
+ Author: Christian Schmitz <support@monkeybreadsoftware.de>
+ Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
+
+Daniel Stenberg (3 May 2024)
+
+- RELEASE-NOTES: synced
+
+Jan Venekamp (2 May 2024)
+
+- bearssl: use common code for cipher suite lookup
+
+ Take advantage of the Curl_cipher_suite_walk_str() and
+ Curl_cipher_suite_get_str() functions introduced in commit fba9afeb.
+
+ This also fixes CURLOPT_SSL_CIPHER_LIST not working at all for bearssl
+ due to commit ff74cef5.
+
+ Closes #13464
+
+Daniel Stenberg (2 May 2024)
+
+- curl.h: change CURL_SSLVERSION_* from enum to defines
+
+ C++20 and later compilers emit a deprecation warning if values from two
+ different enums are combined with a bitwise operation the way the
+ CURL_SSLVERSION_* values were previously created.
+
+ Reported-by: Michael Kaufmann
+ Fixes #13510
+ Closes #13511
+
+- configure: error on missing perl if docs or manual is enabled
+
+ Fixes #13508
+ Reported-by: Harmen Stoppels
+ Closes #13514
+
+- tool_cb_rea: limit rate unpause for -T . uploads
+
+ To avoid getting stuck in a busy-loop when nothing is read from stdin,
+ this function now checks the call rate and might enforce a short sleep
+ when called repeatedly without uploading anything. It is a crude
+ work-around to avoid a 100% busy CPU.
+
+ Reported-by: magisterquis on hackerone
+ Fixes #13174
+ Closes #13506
+
+Viktor Szakats (1 May 2024)
+
+- appveyor: enable websockets for VS2017 jobs
+
+ Follow-up to eb4fe6c6340c3d5b0c347c6e30be004d4f9117d7 #13232
+ Closes #13513
+
+Daniel Stenberg (30 Apr 2024)
+
+- if2ip: make the buf_size arg a size_t
+
+ sizes should be size_t
+
+ Ref: #13489
+ Closes #13505
+
+- cf-https-connect: use timeouts as unsigned ints
+
+ To match the type used in 'set.happy_eyeballs_timeout'.
+
+ Ref: #13489
+ Closes #13503
+
+- hash: change 'slots' to size_t from int
+
+ - an unsigned type makes more sense
+ - size_t seems suitable
+ - on 64 bit args, the struct alignment makes the new Curl_hash remain
+ the same size
+
+ Closes #13502
+
+Viktor Szakats (30 Apr 2024)
+
+- libssh2: replace `access()` with `stat()`
+
+ Prefer `stat()` to verify the presence of key files.
+
+ This drops the last uses of `access()` in the codebase, which was
+ reported to cause issues in some cases.
+
+ Also add `access()` to the list of banned functions in checksrc.
+
+ Ref: https://github.com/curl/curl/pull/13412#issuecomment-2065505415
+ Ref: https://github.com/curl/curl/pull/13482#issuecomment-2078980522
+ Ref: #13497
+ Co-authored-by: Jay Satiro
+ Closes #13498
+
+Daniel Stenberg (30 Apr 2024)
+
+- multi: remove useless assignment
+
+ Spotted by CodeSonar
+
+ Closes #13500
+
+- RELEASE-NOTES: synced
+
+fuzzard (29 Apr 2024)
+
+- cmake: FindNGHTTP2 add static lib name to find_library call
+
+ Add the static library name, nghttp2_static as a name to search.
+
+ This provides cmake parity with the winbuild Makefile.vc allowing
+ the cmake build to find and allow the link to static nghttp2 library.
+
+Viktor Szakats (29 Apr 2024)
+
+- DISTROS: add patch and issues link for curl-for-win
+
+ curl-for-win sometimes includes curl patches that were already merged in
+ master, but not yet part of a stable release.
+
+ Also include the Issues link. Build-specific issues are handled there.
+
+ Ref: #13493
+ Closes #13499
+
+Daniel Stenberg (29 Apr 2024)
+
+- mime: avoid using access()
+
+ If stat() fails, there is no point in calling access()
+
+ Also: return error immediately if the stat() fails.
+
+ Ref: #13482
+ Closes #13497
+
+Stefan Eissing (29 Apr 2024)
+
+- tests: add SNI and peer name checks
+
+ - connect to DNS names with trailing dot
+ - connect to DNS names with double trailing dot
+ - rustls, always give `peer->hostname` and let it
+ figure out SNI itself
+ - add SNI tests for ip address and localhost
+ - document in code and TODO that QUIC with ngtcp2+wolfssl
+ does not do proper peer verification of the certificate
+ - mbedtls, skip tests with ip address verification as not
+ supported by the library
+
+ Closes #13486
+
+Daniel Stenberg (29 Apr 2024)
+
+- curl_getdate.md: document two-digit year handling
+
+ Mentioned-by: Paul Gilmartin
+ Ref: https://curl.se/mail/archive-2024-04/0014.html
+ Closes #13494
+
+Viktor Szakats (29 Apr 2024)
+
+- cmake: add `BUILD_EXAMPLES` option to build examples
+
+ You can enable it with `-DBUILD_EXAMPLES=ON`.
+
+ To match autotools' `make examples` feature.
+ Windows (static) builds not tested.
+
+ Also enable examples in a pair of CI jobs.
+
+ Apply related updates to the macOS CI workflow:
+ - drop unused `CXX` envs.
+ - drop no longer needed `-Wno-error=undef -Wno-error=conversion` flags.
+ - pass `-Wno-deprecated-declarations` to GCC too (for `BUILD_EXAMPLES`).
+ - document why `-Wno-deprecated-declarations` is necessary.
+
+ Closes #13491
+
+Stefan Eissing (26 Apr 2024)
+
+- http3: quiche+ngtcp2 improvements
+
+ - quiche: error transfers that try to receive on a closed
+ or draining connection
+ - ngtcp2: use callback for extending max bidi streams. This
+ allows more precise calculation of MAX_CONCURRENT as we
+ only can start a new stream when the server acknowledges
+ the close - not when we locally have closed it.
+ - remove a fprintf() from h2-download client to avoid excess
+ log files on tests timing out.
+
+ Closes #13475
+
+- vtls: TLS session storage overhaul
+
+ - add session with destructor callback
+ - remove vtls `session_free` method
+ - let `Curl_ssl_addsessionid()` take ownership
+ of session object, freeing it also on failures
+ - change tls backend use
+ - test_17, add tests for SSL session resumption
+
+ Closes #13386
+
+- multi: multi_wait improvements
+
+ - only call `multi_getsock()` once for all transfers
+ - realloc pollset array on demand
+ - fold repeated sockets
+
+ Closes #13150
+
+Philip Heiduck (25 Apr 2024)
+
+- ci: remove microsoft-prod.list
+
+ This is added by default, and it is often broken, but we don't need
+ anything from it.
+
+ Closes #13473
+
+Evgeny Grin (Karlson2k) (25 Apr 2024)
+
+- curl_setup.h: detect 'inline' support
+
+ Closes #13355
+
+Daniel Stenberg (25 Apr 2024)
+
+- multi: avoid memory-leak risk
+
+ 'newurl' is allocated in some conditions and used in a few scenarios,
+ but there were theoretical combinations in which it would not get freed.
+ Move the free to happen unconditionally. Never triggered by tests, but
+ spotted by Coverity.
+
+ Closes #13471
+
+Johann Sebastian Schicho (25 Apr 2024)
+
+- sendf: Curl_cwriter_write: remove comment disallowing zero length writes
+
+ They are needed to pass CLIENTWRITE_EOS.
+
+ Closes #13477
+
+Stefan Eissing (25 Apr 2024)
+
+- CI: macos fixes for new ARM GHA images
+
+ - based on #13478 with additions from #13476
+ - make homebrew install path flexible
+ - fix OpenSSL pkgconfig files libdir
+ - add path to --with-libssh2 target
+ - disable gcc securetransport due to linker
+ errors (missing symbols), probably because
+ the os version is no longer low enough
+
+ Assisted-by: Viktor Szakats
+
+ Closes #13479
+
+- content_encoding: ignore duplicate chunked encoding
+
+ - ignore duplicate "chunked" transfer-encodings from
+ a server to accomodate for broken implementations
+ - add test1482 and test1483
+
+ Reported-by: Mel Zuser
+ Fixes #13451
+ Closes #13461
+
+Daniel Stenberg (25 Apr 2024)
+
+- tool: move tool_ftruncate64 to tool_util.c
+
+ ... and the prototype to tool_setup.h, to make them both available more
+ widely and accurately.
+
+ Follow-up to 00bef95946d3511
+
+ Fixes #13458
+ Closes #13459
+
+Viktor Szakats (24 Apr 2024)
+
+- lib: silence `-Wsign-conversion` in base64, strcase, mprintf
+
+ Closes #13467
+
+- CI: retain failure code after `./configure` with Circle CI
+
+ Suggested-by: Dan Fandrich
+ Follow-up to 43299e93c06b96fea8a8dc9b1c2e49c82bc21801 #13462
+ Follow-up to d7332e3e46c3ef401b34e6a1a129eb4dd846c452 #12635
+ Closes #13468
+
+Daniel Stenberg (24 Apr 2024)
+
+- RELEASE-NOTES: synced
+
+Jan Venekamp (24 Apr 2024)
+
+- mbedTLS: implement CURLOPT_SSL_CIPHER_LIST option
+
+ Use a lookup list to set the cipher suites, allowing the
+ ciphers to be set by either openssl or IANA names.
+
+ To keep the binary size of the lookup list down we compress
+ each entry in the cipher list down to 2 + 6 bytes using the
+ C preprocessor.
+
+ Closes #13442
+
+Viktor Szakats (24 Apr 2024)
+
+- CI: show more failed `config.log` on Circle CI
+
+ Show last 1000 lines of `config.log` if `./configure` fails. This was
+ already done for one job, this patch extends it to all.
+
+ Ref: #13438
+ Closes #13462
+
+Daniel Stenberg (24 Apr 2024)
+
+- telnet: check return code from fileno()
+
+ and return error if necessary
+
+ Spotted by CodeSonar
+
+ Closes #13457
+
+Viktor Szakats (24 Apr 2024)
+
+- tls: fix SecureTransport + BearSSL cmake unity builds
+
+ Avoid clashing static function names by namespacing them.
+
+ Pointed-out-by: Jan Venekamp
+ Ref: https://github.com/curl/curl/pull/13442#discussion_r1576350700
+ Closes #13450
+
+Jay Satiro (24 Apr 2024)
+
+- dllmain: Call OpenSSL thread cleanup for Windows and Cygwin
+
+ - Call OPENSSL_thread_stop on thread termination (DLL_THREAD_DETACH)
+ to prevent a memory leak in case OpenSSL is linked statically.
+
+ - Warn in libcurl-thread.3 that if OpenSSL is linked statically then it
+ may require thread cleanup.
+
+ OpenSSL may need per-thread cleanup to stop a memory leak. For Windows
+ and Cygwin if libcurl was built as a DLL then we can do that for the
+ user by calling OPENSSL_thread_stop on thread termination. However, if
+ libcurl was built statically then we do not have notification of thread
+ termination and cannot do that for the user.
+
+ Also, there are several other unusual cases where it may be necessary
+ for the user to call OPENSSL_thread_stop, so in the libcurl-thread
+ warning I added a link to the OpenSSL documentation.
+
+ Co-authored-by: Viktor Szakats
+
+ Reported-by: southernedge@users.noreply.github.com
+ Reported-by: zmcx16@users.noreply.github.com
+
+ Ref: https://www.openssl.org/docs/man3.0/man3/OPENSSL_thread_stop.html#NOTES
+
+ Fixes https://github.com/curl/curl/issues/12327
+ Closes https://github.com/curl/curl/pull/12408
+
+Jan Venekamp (24 Apr 2024)
+
+- rustls: remove incorrect SSLSUPP_TLS13_CIPHERSUITES flag
+
+ The rustls backend advertises SSLSUPP_TLS13_CIPHERSUITES, but
+ the code does not actually seem to support it (yet?). Removed
+ the flag and corrected documentation.
+
+ Closes #13452
+
+Stefan Eissing (24 Apr 2024)
+
+- quiche: expire all active transfers on connection close
+
+ - when a connection close is detected, all ongoing transfers
+ need to expire bc no more POLL events are likely to happen
+ for them.
+
+ Fixes #13439
+ Reported-by: Jay Satiro
+ Closes #13447
+
+Dan Fandrich (23 Apr 2024)
+
+- tests: fix feature case in test1481
+
+ This test was being skipped everywhere because the feature never
+ matched.
+
+ Closes #13445
+
+Gusted (23 Apr 2024)
+
+- tool_operate: don't truncate the etag save file by default
+
+ This fixes a regression of 75d79a4486b279100209ddf8c7fdb12955fb66e9. The
+ code in tool-operate truncated the etag save file, under the assumption
+ that the file would be written with a new etag value. However since
+ 75d79a4486b279100209ddf8c7fdb12955fb66e9 that might not be the case
+ anymore and could result in the file being truncated when --etag-compare
+ and --etag-save was used and that the etag value matched with what the
+ server responded. Instead the truncation should not be done when a new
+ etag value should be written.
+
+ Test 3204 was added to verify that the file with the etag value doesn't
+ change the contents when used by --etag-compare and --etage-save and
+ that value matches with what the server returns on a non 2xx response.
+
+ Closes #13432
+
+Abdullah Alyan (22 Apr 2024)
+
+- tests: enable test 1117 for hyper
+
+ Closes #13436
+
+Daniel Stenberg (22 Apr 2024)
+
+- sendf: useless assignment in cr_lc_read()
+
+ Spotted by CodeSonar
+
+ Closes #13437
+
+- tool_paramhlp: remove duplicate assign
+
+ Spotted by CodeSonar
+
+ Closes #13433
+
+- transfer: remove useless assignment
+
+ in Curl_xfer_recv_resp
+
+ Spotted by CodeSonar
+
+ Closes #13435
+
+- http: acknowledge a returned error code
+
+ ... and do not overwrite it with a new value that could then hide the
+ problem.
+
+ Spotted by CodeSonar
+
+ Closes #13434
+
+- tool_operate: init vars unconditionally in post_per_transfer
+
+ In case of (the unlikely) early return, they could otherwise remain
+ uninitialized
+
+ Spotted by CodeSonar
+
+ Closes #13430
+
+- RELEASE-NOTES: synced
+
+- urlapi: allow setting port number zero
+
+ Also set and check errno when strtoul() parsing numbers for better error
+ checking.
+
+ Updated test 1560
+
+ Closes #13427
+
+- http_aws_sigv4: remove useless assignment
+
+ This code assigned the variable the same value it already had
+
+ Spotted by CodeSonar
+
+ Closes #13426
+
+- file: remove useless assignment
+
+ This code assigned the variable the same value it already had.
+
+ Spotted by CodeSonar
+
+ Closes #13425
+
+- test2406: verify -f with HTTP/2
+
+Stefan Eissing (19 Apr 2024)
+
+- http2 + ngtcp2: pass CURLcode errors from callbacks
+
+ - errors returned by Curl_xfer_write_resp() and the header variant are
+ not errors in the protocol. The result needs to be returned on the
+ next recv() from the protocol filter.
+
+ - make xfer write errors for response data cause the stream to be
+ cancelled
+
+ - added pytest test_02_14 and test_02_15 to verify that also for
+ parallel processing
+
+ Reported-by: Laramie Leavitt
+ Fixes #13411
+ Closes #13424
+
+Daniel Stenberg (19 Apr 2024)
+
+- request: make Curl_req_init return void
+
+ Since it could not return error and therefore this change removes dead
+ code for the caller.
+
+ Spotted by CodeSonar.
+
+ Closes #13423
+
+- multi: remove the unused Curl_preconnect function
+
+ The implementation has been removed, no point in keeping it around.
+
+ Follow-up to 476adfeac019ed
+
+ Closes #13422
+
+- Curl_creader_read: init two variables to avoid using them uninited
+
+ Spotted by CodeSonar
+
+ Closes #13419
+
+- http: reject HTTP major version switch mid connection
+
+ A connection that has seen an HTTP major version now refuses any other
+ major HTTP version in future responses. Previously, a HTTP/1.x
+ connection would just silently accept HTTP/2 or HTTP/3 in the status
+ lines as long as it had support for those built-in. It would then just
+ lead to confusion and badness.
+
+ Indirectly Spotted by CodeSonar which identified a duplicate assignment
+ in this function.
+
+ Add test 471 to verify
+
+ Closes #13421
+
+- mqtt: when Curl_xfer_recv returns error, don't use nread
+
+ A returned error code makes other return value unreliable, and in this
+ case potentially uninitialized. On error, do not read other return
+ values like the nread counter.
+
+ Spotted by CodeSonar
+
+ Closes #13418
+
+- ftp: fix socket leak on rare error
+
+ In the function AcceptServerConnect() the newly created socket would
+ leak if Curl_conn_tcp_accepted_set() returns error. Which basically
+ should never happen.
+
+ Spotted by CodeSonar.
+
+ Closes #13417
+
+- urlapi: remove unused flags argument from Curl_url_set_authority
+
+ The function is only called from a single place (for HTTP/2 server push)
+ so might as well just assume this fixed option every time.
+
+ Closes #13409
+
+- github/ISSUE_TEMPLATE: tweak the commericual support text
+
+- github/ISSUE_TEMPLATE: link the GitHub discussions too
+
+ ... and move the feature request line to the bottom.
+
+- curl_url_get.md: clarify queries and fragments and CURLU_GET_EMPTY
+
+ Follow-up to 3eac21d86bc5
+
+ Closes #13407
+
+Stefan Eissing (18 Apr 2024)
+
+- tests: check caddy server version to match test expectations
+
+ - new caddy servers no longer return 200 on POSTs, but 405
+ as they should
+
+ Closes #13405
+
+Daniel Stenberg (18 Apr 2024)
+
+- curl_url_set.md: extended
+
+ Closes #13404
+
+- urlapi: add CURLU_GET_EMPTY for empty queries and fragments
+
+ By default the API inhibits empty queries and fragments extracted.
+ Unless this new flag is set.
+
+ This also makes the behavior more consistent: without it set, zero
+ length queries and fragments are considered not present in the URL. With
+ the flag set, they are returned as a zero length strings if they were in
+ fact present in the URL.
+
+ This applies when extracting the individual query and fragment
+ components and for the full URL.
+
+ Closes #13396
+
+- RELEASE-NOTES: synced
+
+- lib1560: test with leading zeroes and more IPv4 versions
+
+ Inspired by WHATWG URL Spec test inputs
+
+ Closes #13400
+
+Christian Schmitz (17 Apr 2024)
+
+- smtp: result of Curl_bufq_cread was not used
+
+ return the result back to the caller.
+
+ Closes #13398
+
+Daniel Stenberg (17 Apr 2024)
+
+- urlapi: fix relative redirects to fragment-only
+
+ Using the URL API for a redirect URL when the redirected-to string
+ starts with a hash, ie is only a fragment, the API would produce the
+ wrong final URL.
+
+ Adjusted test 1560 to test for several new redirect cases.
+
+ Closes #13394
+
+Jiwoo Park (17 Apr 2024)
+
+- url: fix use of an uninitialized variable
+
+ Closes #13399
+
+Patrick Monnerat (17 Apr 2024)
+
+- os400: sync with latest changes
+
+ - Conversion support for new version info character field rtmp_version.
+ - New ILE/RPG declarations.
+
+ Closes #13402
+
+Daniel Stenberg (17 Apr 2024)
+
+- ngtcp2: fix macro use
+
+ macro "H3_STREAM_CTX" requires 2 arguments, but only 1 given
+
+ Follow-up to c6655f7029ec5c128561e3ecf1f93db3ed0432a4
+
+ Closes #13401
+
+Christian Schmitz (17 Apr 2024)
+
+- sendf: fix two typos in comments
+
+ The parameters are named data, not date.
+
+ Closes #13393
+
+- lib: silence warnings on comma misuse
+
+ Building curl with -Wcomma, I see warnings about "possible misuse of
+ comma operator here" and moving fields assignment out of the for() fixes
+ it.
+
+ Closes #13392
+
+Stefan Eissing (17 Apr 2024)
+
+- http/2, http/3: decouple stream state from easy handle
+
+ - add `Curl_hash_offt` as hashmap between a `curl_off_t` and
+ an object. Use this in h2+h3 connection filters to associate
+ `data->id` with the internal stream state.
+ - changed implementations of all affected connection filters
+ - removed `h2_ctx*` and `h3_ctx*` from `struct HTTP` and thus
+ the easy handle
+ - solves the problem of attaching "foreign protocol" easy handles
+ during connection shutdown
+
+ Test 1616 verifies the new hash functions.
+
+ Closes #13204
+
+Daniel Stenberg (17 Apr 2024)
+
+- ROADMAP: remove completed entries, mention websocket
+
+- THANKS-filter: name fixes
+
+Christian Schmitz (17 Apr 2024)
+
+- winbuild: add ENABLE_WEBSOCKETS option
+
+ Closes #13232
+
+Daniel Stenberg (17 Apr 2024)
+
+- dmaketgz: compacter
+
+ Removes the need for disabling shellcheck warnings.
+
+ Follow-up to d28f74913c2
+ Proposed-by: Viktor Szakats
+ Closes #13391
+
+Dan Fandrich (16 Apr 2024)
+
+- tests: Fix uninitialized value warning
+
+ The check for an option must be predicated on options existing at all.
+
+ Follow-up to f7cc9e91
+
+Christian Schmitz (17 Apr 2024)
+
+- idn: add native AppleIDN (icucore) support for macOS/iOS
+
+ I implemented the IDN functions for macOS and iOS using Unicode
+ libraries coming with macOS and iOS.
+
+ Builds and runs here on macOS 14.2.1. Also verified to load and
+ run on older macOS version 10.13.
+
+ Build requires macOS SDK 13 or equivalent.
+
+ Set `-DUSE_APPLE_IDN=ON` CMake option to enable it.
+ With autotools and other build tools, set these manual options:
+ ```
+ CPPFLAGS=-DUSE_APPLE_IDN
+ LIBS=-licucore
+ ```
+
+ Completes TODO 1.6.
+
+ TODO: add autotools option and feature-detection.
+
+ Refs: #5330 #5371
+ Co-authored-by: Viktor Szakats
+ Closes #13246
+
+Stefan Eissing (16 Apr 2024)
+
+- http3: extend download abort tests, fixes in ngtcp2
+
+ - fix flow handling in ngtcp2 to ACK data on streams
+ we abort ourself.
+ - extend test_02_23* cases to also run for h3
+ - skip test_02_23* for OpenSSL QUIC as it gets stalled
+ on progressing the connection
+
+ Closes #13374
+
+Daniel Stenberg (16 Apr 2024)
+
+- tests: add -q as first option when invoking curl for tests
+
+ To reduce the risk that the user running the tests has a .curlrc present
+ that messes things up.
+
+ Support 'option="no-q"' for the <command> tag to switch it off on demand.
+ Use this new feature in test 433 and 436.
+
+ Ref: #13284
+ Closes #13387
+
+- dmaketgz: release tarball generation using docker
+
+ For easier reproducibility.
+
+ Mention using this script in RELEASE-PROCEDURE
+
+ Closes #13388
+
+Viktor Szakats (16 Apr 2024)
+
+- cmake: update ECH code and minor fixups
+
+ - `openssl_check_symbol_exists()` expects a 4th argument now.
+ Follow-up to edc2702a1fe3a4a5386ffd9aa4f240f0c0197fa2 #13373
+
+ - minor comment/script touch-ups.
+ Follow-up to a362962b7289ec02b412890c9515657cf0ed50ac #11922
+
+ - fix indentation.
+
+ Closes #13383
+
+- tests: fix shellcheck issues in `ech_tests.sh`
+
+ Add double-quotes where missing.
+
+ Follow-up to a362962b7289ec02b412890c9515657cf0ed50ac #11922
+ Closes #13382
+
+- dist: add ECH files to tarball
+
+ Also sort `EXTRA_DIST` list in `tests/Makefile.am` and make it diffable.
+
+ Follow-up to a362962b7289ec02b412890c9515657cf0ed50ac #11922
+ Closes #13381
+
+- openvms: look for `USE_IPV6` in `config.h` (was: `ENABLE_IPV6`)
+
+ The OpenVMS script `config_h.com` is parsing the config header
+ generated by autotools. Let's make it look for the macro name we now
+ use universally across the codebase.
+
+ Follow-up to e411c98f702f0fb38dceec95e7507ef15a00d12c #13349
+ Closes #13360
+
+daniel-j-h (16 Apr 2024)
+
+- Dockerfile: for release automation and reproducibility
+
+ Closes #13250
+
+Stefan Eissing (16 Apr 2024)
+
+- cw-out: improved error handling
+
+ - remember error encountered in invoking write callback and always fail
+ afterwards without further invokes
+
+ - check behaviour in test_02_17 with h2-pausing client
+
+ Reported-by: Pavel Kropachev
+ Fixes #13337
+ Closes #13340
+
+Daniel Stenberg (16 Apr 2024)
+
+- version: add "ECH" as a feature
+
+ If available
+
+ Follow-up to a362962b7
+ Closes #13378
+
+- CURLOPT_ECH: polish
+
+ - remove the pointer to build instructions, it won't work in manpages
+ - add see-also
+ - minor white space edits
+
+ Closes #13379
+
+Viktor Szakats (16 Apr 2024)
+
+- tidy-up: whitespace [ci skip]
+
+- mbedtls: fix building with v3 in CMake Unity mode
+
+ Before this patch the internal feature detection macro
+ `HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS` was defined in three files,
+ with an incomplete logic in one of them. In Unity mode that spilled
+ into another source file and broke the build.
+
+ Closes #13377
+
+- cmake: add librtmp/rtmpdump option and detection
+
+ Add CMake option `USE_LIBRTMP`. Disabled by default.
+
+ This library requires OpenSSL TLS-backend when linked statically.
+
+ Follow-up to 6eb9e65781fa1fd8a0bcfe0715187a3a35f09ae4 #13364
+ Closes #13373
+
+Stephen Farrell (16 Apr 2024)
+
+- TLS: add support for ECH (Encrypted Client Hello)
+
+ An EXPERIMENTAL feature used with CURLOPT_ECH and --ech.
+
+ Closes #11922
+
+Daniel Stenberg (15 Apr 2024)
+
+- RELEASE-NOTES: synced
+
+- multi: introduce SETUP state for better timeouts
+
+ Since we can go to the CONNECT state from PENDING, potentially multiple
+ times for a single transfer, this change introdues a SETUP state that
+ happens before CONNECT when doing a new transfer.
+
+ Now, doing a redirect on a handle goes back to SETUP (not CONNECT like
+ before) and we initilize the connect timeout etc in SETUP. Previously,
+ we would do it in CONNECT but that would make it unreliable in cases
+ where a transfer goes in and out between CONNECT and PENDING multiple
+ times.
+
+ SETUP is transient, so the handle never actually stays in that state.
+
+ Additionally: take care of timeouts of PENDING transfers in
+ curl_multi_perform()
+
+ Ref: #13227
+ Closes #13371
+
+Tal Regev (15 Apr 2024)
+
+- cmake: forward `USE_LIBRTMP` option to C
+
+ Define in C `USE_LIBRTMP` if user requested it from cmake.
+
+ Closes #13364
+
+Daniel Stenberg (15 Apr 2024)
+
+- curl_version_info: provide librtmp version
+
+ Ref: https://github.com/curl/curl/pull/13364#issuecomment-2054151942
+ Reported-by: talregev on github
+ Closes #13368
+
+blankie (15 Apr 2024)
+
+- docs: clarify CURLOPT_MAXFILESIZE and CURLOPT_MAXFILESIZE_LARGE
+
+ The bounds of the size parameter were not specified, and nor was it
+ specified how to disable the maximum file size check.
+
+ The documentation also incorrectly stated that CURLOPT_MAXFILESIZE
+ always returns CURLE_OK and that CURLOPT_MAXFILESIZE_LARGE only returns
+ CURLE_OK or CURLE_UNKNOWN_OPTION.
+
+ It also did not mention what the default value is, which is zero. This
+ commit updates the documentation to make note of all these things.
+
+ Closes #13372
+
+Patrick Monnerat (15 Apr 2024)
+
+- OS400: post-shellcheck changes adjustments
+
+ Build scripts must be executed by the os/400 shell (sh), not bash which
+ is a PASE program.
+
+ Shell function get_make_vars() escaping reworked to match $() subcommand
+ construct.
+
+ Follow-up to 8a622baf9e9233241bbe93d6599c99cb46478614
+ Closes #13366
+
+Viktor Szakats (15 Apr 2024)
+
+- OS400: tidy-up
+
+ Drop/fixup mods trying to make some syntax highlighters happier.
+
+ Follow-up to 8a622baf9e9233241bbe93d6599c99cb46478614 #13309
+ Closes #13362
+
+Daniel Stenberg (15 Apr 2024)
+
+- multi: timeout handles even without connection
+
+ When there is a "change" in a multi handle and pending handles are moved
+ back to the main list to be retested if they can proceed further (for
+ example a previous transfer completed or a connection has a confirmed
+ multiplexed state), the timeout check in multi_runsingle() would not
+ trigger because it required an established connection.
+
+ This could make a pending tranfer go back to pending state even though
+ it had been "in progress" for a longer time than permitted. By removing
+ the requirement for an associated connection, the timeout check will be
+ done proper even for transfers that has not yet been assigned one.
+
+ Ref #13227
+ Reported-by: Rahul Krishna M
+ Closes #13276
+
+Patrick Monnerat (15 Apr 2024)
+
+- mprintf: check fputc error rather than matching returned character
+
+ OS/400 ascii fputc wrapper deviates from the posix standard by the
+ fact that it returns the ebcdic encoding of the original ascii
+ character. Testing for a matching value for success will then always
+ fail.
+
+ This commit replaces the chariacter comparison by an explicit error
+ return check.
+
+ Follow-up to ef2cf58
+ Closes #13367
+
+Viktor Szakats (14 Apr 2024)
+
+- ci: add CMake build variation, fixup libssh detection in `linux-old`
+
+ To test without c-ares and hit `easy_lock.h` on an old system. Use this
+ new build step to introduce small variations, and also test libssh2.
+
+ Also add workaround to existing job to enable libssh. (CMake's generic
+ auto-detection doesn't seem to work here.):
+ ```
+ CMake Warning at CMakeLists.txt:908 (find_package):
+ Could not find a package configuration file provided by "libssh" with any
+ of the following names:
+
+ libsshConfig.cmake
+ libssh-config.cmake
+ ```
+ Ref: https://github.com/curl/curl/actions/runs/8661316091/job/23750974358#ste
+ p:5:69
+
+ Closes #13361
+
+- lib: merge `ENABLE_QUIC` C macro into `USE_HTTP3`
+
+ Before this patch `lib/curl_setup.h` defined these two macros right
+ next to each other, then the source code used them interchangeably.
+
+ After this patch, `USE_HTTP3` guards all HTTP/3 / QUIC features.
+ (Like `USE_HTTP2` does for HTTP/2.) `ENABLE_QUIC` is no longer used.
+
+ This patch doesn't change the way HTTP/3 is enabled via autotools
+ or CMake. Builders who enabled HTTP/3 manually by defining both of
+ these macros via `CPPFLAGS` can now delete `-DENABLE_QUIC`.
+
+ Closes #13352
+
+- build: prefer `USE_IPV6` macro internally (was: `ENABLE_IPV6`)
+
+ Before this patch, two macros were used to guard IPv6 features in curl
+ sources: `ENABLE_IPV6` and `USE_IPV6`. This patch makes the source use
+ the latter for consistency with other similar switches.
+
+ `-DENABLE_IPV6` remains accepted for compatibility as a synonym for
+ `-DUSE_IPV6`, when passed to the compiler.
+
+ `ENABLE_IPV6` also remains the name of the CMake and `Makefile.vc`
+ options to control this feature.
+
+ Closes #13349
+
+Dan Fandrich (12 Apr 2024)
+
+- DISTROS: mark rolling release distros
+
+ These are ones that are unlikely to have back-ported curl patches.
+
+ Closes #13353
+
+Daniel Stenberg (12 Apr 2024)
+
+- mbedtls: cut off trailing newlines from debug logs
+
+ To avoid double newlines in the output.
+
+ Reported-by: Gisle Vanem
+ Fixes #13321
+ Closes #13356
+
+- RELEASE-NOTES: synced
+
+Stefan Eissing (12 Apr 2024)
+
+- CURLINFO_REQUEST_SIZE: fixed, add tests for transfer infos reported
+
+ - tests for 'size_request' and other stats reported, for
+ presence and consistency
+
+ Reported-by: Jonatan Vela
+ Fixes #13269
+ Closes #13275
+
+Viktor Szakats (11 Apr 2024)
+
+- dist: add files missing from release tarball
+
+ Closes #13346
+
+- ci: parallelize more, tidy up cmake commands (distcheck, macos)
+
+ Also enable `-DCURL_WERROR=ON` in the Linux cmake build test.
+
+ Closes #13343
+
+Toon Claes (11 Apr 2024)
+
+- docs: add CURLOPT_NOPROGRESS to CURLOPT_XFERINFOFUNCTION example
+
+ It's important to set `CURLOPT_NOPROGRESS` to `0` if you want your
+ transfer callback function, set by `CURLOPT_XFERINFOFUNCTION`, getting
+ called. To emphasize this to the users, add this to the code example.
+
+ Closes #13348
+
+RainRat (11 Apr 2024)
+
+- misc: fix typos
+
+ Closes #13344
+
+Colin Leroy-Mira (11 Apr 2024)
+
+- file: add support for getting basic directory listings
+
+ Not supported on Windows (yet)
+
+ Closes #13137
+
+Viktor Szakats (11 Apr 2024)
+
+- ci: add curl-for-win builds: Linux MUSL, macOS, Windows
+
+ Linux MUSL (llvm/clang), macOS Apple clang, Windows (llvm/clang).
+
+ Configured with HTTP/2 and HTTP/3 and other dependencies (the default
+ curl-for-win) for a comprehensive build test.
+
+ ```
+ curl 8.8.0-DEV (x86_64-unknown-linux-musl) libcurl/8.8.0-DEV LibreSSL/3.9.1 z
+ lib/1.3.1 brotli/1.1.0 zstd/1.5.6 libpsl/0.21.5 libssh2/1.11.0 nghttp2/1.61.0
+ ngtcp2/1.4.0 nghttp3/1.2.0
+ Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns
+ mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp ws wss
+ Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTP3 HTTPS-proxy IPv6 Largefil
+ e libz NTLM PSL SSL threadsafe UnixSockets zstd
+
+ curl 8.8.0-DEV (x86_64-apple-darwin) libcurl/8.8.0-DEV LibreSSL/3.9.1 zlib/1.
+ 3.1 brotli/1.1.0 zstd/1.5.6 libpsl/0.21.5 libssh2/1.11.0 nghttp2/1.61.0 ngtcp
+ 2/1.4.0 nghttp3/1.2.0
+ Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns
+ ldap ldaps mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp ws w
+ ss
+ Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTP3 HTTPS-proxy IPv6 Largefil
+ e libz NTLM PSL SSL threadsafe UnixSockets zstd
+
+ curl 8.8.0-DEV (x86_64-w64-mingw32) libcurl/8.8.0-DEV LibreSSL/3.9.1 zlib/1.3
+ .1 brotli/1.1.0 zstd/1.5.6 WinIDN libpsl/0.21.5 libssh2/1.11.0 nghttp2/1.61.0
+ ngtcp2/1.4.0 nghttp3/1.2.0
+ Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns
+ ldap ldaps mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp ws w
+ ss
+ Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTP3 HTTPS-proxy IDN IPv6 Kerb
+ eros Largefile libz NTLM PSL SPNEGO SSL SSPI threadsafe UnixSockets zstd
+ ```
+
+ Limited to x64, because for build testing the additional CPUs don't add
+ much value compared to the extra build time. They can be enabled easily
+ if deemed useful.
+
+ To the extent of curl-for-win configuration options, it's trivial to add
+ further build combinations.
+
+ Closes #13335
+
+- OS400: fix shellcheck warnings in scripts
+
+ - use `$()` instead of backticks, and re-arrange double-quotes inside.
+ - add missing `|| exit 1` to `cd` calls. (could be dropped by using `set -eu`
+ .)
+ - add `-n` to a few `if`s.
+ - shorten redirections by using `{} >` (as shellcheck recommended).
+ - silence warnings where variables were detected as unused (SC2034).
+ - a couple misc updates to silence warnings.
+ - switch to bash shebang for `-ot` feature.
+ - split two lines to unbreak syntax highlighting in my editor. (`$(expr \`, `
+ $(dirname \`)
+
+ Also enable CI checks for OS/400 shell scripts.
+
+ Ref: #13307
+ Closes #13309
+
+Stefan Eissing (11 Apr 2024)
+
+- lib: add Curl_xfer_write_resp_hd
+
+ Add method in protocol handlers to allow writing of a single,
+ 0-terminated header line. Avoids parsing and copying these lines.
+
+ Closes #13165
+
+- llist: add Curl_llist_append()
+
+ - use for better readability in all places where the "insert_next"
+ actually performs an append to the list
+ - add some tests in unit1300
+
+ Closes #13336
+
+- gnutls: lazy init the trust settings
+
+ - delay loading of trust anchors and CRLs after the ClientHello
+ has been sent off
+ - add tracing to IO operations
+ - on IO errors, return the CURLcode of the underlying filter
+
+ Closes #13339
+
+Marcel Raad (10 Apr 2024)
+
+- http_negotiate: fix `CURL_DISABLE_PROXY` build
+
+ `proxyuserpwd` was removed from `dynamically_allocated_data` in commit
+ f46385d36df.
+
+ Closes https://github.com/curl/curl/pull/13334
+
+Viktor Szakats (10 Apr 2024)
+
+- quic: fixup duplicate static function name (for cmake unity)
+
+ Visible in daily curl-for-win builds:
+ https://github.com/curl/curl-for-win/actions/runs/8621925870
+
+ ```
+ lib/vquic/curl_ngtcp2.c:1916:12: error: redefinition of 'ossl_new_session_cb'
+ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
+ ^
+ lib/vtls/openssl.c:2978:12: note: previous definition is here
+ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
+ ^
+ ```
+ https://github.com/curl/curl-for-win/actions/runs/8621925870/job/23631885439#
+ step:3:6965
+
+ Follow-up to 3210101088dfa3d6a125d213226b092f2f866722 #13172
+ Closes #13332
+
+- appveyor: make VS2010 job build-only, enable Schannel, fix compiler warnings
+
+ Tests were consistently flaky for a while.
+
+ Also fix compiler warnings in `CertOpenStore()` calls for old MSVC compilers:
+ ```
+ C:/projects/curl/lib/vtls/schannel.c(688):
+ warning C4306: 'type cast' : conversion from 'int' to 'LPCSTR' of greater s
+ ize
+ C:/projects/curl/lib/vtls/schannel_verify.c(642):
+ warning C4306: 'type cast' : conversion from 'int' to 'LPCSTR' of greater s
+ ize
+ ```
+ Ref: https://ci.appveyor.com/project/curlorg/curl/builds/49580310/job/ywu2y44
+ kymgc0nif#L106
+
+ Closes #13330
+
+Daniel Stenberg (10 Apr 2024)
+
+- projects: drop MSVC project files for recent versions
+
+ We encourage users to generate visual studio project files using CMake.
+
+ We keep project files in git for ancient visual studio versions that
+ cmake cannot generate files for, but we no longer ship the project files
+ in the tarballs.
+
+ appveyor: switch VisualStudioSolution job to VC12 (Visual Studio 2013)
+
+ Co-Authored-by: Viktor Szakats
+ Co-Authored-by: Jay Satiro
+
+ Closes #13311
+
+Viktor Szakats (9 Apr 2024)
+
+- cmake: use namespaced custom target names
+
+ Rename custom target to namespaced (unique) names to avoid colliding
+ with 3rd-party projects (e.g. libzip) built together with curl.
+
+ Reported-by: hammlee96 on github
+ Fixes #13324
+ Closes #13326
+
+- appveyor: re-enable OpenSSL 3, bump to 3.2.1
+
+ Ref: b62454a875d70f93ab5347c050903596feb45a23 #13266
+ Closes #13329
+
+Stefan Eissing (9 Apr 2024)
+
+- CI: upgrade openssl version to 3.3.0 for openssl-quic
+
+ Closes #13328
+
+Daniel Stenberg (9 Apr 2024)
+
+- RELEASE-NOTES: synced
+
+ Bump to 8.8.0-DEV
+
+- curl_multi_waitfds.md: add protocol mention
+
+ Follow-up to 02beac6bb6b
+
+Dmitry Karpov (9 Apr 2024)
+
+- lib: add curl_multi_waitfds
+
+ New function call, similar to curl_multi_fdset()
+
+ Closes #13135
+
+Viktor Szakats (9 Apr 2024)
+
+- dist: verify tarball reproducibility in CI
+
+ Closes #13327
+
+Stefan Eissing (9 Apr 2024)
+
+- tests: stabilitze test_02_23*
+
+ - h2-download now always opens the output file on first write callback
+ invocation, if it will pause the transfer or not.
+ - Checks on output files then does not depend on the amount of data curl
+ has collected for the first write.
+
+ Closes #13323
+
+- tls: fix compile issues on old-linux CI
+
+ Follow-up to 3210101088dfa
+ Closes #13325
+
+Viktor Szakats (9 Apr 2024)
+
+- dist: add reproducible dir entries to tarballs
+
+ In the initial implementation of reproducible tarballs, they were
+ missing directory entries, while .zip archives had them. It meant
+ that on extracting the tarball, on-disk directory entries got the
+ current timestamp.
+
+ This patch fixes this by including directory entries in the tarball,
+ with reproducible timestamps. It also moves sorting inside tar,
+ to ensure reproducible directory entry timestamps on extract
+ (without the need of `--delay-directory-restore` option, when
+ extracting with GNU tar. BSD tar got that right by default.)
+
+ GNU tar 1.28 (2014-07-28) introduced `--sort=`.
+
+ Ref: https://github.com/curl/curl/pull/13299#discussion_r1555957350
+ Follow-up to 860cd5fc2dc8e165fadd2c19a9b7c73b3ae5069d #13299
+ Closes #13322
+
+Stefan Eissing (9 Apr 2024)
+
+- tls: use shared init code for TCP+QUIC
+
+ Closes #13172
+
+Daniel Stenberg (9 Apr 2024)
+
+- .mailmap: update Gisle's preferred email
+
+Jan Macku (9 Apr 2024)
+
+- doc: pytest `--repeat` -> `--count`
+
+ Pytest doesn't have a `--repeat` option, but it does have a `--count`
+ option.
+
+ ```
+ --count=COUNT Number of times to repeat each test
+ ```
+
+ Closes #13218
+
+Daniel Stenberg (9 Apr 2024)
+
+- src/Makefile.am: access curl.txt using a relative path, not abs
+
+ ... to make it work when mounted using different mount points. Like when
+ generated/used inside and outside of a docker image.
+
+ Closes #13320
+
+- build: remove MacOSX-Framework script
+
+ I don't think this is much used these days.
+
+ Also remove the libcurl.plist file used (only) by this script
+
+ Closes #13313
+
+- release-tools.sh: store the timestamp and release tag too
+
+ When maketgz invokes this script to generate the docs/RELEASE-TOOLS.md
+ file that gets bundled in the release, it now also passes on the exact
+ timestamp and version number so that those details also get mentioned in
+ the document. They will help users reproduce an identical tarball.
+
+ Closes #13319
+
+Viktor Szakats (8 Apr 2024)
+
+- GHA: disable permissions where missing
+
+ Reviewed-by: Daniel Stenberg
+ Closes #13306
+
+Stefan Eissing (8 Apr 2024)
+
+- CI: update component versions
+
+ - ngtcp2: v1.4.0
+ - nghttp3: v1.2.0
+ - nghttp2: v1.61.0
+ - mod_h2: v2.0.27
+
+ Closes #13316
+
+Jérôme Leclercq (8 Apr 2024)
+
+- CMake: check fseeko after detecting HAVE_FILE_OFFSET_BITS
+
+ Closes #13264
+
+Stefan Eissing (8 Apr 2024)
+
+- http2: emit RST when client write fails
+
+ - When the writing of response data fails, reset the stream
+ and do not return a callback error to nghttp2. That would
+ be a fatal error for the connection and harm other requests.
+ - add test cases for various abort scenarios
+
+ Reported-by: Konstantin Kuzov
+ Fixes #13292
+ Closes #13298
+
+Kailun Qin (8 Apr 2024)
+
+- mbedtls: call mbedtls_ssl_setup() after RNG callback is set
+
+ Since mbedTLS v3.6.0, the RNG check added in ssl_conf_check() will fail
+ if no RNG is provided when calling mbedtls_ssl_setup().
+
+ Therefore, mbedtls_ssl_conf_rng() needs to be called before the SSL
+ context is passed to mbedtls_ssl_setup().
+
+ Ref: https://github.com/Mbed-TLS/mbedtls/commit/b422cab052b51ec84758638d6783d
+ 6ba4fc60613
+
+ Signed-off-by: Kailun Qin <kailun.qin@intel.com>
+ Closes #13314
+
+Daniel Stenberg (8 Apr 2024)
+
+- NTLM_WB: drop support
+
+ The feature has not worked for months and has been marked as DEPRECATED
+ for six+ months.
+
+ Closes #13249
+
+- curl_trc: fix build error when lacking verbose messages
+
+ Follow-up from 0b28ece657b2273
+ Closes #13312
+
+Viktor Szakats (8 Apr 2024)
+
+- contrithanks: honor `CURLWWW` variable
+
+ Reviewed-by: Daniel Stenberg
+ Closes #13315
+
+- GHA: add shellcheck job and fix warnings, shell tidy-ups
+
+ Reviewed-by: Daniel Stenberg
+ Closes #13307
+
+- dist: do not require Perl in `maketgz`
+
+ Perl remains required for the tarball build process.
+
+ Follow-up to 860cd5fc2dc8e165fadd2c19a9b7c73b3ae5069d #13299
+
+ Reviewed-by: Daniel Stenberg
+ Closes #13310
+
+Daniel Stenberg (8 Apr 2024)
+
+- RELEASE-NOTES: synced
+
+- docs/cmdline-opts: invoke managen using a relative path
+
+ ... no need to use an absolute path, that makes the build unncessarily
+ fail if invoked using a different mount point. managen now takes options
+ to find the input files.
+
+ Update test1478 to provide the dir arguments to managen
+
+ Closes #13281
+
+- GHA: add valgrind to a wolfSSL build
+
+ Closes #13274
+
+Viktor Szakats (7 Apr 2024)
+
+- dist: `set -eu`, fix shellcheck, make reproducible and smaller tarballs
+
+ - set bash `-eu` and fix fallouts.
+ - fix shellcheck warnings.
+ - set and use `SOURCE_DATE_EPOCH` for reproducibility.
+ Authored-by: Daniel J. H.
+ Ref: #13280
+ - set `TZ=UTC` and `LC_ALL=C` for reproducibility.
+ - make file timestamps in tarball/zip reproducible.
+ - make directory timestamps in zip reproducible.
+ - make timestamps of tarballs/zip reproducible.
+ - make file order in tarball/zip reproducible.
+ - omit extra file metadata from zip for reproducibility.
+ - use maximum zip compression.
+ - use POSIX `ustar` tarball format to avoid supply chain vulnerability:
+ https://seclists.org/oss-sec/2021/q4/0
+ - make uid/gid in tarball reproducible.
+ - omit owner user/group names from tarball for reproducibility and privacy.
+ - omit current timestamp from .gz header for reproducibility.
+ - display SHA-256 hashes of produced tarballs/zip.
+ - fix whitespace.
+
+ `.tar.gz` also became smaller in the process: 4,462,311 -> 4,148,249 bytes (8
+ .7.1)
+
+ Requires GNU tar, GNU date, `sha256sum`.
+
+ Reviewed-by: Daniel Stenberg
+ Ref: #13250
+ Closes #13299
+
+Gisle Vanem (7 Apr 2024)
+
+- tests/http: fix compiler warning
+
+ - Init result code variable to fix clang warning that it may be used
+ uninitialized.
+
+ Fixes https://github.com/curl/curl/issues/13301
+ Closes https://github.com/curl/curl/pull/13304
+
+Stefan Eissing (6 Apr 2024)
+
+- vquic: use new curl_int64_t type
+
+ - add curl_int64_t signed 64-bit type for lib use
+
+ - define CURL_PRId64, CURL_PRIu64 format ids
+
+ - use curl_int64_t in vquic
+
+ curl_int64_t signed complements the existing curl_uint64_t unsigned.
+
+ Note that `curl_int64_t` and `int64_t` are assignable from each other
+ but not identical. Some platforms with 64 long type defint int64_t as
+ "long long" (staring at macOS) which messes up things like pointers and
+ format identifiers.
+
+ Closes https://github.com/curl/curl/pull/13293
+
+Jay Satiro (5 Apr 2024)
+
+- lib: use multi instead of multi_easy for the active multi
+
+ - Use data->multi and not data->multi_easy to refer to the active multi.
+
+ The easy handle's active multi is always data->multi.
+
+ This is a follow up to 757dfdf which changed curl so that an easy handle
+ used with the easy interface and then multi interface cannot have two
+ different multi handles associated with it at the same time
+ (data->multi_easy from the easy interface and data->multi from the multi
+ interface).
+
+ Closes https://github.com/curl/curl/pull/12665
+
+Viktor Szakats (5 Apr 2024)
+
+- tidy-up: whitespace [ci skip]
+
+Daniel Stenberg (5 Apr 2024)
+
+- makefile: remove the sorting from the vc-ide action
+
+ This target generates the MSVC project files. This change removes the
+ extra sorting and instead makes the script use the order of the files as
+ listed in the variables - which are mostly sorted anyway.
+
+ This is an attempt to make the project file generation more easily
+ reproducible.
+
+ Ref: #13250
+ Closes #13294
+
+Gisle Vanem (5 Apr 2024)
+
+- bearssl: fix compiler warnings
+
+ "variables may be uninitialized when used"
+
+ Fixes #13290
+ Closes #13297
+
+Daniel Stenberg (5 Apr 2024)
+
+- DISTROS: Cygwin updates
+
+ Brought-by: Brian Inglis
+ Fixes #13258
+ Co-authored-by: Viktor Szakats
+ Closes #13279
+
+Stefan Eissing (5 Apr 2024)
+
+- lib: add trace support for client reads and writes
+
+ - add `CURL_TRC_READ()` and `CURL_TRC_WRITE()`
+ - use in generic client writers and readers, as well
+ as http headers, chunking and websockets
+
+ Closes #13223
+
+Michał Antoniak (5 Apr 2024)
+
+- urldata: remove fields not used depending on used features
+
+ Reduced size of dynamically_allocated_data structure.
+
+ Reduced number of stored values in enum dupstring and enum dupblob. This
+ affects the reduced array placed in the UserDefined structure.
+
+ Closes #13188
+
+Viktor Szakats (5 Apr 2024)
+
+- cmake: enable `-pedantic-errors` for clang when `CURL_WERROR=ON`
+
+ clang doesn't have the issues of GCC and old CMake versions.
+
+ Note: This introduces asymmetry with autotools, which only enables
+ this for GCC.
+
+ Reviewed-by: Daniel Stenberg
+ Closes #13286
+
+- cmake: fix `CURL_WERROR=ON` for old CMake and use it in GHA/linux-old
+
+ - cmake: fix `-pedantic-errors` for old CMake with `CURL_WERROR=ON` set.
+
+ `-pedantic-errors` option throws a warning with GCC (all versions) and
+ makes `check_symbol_exists()` fail in CMake versions older than
+ v3.23.0 (2022-03-29), when CMake introduced a workaround:
+
+ https://gitlab.kitware.com/cmake/cmake/-/issues/13208
+ https://gitlab.kitware.com/cmake/cmake/-/commit/eeb45401163d831b8c841ef6eba
+ 81466b4067b68
+ https://gitlab.kitware.com/cmake/cmake/-/commit/1ab7c3cd28b27ca162c4559e102
+ 6e5cad1898ade
+
+ Follow-up to 3829759bd042c03225ae862062560f568ba1a231 #12489
+
+ - set `CURL_WERROR=ON` for the `linux-old` job in CI.
+
+ Closes #13282
+
+- lib: use `#error` instead of invalid syntax in `curl_setup_once.h`
+
+ Reviewed-by: Daniel Stenberg
+ Closes #13287
+
+Daniel Stenberg (5 Apr 2024)
+
+- GHA: on macOS remove $HOME/.curlrc
+
+ A recent image upgrade added a $HOME/.curlrc by default using --ipv4.
+
+ Ref: https://github.com/actions/runner-images/pull/9586
+ Fixes #13284
+ Closes #13285
+
+Viktor Szakats (4 Apr 2024)
+
+- cmake: fixup `DEPENDS` filename
+
+ Fixing:
+ ```
+ make[2]: Circular docs/curl-config.1 <- docs/curl-config.1 dependency dropped
+ .
+ make[2]: Circular docs/mk-ca-bundle.1 <- docs/mk-ca-bundle.1 dependency dropp
+ ed.
+ ```
+ Ref: https://github.com/curl/curl/actions/runs/8559617487/job/23456740844?pr=
+ 13282#step:6:18
+
+ Follow-up to 5023ffad2c27d4b916ddb91800f99ecc5d3aad07 #13197
+ Closes #13283
+
+- GHA: enable unity mode for cmake jobs + tidy-ups
+
+ Unity mode is not supported by CMake v3.7.2 used in linux-old, but
+ enable it anyway for consistency and to kick in automatically once
+ migrating to a newer old Linux in the future.
+
+ Also:
+ - replace `CMAKE_COMPILE_WARNING_AS_ERROR` with `CURL_WERROR`.
+ - delete default build option `PICKY_COMPILER=ON`.
+
+ Closes #13277
+
+Dan Fandrich (4 Apr 2024)
+
+- CI: Add CI build on Debian stretch to test old support
+
+ This version still has ELTS support and contains some old versions of
+ key components like cmake to help prevent us from breaking that support.
+
+ Closes #13029
+
+Stefan Eissing (4 Apr 2024)
+
+- request: paused upload on completed download, assess connection
+
+ A transfer with a completed download that is still uploading needs to
+ check the connection state when it is PAUSEd, since connection
+ close/errors would otherwise go unnoticed.
+
+ Reported-by: Sergey Bronnikov
+ Fixes #13260
+ Closes #13271
+
+Daniel Stenberg (4 Apr 2024)
+
+- url: do not URL decode proxy crendentials
+
+ The two options CURLOPT_PROXYUSERNAME and CURLOPT_PROXYPASSWORD set the
+ actual names as-is, not URL encoded.
+
+ Modified test 503 to use percent-encoded strings in the credential
+ strings that should be passed on as-is.
+
+ Reported-by: Sergey Ogryzkov
+ Fixes #13265
+ Closes #13270
+
+Viktor Szakats (4 Apr 2024)
+
+- appveyor: enable cmake unity mode by default
+
+ Leave one non-unity cmake job. This makes the jobs finish slightly
+ quicker, while giving more coverage for unity issues.
+
+ Before:
+ https://ci.appveyor.com/project/curlorg/curl/builds/49496977
+ https://ci.appveyor.com/project/curlorg/curl/builds/49500372
+ After:
+ https://ci.appveyor.com/project/curlorg/curl/builds/49500338
+
+ Also fixup unrelated whitespace.
+
+ Reviewed-by: Daniel Stenberg
+ Closes #13217
+
+Daniel Stenberg (4 Apr 2024)
+
+- RELEASE-NOTES: synced
+
+Viktor Szakats (4 Apr 2024)
+
+- cmake: speed up libcurl doc building again
+
+ This time limit the number of files per command to avoid exceeding
+ limitations of certain OS/shell envs.
+
+ Such known env is Windows with the `cmd.exe` shell, which features an
+ 8K command-line length limit to this day.
+
+ Allowlisting `UNIX` to have no limit and using a limit of 200 for other
+ envs to be safe. If there is a way to detect `cmd.exe` and/or we know
+ which precise envs are sensitive to this, we can tweak these conditions
+ further.
+
+ Even with the low limit, this patch reduces external commands by 200x,
+ making builds much faster.
+
+ Ref: #12762 2620aa930bc73af1e4c70b10e3125b957b96ecfb (initial)
+ Ref: #13047 f03c85635f35269f1f45b983bf216624f541760a (revert)
+
+ Reviewed-by: Daniel Stenberg
+ Closes #13207
+
+- cmake: tidy-up to use `WORKING_DIRECTORY`
+
+ Reviewed-by: Daniel Stenberg
+ Closes #13206
+
+- cmake: generate misc manpages and install `mk-ca-bundle.pl`
+
+ - install `mk-ca-bundle.pl` like autotools does.
+
+ - generate and install `mk-ca-bundle.1` and `curl-config.1` like
+ autotools. This fixes tests 1140 and 1173.
+
+ Reported-by: Dan Fandrich
+ Fixes #13194
+
+ - add option `BUILD_MISC_DOCS` to control building the above two
+ manpages. Enabled by default.
+
+ - appveyor: stop disabling tests 1140 and 1173.
+
+ Reviewed-by: Daniel Stenberg
+ Closes #13197
+
+Fabian Keil (4 Apr 2024)
+
+- wolfssl: plug memory leak in wolfssl_connect_step2()
+
+ Fixes:
+
+ test 2034...[simple HTTPS GET with DER public key pinning]
+ ==61829== 22,610 (3,744 direct, 18,866 indirect) bytes in 1 blocks are d
+ efinitely lost in loss record 51 of 54
+ ==61829== at 0x484BB74: malloc (vg_replace_malloc.c:446)
+ ==61829== by 0x4B53A80: wolfSSL_Malloc (memory.c:344)
+ ==61829== by 0x4C1C8E1: wolfSSL_X509_new (x509.c:5326)
+ ==61829== by 0x4C3977D: d2i_X509orX509REQ (x509.c:3628)
+ ==61829== by 0x4C1D1F4: wolfSSL_X509_d2i (x509.c:3664)
+ ==61829== by 0x4C1C37B: wolfSSL_X509_dup (x509.c:13425)
+ ==61829== by 0x4C197DB: wolfSSL_get_peer_certificate (ssl.c:18765)
+ ==61829== by 0x33297C: wolfssl_connect_step2 (wolfssl.c:875)
+ ==61829== by 0x331669: wolfssl_connect_common (wolfssl.c:1287)
+ ==61829== by 0x3303E9: wolfssl_connect_nonblocking (wolfssl.c:1319)
+ ==61829== by 0x32FE89: ssl_connect_nonblocking (vtls.c:510)
+ ==61829== by 0x32DBE5: ssl_cf_connect (vtls.c:1679)
+ ==61829== by 0x27ABD7: Curl_conn_cf_connect (cfilters.c:307)
+ ==61829== by 0x27D9CF: cf_setup_connect (connect.c:1199)
+ ==61829== by 0x27ABD7: Curl_conn_cf_connect (cfilters.c:307)
+ ==61829== by 0x283CEA: cf_hc_baller_connect (cf-https-connect.c:135)
+
+ Closes #13272
+
+Viktor Szakats (3 Apr 2024)
+
+- appveyor: OpenSSL 3 no longer found by CMake, revert to 1.1.1
+
+ OpenSSL moved directories, and bumped versions in AppVeyor CI.
+
+ Downgrading is not an ideal solution, but however trivial the solution
+ may be, I failed to come with anything that made CMake recognize either
+ OpenSSL 3.1 or 3.2.
+
+ Possibly caused by:
+ https://github.com/appveyor/build-images/commit/702e8cdca01f28f6a40687783f493
+ c786cebbe2c
+ https://github.com/appveyor/build-images/pull/149
+
+ Closes #13266
+
+hongfei.li (3 Apr 2024)
+
+- winbuild: use $(RC) correctly
+
+ Cloes #13267
+
+Daniel Stenberg (3 Apr 2024)
+
+- dist: remove the curl-config.1 from the tarball
+
+ The markdown file is already there and the .1 file gets generated in the
+ build.
+
+ Ref: #13250
+ Closes #13268
+
+- curl_global_trace.md: shorten the description
+
+ Closes #13263
+
+- test1901: verify chunked POST from callback with CURLOPT_POSTFIELDSIZE set
+
+ Follow-up to 721941aadf4ad
+
+ Ref: #13257
+ Closes #13262
+
+Stefan Eissing (2 Apr 2024)
+
+- http: with chunked POST forced, disable length check on read callback
+
+ - when an application forces HTTP/1.1 chunked transfer encoding
+ by setting the corresponding header and instructs curl to use
+ the CURLOPT_READFUNCTION, disregard any POST length information.
+ - this establishes backward compatibility with previous curl versions
+
+ Applications are encouraged to not force "chunked", but rather
+ set length information for a POST. By setting -1, curl will
+ auto-select chunked on HTTP/1.1 and work properly on other HTTP
+ versions.
+
+ Reported-by: Jeff King
+ Fixes #13229
+ Closes #13257
+
+Jay Satiro (1 Apr 2024)
+
+- INSTALL-CMAKE.md: explain `cmake -G <generator-name>`
+
+ - Explain that CMake's -G option can be used to specify which build
+ system to generate files for.
+
+ Example: cmake ../curl -G "MinGW Makefiles"
+
+ Ref: https://github.com/curl/curl/pull/12224#issuecomment-2026813645
+
+ Closes https://github.com/curl/curl/pull/13244
+
+Daniel Stenberg (1 Apr 2024)
+
+- libcurl-opts: mention pipelining less
+
+ libcurl has not supported HTTP pipelining since many years. Remove a few
+ (more) mentions of the feature.
+
+ Closes #13254
+
+Daniel McCarney (31 Mar 2024)
+
+- m4: reposition USE_RUSTLS="yes" for pkg-config
+
+ It's necessary to set this var to "yes" _after_ AC_DEFINE and AC_SUBST
+ in order for a later `test` to pass so that `check_for_ca_bundle=1` ends
+ up being set. This is in turn required for the default CA certificate
+ bundle to be set when building w/ rustls & pkg-config.
+
+ Reported-by: Matt Jolly
+ Fixes #13248
+ Closes #13251
+
+Daniel Stenberg (31 Mar 2024)
+
+- maketgz: put docs/RELEASE-TOOL.md into the tarball
+
+ Generated with scripts/release-tools.sh
+
+ The script lists the exact Debian package names and version numbers for
+ the tools that are used to generate the tarball.
+
+ Closes #13239
+
+- cd2nroff/manage: use UTC when SOURCE_DATE_EPOCH is set
+
+ Make them independent of the TZ setting. Also set a date string like
+ YYYY-MM-DD to avoid a local month name in the date.
+
+ Reported-by: Carlos Henrique Lima Melara
+ Fixes #13242
+ Closes #13243
+
+- RELEASE-NOTES: synced
+
+- docs/MAIL-ETIQUETTE: convert to markdown
+
+ To render nicer. To get spellchecked.
+
+ Closes #13247
+
+- reuse: add copyright + license info to individual docs/*.md files
+
+ Instead of use 'docs/*.md' in dep5. For clarity and avoiding a wide-
+ matching wildcard.
+
+ + Remove mention of old files from .reuse/dep5
+ + add info to .github/dependabot.yml
+ + make scripts/copyright.pl warn on non-matching patterns
+
+ Closes #13245
+
+- test470: warn about unicode quote character read from config file
+
+ Idea-by: Emanuele Torre
+
+- test469: verify warning when argument has unicode quote
+
+- tool_getparam: output warning for leading unicode quote character
+
+ ... in the option argument.
+
+ Typically this is a mistake done when copying example command lines from
+ online documentation using the wrong quote character.
+
+ Presumably there are also other potential quote characters that might be
+ used, and this check is done without even knowing that unicode is used!
+
+ Reported-by: Sanjay Pujare
+ Fixes #13214
+ Closes #13215
+
+- tool: follow-up getenv fix
+
+ Remove a double free. Change the IPFS env use to a plain getenv() simply
+ because coverity gets confused.
+
+ Follow-up to 9126b141c9398fe
+ Closes #13241
+
+- idn: make Curl_idnconvert_hostname() use Curl_idn_decode()
+
+ In the name of less code duplication
+
+ Closes #13236
+
+- curl-confopts.m4: define CARES_NO_DEPRECATED when c-ares is used
+
+ Starting in 1.28.0 c-ares added deprecation warnings for some API calls
+ libcurl uses.
+
+ Closes #13240
+
+- vquic: use CURL_FORMAT_CURL_OFF_T for 64 bit printf output
+
+ Reported-by: Keitagit-kun on github
+ Fixes #13224
+ Closes #13231
+
+- openldap: create ldap URLs correctly for IPv6 addresses
+
+ Reported-by: Sergio Durigan Junior
+ Fixes #13228
+ Closes #13235
+
+- curl: use curl_getenv instead of the curlx_ version
+
+ The curlx one was once introduced when we still considered dropping the
+ libcurl function at some point. To reduce confusion and to make it
+ easier to understand when curl_free() should be used, use the actual
+ libcurl function call directly instead.
+
+ Closes #13230
+
+Evgeny Grin (Karlson2k) (30 Mar 2024)
+
+- curl_sha512_256: do not use workaround for NetBSD when not needed
+
+ Assisted-by: riastradh on github
+ Assisted-by: Michael Kaufmann
+ Closes #13225
+
+Matt Jolly (30 Mar 2024)
+
+- m4: fix rustls pkg-config codepath
+
+ The previous pkg-config code would successfully detect rustls but did
+ not set all appropriate variables and call the right macros to properly
+ configure cURL.
+
+ Reported-by: kpcyrd on github
+ Fixes #13200
+ Closes #13202
+
+Daniel McCarney (30 Mar 2024)
+
+- deps: update librustls 0.12.0 -> 0.13.0
+
+ This commit updates the optional rustls-ffi librustls dependency from
+ 0.12.0 to 0.13.0. This version is based on the latest available rustls
+ release (0.23.4).
+
+ The breaking API changes from 0.12.0 to 0.13.0 are in API surface unused
+ by curl, so this is an in-place update without any code changes.
+
+ The `RUSTLS.md` documentation is updated to reflect the new version in
+ use, and to clarify that `cbindgen` isn't required to build `librustls`
+ - it's only used by developers to update the vendored `rustls.h` header
+ file maintained upstream.
+
+ Closes #13238
+
+Daniel Stenberg (28 Mar 2024)
+
+- RELEASE-NOTES: synced
+
+- tool_xattr: "guess" URL scheme if none is provided
+
+ ... when figuring out the source URL to store.
+
+ Reported-by: Dagfinn Ilmari Mannsåker
+ Fixes #13205
+ Closes #13221
+
+- tool_xattr: in debug builds, act normally if CURL_FAKE_XATTR is not set
+
+ Closes #13220
+
+Stefan Eissing (28 Mar 2024)
+
+- content_encoding: brotli and others, pass through 0-length writes
+
+ - curl's transfer handling may write 0-length chunks at the end of the
+ download with an EOS flag. (HTTP/2 does this commonly)
+
+ - content encoders need to pass-through such a write and not count this
+ as error in case they are finished decoding
+
+ Fixes #13209
+ Fixes #13212
+ Closes #13219
+
+Tobias Stoeckmann (28 Mar 2024)
+
+- libssh2: set length to 0 if strdup failed
+
+ Internally, libssh2 dereferences the NULL pointer if length is non-zero.
+ The callback function cannot return the error condition, so at least
+ prevent subsequent crash.
+
+ Closes #13213
+
+Daniel Stenberg (28 Mar 2024)
+
+- RELEASE-PROCEDURE: mention an initial working build
+
+ This is the step that was not done and caused the 8.7.0 mishap (it
+ lacked the correctly generated hugehelp file).
+
+ Remove the mention of the copyright script as this is verified by a CI
+ job these days: the REUSE one.
+
+ Closes #13216
+
+Paul Howarth (28 Mar 2024)
+
+- curl_sha512_255: fix detection of OpenSSL 1.1.1 or later
+
+ Use the same OPENSSL_VERSION_NUMBER comparison as in lib/vtls/openssl.c.
+
+ Closes #13208
+
+Robert Moreton (28 Mar 2024)
+
+- cf-socket: remove references to l_ip, l_port
+
+ Fixes #13210
+ Closes #13211
+
+Daniel Stenberg (28 Mar 2024)
+
+- openssl: do not set SSL_MODE_RELEASE_BUFFERS
+
+ While it might save some memory, it causes OpenSSL to instead do a huge
+ amount of allocations.
+
+ Ref: #13136
+ Closes #13203
+
+- curl: make --help adapt to the terminal width
+
+ Instead of assuming and working with 80 colums, try figuring out what
+ width is actually used.
+
+ Ref: #13141
+
+ Closes #13171
+
+- RELEASE-NOTES: synced
+
+ and bump to 8.7.2 for now
+
+- configure: make --disable-docs imply --disable-manual
+
+ Because when the docs is not built, the necesary curl.txt file is not
+ present so then the manual cannot get built.
+
+ Reported-by: Harry Sintonen
+ Closes #13191
+
+Chris Webb (27 Mar 2024)
+
+- cmdline-docs: fix make install with configure --disable-docs
+
+ make -C docs/cmdline-opts install depends on all-am, which in turn
+ depends on $(MANS), unconditionally defined to be $(man_MANS).
+
+ As with CLEANFILES, only add curl.1 to man_MANS when BUILD_DOCS is true
+ so we don't try to build curl.1 unnecessarily.
+
+ Closes #13198
+
Version 8.7.1 (27 Mar 2024)
Daniel Stenberg (27 Mar 2024)
@@ -7090,3935 +10707,3 @@ boilingoden (4 Nov 2023)
xref: https://curl.se/changes.html#7_70_0
Closes #12266
-
-Viktor Szakats (3 Nov 2023)
-
-- appveyor: make VS2008-built curl tool runnable
-
- By linking the CRT statically. This avoids the error about missing
- runtime DLL `MSVCR90.dll` when running the freshly built `curl.exe`.
-
- Closes #12263
-
-Stefan Eissing (3 Nov 2023)
-
-- url: proxy ssl connection reuse fix
-
- - tunnel https proxy used for http: transfers does
- no check if proxy-ssl configuration matches
- - test cases added, test_10_12 fails on 8.4.0
-
- Closes #12255
-
-Jay Satiro (3 Nov 2023)
-
-- curl_sspi: support more revocation error names in error messages
-
- - Add these revocation errors to sspi error list:
- CRYPT_E_NO_REVOCATION_DLL, CRYPT_E_NO_REVOCATION_CHECK,
- CRYPT_E_REVOCATION_OFFLINE and CRYPT_E_NOT_IN_REVOCATION_DATABASE.
-
- Prior to this change those error codes were not matched to their macro
- name and instead shown as "unknown error".
-
- Before:
-
- schannel: next InitializeSecurityContext failed:
- Unknown error (0x80092013) - The revocation function was
- unable to check revocation because the revocation server was offline.
-
- After:
-
- schannel: next InitializeSecurityContext failed:
- CRYPT_E_REVOCATION_OFFLINE (0x80092013) - The revocation function was
- unable to check revocation because the revocation server was offline.
-
- Bug: https://github.com/curl/curl/issues/12239
- Reported-by: Niracler Li
-
- Closes https://github.com/curl/curl/pull/12241
-
-- strdup: don't allow Curl_strndup to read past a null terminator
-
- - Use malloc + strncpy instead of Curl_memdup to dupe the string before
- null terminating it.
-
- Prior to this change if Curl_strndup was passed a length longer than
- the allocated string then it could copy out of bounds.
-
- This change is for posterity. Curl_strndup was added in the parent
- commit and currently none of the calls to it pass a length that would
- cause it to read past the allocated length of the input.
-
- Follow-up to d3b3ba35.
-
- Closes https://github.com/curl/curl/pull/12254
-
-Daniel Stenberg (2 Nov 2023)
-
-- lib: add and use Curl_strndup()
-
- The Curl_strndup() function is similar to memdup(), but copies 'n' bytes
- then adds a terminating null byte ('\0').
-
- Closes #12251
-
-- CURPOST_POSTFIELDS.3: add CURLOPT_COPYPOSTFIELDS in SEE ALSO
-
-Stefan Eissing (2 Nov 2023)
-
-- pytest: use lower count in repeat tests
-
- - lower large iteration counts in some tests somewhat for
- the same coverage with less duration
-
- Closes #12248
-
-Daniel Stenberg (2 Nov 2023)
-
-- RELEASE-NOTES: synced
-
-- docs: clarify that curl passes on input unfiltered
-
- ... for several options.
-
- Reported-by: Ophir Lojkine
-
- Closes #12249
-
-- urlapi: when URL encoding the fragment, pass in the right length
-
- A benign bug because it would only add an extra null terminator.
-
- Made lib1560 get a test that runs this code.
-
- Closes #12250
-
-Stefan Eissing (2 Nov 2023)
-
-- vtls: late clone of connection ssl config
-
- - perform connection cache matching against `data->set.ssl.primary`
- and proxy counterpart
- - fully clone connection ssl config only when connection is used
-
- Closes #12237
-
-- msh3: error when built with CURL_DISABLE_SOCKETPAIR set
-
- Reported-by: Gisle Vanem
- Closes #12252
- Fixes #12213
-
-Daniel Stenberg (2 Nov 2023)
-
-- hsts: skip single-dot hostname
-
- Reported-by: Maksymilian Arciemowicz
-
- Closes #12247
-
-- vtls: fix build without proxy
-
- Follow-up to bf0e278a3c54bc7fee7360da17c
-
- closes #12243
-
-- docs/example/keepalive.c: show TCP keep-alive options
-
- Closes #12242
-
-- lib1560: verify appending blank URL encoded query string
-
-- urlapi: skip appending NULL pointer query
-
- Reported-by: kirbyn17 on hackerone
-
- Closes #12240
-
-- lib1560: verify setting host to "" with and without URL encode
-
-- urlapi: avoid null deref if setting blank host to url encode
-
- Reported-by: kirbyn17 on hackerone
-
- Closes #12240
-
-- dynbuf: assert for NULL pointer inputs
-
- Help us catch more mistakes.
-
- Closes #12238
-
-- HTTP3: ngtcp2 builds are no longer experimental
-
- The other HTTP/3 backends are still experimental.
-
- Closes #12235
-
-Stefan Eissing (31 Oct 2023)
-
-- vtls: cleanup SSL config management
-
- - remove `Curl_ssl_get_config()`, no longer needed
-
- Closes #12204
-
-Daniel Stenberg (31 Oct 2023)
-
-- libcurl-thread.3: simplify the TLS section
-
- All TLS libraries curl can use are threadsafe since OpenSSL 1.1.x, August
- 2016.
-
- Closes #12233
-
-- configure: better --disable-http
-
- - disable HTTPS-proxy as well, since it can't work without HTTP
-
- - curl_setup: when HTTP is disabled, also disable all features that are
- HTTP-only
-
- - version: HTTPS-proxy only exists if HTTP support exists
-
- Closes #12223
-
-- http: consider resume with CURLOPT_FAILONERRROR and 416 to be fine
-
- Finding a 'Content-Range:' in the response changed the handling.
-
- Add test case 1475 to verify -C - with 416 and Content-Range: header,
- which is almost exactly like test 194 which instead uses a fixed -C
- offset. Adjusted test 194 to also be considered fine.
-
- Fixes #10521
- Reported-by: Smackd0wn
- Fixes #12174
- Reported-by: Anubhav Rai
- Closes #12176
-
-Stefan Eissing (30 Oct 2023)
-
-- GHA: fix checkout of quictls repository to use correct branch name
-
- Follow-up to c868b0e30f10cd0ac7
-
- Closes #12232
-
-Daniel Stenberg (30 Oct 2023)
-
-- docs/example/localport.c: show off CURLOPT_LOCALPORT
-
- Closes #12230
-
-- docs/examples/interface.c: show CURLOPT_INTERFACE use
-
- Although super simple.
-
- Closes #12229
-
-Viktor Szakats (30 Oct 2023)
-
-- build: fix compiler warning with auths disabled
-
- ```
- ./curl/lib/http.c:979:12: warning: unused function 'is_valid_auth_separator'
- [-Wunused-function]
- static int is_valid_auth_separator(char ch)
- ^
- 5 warnings generated.
- ```
-
- Follow-up to e92edfbef64448ef461117769881f3ed776dec4e #11490
-
- Closes #12227
-
-- build: require Windows XP or newer
-
- After this patch we assume availability of `getaddrinfo` and
- `freeaddrinfo`, first introduced in Windows XP. Meaning curl
- now requires building for Windows XP as a minimum.
-
- TODO: assume these also in autotools.
-
- Ref: https://github.com/curl/curl/pull/12221#issuecomment-1783761806
- Closes #12225
-
-- appveyor: bump one job to OpenSSL 3.1 (was 1.1.1)
-
- Use 3.1 with the modern runner image.
-
- We still use 1.1.1 in 8 jobs.
-
- 1.1.1 is EOL since 2023-09-11:
- https://www.openssl.org/blog/blog/2023/03/28/1.1.1-EOL/
-
- Also:
- - add missing SSL-backend to job descriptions.
- - tidy up CPU in job descriptions.
-
- Closes #12226
-
-Daniel Stenberg (30 Oct 2023)
-
-- RELEASE-NOTES: synced
-
-- GHA: bump ngtcp2, nghttp3, nghttp2 and quictls versions
-
- ngtcp2 1.0.1
- nghttp3 1.0.0
- nghttp2 1.58.0
- quictls 3.1.4+quic
-
- also sync HTTP3.md with these changes
-
- Closes #12132
-
-Kareem (29 Oct 2023)
-
-- wolfssl: add default case for wolfssl_connect_step1 switch
-
- Closes #12218
-
-Jay Satiro (29 Oct 2023)
-
-- curl_setup: disallow Windows IPv6 builds missing getaddrinfo
-
- - On Windows if IPv6 is enabled but getaddrinfo is missing then #error
- the build.
-
- curl can be built with IPv6 support (ENABLE_IPV6) but without the
- ability to resolve hosts to IPv6 addresses (HAVE_GETADDRINFO). On
- Windows this is highly unlikely and should be considered a bad build
- configuration.
-
- Such a bad configuration has already given us a bug that was hard to
- diagnose. See #12134 and #12136 for discussion.
-
- Ref: https://github.com/curl/curl/issues/12134
- Ref: https://github.com/curl/curl/pull/12136
-
- Closes https://github.com/curl/curl/pull/12221
-
-Nico Rieck (29 Oct 2023)
-
-- openssl: make CURLSSLOPT_NATIVE_CA import Windows intermediate CAs
-
- - If CURLSSLOPT_NATIVE_CA on Windows then import from intermediate CA
- "CA" store after importing from root CA "ROOT" store.
-
- This change allows curl to work in situations where a server does not
- send all intermediate certs and they are present in the "CA" store (the
- store with intermediate CAs). This is already allowed by the Schannel
- backend.
-
- Also this change makes partial chain verification possible for those
- certs since we allow partial chain verification by default for OpenSSL
- (unless CURLSSLOPT_NO_PARTIALCHAIN). This is not allowed by the Schannel
- backend.
-
- Prior to this change CURLSSLOPT_NATIVE_CA only imported "ROOT" certs.
-
- Fixes https://github.com/curl/curl/issues/12155
- Closes https://github.com/curl/curl/pull/12185
-
-Viktor Szakats (28 Oct 2023)
-
-- Makefile.mk: fix `-rtmp` option for non-Windows [ci skip]
-
-Daniel Stenberg (28 Oct 2023)
-
-- asyn-ares: handle no connection in the addrinfo callback
-
- To avoid crashing.
-
- Follow-up from 56a4db2
- Closes #12219
-
-Jay Satiro (28 Oct 2023)
-
-- hostip6: fix DEBUG_ADDRINFO builds
-
- - Removed unused and incorrect parameter from dump_addrinfo().
-
- Bug: https://github.com/curl/curl/commit/56a4db2e#commitcomment-131050442
- Reported-by: Gisle Vanem
-
- Closes https://github.com/curl/curl/pull/12212
-
-Viktor Szakats (28 Oct 2023)
-
-- Makefile.mk: restore `_mingw.h` for default `_WIN32_WINNT`
-
- In 8.4.0 we deleted `_mingw.h` as part of purging old-mingw support.
- Turns out `_mingw.h` had the side-effect of setting a default
- `_WIN32_WINNT` value expected by `lib/config-win32.h` to enable
- `getaddrinfo` support in `Makefile.mk` mingw-w64 builds. This caused
- disabling support for this unless specifying the value manually.
-
- Restore this header and update its comment to tell why we continue
- to need it.
-
- This triggered a regression in official Windows curl builds starting
- with 8.4.0_1. Fixed in 8.4.0_6. (8.5.0 will be using CMake.)
-
- Regression from 38029101e2d78ba125732b3bab6ec267b80a0e72 #11625
-
- Reported-by: zhengqwe on github
- Helped-by: Nico Rieck
- Fixes #12134
- Fixes #12136
- Closes #12217
-
-- hostip: silence compiler warning `-Wparentheses-equality`
-
- Seen with LLVM 17.
-
- ```
- hostip.c:1336:22: warning: equality comparison with extraneous parentheses [-
- Wparentheses-equality]
- 1336 | (a->ai_family == PF_INET)) {
- | ~~~~~~~~~~~~~^~~~~~~~~~
- hostip.c:1336:22: note: remove extraneous parentheses around the comparison t
- o silence this warning
- 1336 | (a->ai_family == PF_INET)) {
- | ~ ^ ~
- hostip.c:1336:22: note: use '=' to turn this equality comparison into an assi
- gnment
- 1336 | (a->ai_family == PF_INET)) {
- | ^~
- | =
- 1 warning generated.
- ```
-
- Follow-up to b651aba0962bb31353f55de4dc35f745952a1b10 #12145
-
- Reviewed-by: Daniel Stenberg
- Closes #12215
-
-Stefan Eissing (27 Oct 2023)
-
-- doh: use PIPEWAIT when HTTP/2 is attempted
-
- Closes #12214
-
-Daniel Stenberg (27 Oct 2023)
-
-- setopt: remove outdated cookie comment
-
- Closes #12206
-
-Stefan Eissing (27 Oct 2023)
-
-- cfilter: provide call to tell connection to forget a socket
-
- - fixed libssh.c workaround for a socket being closed by
- the library
- - eliminate the terrible hack in cf-socket.c to guess when
- this happened and try not closing the socket again.
- - fixes race in eyeballing when socket could have failed to
- be closed for a discarded connect attempt
-
- Closes #12207
-
-- url: protocol handler lookup tidy-up
-
- - rename lookup to what it does
- - use ARRAYSIZE instead of NULL check for end
- - offer alternate lookup for 0-terminated strings
-
- Closes #12216
-
-Viktor Szakats (27 Oct 2023)
-
-- build: variadic macro tidy-ups
-
- - delete unused `HAVE_VARIADIC_MACROS_C99/GCC` feature checks.
- (both autotools and CMake.)
- - delete duplicate `NULL` check in `Curl_trc_cf_infof()`.
- - fix compiler warning in `CURL_DISABLE_VERBOSE_STRINGS` builds.
- ```
- ./lib/cf-socket.c:122:41: warning: unused parameter 'data' [-Wunused-parame
- ter]
- static void nosigpipe(struct Curl_easy *data,
- ^
- ```
- - fix `#ifdef` comments in `lib/curl_trc.{c,h}`.
- - fix indentation in some `infof()` calls.
-
- Follow-up to dac293cfb7026b1ca4175d88b80f1432d3d3c684 #12167
-
- Cherry-picked from #12105
- Closes #12210
-
-- cmake: speed up threads setup for Windows
-
- Win32 threads are always available. We enabled them unconditionally
- (with `ENABLE_THREADED_RESOLVER`). CMake built-in thread detection
- logic has this condition hard-coded for Windows as well (since at least
- 2007).
-
- Instead of doing all the work of detecting pthread combinations on
- Windows, then discarding those results, skip these efforts and assume
- built-in thread support when building for Windows.
-
- This saves 1-3 slow CMake configuration steps.
-
- Reviewed-by: Daniel Stenberg
- Closes #12202
-
-- cmake: speed up zstd detection
-
- Before this patch we detected the presence of a specific zstd API to
- see if we can use the library. zstd published that API in its first
- stable release: v1.0.0 (2016-08-31).
-
- Replace that method by detecting the zstd library version instead and
- accepting if it's v1.0.0 or newer. Also display this detected version
- and display a warning if the zstd found is unfit for curl.
-
- We use the same version detection method as zstd itself, via its public
- C header.
-
- This deviates from autotools which keeps using the slow method of
- looking for the API by building a test program. The outcome is the same
- as long as zstd keeps offering this API.
-
- Ref: https://github.com/facebook/zstd/commit/5a0c8e24395079f8e8cdc90aa1659cd5
- ab1b7427 (2016-08-12, committed)
- Ref: https://github.com/facebook/zstd/releases/tag/v0.8.1 (2016-08-18, first
- released)
- Ref: https://github.com/facebook/zstd/releases/tag/v1.0.0
-
- Reviewed-by: Daniel Stenberg
- Closes #12200
-
-Daniel Stenberg (26 Oct 2023)
-
-- openssl: fix infof() to avoid compiler warning for %s with null
-
- vtls/openssl.c: In function ‘ossl_connect_step2’:
- ../lib/curl_trc.h:120:10: error: ‘%s’ directive argument is null [-Werror
- =format-overflow=]
- 120 | Curl_infof(data, __VA_ARGS__); } while(0)
- | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- vtls/openssl.c:4008:5: note: in expansion of macro ‘infof’
- 4008 | infof(data, "SSL connection using %s / %s / %s / %s",
- | ^~~~~
- vtls/openssl.c:4008:49: note: format string is defined here
- 4008 | infof(data, "SSL connection using %s / %s / %s / %s",
- | ^~
-
- Follow-up to b6e6d4ff8f253c8b8055bab
- Closes #12196
-
-Stefan Eissing (26 Oct 2023)
-
-- lib: apache style infof and trace macros/functions
-
- - test for a simplified C99 variadic check
- - args to infof() in --disable-verbose are no longer disregarded but
- must compile.
-
- Closes #12167
- Fixes #12083
- Fixes #11880
- Fixes #11891
-
-Daniel Stenberg (26 Oct 2023)
-
-- RELEASE-NOTES: synced
-
-Stefan Eissing (26 Oct 2023)
-
-- urldata: move async resolver state from easy handle to connectdata
-
- - resolving is done for a connection, not for every transfer
- - save create/dup/free of a cares channel for each transfer
- - check values of setopt calls against a local channel if no
- connection has been attached yet, when needed.
-
- Closes #12198
-
-Daniel Stenberg (26 Oct 2023)
-
-- CURLOPT_WRITEFUNCTION.3: clarify what libcurl returns for CURL_WRITEFUNC_ERRO
- R
-
- It returns CURLE_WRITE_ERROR. It was not previously stated clearly.
-
- Reported-by: enWILLYado on github
- Fixes #12201
- Closes #12203
-
-Viktor Szakats (25 Oct 2023)
-
-- autotools: update references to deleted `crypt-auth` option
-
- Delete leftovers of the `crypt-auth` `./configure` option and
- add the new ones that replaced them.
-
- Follow-up to e92edfbef64448ef461117769881f3ed776dec4e #11490
-
- Reviewed-by: Daniel Stenberg
- Closes #12194
-
-Stefan Eissing (25 Oct 2023)
-
-- lib: introduce struct easy_poll_set for poll information
-
- Connection filter had a `get_select_socks()` method, inspired by the
- various `getsocks` functions involved during the lifetime of a
- transfer. These, depending on transfer state (CONNECT/DO/DONE/ etc.),
- return sockets to monitor and flag if this shall be done for POLLIN
- and/or POLLOUT.
-
- Due to this design, sockets and flags could only be added, not
- removed. This led to problems in filters like HTTP/2 where flow control
- prohibits the sending of data until the peer increases the flow
- window. The general transfer loop wants to write, adds POLLOUT, the
- socket is writeable but no data can be written.
-
- This leads to cpu busy loops. To prevent that, HTTP/2 did set the
- `SEND_HOLD` flag of such a blocked transfer, so the transfer loop cedes
- further attempts. This works if only one such filter is involved. If a
- HTTP/2 transfer goes through a HTTP/2 proxy, two filters are
- setting/clearing this flag and may step on each other's toes.
-
- Connection filters `get_select_socks()` is replaced by
- `adjust_pollset()`. They get passed a `struct easy_pollset` that keeps
- up to `MAX_SOCKSPEREASYHANDLE` sockets and their `POLLIN|POLLOUT`
- flags. This struct is initialized in `multi_getsock()` by calling the
- various `getsocks()` implementations based on transfer state, as before.
-
- After protocol handlers/transfer loop have set the sockets and flags
- they want, the `easy_pollset` is *always* passed to the filters. Filters
- "higher" in the chain are called first, starting at the first
- not-yet-connection one. Each filter may add sockets and/or change
- flags. When all flags are removed, the socket itself is removed from the
- pollset.
-
- Example:
-
- * transfer wants to send, adds POLLOUT
- * http/2 filter has a flow control block, removes POLLOUT and adds
- POLLIN (it is waiting on a WINDOW_UPDATE from the server)
- * TLS filter is connected and changes nothing
- * h2-proxy filter also has a flow control block on its tunnel stream,
- removes POLLOUT and adds POLLIN also.
- * socket filter is connected and changes nothing
- * The resulting pollset is then mixed together with all other transfers
- and their pollsets, just as before.
-
- Use of `SEND_HOLD` is no longer necessary in the filters.
-
- All filters are adapted for the changed method. The handling in
- `multi.c` has been adjusted, but its state handling the the protocol
- handlers' `getsocks` method are untouched.
-
- The most affected filters are http/2, ngtcp2, quiche and h2-proxy. TLS
- filters needed to be adjusted for the connecting handshake read/write
- handling.
-
- No noticeable difference in performance was detected in local scorecard
- runs.
-
- Closes #11833
-
-Daniel Stenberg (25 Oct 2023)
-
-- tests/README: SOCKS tests are not using OpenSSH, it has its own server
-
- Follow-up to 04fd67555cc
-
- Closes #12195
-
-Jacob Hoffman-Andrews (25 Oct 2023)
-
-- tets: make test documentation more user-friendly
-
- Put the instructions to run tests right at the top of tests/README.md.
-
- Give instructions to read the runtests.1 man page for information
- about flags. Delete redundant copy of the flags documentation in the
- README.
-
- Add a mention in README.md of the important parallelism flag, to make
- test runs go much faster.
-
- Move documentation of output line format into the runtests.1 man page,
- and update it with missing flags.
-
- Fix the order of two flags in the man page.
-
- Closes #12193
-
-Viktor Szakats (24 Oct 2023)
-
-- cmake: pre-fill rest of detection values for Windows
-
- The goal of this patch is to avoid unnecessary feature detection work
- when doing Windows builds with CMake. Do this by pre-filling well-known
- detection results for Windows and specifically for mingw-w64 and MSVC
- compilers. Also limit feature checks to platforms where the results are
- actually used. Drop a few redundant ones. And some tidying up.
-
- - pre-fill remaining detection values in Windows CMake builds.
-
- Based on actual detection results observed in CI runs, preceding
- similar work over libssh2 and matching up values with
- `lib/config-win32.h`.
-
- This brings down CMake configuration time from 58 to 14 seconds on the
- same local machine.
-
- On AppVeyor CI this translates to:
- - 128 seconds -> 50 seconds VS2022 MSVC with OpenSSL (per CMake job):
- https://ci.appveyor.com/project/curlorg/curl/builds/48208419/job/4gw66ecr
- jpy7necb#L296
- https://ci.appveyor.com/project/curlorg/curl/builds/48217440/job/8m4fwrr2
- fe249uo8#L186
- - 62 seconds -> 16 seconds VS2017 MINGW (per CMake job):
- https://ci.appveyor.com/project/curlorg/curl/builds/48208419/job/s1y8q5iv
- lcs7ub29?fullLog=true#L290
- https://ci.appveyor.com/project/curlorg/curl/builds/48217440/job/pchpxyjs
- yc9kl13a?fullLog=true#L194
-
- The formula is about 1-3 seconds delay for each detection. Almost all
- of these trigger a full compile-link cycle behind the scenes, slow
- even today, both cross and native, mingw-w64 and apparently MSVC too.
- Enabling .map files or other custom build features slows it down
- further. (Similar is expected for autotools configure.)
-
- - stop detecting `idn2.h` if idn2 was deselected.
- autotools does this.
-
- - stop detecting `idn2.h` if idn2 was not found.
- This deviates from autotools. Source code requires both header and
- lib, so this is still correct, but faster.
-
- - limit `ADDRESS_FAMILY` detection to Windows.
-
- - normalize `HAVE_WIN32_WINNT` value to lowercase `0x0a12` format.
-
- - pre-fill `HAVE_WIN32_WINNT`-dependent detection results.
- Saving 4 (slow) feature-detections in most builds: `getaddrinfo`,
- `freeaddrinfo`, `inet_ntop`, `inet_pton`
-
- - fix pre-filled `HAVE_SYS_TIME_H`, `HAVE_SYS_PARAM_H`,
- `HAVE_GETTIMEOFDAY` for mingw-w64.
- Luckily this do not change build results, as `WIN32` took
- priority over `HAVE_GETTIMEOFDAY` with the current source
- code.
-
- - limit `HAVE_CLOCK_GETTIME_MONOTONIC_RAW` and
- `HAVE_CLOCK_GETTIME_MONOTONIC` detections to non-Windows.
- We're not using these in the source code for Windows.
-
- - reduce compiler warning noise in CMake internal logs:
- - fix to include `winsock2.h` before `windows.h`.
- Apply it to autotools test snippets too.
- - delete previous `-D_WINSOCKAPI_=` hack that aimed to fix the above.
- - cleanup `CMake/CurlTests.c` to emit less warnings.
-
- - delete redundant `HAVE_MACRO_SIGSETJMP` feature check.
- It was the same check as `HAVE_SIGSETJMP`.
-
- - delete 'experimental' marking from `CURL_USE_OPENSSL`.
-
- - show CMake version via `CMakeLists.txt`.
- Credit to the `zlib-ng` project for the idea:
- https://github.com/zlib-ng/zlib-ng/blob/61e181c8ae93dbf56040336179c9954078b
- d1399/CMakeLists.txt#L7
-
- - make `CMake/CurlTests.c` pass `checksrc`.
-
- - `CMake/WindowsCache.cmake` tidy-ups.
-
- - replace `WIN32` guard with `_WIN32` in `CMake/CurlTests.c`.
-
- Closes #12044
-
-Jay Satiro (24 Oct 2023)
-
-- page-footer: clarify exit code 25
-
- - Clarify that curl tool exit code 25 means an upload failed to start.
-
- Exit code 25 is equivalent to CURLE_UPLOAD_FAILED (25). Prior to this
- change the documentation only mentioned the case of FTP STOR failing.
-
- Reported-by: Emanuele Torre
-
- Ref: https://github.com/curl/curl/blob/curl-8_4_0/docs/libcurl/libcurl-errors
- .3#L113-L115
-
- Fixes https://github.com/curl/curl/issues/12189
- Closes https://github.com/curl/curl/pull/12190
-
-Daniel Stenberg (24 Oct 2023)
-
-- scripts/cijobs.pl: adjust for appveyor
-
- Follow-up to a1d73a6bb
-
-Alex Bozarth (24 Oct 2023)
-
-- OpenSSL: Include SIG and KEM algorithms in verbose
-
- Currently the verbose output does not include which algorithms are used
- for the signature and key exchange when using OpenSSL. Including the
- algorithms used will enable better debugging when working on using new
- algorithm implementations. Know what algorithms are used has become more
- important with the fast growing research into new quantum-safe
- algorithms.
-
- This implementation includes a build time check for the OpenSSL version
- to use a new function that will be included in OpenSSL 3.2 that was
- introduced in openssl/openssl@6866824
-
- Based-on-patch-by: Martin Schmatz <mrt@zurich.ibm.com>
- Closes #12030
-
-Daniel Stenberg (23 Oct 2023)
-
-- http2: provide an error callback and failf the message
-
- Getting nghttp2's error message helps users understand what's going
- on. For example when the connection is brought down due a forbidden
- header is used - as that header is then not displayed by curl itself.
-
- Example:
-
- curl: (92) Invalid HTTP header field was received: frame type: 1,
- stream: 1, name: [upgrade], value: [h2,h2c]
-
- Ref: #12172
- Closes #12179
-
-Turiiya (23 Oct 2023)
-
-- BINDINGS: add V binding
-
- Closes #12182
-
-Daniel Stenberg (22 Oct 2023)
-
-- configure: check for the fseeko declaration too
-
- ... and make the code require both symbol and declaration.
-
- This is because for Android, the symbol is always present in the lib at
- build-time even when not actually available in run-time.
-
- Assisted-by: Viktor Szakats
- Reported-by: 12932 on github
- Fixes #12086
- Closes #12158
-
-Viktor Szakats (22 Oct 2023)
-
-- cmake: fix OpenSSL quic detection in quiche builds
-
- An orphan call to `CheckQuicSupportInOpenSSL()` remained after a recent
- update when checking QUIC for quiche. Move back QUIC detection to
- a function and fixup callers to use that. Also make sure that quiche
- gets QUIC from BoringSSL, because it doesn't support other forks at this
- time.
-
- Regression from dee310d54261f9a8416e87d50bccfe2cbe404949 #11555
-
- Reported-by: Casey Bodley <cbodley@redhat.com>
- Fixes #12160
- Closes #12162
-
-Daniel Stenberg (22 Oct 2023)
-
-- RELEASE-NOTES: synced
-
- bump to 8.5.0 for pending release
-
-Dan Fandrich (21 Oct 2023)
-
-- test3103: add missing quotes around a test tag attribute
-
-Loïc Yhuel (21 Oct 2023)
-
-- tool: fix --capath when proxy support is disabled
-
- After 95e8515ca0, --capath always sets CURLOPT_PROXY_CAPATH, which fails
- with CURLE_UNKNOWN_OPTION when proxy support is disabled.
-
- Closes #12089
-
-Daniel Stenberg (21 Oct 2023)
-
-- openldap: move the alloc of ldapconninfo to *connect()
-
- Fixes a minor memory leak on LDAP connection reuse.
-
- Doing the allocation already in *setup_connection() is wrong since that
- connect struct might get discarded early when an existing connection is
- reused instead.
-
- Closes #12166
-
-- openldap: set the callback argument in oldap_do
-
- ... to make sure it has the current 'data' pointer and not a stale old
- one.
-
- Reported-by: Dan Fandrich
- Closes #12166
-
-- gnutls: support CURLSSLOPT_NATIVE_CA
-
- Remove the CURL_CA_FALLBACK logic. That build option was added to allow
- primarily OpenSSL to use the default paths for loading the CA certs. For
- GnuTLS it was instead made to load the "system certs", which is
- different and not desirable.
-
- The native CA store loading is now asked for with this option.
-
- Follow-up to 7b55279d1d856
-
- Co-authored-by: Jay Satiro
-
- Closes #12137
-
-Stefan Eissing (21 Oct 2023)
-
-- RTSP: improved RTP parser
-
- - fix HTTP header parsing to report incomplete
- lines it buffers as consumed!
- - re-implement the RTP parser for interleave RTP
- messages for robustness. It is now keeping its
- state at the connection
- - RTSP protocol handler "readwrite" implementation
- now tracks if the response is before/in/after
- header parsing or "in" a bod by calling
- "Curl_http_readwrite_headers()" itself. This
- allows it to know when non-RTP bytes are "junk"
- or HEADER or BODY.
- - tested with #12035 and various small receive
- sizes where current master fails
-
- Closes #12052
-
-- http2: header conversion tightening
-
- - fold the code to convert dynhds to the nghttp2 structs
- into a dynhds internal method
- - saves code duplication
- - pacifies compiler analyzers
-
- Closes #12097
-
-Daniel Stenberg (21 Oct 2023)
-
-- curl_ntlm_wb: fix elif typo
-
- Reported-by: Manfred Schwarb
- Follow-up to d4314cdf65ae
- Bug: https://github.com/curl/curl/commit/d4314cdf65aee295db627016934bd9eb621a
- b077#r130551295
-
-Dan Fandrich (20 Oct 2023)
-
-- test1683: remove commented-out check alternatives
-
- Python precheck/postcheck alternatives were included but commented out.
- Since these are not used and perl is guaranteed to be available to run
- the perl versions anyway, the Python ones are removed.
-
-Daniel Stenberg (20 Oct 2023)
-
-- hostip: show the list of IPs when resolving is done
-
- Getting 'curl.se' today then gets this verbose output which might help
- debugging connectivity related matters.
-
- * Host curl.se:80 was resolved.
- * IPv6: 2a04:4e42::347, 2a04:4e42:200::347, 2a04:4e42:400::347,
- 2a04:4e42:600::347, 2a04:4e42:800::347, 2a04:4e42:a00::347,
- 2a04:4e42:c00::347, 2a04:4e42:e00::347
- * IPv4: 151.101.193.91, 151.101.1.91, 151.101.65.91, 151.101.129.91
-
- Co-authored-by: Jay Satiro
- Closes #12145
-
-rilysh (20 Oct 2023)
-
-- docs: fix function typo in curl_easy_option_next.3
-
- Closes #12170
-
-Daniel Stenberg (20 Oct 2023)
-
-- vssh: remove the #ifdef for Curl_ssh_init, use empty macro
-
- In the same style as other init calls
-
-- easy: remove duplicate wolfSSH init call
-
- It is already done in Curl_ssh_init() where it belongs.
-
- Closes #12168
-
-- socks: make SOCKS5 use the CURLOPT_IPRESOLVE choice
-
- Fixes #11949
- Reported-by: Ammar Faizi
- Closes #12163
-
-- urldata: move the 'internal' boolean to the state struct
-
- ... where all the other state bits for the easy handles live.
-
- Closes #12165
-
-- url: don't touch the multi handle when closing internal handles
-
- Reported-by: Maksymilian Arciemowicz
- Closes #12165
-
-Faraz Fallahi (19 Oct 2023)
-
-- getenv: PlayStation doesn't have getenv()
-
- Closes #12140
-
-Daniel Stenberg (19 Oct 2023)
-
-- transfer: only reset the FTP wildcard engine in CLEAR state
-
- To avoid the state machine to start over and redownload all the files
- *again*.
-
- Reported-by: lkordos on github
- Regression from 843b3baa3e3cb228 (shipped in 8.1.0)
- Bisect-by: Dan Fandrich
- Fixes #11775
- Closes #12156
-
-Stefan Eissing (19 Oct 2023)
-
-- GHA: move mod_h2 version in CI to v2.0.25
-
- Closes #12157
-
-Daniel Stenberg (19 Oct 2023)
-
-- ntlm_wb: use pipe instead of socketpair when possible
-
- Closes #12149
-
-- RELEASE-NOTES: synced
-
-- asyn-thread: use pipe instead of socketpair for IPC when available
-
- If pipe() is present. Less overhead.
-
- Helped-by: Viktor Szakats
- Closes #12146
-
-Dan Fandrich (17 Oct 2023)
-
-- tests: Fix Windows test helper tool search & use it for handle64
-
- The checkcmd() and checktestcmd() functions would not have worked on
- Windows due to hard-coding the UNIX PATH separator character and not
- adding .exe file extension. This meant that tools like stunnel, valgrind
- and nghttpx would not have been found and used on Windows, and
- inspection of previous test runs show none of those being found in pure
- Windows CI builds.
-
- With this fixed, they can be used to detect the handle64.exe program
- before attempting to use it. When handle64.exe was called
- unconditionally without it existing, it caused perl to abort the test
- run with the error
-
- The running command stopped because the preference variable
- "ErrorActionPreference" or common parameter is set to Stop:
- sh: handle64.exe: command not found
-
- Closes #12115
-
-Daniel Stenberg (17 Oct 2023)
-
-- multi: use pipe instead of socketpair to *wakeup()
-
- If pipe() is present. Less overhead.
-
- Closes #12142
-
-Jay Satiro (17 Oct 2023)
-
-- build: fix 'threadsafe' feature detection for older gcc
-
- - Add 'threadsafe' to the feature list shown during build if POSIX
- threads are being used.
-
- This is a follow-up to 5adb6000 which added support for building a
- thread-safe libcurl with older versions of gcc where atomic is not
- available but pthread is.
-
- Reported-by: Dan Fandrich
- Co-authored-by: Dan Fandrich
-
- Fixes https://github.com/curl/curl/issues/12125
- Closes https://github.com/curl/curl/pull/12127
-
-Daniel Stenberg (16 Oct 2023)
-
-- test729: verify socks4a with excessive proxy user name length
-
-- socks: better buffer size checks for socks4a user and hostname
-
- Also limit the proxy user name to 255 bytes, which is the same limit as
- in SOCKS5.
-
- Reported-by: sd0 on hackerone
- Closes #12139
-
-- curl.h: on FreeBSD include sys/param.h instead of osreldate.h
-
- Should things build on Playstation as well
-
- Fixes #12107
- Reported-by: Faraz Fallahi
- Closes #12123
-
-Marcin Rataj (16 Oct 2023)
-
-- tool_operate: fix links in ipfs errors
-
- URL fragment links generated from headers in
- https://curl.se/docs/ipfs.html are lowercase.
-
- Closes #12133
-
-Viktor Szakats (15 Oct 2023)
-
-- cmake: replace `check_library_exists_concat()`
-
- The idea of `check_library_exists_concat()` is that it detects an
- optional component and adds it to the list of libs that we also use in
- subsequent component checks. This caused problems when detecting
- components with unnecessary dependencies that were not yet built.
-
- CMake offers the `CMAKE_REQUIRED_LIBRARIES` variable to set libs used
- for component checks, which we already use in most cases. That left 4
- uses of `check_library_exists_concat()`. Only one of these actually
- needed the 'concat' feature (ldap/lber).
-
- Delete this function and replace it with standard
- `check_library_exists()` and manual management of our `CURL_LIBS`
- list we use when linking build targets. And special logic to handle the
- ldap/lber case.
-
- (We have a similar function for headers: `check_include_file_concat()`.
- It works, but problematic for performance reasons and because it hides
- the actual headers required in `check_symbol_exists()` calls.)
-
- Ref: #11537 #11558
- Fixes #11285
- Fixes #11648
- Closes #12070
-
-LoRd_MuldeR (15 Oct 2023)
-
-- tool_cb_wrt: fix write output for very old Windows versions
-
- - Pass missing parameter for 'lpNumberOfCharsWritten' to WriteConsoleW()
- function.
-
- Apparently this parameter was *not* optional on older Windows versions.
-
- Issue observed on Windows XP SP2. Issue not observed on Windows 7 SP1.
- So at some point between those two Microsoft changed the behavior.
-
- Prior to this change, on those versions if parameter is NULL then the
- function call fails with error ERROR_INVALID_ACCESS.
-
- Regression since af3f4e41.
-
- Ref: https://github.com/MicrosoftDocs/Console-Docs/issues/299
-
- Fixes https://github.com/curl/curl/issues/12131
- Closes https://github.com/curl/curl/pull/12130
-
-Jay Satiro (15 Oct 2023)
-
-- tool_urlglob: fix build for old gcc versions
-
- - Don't use __builtin_mul_overflow for GCC 4 and earlier.
-
- The function was added in GCC 5.
-
- Ref: https://gcc.gnu.org/gcc-5/changes.html
-
- Reported-by: Dan Fandrich
-
- Fixes https://github.com/curl/curl/issues/12124
- Closes https://github.com/curl/curl/pull/12128
-
-Carlos Henrique Lima Melara (14 Oct 2023)
-
-- docs/libcurl: fix three minor man page format mistakes
-
- Reported-by: Samuel Henrique
-
- Closes https://github.com/curl/curl/pull/12126
-
-Jay Satiro (14 Oct 2023)
-
-- tests/server: add more SOCKS5 handshake error checking
-
- - Add additional checking for missing and too-short SOCKS5 handshake
- messages.
-
- Prior to this change the SOCKS5 test server did not check that all parts
- of the handshake were received successfully. If those parts were missing
- or too short then the server would access uninitialized memory.
-
- This issue was discovered in CI job 'memory-sanitizer' test results.
- Test 2055 was failing due to the SOCKS5 test server not running. It was
- not running because either it crashed or memory sanitizer aborted it
- during Test 728. Test 728 connects to the SOCKS5 test server on a
- redirect but does not send any data on purpose. The test server was not
- prepared for that.
-
- Reported-by: Dan Fandrich
-
- Fixes https://github.com/curl/curl/issues/12117
- Closes https://github.com/curl/curl/pull/12118
-
-Daniel Stenberg (14 Oct 2023)
-
-- RELEASE-NOTES: synced
-
-Sohom Datta (14 Oct 2023)
-
-- tool_getparam: limit --rate to be smaller than number of ms
-
- Currently, curl allows users to specify absurd request rates that might
- be higher than the number of milliseconds in the unit (ex: curl --rate
- 3600050/h http://localhost:8080 does not error out despite there being
- only 3600000ms in a hour).
-
- This change adds a conditional check before the millisecond calculation
- making sure that the number is not higher than the numerator (the unit)
- If the number is higher, curl errors out with PARAM_NUMBER_TOO_LARGE
-
- Closes #12116
-
-Daniel Stenberg (14 Oct 2023)
-
-- opts: fix two minor man page format mistakes
-
-Jay Satiro (14 Oct 2023)
-
-- curl_trc: remove a bad assertion
-
- - Remove DEBUGASSERT that an internal handle must not have user
- private_data set before calling the user's debug callback.
-
- This is a follow-up to 0dc40b2a. The user can distinguish their easy
- handle from an internal easy handle by setting CURLOPT_PRIVATE on their
- easy handle. I had wrongly assumed that meant the user couldn't then
- set CURLOPT_PRIVATE on an internal handle as well.
-
- Bug: https://github.com/curl/curl/pull/12060#issuecomment-1754594697
- Reported-by: Daniel Stenberg
-
- Closes https://github.com/curl/curl/pull/12104
-
-Dan Fandrich (13 Oct 2023)
-
-- test613: stop showing an error on missing output file
-
- This test would show an error message if the output was missing during
- the log post-processing step, but the message was not captured by the
- test harness and wasn't useful since the normal golden log file
- comparison would the problem more clearly.
-
-Stefan Eissing (13 Oct 2023)
-
-- quic: manage connection idle timeouts
-
- - configure a 120s idle timeout on our side of the connection
- - track the timestamp when actual socket IO happens
- - check IO timestamp to our *and* the peer's idle timeouts
- in "is this connection alive" checks
-
- Reported-by: calvin2021y on github
- Fixes #12064
- Closes #12077
-
-Dan Fandrich (13 Oct 2023)
-
-- CI: ignore test 286 on Appveyor gcc 9 build
-
- This test fails sometimes with a super fast retry loop due to what may
- just be a compiler bug. The test results are ignored on the one CI job
- where it occurs because there seems to be nothing we can do to fix it.
-
- Fixes #12040
- Closes #12106
-
-Viktor Szakats (13 Oct 2023)
-
-- lib: fix gcc warning in printf call
-
- Do not pass NULL to printf %s.
-
- Seen with gcc 13.2.0 on Debian:
- ```
- .../curl/lib/connect.c:696:27: warning: '%s' directive argument is null [-Wfo
- rmat-overflow=]
- ```
- Ref: https://github.com/curl/curl-for-win/actions/runs/6476161689/job/1758442
- 6483#step:3:11104
-
- Ref: #10284
- Co-authored-by: Jay Satiro
- Closes #12082
-
-Alex Klyubin (13 Oct 2023)
-
-- http2: safer invocation of populate_binsettings
-
- populate_binsettings now returns a negative value on error, instead of a
- huge positive value. Both places which call this function have been
- updated to handle this change in its contract.
-
- The way populate_binsettings had been used prior to this change the huge
- positive values -- due to signed->unsigned conversion of the potentially
- negative result of nghttp2_pack_settings_payload which returns negative
- values on error -- are not possible. But only because http2.c currently
- always provides a large enough output buffer and provides H2 SETTINGS
- IVs which pass the verification logic inside nghttp2. If the
- verification logic were to change or if http2.c started passing in more
- IVs without increasing the output buffer size, the overflow could become
- reachable, and libcurl/curl might start leaking memory contents to
- servers/proxies...
-
- Closes #12101
-
-Daniel Stenberg (13 Oct 2023)
-
-- openssl: avoid BN_num_bits() NULL pointer derefs
-
- Reported-by: icy17 on github
- Fixes #12099
- Closes #12100
-
-- wolfssl: require WOLFSSL_SYS_CA_CERTS for loading system CA
-
- This define is set in wolfssl's options.h file when this function and
- feature is present. Handles both builds with the feature explicitly
- disabled and wolfSSL versions before 5.5.2 - which introduced this API
- call.
-
- Closes #12108
-
-- tool_urlglob: make multiply() bail out on negative values
-
- - Does not work correctly with negative values
- - use __builtin_mul_overflow() on gcc
-
- Reported-by: Torben Dury
- Closes #12102
-
-Loïc Yhuel (13 Oct 2023)
-
-- cmake: fix CURL_DISABLE_GETOPTIONS
-
- - Add CURL_DISABLE_GETOPTIONS to curl_config.h.cmake.
-
- Prior to this change the option had no effect because it was missing
- from that file.
-
- Closes https://github.com/curl/curl/pull/12091
-
-- easy_lock: add a pthread_mutex_t fallback
-
- This allows to keep the init threadsafe with gcc < 4.9.0 (no C11
- atomics).
-
- Closes https://github.com/curl/curl/pull/12090
-
-Viktor Szakats (12 Oct 2023)
-
-- CI: add autotools, out-of-tree, debug build to distro check job
-
- Add a job that builds curl from a generated source tarball sample, with
- autotools, out-of-tree, in debug mode.
-
- Ref: #12085
- Closes #12088
-
-Daniel Stenberg (12 Oct 2023)
-
-- http: avoid Expect: 100-continue if Upgrade: is used
-
- Reported-by: Daniel Jelinski
- Fixes #12022
- Closes #12062
-
-Jan Alexander Steffens (heftig) (12 Oct 2023)
-
-- docs: use SOURCE_DATE_EPOCH for generated manpages
-
- This should make builds from Git reproducible.
-
- Closes #12092
-
-Daniel Stenberg (12 Oct 2023)
-
-- RELEASE-NOTES: synced
-
- Bumped to 8.4.1
-
-Viktor Szakats (12 Oct 2023)
-
-- cmake: fix `HAVE_H_ERRNO_ASSIGNABLE` detection
-
- Fix `HAVE_H_ERRNO_ASSIGNABLE` to not run, only compile its test snippet,
- aligning this with autotools. This fixes an error when doing
- cross-builds and also actually detects this feature. It affected systems
- not allowlisted into this, e.g. SerenityOS.
-
- We used this detection result to enable `HAVE_GETADDRINFO_THREADSAFE`.
-
- Follow-up to 04a3a377d83fd72c4cf7a96c9cb6d44785e33264 #11979
- Ref: #12095 (closed in favour of this patch)
- Ref: #11964 (effort to sync cmake detections with autotools)
-
- Reported-by: Kartatz on Github
- Assisted-by: Kartatz on Github
- Fixes #12093
- Closes #12094
-
-- build: add `src/.checksrc` to source tarball
-
- Regression from e5bb88b8f824ed87620bd923552534c83c2a516e #11958
-
- Bug: https://github.com/curl/curl/pull/11958#issuecomment-1757079071
- Reported-by: Romain Geissler
- Fixes #12084
- Closes #12085
-
-Version 8.4.0 (11 Oct 2023)
-
-Daniel Stenberg (11 Oct 2023)
-
-- RELEASE-NOTES: synced
-
-- THANKS: add contributors from 8.4.0
-
-Jay Satiro (11 Oct 2023)
-
-- socks: return error if hostname too long for remote resolve
-
- Prior to this change the state machine attempted to change the remote
- resolve to a local resolve if the hostname was longer than 255
- characters. Unfortunately that did not work as intended and caused a
- security issue.
-
- Bug: https://curl.se/docs/CVE-2023-38545.html
-
-Stefan Eissing (10 Oct 2023)
-
-- CI: remove slowed-network tests
-
- - remove these tests as they are currently not reliable in our CI
- setups.
-
- curl handles the test cases, but CI sometimes fails on these due to
- additional conditions. Rather than mix them in, an additional CI job
- will be added in the future that is specific to them.
-
- Closes https://github.com/curl/curl/pull/12075
-
-Jay Satiro (10 Oct 2023)
-
-- libcurl-env-dbg.3: move debug variables from libcurl-env.3
-
- - Move documentation of libcurl environment variables used only in debug
- builds from libcurl-env into a separate document libcurl-env-dbg.
-
- - Document more debug environment variables.
-
- Previously undocumented or missing a description:
-
- CURL_ALTSVC_HTTP, CURL_DBG_SOCK_WBLOCK, CURL_DBG_SOCK_WPARTIAL,
- CURL_DBG_QUIC_WBLOCK, CURL_DEBUG, CURL_DEBUG_SIZE, CURL_GETHOSTNAME,
- CURL_HSTS_HTTP, CURL_FORCETIME, CURL_SMALLREQSEND, CURL_SMALLSENDS,
- CURL_TIME.
-
- Closes https://github.com/curl/curl/pull/11811
-
-Dan Fandrich (9 Oct 2023)
-
-- test670: increase the test timeout
-
- This should make it more immune to loaded servers.
-
- Ref: #11328
-
-Stefan Eissing (9 Oct 2023)
-
-- MQTT: improve receive of ACKs
-
- - add `mq->recvbuf` to provide buffering of incomplete
- ACK responses
- - continue ACK reading until sufficient bytes available
- - fixes test failures on low network receives
-
- Closes #12071
-
-Viktor Szakats (9 Oct 2023)
-
-- quic: fix BoringSSL build
-
- Add guard around `SSL_CTX_set_ciphersuites()` use.
-
- Bug: https://github.com/curl/curl/pull/12065#issuecomment-1752171885
-
- Follow-up to aa9a6a177017e4b74d33cdf85a3594900f4a7f81
-
- Co-authored-by: Jay Satiro
- Reviewed-by: Daniel Stenberg
- Closes #12067
-
-Stefan Eissing (9 Oct 2023)
-
-- test1540: improve reliability
-
- - print that bytes have been received on pausing, but not how many
-
- Closes #12069
-
-- test2302: improve reliability
-
- - make result print collected write data, unless
- change in meta flags is detected
- - will show same result even when data arrives via
- several writecb invocations
-
- Closes #12068
-
-Daniel Stenberg (9 Oct 2023)
-
-- curl_easy_pause: set "in callback" true on exit if true
-
- Because it might have called another callback in the mean time that then
- set the bit FALSE on exit.
-
- Reported-by: Jay Satiro
- Fixes #12059
- Closes #12061
-
-Viktor Szakats (8 Oct 2023)
-
-- h3: add support for ngtcp2 with AWS-LC builds
-
- ```
- curl 8.4.0-DEV (x86_64-apple-darwin) libcurl/8.4.0-DEV (SecureTransport) AWS-
- LC/1.15.0 nghttp2/1.56.0 ngtcp2/0.19.1 nghttp3/0.15.0
- Release-Date: [unreleased]
- Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps
- mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss
- Features: alt-svc AsynchDNS HSTS HTTP2 HTTP3 HTTPS-proxy IPv6 Largefile Multi
- SSL NTLM SSL threadsafe UnixSockets
- ```
-
- Also delete an obsolete GnuTLS TODO and update the header comment in
- `FindNGTCP2.cmake`.
-
- Reviewed-by: Daniel Stenberg
- Closes #12066
-
-- build: do not publish `HAVE_BORINGSSL`, `HAVE_AWSLC` macros
-
- Syncing this up with CMake.
-
- Source code uses the built-in `OPENSSL_IS_AWSLC` and
- `OPENSSL_IS_BORINSSL` macros to detect BoringSSL and AWS-LC. No help is
- necessary from the build tools.
-
- The one use of `HAVE_BORINGSSL` in the source turned out to be no longer
- necessary for warning-free BoringSSL + Schannel builds. Ref: #1610 #2634
-
- autotools detects this anyway for display purposes.
- CMake detects this to decide whether to use the BoringSSL-specific
- crypto lib with ngtcp2. It detects AWS-LC, but doesn't use the detection
- result just yet (planned in #12066).
-
- Ref: #11964
-
- Reviewed-by: Daniel Stenberg
- Reviewed-by: Jay Satiro
- Closes #12065
-
-Marc Hoersken (8 Oct 2023)
-
-- CI: move distcheck job from Azure Pipelines to GitHub Actions
-
- This will allow for more trigger excludes within Azure Pipelines.
-
- Also fixes seemingly broken check with scripts/installcheck.sh.
- Ref: 190374c74ec4e5247d9066544c86e8d095e1d7b5
-
- Assisted-by: Philip Heiduck
- Closes #9532
-
-Daniel Stenberg (8 Oct 2023)
-
-- url: fall back to http/https proxy env-variable if ws/wss not set
-
- Reported-by: Craig Andrews
- Fixes #12031
- Closes #12058
-
-Stefan Eissing (8 Oct 2023)
-
-- cf-socket: simulate slow/blocked receives in debug
-
- add 2 env variables for non-UDP sockets:
- 1. CURL_DBG_SOCK_RBLOCK: percentage of receive calls that randomly
- should return EAGAIN
- 2. CURL_DBG_SOCK_RMAX: max amount of bytes read from socket
-
- Closes #12035
-
-- http2: refused stream handling for retry
-
- - answer HTTP/2 streams refused via a GOAWAY from the server to
- respond with CURLE_RECV_ERROR in order to trigger a retry
- on another connection
-
- Reported-by: black-desk on github
- Ref #11859
- Closes #12054
-
-Jay Satiro (8 Oct 2023)
-
-- CURLOPT_DEBUGFUNCTION.3: warn about internal handles
-
- - Warn that the user's debug callback may be called with the handle
- parameter set to an internal handle.
-
- Without this warning the user may assume that the only handles their
- debug callback receives are the easy handles on which they set
- CURLOPT_DEBUGFUNCTION.
-
- This is a follow-up to f8cee8cc which changed DoH handles to inherit
- the debug callback function set in the user's easy handle. As a result
- those handles are now passed to the user's debug callback function.
-
- Closes https://github.com/curl/curl/pull/12034
-
-- url: fix typo
-
-Daniel Stenberg (8 Oct 2023)
-
-- test458: verify --expand-output, expanding a file name accepting option
-
- Verifies the fix in #12055 (commit f2c8086ff15e6e995e1)
-
-- tool_getparam: accept variable expansion on file names too
-
- Reported-by: PBudmark on github
- Fixes #12048
- Closes #12055
-
-- RELEASE-NOTES: synced
-
-- multi: do CURLM_CALL_MULTI_PERFORM at two more places
-
- ... when it does a state transition but there is no particular socket or
- timer activity. This was made apparent when commit b5bb84c removed a
- superfluous timer expiry.
-
- Reported-by: Dan Fandrich.
- Fixes #12033
- Closes #12056
-
-Viktor Szakats (7 Oct 2023)
-
-- GHA/linux: mbedtls 3.5.0 + minor dep bumps
-
- Closes #12057
-
-Dan Fandrich (7 Oct 2023)
-
-- CI: bump OpenLDAP package version on FreeBSD
-
- The old one is no longer available.
-
-Marc Hoersken (7 Oct 2023)
-
-- docs/libcurl/opts/Makefile.inc: add missing manpage files
-
- Detected with #9532
-
-Dan Fandrich (7 Oct 2023)
-
-- tests: fix a race condition in ftp server disconnect
-
- If a client disconnected and reconnected quickly, before the ftp server
- had a chance to respond, the protocol message/ack (ping/pong) sequence
- got out of sync, causing messages sent to the old client to be delivered
- to the new. A disconnect must now be acknowledged and intermediate
- requests thrown out until it is, which ensures that such synchronization
- problems can't occur. This problem could affect ftp, pop3, imap and smtp
- tests.
-
- Fixes #12002
- Closes #12049
-
-Viktor Szakats (7 Oct 2023)
-
-- appveyor: bump mingw-w64 job to gcc 13 (was: 8)
-
- This sets gcc 6, 7, 9, 13 in our test mix (was: 6, 7, 8, 9).
- Adding a modern gcc version to the tests.
-
- (The gcc 8 job used to take around 50 minutes. The new image with gcc 13
- finished in 32, 35, 34 minutes in the 3 test runs so far.)
-
- It also adds a modern CMake version and OS env to our mingw-w64 builds.
-
- Closes #12051
-
-David Benjamin (6 Oct 2023)
-
-- openssl: use X509_ALGOR_get0 instead of reaching into X509_ALGOR
-
- While the struct is still public in OpenSSL, there is a (somewhat
- inconvenient) accessor. Use it to remain compatible if it becomes opaque
- in the future.
-
- Closes #12038
-
-Daniel Stenberg (6 Oct 2023)
-
-- curl_easy_pause.3: mention it works within callbacks
-
- Reported-by: Maxim Dzhura
- Bug: https://curl.se/mail/lib-2023-10/0010.html
- Closes #12046
-
-- curl_easy_pause.3: mention h2/h3 buffering
-
- Asked-by: Maxim Dzhura
- Ref: https://curl.se/mail/lib-2023-10/0011.html
-
- Closes #12045
-
-Viktor Szakats (6 Oct 2023)
-
-- cmake: re-add missed C89 headers for specific detections
-
- We removed C89 `setjmp.h` and `signal.h` detections and excluded them
- from the global header list we use when detecting functions [1]. Then
- missed to re-add these headers to the specific functions which need
- them to be detected [2]. Fix this omission in this patch.
-
- [1] Follow-up to 3795fcde995d96db641ddbcc8a04f9f0f03bef9f #11951
- [2] Follow-up to 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940
-
- Closes #12043
-
-Daniel Stenberg (6 Oct 2023)
-
-- multi: set CURLM_CALL_MULTI_PERFORM after switch to DOING_MORE
-
- Since there is nothing to wait for there. Avoids the test 1233 hang
- reported in #12033.
-
- Reported-by: Dan Fandrich
- Closes #12042
-
-Dan Fandrich (5 Oct 2023)
-
-- test1903: actually verify the cookies after the test
-
- The test otherwise could do just about anything (except leak memory in
- debug mode) and its bad behaviour wouldn't be detected. Now, check the
- resulting cookie file to ensure the cookies are still there.
-
- Closes #12041
-
-- test: add missing <feature>s
-
- The tests will otherwise fail if curl has them disabled.
-
-- test1906: set a lower timeout since it's hit on Windows
-
- msys2 builds actually hit the connect timeout in normal operation, so
- lower the timeout from 5 minutes to 5 seconds to reduce test time.
-
- Ref: #11328
- Closes #12036
-
-Daniel Stenberg (5 Oct 2023)
-
-- RELEASE-NOTES: synced
-
-Jay Satiro (5 Oct 2023)
-
-- idn: fix WinIDN null ptr deref on bad host
-
- - Return CURLE_URL_MALFORMAT if IDN hostname cannot be converted from
- UTF-8 to UTF-16.
-
- Prior to this change a failed conversion erroneously returned CURLE_OK
- which meant 'decoded' pointer (what would normally point to the
- punycode) would not be written to, remain NULL and be dereferenced
- causing an access violation.
-
- Closes https://github.com/curl/curl/pull/11983
-
-Dan Fandrich (4 Oct 2023)
-
-- tests: close the shell used to start sshd
-
- This shell isn't needed once sshd starts, so use "exec" so it doesn't
- stick around.
-
- Closes #12032
-
-Daniel Stenberg (4 Oct 2023)
-
-- base64: also build for curl
-
- Since the tool itself now uses the base64 code using the curlx way, it
- needs to build also when the tool needs it. Starting now, the tool build
- defines BULDING_CURL to allow lib-side code to use it.
-
- Follow-up to 2e160c9c6525
-
- Closes #12010
-
-Eduard Strehlau (4 Oct 2023)
-
-- tests: Fix zombie processes left behind by FTP tests.
-
- ftpserver.pl correctly cleans up spawned server processes,
- but forgets to wait for the shell used to spawn them.
- This is barely noticeable during a normal testrun,
- but causes process exhaustion and test failure
- during a complete torture run of the FTP tests.
-
- Fixes #12018
- Closes #12020
-
-Dan Fandrich (4 Oct 2023)
-
-- github/labeler: improve labeler matches
-
-- test574: add a timeout to the test
-
- This one hangs occasionally, so this will speed up a test run and allow
- logs to be seen when it does.
-
- Closes #12025
-
-- tests: propagate errors in libtests
-
- Use the test macros to automatically propagate some errors, and check
- and log others while running the tests. This can help in debugging
- exactly why a test has failed.
-
-- tests: set --expect100-timeout to improve test reliability
-
- On an overloaded server, the default 1 second timeout can go by without
- the test server having a chance to respond with the expected headers,
- causing tests to fail. Increase the 1 second timeout to 99 seconds so
- this failure mode is no longer a problem on test 1129. Some other tests
- already set a high value, but make them consistently 99 seconds so if
- something goes wrong the test is stalled for less time.
-
- Ref: #11328
-
-- CI: ignore the "flaky" and "timing-dependent" test results in CMake
-
- This was already done for automake builds but CMake builds were missed.
- Test 1086 actually causes the test harness to crash with:
-
- Warning: unable to close filehandle DWRITE properly: Broken pipe at C:/projec
- ts/curl/tests/ftpserver.pl line 527
-
- Rather than fix it now, this change leaves test 1086 entirely skipped on
- those builds that show this problem.
-
- Follow-up to 589dca761
-
- Ref: #11865
-
-Viktor Szakats (4 Oct 2023)
-
-- cmake: improve OpenLDAP builds
-
- - cmake: detect OpenLDAP based on function `ldap_init_fd`.
- autotools does this. autotools also publishes this detection result
- in `HAVE_LDAP_INIT_FD`. We don't mimic that with CMake as the source
- doesn't use this value. (it might need to be remove-listed in
- `scripts/cmp-config.pl` for future OpenLDAP test builds.)
- This also deletes existing self-declaration method via the
- CMake-specific `CURL_USE_OPENLDAP` configuration.
-
- - cmake: define `LDAP_DEPRECATED=1` for OpenLDAP.
- Like autotools does. This fixes a long list of these warnings:
- ```
- /usr/local/opt/openldap/include/ldap.h:1049:5: warning: 'LDAP_DEPRECATED' i
- s not defined, evaluates to 0 [-Wundef]
- ```
-
- - cmake: delete LDAP TODO comment no longer relevant.
-
- Also:
-
- - autotools: replace domain name `dummy` with `0.0.0.0` in LDAP feature
- detection functions.
-
- Ref: #11964 (effort to sync cmake detections with autotools)
-
- Closes #12024
-
-- cmake: fix unity builds for more build combinations
-
- By using unique static function/variable names in source files
- implementing these interfaces.
-
- - OpenLDAP combined with any SSH backend.
-
- - MultiSSL with mbedTLS, OpenSSL, wolfSSL, SecureTransport.
-
- Closes #12027
-
-Daniel Stenberg (4 Oct 2023)
-
-- tests: remove leading spaces from some tags
-
- The threee tags `<name>`, `</name>` and `<command>` were frequently used
- with a leading space that this removes. The reason this habbit is so
- widespread in testcases is probably that they have been copy and pasted.
-
- Hence, fixing them all now might curb this practice from now on.
-
- Closes #12028
-
-Viktor Szakats (4 Oct 2023)
-
-- GHA: bump actions/checkout
-
- Follow-up to 2e0fa50fc16b9339f51e0a7bfff0352829323acb #11964
- Follow-up to c39585d9b7ef3cbfc1380812dec60e7b275b6af3 #12000
-
- Closes #12023
-
-- spelling: fix codespell 2.2.6 typos
-
- Closes #12019
-
-Daniel Stenberg (3 Oct 2023)
-
-- GHA: add workflow to compare configure vs cmake outputs
-
- Uses scripts/cmp-config.pl two compare two curl_config.h files,
- presumbly generated with configure and cmake. It displays the
- differences and filters out a lot of known lines we ignore.
-
- The script also shows the matches that were *not* used. Possibly
- subjects for removal.
-
- Closes #11964
-
-- appveyor: enable test 571
-
- Follow-up from 8a940fd55c175f7 / #12013
-
- Closes #12017
-
-Viktor Szakats (3 Oct 2023)
-
-- build: alpha-sort source files for lib and src
-
- Closes #12014
-
-- cmake: delete old `HAVE_LDAP_URL_PARSE` logic
-
- Left there by accident after adding proper detection for this.
-
- Follow-up to 772f0d8edf1c3c2745543f42388ccec5a16ee2c0 #12006
-
- Ref: #11964 (effort to sync cmake detections with autotools)
-
- Closes #12015
-
-Stefan Eissing (3 Oct 2023)
-
-- tests: increase lib571 timeout from 3s to 30s
-
- - 3s is too short for our CI, making this test fail occasionally
- - test usually experiences no delay run locally, so 30s wont hurt
-
- Closes #12013
-
-Viktor Szakats (3 Oct 2023)
-
-- cmake: fix unity with Windows Unicode + TrackMemory
-
- Found the root cause of the startup crash in unity builds with Unicode
- and TrackMemory enabled at the same time.
-
- We must make sure that the `memdebug.h` header doesn't apply to
- `lib/curl_multibyte.c` (as even noted in a comment there.) In unity
- builds all headers apply to all sources, including `curl_multibyte.c`.
- This probably resulted in an infinite loop on startup.
-
- Exclude this source from unity compilation with TrackMemory enabled,
- in both libcurl and curl tool. Enable unity mode for a debug Unicode
- CI job to keep it tested. Also delete the earlier workaround that
- fully disabled unity for affected builds.
-
- Follow-up to d82b080f6374433ce7c98241329189ad2d3976f8 #12005
- Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 #11095
-
- Closes #11928
-
-- cmake: disable unity mode with Windows Unicode + TrackMemory
-
- "TrackMemory" is `ENABLE_DEBUG=ON` (aka `ENABLE_CURLDEBUG=ON`,
- aka `-DCURLDEBUG`).
-
- There is an issue with memory tracking and Unicode when built in "unity"
- mode, which results in the curl tool crashing right on startup, even
- without any command-line option. Interestingly this doesn't happen under
- WINE (at least on the system I tested this on), but consistenly happens
- on real Windows machines. Crash is 0xC0000374 heap corruption. Both
- shared and static curl executables are affected.
-
- This limitation probably won't hit too many people, but it remains
- a TODO to find and fix the root cause and drop this workaround.
-
- Example builds and runs:
- https://ci.appveyor.com/project/curlorg/curl/builds/48169111/job/17cptxhtpubd
- 7iwj#L313 (static)
- https://ci.appveyor.com/project/curlorg/curl/builds/48169111/job/76e1ge758tby
- qu9c#L317 (shared)
-
- Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 #11095
-
- Ref: #11928
- Closes #12005
-
-- cmake: tidy-up `NOT_NEED_LBER_H` detection
-
- Follow-up to 772f0d8edf1c3c2745543f42388ccec5a16ee2c0 #12006
-
-- appveyor: rewrite batch in PowerShell + CI improvements
-
- 1. Rewrite in PowerShell:
-
- - rewrite MS-DOS batch build script in PowerShell.
- - move some bash operations into native PowerShell.
- - fixups for PowerShell insisting on failure when a command outputs
- something to stderr.
- - fix to actually run `curl -V` after every build.
- (and exclude ARM64 builds.)
- - also say why we skipped `curl -V` if we had to skip.
- - fix CMake warnings about unused configuration variables, by adapting
- these dynamically for build cases.
- - dedupe OpenSSL path into a variable.
- - disable `test1451` failing with a warning anyway due to missing python
- impacket. (after trying and failing to install impacket)
- PowerShell promotes these warnings to errors by PowerShell. We can also
- suppress they wholesale if they start causing issues in the future,
- like we already to with `autoreconf` and `./configure`.
-
- PowerShell is better than MS-DOS batches, so the hope is this makes it
- easier to extend and maintain the AppVeyor build logic. POSIX/bash isn't
- supported inline by AppVeyor on Windows build machines, but we are okay
- to keep it in an external script, so it's also an option.
-
- 2. CI improvements:
-
- - enable tests for a "unity" build job.
- - speed-up CI initialization by using shallow clones of the curl repo.
- - speed-up CMake MSVC jobs with `TrackFileAccess=false`.
- - enable parallelism in `VisualStudioSolution` builds.
- - display CMake version before builds.
- - always show the CPU in job names.
- - tell which jobs are build-only in job names.
- - move `TESTING:` value next to `DISABLED_TESTS:` in two jobs.
- - add `config.log` (autotools) to dumped logs (need to enable manually).
-
- 3. Style:
-
- - use single-quotes in YAML like we do in other CI YAML files.
- It also allows to drop quoting characters and lighter to write/read.
- (keep double quotes for PowerShell strings needing expansion.)
-
- Closes #11999
-
-- cmake: fix `HAVE_LDAP_SSL`, `HAVE_LDAP_URL_PARSE` on non-Windows
-
- - set `HAVE_LDAP_URL_PARSE` if `ldap_url_parse` function exists.
- Before this patch we set it based it on the presence of `stricmp`,
- which correctly enabled it on e.g. Windows, but was inaccurate for
- other platforms.
-
- - always set `HAVE_LDAP_SSL` if an LDAP backend is detected and
- LDAPS is not explicitly disabled. This mimics autotools behaviour.
- Previously we set it only for Windows LDAP. After this fix, LDAPS is
- correctly enabled in default macOS builds.
-
- - enable LDAP[S] for a CMake macOS CI job. Target OS X 10.9 (Mavericks)
- to avoid deprecation warnings for LDAP API.
-
- - always detect `HAVE_LDAP_SSL_H`, even with LDAPS explicitly disabled.
- This doesn't make much sense, but let's do it to sync behaviour with
- autotools.
-
- - fix benign typo in variable name.
-
- Ref: #11964 (effort to sync cmake detections with autotools)
-
- Closes #12006
-
-- autotools: restore `HAVE_IOCTL_*` detections
-
- This restores `CURL_CHECK_FUNC_IOCTL` detection. I deleted it in
- 4d73854462f30948acab12984b611e9e33ee41e6 and
- c3456652a0c72d1845d08df9769667db7e159949 (2022-08), because the
- `HAVE_IOCTL` result it generated was unused in the source. But,
- I did miss the fact that this had two dependent checks:
- `CURL_CHECK_FUNC_IOCTL_FIONBIO`,
- `CURL_CHECK_FUNC_IOCTL_SIOCGIFADDR` that we do actually need:
- `HAVE_IOCTL_FIONBIO`, `HAVE_IOCTL_SIOCGIFADDR`.
-
- Regression from 4d73854462f30948acab12984b611e9e33ee41e6
-
- Ref: #11964 (effort to sync cmake detections with autotools)
-
- Closes #12008
-
-Daniel Stenberg (2 Oct 2023)
-
-- RELEASE-PROCEDURE.md: updated coming release dates
-
-- RELEASE-NOTES: synced
-
-Viktor Szakats (1 Oct 2023)
-
-- cmake: pre-cache `HAVE_POLL_FINE` on Windows
-
- Windows doesn't support `poll()`, so we can safely skip checking for
- fine poll.
-
- Closes #12003
-
-- gha: bump actions to latest versions
-
- - actions@checkout@v4 (from v3 and v2)
-
- - fsfe/reuse-action@v2 (from v1)
-
- Closes #12000
-
-Stefan Eissing (30 Sep 2023)
-
-- h2: testcase and fix for pausing h2 streams
-
- - refs #11982 where it was noted that paused transfers may
- close successfully without delivering the complete data
- - made sample poc into tests/http/client/h2-pausing.c and
- added test_02_27 to reproduce
-
- Closes #11989
- Fixes #11982
- Reported-by: Harry Sintonen
-
-Viktor Szakats (30 Sep 2023)
-
-- cmake: validate `CURL_DEFAULT_SSL_BACKEND` config value
-
- Before this patch CMake builds accepted any value and it was used at
- runtime as-is. This patch make sure that the selected default backend
- is also enabled in the build. It also enforces a full lowercase value.
-
- This improves reproducibility and brings CMake in sync with autotools
- which already worked like described above.
-
- Follow-up to 26c7feb8b9d51a57fab3325571b4bbfa03b11af0 #11774
-
- Closes #11998
-
-- autotools: adjust `CURL_CA_PATH` value to CMake
-
- autotools was using the same value as CMake, but with an ending
- slash. Delete the ending slash to match configurations.
-
- Ref: #11964 (effort to sync cmake detections with autotools)
-
- Closes #11997
-
-- cmake: detect `sys/wait.h` and `netinet/udp.h`
-
- Ref: #11964 (effort to sync cmake detections with autotools)
-
- Closes #11996
-
-Daniel Stenberg (30 Sep 2023)
-
-- lib: provide and use Curl_hexencode
-
- Generates a lower case ASCII hex output from a binary input.
-
- Closes #11990
-
-- configure: check for the capath by default
-
- ... if the chosen TLS backend supports it: OpenSSL, GnuTLS, mbedTLS or wolfSS
- L
-
- cmake: synced
-
- Assisted-by: Viktor Szakats
- Closes #11987
-
-- wolfssl: ignore errors in CA path
-
- The default wolfSSL_CTX_load_verify_locations() function is quite picky
- with the certificates it loads and will for example return error if just
- one of the certs has expired.
-
- With the *_ex() function and its WOLFSSL_LOAD_FLAG_IGNORE_ERR flag, it
- behaves more similar to what OpenSSL does by default.
-
- Even the set of default certs on my Debian unstable has several expired
- ones.
-
- Assisted-by: Juliusz Sosinowicz
- Assisted-by: Michael Osipov
-
- Closes #11987
-
-- create-dirs.d: clarify it also uses --output-dirs
-
- Reported-by: Robert Simpson
- Fixes #11991
- Closes #11995
-
-Viktor Szakats (30 Sep 2023)
-
-- appveyor: fix yamlint issues, indent
-
- Also:
- - use double quotes in all batch if statements.
-
- Closes #11994
-
-- cmake: detect `HAVE_CLOCK_GETTIME_MONOTONIC_RAW`
-
- Based on existing autotools logic.
-
- Ref: #11964 (effort to sync cmake detections with autotools)
-
- Closes #11981
-
-- cmake: detect `HAVE_GETADDRINFO_THREADSAFE`
-
- Based on existing autotools logic.
-
- autotools checks for old versions of the allowlisted target OSes and
- disables this feature when seeing them. In CMake we assume we're running
- on newer systems and enable regardless of OS version.
-
- autotools always runs all 3 probes for non-fast-tracked systems and
- enables this feature if any one of them was successful. To save
- configuration time, CMake stops at the first successful check.
-
- OpenBSD is not fast-tracked and then gets blocklisted as a generic BSD
- system. I haven't double-checked if this is correct, but looks odd.
-
- Ref: #11964 (effort to sync cmake detections with autotools)
-
- Closes #11979
-
-- cmake: fix `HAVE_WRITABLE_ARGV` detection
-
- Move detection before the creation of detection results in
- `curl_config.h`.
-
- Ref: #11964 (effort to sync cmake detections with autotools)
-
- Closes #11978
-
-- appveyor: minor improvements
-
- - run `curl -V` after builds to see if they run and with what features.
- Except for one job where a CRT DLL is missing. And ARM64 which should
- fail, but is silently not launched instead.
-
- - copy libcurl DLL next to curl tool and tests binaries in shared mode.
- This makes it possible to run the tests. (We don't run tests after
- these builds yet.)
-
- - list the DLLs and EXEs present after the builds.
-
- - add `DEBUG` variable for CMake builds to allow disabling it, for
- testing non-debug builds. (currently enabled for all)
-
- - add commented lines that dump CMake configuration logs for debugging
- build/auto-detection issues.
-
- - add gcc version to jobs where missing.
-
- - switch a job to the native MSYS2 mingw-w64 toolchain. This adds gcc 9
- to the build mix.
-
- - make `SHARED=OFF` and `OPENSSL=OFF` defaults global.
-
- - delete a duplicate backslash.
-
- Closes #11976
-
-- configure: replace adhoc domain with `localhost` in tests
-
- Reviewed-by: Daniel Stenberg
- Closes #11988
-
-- tidy-up: use more example domains
-
- Also make use of the example TLD:
- https://en.wikipedia.org/wiki/.example
-
- Reviewed-by: Daniel Stenberg
- Closes #11992
-
-Dan Fandrich (29 Sep 2023)
-
-- runtests: display the test status if tests appear hung
-
- It sometimes happens that a test hangs during a test run and never
- returns. The test harness will wait indefinitely for the results and on
- CI servers the CI job will eventually be killed after an hour or two.
- At the end of a test run, if results haven't come in within a couple of
- minutes, display the status of all test runners and what tests they're
- running to help in debugging the problem.
-
- This feature is really only kick in with parallel testing enabled, which
- is fine because without parallel testing it's usually easy to tell what
- test has hung.
-
- Closes #11980
-
-- github/labeler: remove workaround for labeler
-
- This was added due to what seemed to be a bug regarding the sync-labels:
- config option, but it looks like it wasn't necessary.
-
- Follow-up to b2b0534e7
-
-Viktor Szakats (29 Sep 2023)
-
-- docs: upgrade an URL to HTTPS in `BINDINGS.md` [ci skip]
-
-Daniel Stenberg (29 Sep 2023)
-
-- docs: replace made up domains with example.com
-
- in FAQ and MANUAL.md
-
- - example.com was made for this purpose.
-
- - reduces the risk that one of those domains suddenly start hosting
- something nasty and we provide links to them
-
- Closes #11986
-
-Michael Osipov (29 Sep 2023)
-
-- acinclude.m4: Document proper system truststore on FreeBSD
-
- The default system truststore on FreeBSD has been /etc/ssl/certs for many
- years now. It is managed canonically through certctl(8) and contains hashed
- symlinks for OpenSSL and other TLS providers.
- The previous ones require security/ca_root_nss which might not be installed o
- r
- will not contain any custom CA certificates.
-
- Closes #11985
-
-Daniel Stenberg (29 Sep 2023)
-
-- FAQ: How do I upgrade curl.exe in Windows?
-
- This is a growing question, better answer it here to get somewhere to
- point users to.
-
- Closes #11984
-
-Viktor Szakats (28 Sep 2023)
-
-- cmake: pre-cache `HAVE_BASENAME` for mingw-w64 and MSVC
-
- `basename` is present in mingw-w64, missing from MSVC. Pre-cache
- accordingly to make configure faster.
-
- Notice that `basename` has a bug so we later disable it even with
- mingw-w64:
- https://github.com/curl/curl/blob/781242ffa44a9f9b95b6da5ac5a1bf6372ec6257/li
- b/curl_setup.h#L820-L825
-
- Closes #11974
-
-Daniel Stenberg (28 Sep 2023)
-
-- cmake: add missing checks
-
- - check for arc4random. To make rand.c use it accordingly.
- - check for fcntl
- - fix fseek detection
- - add SIZEOF_CURL_SOCKET_T
- - fix USE_UNIX_SOCKETS
- - define HAVE_SNPRINTF to 1
- - check for fnmatch
- - check for sched_yield
- - remove HAVE_GETPPID duplicate from curl_config.h
- - add HAVE_SENDMSG
-
- Ref: #11964
-
- Co-authored-by: Viktor Szakats
- Closes #11973
-
-- configure: remove unused checks
-
- - for sys/uio.h
- - for fork
- - for connect
-
- Ref: #11964
-
- Closes #11973
-
-- lib: remove TIME_WITH_SYS_TIME
-
- It is not used in any code anywhere.
-
- Ref: #11964
- Closes #11975
-
-- docs: update curl man page references
-
- Detected by the manpage-syntax update
-
- Closes #11963
-
-- manpage-syntax: verify curl man page references
-
- 1. References to curl symbols are now checked that they indeed exist as
- man pages. This for \f references as well as the names referenced in the
- SEE ALSO section.
-
- Allowlist curl.1 since it is not always built in builds
-
- 2. References to curl symbols that lack section now causes warning, since tha
- t
- will prevent them from getting linked properly
-
- 3. Check for "bare" references to curl functions and warn, they should be
- references
-
- Closes #11963
-
-- cmake: add check for suseconds_t
-
- And fix the HAVE_LONGLONG define
-
- Ref: #11964
- Closes #11977
-
-Viktor Szakats (28 Sep 2023)
-
-- tidy-up: whitespace fixes
-
- Closes #11972
-
-- cmake: detect TLS-SRP in OpenSSL/wolfSSL/GnuTLS
-
- With new option `CURL_DISABLE_SRP=ON` to force-disable it.
- To match existing option and detection logic in autotools.
-
- Also:
- - fix detecting GnuTLS.
- We assume `nettle` as a GnuTLS dependency.
- - add CMake GnuTLS CI job.
- - bump AppVeyor CMake OpenSSL MSVC job to OpenSSL 1.1.1 (from 1.0.2)
- TLS-SRP fails to detect with 1.0.2 due to an OpenSSL header bug.
- - fix compiler warning when building with GnuTLS and disabled TLS-SRP.
- - fix comment typos, whitespace.
-
- Ref: #11964
-
- Closes #11967
-
-- tool: use our own stderr variable
-
- Earlier this year we changed our own stderr variable to use the standard
- name `stderr` (to avoid bugs where someone is using `stderr` instead of
- the curl-tool specific variable). This solution needed to override the
- standard `stderr` symbol via the preprocessor. This in turn didn't play
- well with unity builds and caused curl tool to crash or stay silent due
- to an uninitialized stderr. This was a hard to find issue, fixed by
- manually breaking out one file from the unity sources.
-
- To avoid two these two tricks, this patch implements a different
- solution: Restore using our own local variable for our stderr output and
- leave `stderr` as-is. To avoid using `stderr` by mistake, add a
- `checksrc` rule (based on logic we already used in lib for `strerror`)
- that detects any `stderr` use in `src` and points to using our own
- variable instead: `tool_stderr`.
-
- Follow-up to 06133d3e9b8aeb9e9ca0b3370c246bdfbfc8619e
- Follow-up to 2f17a9b654121dd1ecf4fc043c6d08a9da3522db
-
- Closes #11958
-
-Loïc Yhuel (28 Sep 2023)
-
-- connect: only start the happy eyeballs timer when needed
-
- The timeout is only used when there is a second address family, for the
- delayed eyeballer.
-
- Closes #11939
-
-Daniel Stenberg (28 Sep 2023)
-
-- tool_operate: free 'gateway' correctly
-
- Pointed out by Coverity. The fix in 93885cf3a8d4e was incomplete.
-
- Also removed repeated wording in IPFS related error messages.
-
- Closes #11969
-
-Stefan Eissing (28 Sep 2023)
-
-- lib: move handling of `data->req.writer_stack` into Curl_client_write()
-
- - move definitions from content_encoding.h to sendf.h
- - move create/cleanup/add code into sendf.c
- - installed content_encoding writers will always be called
- on Curl_client_write(CLIENTWRITE_BODY)
- - Curl_client_cleanup() frees writers and tempbuffers from
- paused transfers, irregardless of protocol
-
- Closes #11908
-
-Loïc Yhuel (28 Sep 2023)
-
-- multi: round the timeout up to prevent early wakeups
-
- Curl_timediff rounds down to the millisecond, so curl_multi_perform can
- be called too early, then we get a timeout of 0 and call it again.
-
- The code already handled the case of timeouts which expired less than
- 1ms in the future. By rounding up, we make sure we will never ask the
- platform to wake up too early.
-
- Closes #11938
-
-Daniel Stenberg (28 Sep 2023)
-
-- RELEASE-NOTES: spell out that IPFS is via gateway
-
-- RELEASE-NOTES: synced
-
-- tool_operate: avoid strlen() -1 on zero length content from file
-
- Follow-up to 65b563a96a226649ba12cb1e
-
- Closes #11959
-
-- tool_operate: fix memory mixups
-
- Switch to plain getenv() from curl_getenv() to avoid the allocation and
- having to keep track of which free() or curl_free() that need to be
- used.
-
- Coverity found issues and a memory leak.
-
- Follow-up to 65b563a96a226649ba12cb1e
-
- Closes #11959
-
-Viktor Szakats (27 Sep 2023)
-
-- curl-functions.m4: fixup recent bad edits
-
- Follow-up to 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940
-
- Closes #11966
-
-Daniel Stenberg (27 Sep 2023)
-
-- curl-functions.m4: fix include line
-
- This made the getaddrinfo detection fail, but we did not spot it in the
- CI because it graciously falled back to using legacy functions instead!
-
- Follow-up to 96c29900bcec (#11940)
-
- Closes #11965
-
-- inet_ntop: add typecast to silence Coverity
-
- CID 1024653: Integer handling issues (SIGN_EXTENSION)
-
- Suspicious implicit sign extension: "src[i]" with type "unsigned char
- const" (8 bits, unsigned) is promoted in "src[i] << (1 - i % 2 << 3)" to
- type "int" (32 bits, signed), then sign-extended to type "unsigned long"
- (64 bits, unsigned). If "src[i] << (1 - i % 2 << 3)" is greater than
- 0x7FFFFFFF, the upper bits of the result will all be 1.
-
- 111 words[i/2] |= (src[i] << ((1 - (i % 2)) << 3));
-
- The value will not be greater than 0x7FFFFFFF so this still cannot
- happen.
-
- Also, switch to ints here instead of longs. The values stored are 16 bit
- so at least no need to use 64 bit variables. Also, longs are 32 bit on
- some platforms so this logic still needs to work with 32 bits.
-
- Closes #11960
-
-- docs: adapt SEE ALSO sections to new requirements
-
- To please manpage-syntax.pl used by test 1173
-
- Closes #11957
-
-- manpage-syntax.pl: verify SEE ALSO syntax
-
- - Enforce a single reference per .BR line
- - Skip the quotes around the section number for example (3)
- - Insist on trailing commas on all lines except the last
- - Error on comma on the last SEE ALSO entry
-
- - List the entries alpha-sorted, not enforced just recommended
-
- Closes #11957
-
-- connect: expire the timeout when trying next
-
- ... so that it gets called again immediately and can continue trying
- addresses to connect to. Otherwise it might unnecessarily wait for a
- while there.
-
- Fixes #11920
- Reported-by: Loïc Yhuel
- Closes #11935
-
-- http: remove wrong comment for http_should_fail
-
- Reported-by: Christian Schmitz
- Ref: #11936
- Closes #11941
-
-Dan Fandrich (26 Sep 2023)
-
-- tool_setopt: remove unused function tool_setopt_flags
-
- This function is identical to tool_setopt_bitmask except that it treats
- the argument as unsigned.
-
- Closes #11943
-
-Viktor Szakats (26 Sep 2023)
-
-- cmake: add feature checks for `memrchr` and `getifaddrs`
-
- - `HAVE_MEMRCHR` for `memrchr`.
- - `HAVE_GETIFADDRS` for `getifaddrs`.
- This was present in `lib/curl_config.h.cmake` but missed the detection
- logic.
-
- To match existing autotools feature checks.
-
- Closes #11954
-
-- cmake: move global headers to specific checks
-
- Before this patch we added standard headers unconditionally to the
- global list of headers used for feature checks. This is unnecessary
- and also doesn't help CMake 'Generate' performance. This patch moves
- these headers to each feature check where they are actually needed.
- Stop using `stddef.h`, as it seems unnecessary.
-
- I've used autotools' `m4/curl-functions.m4` to figure out these
- dependencies.
-
- Also delete checking for the C89 standard header `time.h`, that I
- missed in the earlier commit.
-
- Ref: 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940
-
- Closes #11951
-
-- src/mkhelp: make generated code pass `checksrc`
-
- Closes #11955
-
-- tests: show which curl tool `runtests.pl` is using
-
- To help debugging when there is issue finding or running it.
-
- Closes #11953
-
-- CI/azure: make `MAKEFLAGS` global to parallelize all jobs
-
- https://dev.azure.com/daniel0244/curl/_build/results?buildId=17528 (before)
- https://dev.azure.com/daniel0244/curl/_build/results?buildId=17545 (after, wi
- th -j3)
-
- Closes #11952
-
-- CI/azure: migrate old mingw MSYS1 jobs to MSYS2
-
- Also delete an accidental variable reference.
-
- Follow-up to 38029101e2d78ba125732b3bab6ec267b80a0e72
-
- Closes #11945
-
-Daniel Stenberg (26 Sep 2023)
-
-- docs: add see also curl_multi_get_handles to some man pages
-
- Assisted-by: Jay Satiro
-
- Closes #11942
-
-Viktor Szakats (26 Sep 2023)
-
-- cmake: assume `_fseeki64` and no `fseeko` on Windows
-
- `_fseeki64` is present in mingw-w64 1.0 (2011-09-26) headers, and
- at least Watcom C 1.9 (2010) headers and MSVS 2008 [1].
-
- `fseeko` is not present in any of these.
-
- (mingw-w64 1.0 also offers `fseeko64`.)
-
- [1] https://github.com/curl/curl/pull/11944#issuecomment-1734995004
-
- Follow-up to 9c7165e96a3a9a2d0b7059c87c699b5ca8cdae93 #11918
-
- Closes #11950
-
-- build: delete checks for C89 standard headers
-
- Delete checks and guards for standard C89 headers and assume these are
- available: `stdio.h`, `string.h`, `time.h`, `setjmp.h`, `stdlib.h`,
- `stddef.h`, `signal.h`.
-
- Some of these we already used unconditionally, some others we only used
- for feature checks.
-
- Follow-up to 9c7165e96a3a9a2d0b7059c87c699b5ca8cdae93 #11918 (for `stdio.h` i
- n CMake)
-
- Closes #11940
-
-Stefan Eissing (26 Sep 2023)
-
-- multiif.h: remove Curl_multi_dump declaration
-
- Follow-up to d850eea2 which removed the Curl_multi_dump definition.
-
- Closes https://github.com/curl/curl/pull/11946
-
-Jay Satiro (26 Sep 2023)
-
-- config-win32: define HAVE__FSEEKI64
-
- Follow-up to 9c7165e9 which added an fseeko wrapper to the lib that
- calls _fseeki64 if it is available.
-
- Closes https://github.com/curl/curl/pull/11944
-
-- docs: explain how PINNEDPUBLICKEY is independent of VERIFYPEER
-
- - Explain that peer verification via CURLOPT_PINNEDPUBLICKEY takes place
- even if peer verification via CURLOPT_SSL_VERIFYPEER is turned off.
-
- The behavior is verified by test2048.
-
- Bug: https://github.com/curl/curl/issues/2935#issuecomment-418371872
- Reported-by: claudiusaiz@users.noreply.github.com
-
- Bug: https://github.com/curl/curl/discussions/11910
- Reported-by: Hakan Sunay Halil
-
- Closes https://github.com/curl/curl/pull/11930
-
-Stefan Eissing (26 Sep 2023)
-
-- openssl: improve ssl shutdown handling
-
- - If SSL shutdown is not finished then make an additional call to
- SSL_read to gather additional tracing.
-
- - Fix http2 and h2-proxy filters to forward do_close() calls to the next
- filter.
-
- For example h2 and SSL shutdown before and after this change:
-
- Before:
-
- Curl_conn_close -> cf_hc_close -> Curl_conn_cf_discard_chain ->
- ssl_cf_destroy
-
- After:
-
- Curl_conn_close -> cf_hc_close -> cf_h2_close -> cf_setup_close ->
- ssl_cf_close
-
- Note that currently the tracing does not show output on the connection
- closure handle. Refer to discussion in #11878.
-
- Ref: https://github.com/curl/curl/discussions/11878
-
- Closes https://github.com/curl/curl/pull/11858
-
-Loïc Yhuel (26 Sep 2023)
-
-- multi: fix small timeouts
-
- Since Curl_timediff rounds down to the millisecond, timeouts which
- expire in less than 1ms are considered as outdated and removed from the
- list. We can use Curl_timediff_us instead, big timeouts could saturate
- but this is not an issue.
-
- Closes #11937
-
-Viktor Szakats (25 Sep 2023)
-
-- cmake: fix stderr initialization in unity builds
-
- Before this patch, in certain build configurations the curl tool may
- not have displayed anything (debug, macOS), or crashed at startup
- (debug, Windows).
-
- Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719
- Necessary after 2f17a9b654121dd1ecf4fc043c6d08a9da3522db
-
- Closes #11929
-
-- cmake: fix missing `zlib.h` when compiling `libcurltool`
-
- Came up while testing debug/testing build for Windows. I'm not sure why
- it didn't come up in earlier tests with similar config.
- `tool_hugehelp.c` might indeed require `zlib.h` and without linking
- `CURL_LIBS` to the `curltool` target, CMake doesn't seem to add detected
- dependency headers to the compiler command.
-
- ```
- [ 25%] Building C object src/CMakeFiles/curltool.dir/tool_hugehelp.c.obj
- cd .../curl/bld-cmake-llvm-x64/src && /usr/local/opt/llvm/bin/clang
- --target=x86_64-w64-mingw32 --sysroot=/usr/local/opt/mingw-w64/toolchain-x8
- 6_64
- -DCURLDEBUG -DCURL_STATICLIB -DHAVE_CONFIG_H -DUNICODE -DUNITTESTS -D_UNICO
- DE
- -I.../curl/include -I.../curl/lib -I.../curl/bld-cmake-llvm-x64/lib
- -I.../curl/bld-cmake-llvm-x64/include -I.../curl/src -Wno-unused-command-li
- ne-argument
- -D_UCRT -DDEBUGBUILD -DHAS_ALPN -DUSE_MANUAL=1 -fuse-ld=lld -Wl,-s -static
- -libgcc
- -lucrt [...] -O3 -DNDEBUG -municode -MD
- -MT src/CMakeFiles/curltool.dir/tool_hugehelp.c.obj
- -MF CMakeFiles/curltool.dir/tool_hugehelp.c.obj.d
- -o CMakeFiles/curltool.dir/tool_hugehelp.c.obj -c .../curl/bld-cmake-llvm-x
- 64/src/tool_hugehelp.c
- .../curl/bld-cmake-llvm-x64/src/tool_hugehelp.c:6:10: fatal error: 'zlib.h' f
- ile not found
- 6 | #include <zlib.h>
- | ^~~~~~~~
- ```
-
- Follow-up to 39e7c22bb459c2e818f079984989a26a09741860
-
- Closes #11927
-
-- cmake: fix duplicate symbols when linking tests
-
- The linker resolves this automatically in non-unity builds. In unity
- builds the linker cannot drop a single object with the duplicates,
- resulting in these errors. The root issue is that we started including
- certain objects both via both libcurlu and libcurltool libs.
-
- Regression from 39e7c22bb459c2e818f079984989a26a09741860
-
- Windows errors:
- ```
- [ 3%] Linking C executable unit1303.exe
- [ 3%] Building C object tests/server/CMakeFiles/rtspd.dir/__/__/lib/curl_mul
- tibyte.c.obj
- ../../lib/libcurlu-d.a(unity_0.c.obj): In function `curlx_convert_UTF8_to_wch
- ar':
- C:/projects/curl/lib/curl_multibyte.c:44: multiple definition of `curlx_conve
- rt_UTF8_to_wchar'
- ../../src/libcurltool-d.a(unity_0.c.obj):C:/projects/curl/lib/curl_multibyte.
- c:44: first defined here
- ../../lib/libcurlu-d.a(unity_0.c.obj): In function `curlx_convert_wchar_to_UT
- F8':
- C:/projects/curl/lib/curl_multibyte.c:66: multiple definition of `curlx_conve
- rt_wchar_to_UTF8'
- ../../src/libcurltool-d.a(unity_0.c.obj):C:/projects/curl/lib/curl_multibyte.
- c:66: first defined here
- ../../lib/libcurlu-d.a(unity_0.c.obj): In function `curlx_win32_open':
- C:/projects/curl/lib/curl_multibyte.c:92: multiple definition of `curlx_win32
- _open'
- ../../src/libcurltool-d.a(unity_0.c.obj):C:/projects/curl/lib/curl_multibyte.
- c:92: first defined here
- ../../lib/libcurlu-d.a(unity_0.c.obj): In function `curlx_win32_fopen':
- C:/projects/curl/lib/curl_multibyte.c:120: multiple definition of `curlx_win3
- 2_fopen'
- ../../src/libcurltool-d.a(unity_0.c.obj):C:/projects/curl/lib/curl_multibyte.
- c:120: first defined here
- ../../lib/libcurlu-d.a(unity_0.c.obj): In function `curlx_win32_stat':
- [...]
- ```
- Ref: https://ci.appveyor.com/project/curlorg/curl/builds/48110107/job/nvlhpt9
- aa4ehny5q#L247
-
- macOS errors:
- ```
- [ 56%] Linking C executable unit1302
- duplicate symbol '_curlx_sotouz' in:
- ../../lib/libcurlu.a(unity_0_c.c.o)
- ../../src/libcurltool.a(unity_0_c.c.o)
- duplicate symbol '_curlx_sitouz' in:
- ../../lib/libcurlu.a(unity_0_c.c.o)
- ../../src/libcurltool.a(unity_0_c.c.o)
- duplicate symbol '_curlx_uztosz' in:
- ../../lib/libcurlu.a(unity_0_c.c.o)
- ../../src/libcurltool.a(unity_0_c.c.o)
- [...]
- ```
- with config:
- ```
- -DCMAKE_UNITY_BUILD=ON \
- -DENABLE_DEBUG=ON -DBUILD_TESTING=ON -DCMAKE_C_FLAGS=-DDEBUGBUILD \
- -DBUILD_SHARED_LIBS=ON \
- -DBUILD_STATIC_LIBS=OFF
- ```
-
- Closes #11926
-
-- cmake: lib `CURL_STATICLIB` fixes (Windows)
-
- - always define `CURL_STATICLIB` when building libcurl for Windows.
-
- This disables `__declspec(dllexport)` for exported libcurl symbols.
- In normal mode (hide symbols) these exported symbols are specified
- via `libcurl.def`. When not hiding symbols, all symbols are exported
- by default.
-
- Regression from 1199308dbc902c52be67fc805c72dd2582520d30
-
- Fixes #11844
-
- - fix to omit `libcurl.def` when not hiding private symbols.
-
- Regression from 2ebc74c36a19a1700af394c16855ce144d9878e3
-
- - fix `ENABLED_DEBUG=ON` + shared curl tool Windows builds by also
- omitting `libcurl.def` in this case, and exporting all symbols
- instead. This ensures that a shared curl tool can access all debug
- functions which are not normally exported from libcurl DLL.
-
- - delete `INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB"` for "objects"
- target.
-
- Follow-up to 2ebc74c36a19a1700af394c16855ce144d9878e3
-
- - delete duplicate `BUILDING_LIBCURL` definitions.
-
- - fix `HIDES_CURL_PRIVATE_SYMBOLS` to not overwrite earlier build settings.
-
- Follow-up to 1199308dbc902c52be67fc805c72dd2582520d30
-
- Closes #11914
-
-Daniel Stenberg (25 Sep 2023)
-
-- RELEASE-NOTES: synced
-
-Dan Fandrich (25 Sep 2023)
-
-- tests: fix log directory path in IPFS tests
-
- Hard-coding the log directory name fails with parallel tests.
-
- Follow-up to 65b563a96
-
- Ref: #8805
-
-Daniel Stenberg (25 Sep 2023)
-
-- curl_multi_get_handles: get easy handles from a multi handle
-
- Closes #11750
-
-Stefan Eissing (25 Sep 2023)
-
-- http: h1/h2 proxy unification
-
- - use shared code for setting up the CONNECT request
- when tunneling, used in HTTP/1.x and HTTP/2 proxying
- - eliminate use of Curl_buffer_send() and other manipulations
- of `data->req` or `data->state.ulbuf`
-
- Closes #11808
-
-Natanael Copa (25 Sep 2023)
-
-- lib: use wrapper for curl_mime_data fseek callback
-
- fseek uses long offset which does not match with curl_off_t. This leads
- to undefined behavior when calling the callback and caused failure on
- arm 32 bit.
-
- Use a wrapper to solve this and use fseeko which uses off_t instead of
- long.
-
- Thanks to the nice people at Libera IRC #musl for helping finding this
- out.
-
- Fixes #11882
- Fixes #11900
- Closes #11918
-
-- configure: sort AC_CHECK_FUNCS
-
- No functional changes.
-
-Daniel Stenberg (25 Sep 2023)
-
-- warnless: remove unused functions
-
- Previously put there for use with the intel compiler
-
- Closes #11932
-
-- GHA/linux: run singleuse to detect single-use global functions
-
- Use --unit for configure --enable-debug builds
-
- Closes #11932
-
-- singleuse: add scan for use in other source codes
-
- This should reduce false-positive to almost zero. Checks for presence in
- unit tests if --unit is specified, which is intended for debug builds
- where unit testing is enabled.
-
- Closes #11932
-
-- multi: remove Curl_multi_dump
-
- A debug-only function that is basically never used. Removed to ease the
- use of the singleuse script to detect non-static functions not used
- outside the file where it is defined.
-
- Closes #11931
-
-Viktor Szakats (24 Sep 2023)
-
-- tests: fix compiler warnings
-
- Seen with llvm 17 on Windows x64.
-
- ```
- .../curl/tests/server/rtspd.c:136:13: warning: no previous extern declaration
- for non-static variable 'logdir' [-Wmissing-variable-declarations]
- 136 | const char *logdir = "log";
- | ^
- .../curl/tests/server/rtspd.c:136:7: note: declare 'static' if the variable i
- s not intended to be used outside of this translation unit
- 136 | const char *logdir = "log";
- | ^
- .../curl/tests/server/rtspd.c:137:6: warning: no previous extern declaration
- for non-static variable 'loglockfile' [-Wmissing-variable-declarations]
- 137 | char loglockfile[256];
- | ^
- .../curl/tests/server/rtspd.c:137:1: note: declare 'static' if the variable i
- s not intended to be used outside of this translation unit
- 137 | char loglockfile[256];
- | ^
- .../curl/tests/server/fake_ntlm.c:43:13: warning: no previous extern declarat
- ion for non-static variable 'logdir' [-Wmissing-variable-declarations]
- 43 | const char *logdir = "log";
- | ^
- .../curl/tests/server/fake_ntlm.c:43:7: note: declare 'static' if the variabl
- e is not intended to be used outside of this translation unit
- 43 | const char *logdir = "log";
- | ^
- .../curl/src/tool_doswin.c:350:8: warning: possible misuse of comma operator
- here [-Wcomma]
- 350 | ++d, ++s;
- | ^
- .../curl/src/tool_doswin.c:350:5: note: cast expression to void to silence wa
- rning
- 350 | ++d, ++s;
- | ^~~
- | (void)( )
- ```
-
- ```
- .../curl/tests/libtest/lib540.c:146:27: warning: result of comparison 'long'
- > 2147483647 is always false [-Wtautological-type-limit-compare]
- 146 | int itimeout = (L > (long)INT_MAX) ? INT_MAX : (int)L;
- | ~ ^ ~~~~~~~~~~~~~
- 1 warning generated.
-
- .../curl/tests/libtest/libntlmconnect.c:195:31: warning: result of comparison
- 'long' > 2147483647 is always false [-Wtautological-type-limit-compare]
- 195 | int itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeo
- ut;
- | ~~~~~~~ ^ ~~~~~~~~~~~~~
- 1 warning generated.
-
- .../curl/tests/libtest/lib591.c:117:31: warning: result of comparison 'long'
- > 2147483647 is always false [-Wtautological-type-limit-compare]
- 117 | int itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeo
- ut;
- | ~~~~~~~ ^ ~~~~~~~~~~~~~
- 1 warning generated.
- .../curl/tests/libtest/lib597.c:99:31: warning: result of comparison 'long' >
- 2147483647 is always false [-Wtautological-type-limit-compare]
- 99 | int itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeo
- ut;
- | ~~~~~~~ ^ ~~~~~~~~~~~~~
- 1 warning generated.
- ```
-
- Seen on macOS Intel:
- ```
- .../curl/tests/server/sws.c:440:64: warning: field precision should have type
- 'int', but argument has type 'size_t' (aka 'unsigned long') [-Wformat]
- msnprintf(logbuf, sizeof(logbuf), "Got request: %s %.*s HTTP/%d.%d"
- ,
- ~~^~
- 1 warning generated.
- ```
-
- Closes #11925
-
-Jay Satiro (24 Sep 2023)
-
-- url: fix netrc info message
-
- - Fix netrc info message to use the generic ".netrc" filename if the
- user did not specify a netrc location.
-
- - Update --netrc doc to add that recent versions of curl on Windows
- prefer .netrc over _netrc.
-
- Before:
- * Couldn't find host google.com in the (nil) file; using defaults
-
- After:
- * Couldn't find host google.com in the .netrc file; using defaults
-
- Closes https://github.com/curl/curl/pull/11904
-
-Dan Fandrich (23 Sep 2023)
-
-- wolfssh: do cleanup in Curl_ssh_cleanup
-
- Closes: #11921
-
-Daniel Stenberg (24 Sep 2023)
-
-- tool_listhelp: regenerated
-
- Polished the --ipfs-gateway description
-
- Fixed the --trace-config description
-
- The script also fixed some other small mistakes
-
- Closes #11923
-
-Viktor Szakats (23 Sep 2023)
-
-- Makefile.mk: always set `CURL_STATICLIB` for lib (Windows)
-
- Also fix to export all symbols in Windows debug builds, making
- `-debug-dyn` builds work with `-DCURL_STATICLIB` set.
-
- Ref: https://github.com/curl/curl/pull/11914 (same for CMake)
-
- Closes #11924
-
-Daniel Stenberg (23 Sep 2023)
-
-- quic: set ciphers/curves the same way regular TLS does
-
- for OpenSSL/BoringSSL
-
- Fixes #11796
- Reported-by: Karthikdasari0423 on github
- Assisted-by: Jay Satiro
- Closes #11836
-
-- test457: verify --max-filesize with chunked encoding
-
-- lib: let the max filesize option stop too big transfers too
-
- Previously it would only stop them from getting started if the size is
- known to be too big then.
-
- Update the libcurl and curl docs accordingly.
-
- Fixes #11810
- Reported-by: Elliot Killick
- Assisted-by: Jay Satiro
- Closes #11820
-
-Viktor Szakats (23 Sep 2023)
-
-- mingw: delete support for legacy mingw.org toolchain
-
- Drop support for "old" / "legacy" / "classic" / "v1" / "mingw32" MinGW:
- https://en.wikipedia.org/wiki/MinGW, https://osdn.net/projects/mingw/
- Its homepage used to be http://mingw.org/ [no HTTPS], and broken now.
- It supported the x86 CPU only and used a old Windows API header and
- implib set, often causing issues. It also misses most modern Windows
- features, offering old versions of both binutils and gcc (no llvm/clang
- support). It was last updated 2 years ago.
-
- curl now relies on toolchains based on the mingw-w64 project:
- https://www.mingw-w64.org/ https://sourceforge.net/projects/mingw-w64/
- https://www.msys2.org/ https://github.com/msys2/msys2
- https://github.com/mstorsjo/llvm-mingw
- (Also available via Linux and macOS package managers.)
-
- Closes #11625
-
-Mark Gaiser (23 Sep 2023)
-
-- curl: add support for the IPFS protocols:
-
- - ipfs://<cid>
- - ipns://<cid>
-
- This allows you tu use ipfs in curl like:
- curl ipfs://<cid>
- and
- curl ipns://<cid>
-
- For more information consult the readme at:
- https://curl.se/docs/ipfs.html
-
- Closes #8805
-
-Daniel Stenberg (23 Sep 2023)
-
-- bufq: remove Curl_bufq_skip_and_shift (unused)
-
- Closes #11915
-
-- scripts/singleuse.pl: add curl_global_trace
-
-Viktor Szakats (22 Sep 2023)
-
-- cmake: fix unity symbol collisions in h2 builds
-
- Regression from 331b89a319d0067fa1e6441719307cfef9c7960f
-
- Reviewed-by: Daniel Stenberg
- Reviewed-by: Jay Satiro
- Closes #11912
-
-Daniel Stenberg (22 Sep 2023)
-
-- RELEASE-NOTES: synced
-
-Dan Fandrich (21 Sep 2023)
-
-- github/labeler: improve the match patterns
-
- This includes new rules for setting the appleOS and logging labels and
- matches on some example files. Also, enable dot mode for wildcard
- matches in the .github directory.
-
-Daniel Stenberg (21 Sep 2023)
-
-- upload-file.d: describe the file name slash/backslash handling
-
- Closes #11911
-
-Jakub Jelen (21 Sep 2023)
-
-- libssh: cap SFTP packet size sent
-
- Due to libssh limitations
-
- Signed-off-by: Jakub Jelen <jjelen@redhat.com>
-
- Closes #11804
-
-Daniel Stenberg (21 Sep 2023)
-
-- curl.h: mark CURLSSLBACKEND_NSS as deprecated since 8.3.0
-
- Closes #11905
-
-- mailmap: unify Michael Osipov under a single email
-
-Ted Lyngmo (21 Sep 2023)
-
-- docs: use CURLSSLBACKEND_NONE
-
- [ssl] use CURLSSLBACKEND_NONE instead of (curl_sslbackend)-1 in
- documentation and examples.
-
- Signed-off-by: Ted Lyngmo <ted@lyncon.se>
-
- Closes #11909
-
-Dan Fandrich (21 Sep 2023)
-
-- github/labeler: give the sync-labels config item a default value
-
- This shouldn't be necessary and is likely a bug with this beta version
- of the labeller.
-
- Also, fix the negative matches for the documentation label.
-
- Follow-up to dd12b452a
- Closes #11907
-
-- github/labeler: fix up more the labeler config format
-
- The new version didn't like the workaround we had for a bug in the
- previous labeler version, and it should no longer be needed.
-
- Follow-up to dd12b452a
- Closes #11906
-
-- github/labeler: fix indenting to try to appease labeller
-
- Follow-up to dd12b452a
-
-Jay Satiro (21 Sep 2023)
-
-- libssh2: fix error message on failed pubkey-from-file
-
- - If libssh2_userauth_publickey_fromfile_ex returns -1 then show error
- message "SSH public key authentication failed: Reason unknown (-1)".
-
- When libssh2_userauth_publickey_fromfile_ex returns -1 it does so as a
- generic error and therefore doesn't set an error message. AFAICT that is
- not documented behavior.
-
- Prior to this change libcurl retrieved the last set error message which
- would be from a previous function failing. That resulted in misleading
- auth failed error messages in verbose mode.
-
- Bug: https://github.com/curl/curl/issues/11837#issue-1891827355
- Reported-by: consulion@users.noreply.github.com
-
- Closes https://github.com/curl/curl/pull/11881
-
-Stefan Eissing (21 Sep 2023)
-
-- pytest: exclude test_03_goaway in CI runs due to timing dependency
-
- Closes #11860
-
-- lib: disambiguate Curl_client_write flag semantics
-
- - use CLIENTWRITE_BODY *only* when data is actually body data
- - add CLIENTWRITE_INFO for meta data that is *not* a HEADER
- - debug assertions that BODY/INFO/HEADER is not used mixed
- - move `data->set.include_header` check into Curl_client_write
- so protocol handlers no longer have to care
- - add special in FTP for `data->set.include_header` for historic,
- backward compatible reasons
- - move unpausing of client writes from easy.c to sendf.c, so that
- code is in one place and can forward flags correctly
-
- Closes #11885
-
-Patrick Monnerat (21 Sep 2023)
-
-- tftpd: always use curl's own tftp.h
-
- Using the system's provided arpa/tftp.h and optimizing, GCC 12 detects
- and reports a stringop-overread warning:
-
- tftpd.c: In function ‘write_behind.isra’:
- tftpd.c:485:12: warning: ‘write’ reading between 1 and 2147483647 bytes f
- rom a region of size 0 [-Wstringop-overread]
- 485 | return write(test->ofile, writebuf, count);
- | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- In file included from tftpd.c:71:
- /usr/include/arpa/tftp.h:58:30: note: source object ‘tu_data’ of size 0
- 58 | char tu_data[0]; /* data or error stri
- ng */
- | ^~~~~~~
-
- This occurs because writebuf points to this field and the latter
- cannot be considered as being of dynamic length because it is not
- the last field in the structure. Thus it is bound to its declared
- size.
-
- This commit always uses curl's own version of tftp.h where the
- target field is last in its structure, effectively avoiding the
- warning.
-
- As HAVE_ARPA_TFTP_H is not used anymore, cmake/configure checks for
- arpa/tftp.h are removed.
-
- Closes #11897
-
-Dan Fandrich (20 Sep 2023)
-
-- test1474: make precheck more robust on non-Solaris systems
-
- If uname -r returns something odd, perl could return an error code and
- the test would be erroneously skipped. The qx// syntax avoid this.
-
- Followup to 08f9b2148
-
-- github/labeler: switch to the 5 beta version
-
- This version adds an important feature that will allow more PRs to be
- labelled. Rather than being limited to labeling PRs with files that
- match a single glob, it can now label them if multiple changed files
- match any one of a number of globs.
-
-Daniel Stenberg (20 Sep 2023)
-
-- lib: enable hmac for digest as well
-
- Previously a build that disabled NTLM and aws-sigv4 would fail to build
- since the hmac was disabled, but it is also needed for digest auth.
-
- Follow-up to e92edfbef64448ef
-
- Fixes #11890
- Reported-by: Aleksander Mazur
- Closes #11896
-
-- idn: if idn2_check_version returns NULL, return error
-
- ... this avoids a NULL dereference for this unusual case.
-
- Reported-by: s0urc3_ on hackerone
- Closes #11898
-
-- http: fix CURL_DISABLE_BEARER_AUTH breakage
-
- When bearer auth was disabled, the if/else logic got wrong and caused
- problems.
-
- Follow-up to e92edfbef64448ef461
- Fixes #11892
- Reported-by: Aleksander Mazur
- Closes #11895
-
-Michael Osipov (20 Sep 2023)
-
-- wolfssl: allow capath with CURLOPT_CAINFO_BLOB
-
- Remain consistent with OpenSSL. While CAfile is nulled as documented
- with CURLOPT_CAINFO_BLOB, CApath remains intact.
-
- Closes #11886
-
-- wolfssl: use ssl_cafile/ssl_capath variables consistent with openssl.c
-
- Closes #11886
-
-Dan Fandrich (19 Sep 2023)
-
-- test1474: disable test on NetBSD, OpenBSD and Solaris 10
-
- These kernels only send a fraction of the requested amount of the first
- large block, invalidating the assumptions of the test and causing it to
- fail.
-
- Assisted-by: Christian Weisgerber
- Ref: https://curl.se/mail/lib-2023-09/0021.html
- Closes #11888
-
-Ryan Schmidt (20 Sep 2023)
-
-- cmake, configure: also link with CoreServices
-
- When linking with CoreFoundation, also link with CoreServices which is
- apparently required to avoid an NSInvalidArgumentException in software
- linking with libcurl on macOS Sonoma 14 and later.
-
- Fixes #11893
- Closes #11894
-
-Marc Hoersken (19 Sep 2023)
-
-- CI/azure: remove pip, wheel, cryptography, pyopenssl and impacket
-
- These dependencies are now already included in the Docker image.
-
- Ref: https://github.com/mback2k/curl-docker-winbuildenv/commit/2607a31bcab544
- b41d15606e97f38cf312c1ce56
-
- Closes #11889
-
-Daniel Stenberg (19 Sep 2023)
-
-- wolfssl: if CURLOPT_CAINFO_BLOB is set, ignore the CA files
-
- Ref: #11883
- Reported-by: Michael Osipov
- Closes #11884
-
-- RELEASE-NOTES: synced
-
-- test3103: CURLOPT_COOKIELIST test
-
-- cookie: set ->running in cookie_init even if data is NULL
-
- This is a regression introduced in b1b326ec500 (shipped in curl 8.1.0)
-
- Test 3103 verifies.
-
- Fixes #11875
- Reported-by: wangp on github
- Closes #11876
-
-- test498: total header size for all redirects is larger than accepted
-
-- http: use per-request counter to check too large headers
-
- Not the counter that accumulates all headers over all redirects.
-
- Follow-up to 3ee79c1674fd6
-
- Do a second check for 20 times the limit for the accumulated size for
- all headers.
-
- Fixes #11871
- Reported-by: Joshix-1 on github
- Closes #11872
-
-Jay Satiro (18 Sep 2023)
-
-- THANKS: add Eric Murphy
-
- He reported #11850 (quiche build error) but I forgot to add a
- 'reported-by' entry in the fix 267e14f1.
-
-Daniel Stenberg (18 Sep 2023)
-
-- h2-proxy: remove left-over mistake in drain_tunnel()
-
- Left-over from 331b89a319
-
- Reported-by: 南宫雪珊
-
- Closes https://github.com/curl/curl/pull/11877
-
-vvb2060 (18 Sep 2023)
-
-- lib: failf/infof compiler warnings
-
- Closes #11874
-
-Daniel Stenberg (17 Sep 2023)
-
-- rand: fix 'alnum': array is too small to include a terminating null character
-
- It was that small on purpose, but this change now adds the null byte to
- avoid the error.
-
- Follow-up to 3aa3cc9b052353b1
-
- Reported-by: Dan Fandrich
- Ref: #11838
- Closes #11870
-
-Mathias Fuchs (16 Sep 2023)
-
-- cmake: fix the help text to the static build option in CMakeLists.txt
-
- Closes #11843
-
-John Haugabook (16 Sep 2023)
-
-- MANUAL.md: change domain to example.com
-
- Closes #11866
-
-Daniel Stenberg (16 Sep 2023)
-
-- doh: inherit DEBUGFUNCTION/DATA
-
- When creating new transfers for doing DoH, they now inherit the debug
- settings from the initiating transfer, so that the application can
- redirect and handle the verbose output correctly even for the DoH
- transfers.
-
- Reported-by: calvin2021y on github
- Fixes #11864
- Closes #11869
-
-Dan Fandrich (16 Sep 2023)
-
-- http_aws_sigv4: fix sorting with empty parts
-
- When comparing with an empty part, the non-empty one is always
- considered greater-than. Previously, the two would be considered equal
- which would randomly place empty parts amongst non-empty ones. This
- showed as a test 439 failure on Solaris as it uses a different
- implementation of qsort() that compares parts differently.
-
- Fixes #11855
- Closes #11868
-
-- CI: ignore the "flaky" and "timing-dependent" test results
-
- CI builds will now run these tests, but will ignore the results if they
- fail. The relevant tests are ones that are sensitive to timing or
- have edge conditions that make them more likely to fail on CI servers,
- which are often heavily overloaded and slow.
-
- This change only adds two additional tests to be ignored, since the
- others already had the flaky keyword.
-
- Closes #11865
-
-- runtests: eliminate a warning on old perl versions
-
- The warning "Use of implicit split to @_ is deprecated" showed between
- perl versions about 5.8 through 5.11.
-
-- tests: log the test result code after each libtest
-
- This makes it easier to determine the test status. Also, capitalize
- FAILURE and ABORT messages in log lines to make them easier to spot.
-
-Harry Sintonen (16 Sep 2023)
-
-- misc: better random strings
-
- Generate alphanumerical random strings.
-
- Prior this change curl used to create random hex strings. This was
- mostly okay, but having alphanumerical random strings is better: The
- strings have more entropy in the same space.
-
- The MIME multipart boundary used to be mere 64-bits of randomness due
- to being 16 hex chars. With these changes the boundary is 22
- alphanumerical chars, or little over 130 bits of randomness.
-
- Closes #11838
-
-Daniel Stenberg (15 Sep 2023)
-
-- cookie: reduce variable scope, add const
-
-- cookie: do not store the expire or max-age strings
-
- Convert it to an expire time at once and save memory.
-
- Closes #11862
-
-- cookie: remove unnecessary struct fields
-
- Plus: reduce the hash table size from 256 to 63. It seems unlikely to
- make much of a speed difference for most use cases but saves 1.5KB of
- data per instance.
-
- Closes #11862
-
-- RELEASE-NOTES: synced
-
- Bumped to 8.4.0, the next presumed version
-
-Dan Fandrich (14 Sep 2023)
-
-- test2600: remove special case handling for USE_ALARM_TIMEOUT
-
- This was originally added to handle platforms that supported only 1
- second granularity in connect timeouts, but after some recent changes
- the test currently permafails on several Windows platforms.
-
- The need for this special-case was removed in commit 8627416, which
- increased the connect timeout in all cases to well above 1 second.
-
- Fixes #11767
- Closes #11849
-
-Daniel Stenberg (14 Sep 2023)
-
-- SECURITY-PROCESS.md. call it vulnerability disclosure policy
-
- SECURITY-PROCESS.md -> VULN-DISCLOSURE-POLICY.md
-
- This a name commonly used for a document like this. This name helps
- users find it.
-
- Closes #11852
-
-Junho Choi (14 Sep 2023)
-
-- quiche: fix build error with --with-ca-fallback
-
- - Fix build error when curl is built with --with-quiche
- and --with-ca-fallback.
-
- - Add --with-ca-fallback to the quiche CI job.
-
- Fixes https://github.com/curl/curl/issues/11850
- Closes https://github.com/curl/curl/pull/11847
-
-Jay Satiro (14 Sep 2023)
-
-- escape: replace Curl_isunreserved with ISUNRESERVED
-
- - Use the ALLCAPS version of the macro so that it is clear a macro is
- being called that evaluates the variable multiple times.
-
- - Also capitalize macro isurlpuntcs => ISURLPUNTCS since it evaluates
- a variable multiple times.
-
- This is a follow-up to 291d225a which changed Curl_isunreserved into an
- alias macro for ISUNRESERVED. The problem is the former is not easily
- identified as a macro by the caller, which could lead to a bug.
-
- For example, ISUNRESERVED(*foo++) is easily identifiable as wrong but
- Curl_isunreserved(*foo++) is not even though they both are the same.
-
- Closes https://github.com/curl/curl/pull/11846
-
-Dan Fandrich (13 Sep 2023)
-
-- tests: increase the default server logs lock timeout
-
- This timeout is used to wait for the server to finish writing its logs
- before checking them against the expected values. An overloaded machine
- could take more than the two seconds previously allocated, so increase
- the timeout to 5 seconds.
-
- Ref: #11328
- Closes #11834
-
-- tests: increase TEST_HANG_TIMEOUT in two tests
-
- These tests had a 5 second timeout compared to 60 seconds for all other
- tests. Make these consistent with the others for more reliability on
- heavily-loaded machines.
-
- Ref: #11328
-
-- test1056: disable on Windows
-
- This test relies on the IPv6 scope field being ignored when connecting to
- ipv6-localhost (i.e. [::1%259999] is treated as [::1]). Maybe this is a bit
- dodgy, but it works on all our test platforms except Windows. This
- test was disabled manually on all Windows CI builds already, so instead
- add an incompatible feature and precheck so it's skipped on Windows
- everywhere automatically.
-
-- test587: add a slight delay after test
-
- This test is designed to connect to the server, then immediately send a
- few bytes and disconnect. In some situations, such as on a loaded
- server, this doesn't give the server enough time to write its lock file
- before its existence is checked. The test harness then fails to find the
- server's input log file (because it hasn't been written yet) and fails
- the test. By adding a short delay after the test, the HTTP server has
- enough time to write its lock file which gives itself more time to write
- its remaining files.
-
- Ref: #11328
-
-- tests: stop overriding the lock timeout
-
- These tests reduce the server lock wait timeout which can increase
- flakiness on loaded machines. Since this is merely an optimization,
- eliminate them in favour of reliability.
-
- Ref: #11328
-
-- tests: add some --expect100-timeout to reduce timing dependencies
-
- These tests can fail when the test machine is so slow that the test HTTP
- server didn't get a chance to complete before the client's one second
- 100-continue timeout triggered. Increase that 1 second to 999 seconds so
- this situation doesn't happen.
-
- Ref: #11328
-
-- test661: return from test early in case of curl error
-
-- tests: add the timing-dependent keyword on several tests
-
- These are ones likely to fail on heavily-loaded machines that alter the
- normal test timing. Most of these tests already had the flaky keyword
- since this condition makes them more likely to fail on CI.
-
-- test1592: greatly increase the maximum test timeout
-
- It was too short to be reliable on heavily loaded CI machines, and
- as a fail-safe only, it didn't need to be short.
-
- Ref: #11328
-
-- test: minor test cleanups
-
- Remove an obsolete block of code in tests 2032 & 576.
- Add a comment in test 1474.
-
-- tests: quadruple the %FTPTIME2 and %FTPTIME3 timeouts
-
- This gives more of a margin for error when running on overloaded CI
- servers.
-
- Ref: #11328
-
-- tests: improve SLOWDOWN test reliability by reducing sent data
-
- These tests are run in SLOWDOWN mode which adds a 10 msec delay after
- each character output, which means it takes at least 1.6 seconds (and
- 320 kernel calls) just to get through the long welcome banner. On an
- overloaded system, this can end up taking much more than 1.6 seconds,
- and even more than the 7 or 16 second curl timeout that the tests rely
- on, causing them to fail. Reducing the size of the welcome banner drops
- the total number of characters sent before the transfer starts by more
- than half, which reduces the opportunity for test-breaking slowdowns by
- the same amount.
-
- Ref: #11328
-
-- test650: fix an end tag typo
-
-Jay Satiro (13 Sep 2023)
-
-- tool_cb_wrt: fix debug assertion
-
- - Fix off-by-one out-of-bounds array index in Windows debug assertion.
-
- Bug: https://github.com/curl/curl/commit/af3f4e41#r127212213
- Reported-by: Gisle Vanem
-
-Daniel Stenberg (13 Sep 2023)
-
-- ctype: add ISUNRESERVED()
-
- ... and make Curl_isunreserved() use that macro instead of providing a
- separate funtion for the purpose.
-
- Closes #11840
-
-Version 8.3.0 (13 Sep 2023)
-
-Daniel Stenberg (13 Sep 2023)
-
-- RELEASE-NOTES: syn ced
-
- curl 8.3.0 release
-
-- THANKS: contributors from 8.3.0
-
-Thorsten Klein (12 Sep 2023)
-
-- cmake: set SIZEOF_LONG_LONG in curl_config.h
-
- in order to support 32bit builds regarding wolfssl CTC_SETTINGS
-
- Closes #11839
-
-Jay Satiro (12 Sep 2023)
-
-- curl_ngtcp2: fix error message
-
-- http_aws_sigv4: handle no-value user header entries
-
- - Handle user headers in format 'name:' and 'name;' with no value.
-
- The former is used when the user wants to remove an internal libcurl
- header and the latter is used when the user actually wants to send a
- no-value header in the format 'name:' (note the semi-colon is converted
- by libcurl to a colon).
-
- Prior to this change the AWS header import code did not special case
- either of those and the generated AWS SignedHeaders would be incorrect.
-
- Reported-by: apparentorder@users.noreply.github.com
-
- Ref: https://curl.se/docs/manpage.html#-H
-
- Fixes https://github.com/curl/curl/issues/11664
- Closes https://github.com/curl/curl/pull/11668
-
-Dan Fandrich (11 Sep 2023)
-
-- CI: run pytest with the -v option
-
- This lists of the test cases being run so it can be tracked over time.
-
- Closes #11824
-
-Daniel Stenberg (11 Sep 2023)
-
-- HTTP3: the msquic backend is not functional
-
- I ask that we do not submit bugs for this backend just yet as we know it
- does not fully work.
-
- Closes #11831
- Closes #11819
-
-- aws_sigv4: the query canon code miscounted URL encoded input
-
- Added some extra ampersands to test 439 to verify "blank" query parts
-
- Follow-up to fc76a24c53b08cdf
-
- Closes #11829
-
-vvb2060 (11 Sep 2023)
-
-- quic: don't set SNI if hostname is an IP address
-
- We already do this for TLS connections.
-
- RFC 6066 says: Literal IPv4 and IPv6 addresses are not permitted in
- "HostName".
-
- Ref: https://www.rfc-editor.org/rfc/rfc6066#section-3
-
- Fixes https://github.com/curl/curl/issues/11827
- Closes https://github.com/curl/curl/pull/11828
-
-Daniel Stenberg (10 Sep 2023)
-
-- RELEASE-NOTES: synced
diff --git a/libs/libcurl/docs/THANKS b/libs/libcurl/docs/THANKS
index ecd6e9eb9a..7910255eda 100644
--- a/libs/libcurl/docs/THANKS
+++ b/libs/libcurl/docs/THANKS
@@ -19,6 +19,7 @@ Aaron Oneal
Aaron Orenstein
Aaron Scarisbrick
aasivov on github
+Abdullah Alyan
Abhinav Singh
Abram Pousada
accountantM on github
@@ -181,6 +182,7 @@ Andrei Sedoi
Andrei Valeriu BICA
Andrei Virtosu
Andrej E Baranov
+Andrew
Andrew Barnert
Andrew Barnes
Andrew Benham
@@ -225,6 +227,7 @@ Anthony Hu
Anthony Ramine
Anthony Shaw
Antoine Aubert
+Antoine Bollengier
Antoine Calando
Antoine du Hamel
Antoine Pietri
@@ -357,6 +360,7 @@ Björn Stenberg
black-desk on github
Blaise Potard
Blake Burkhart
+blankie
bnfp on github
Bo Anderson
Bob Relyea
@@ -455,6 +459,7 @@ cbartl on github
cclauss on github
Cering on github
Cesar Eduardo Barros
+Ch40zz on github
Chad Monroe
Chandrakant Bagul
Chara White
@@ -540,6 +545,7 @@ Colin Blair
Colin Cross
Colin Hogben
Colin Leroy
+Colin Leroy-Mira
Colin O'Dell
Colin Watson
Colm Buckley
@@ -573,6 +579,7 @@ d912e3 on github
Da-Yoon Chung
daboul on github
Dag Ekengren
+Dagfinn Ilmari Mannsåker
Dagobert Michelsen
Daiki Ueno
Dair Grant
@@ -604,6 +611,7 @@ Daniel Faust
Daniel Gustafsson
Daniel Hallberg
Daniel Hwang
+Daniel J. H.
Daniel Jeliński
Daniel Johnson
Daniel Kahn Gillmor
@@ -613,6 +621,7 @@ Daniel Kurečka
Daniel Lee Hwang
Daniel Lublin
Daniel Marjamäki
+Daniel McCarney
Daniel Melani
Daniel Mentz
Daniel Romero
@@ -912,6 +921,7 @@ Fabrizio Ammollo
Fahim Chandurwala
Faizur Rahman
Faraz Fallahi
+farazrbx on github
Farzin on github
Fata Nugraha
Fawad Mirza
@@ -974,6 +984,7 @@ FuccDucc on github
Fujii Hironori
fullincome on github
fundawang on github
+fuzzard
Gabe
Gabriel Corona
Gabriel Kuri
@@ -1033,6 +1044,7 @@ Glenn Sheridan
Glenn Strauss
godmar on github
Godwin Stewart
+Gonçalo Carvalho
Google Inc.
Gordon Marler
Gorilla Maguila
@@ -1067,6 +1079,7 @@ Gunter Knauf
guoxinvmware on github
Gustaf Hui
Gustavo Grieco
+Gusted
Guy Poizat
GwanYeong Kim
Gwen Shapira
@@ -1079,6 +1092,7 @@ Hagai Auro
Haibo Huang
Hakan Sunay Halil
Hamish Mackenzie
+hammlee96 on github
hamstergene on github
Han Han
Han Qiao
@@ -1095,6 +1109,7 @@ Hans-Jurgen May
Hao Wu
Hardeep Singh
Haris Okanovic
+Harmen Stoppels
Harold Stuart
Harry Mallon
Harry Sarson
@@ -1130,6 +1145,7 @@ Hiroki Kurosawa
Hirotaka Tagawa
Ho-chi Chen
Hoi-Ho Chan
+Hongfei Li
Hongli Lai
Hongyi Zhao
Howard Blaise
@@ -1192,6 +1208,7 @@ Isaac Boukris
Isaiah Norton
Ishan SinghLevett
Ithubg on github
+Ivan
Ivan Avdeev
Ivan Tsybulin
ivanfywang
@@ -1353,6 +1370,7 @@ Jiri Dvorak
Jiri Hruska
Jiri Jaburek
Jishan Shaikh
+Jiwoo Park
Jiří Bok
Jiří Malák
jmdavitt on github
@@ -1372,6 +1390,7 @@ Johan Anderson
Johan Lantz
Johan Nilsson
Johan van Selst
+Johann Sebastian Schicho
Johann150 on github
Johannes Bauer
Johannes Ernst
@@ -1513,6 +1532,7 @@ jzinn on github
János Fekete
Jérémy Rabasco
Jérémy Rocher
+Jérôme Leclercq
Jörg Mueller-Tolk
Jörn Hartroth
Jürgen Gmach
@@ -1524,7 +1544,9 @@ Kai Noda
Kai Pastor
Kai Sommerfeld
Kai-Uwe Rommel
+Kailun Qin
Kalle Vahlman
+kalvdans on github
Kamil Dudka
Kane York
Kang Lin
@@ -1592,12 +1614,13 @@ Koichi Shiraishi
kokke on github
Konstantin Isakov
Konstantin Kushnir
+Konstantin Kuzov
Konstantin Vlasov
KotlinIsland on github
kotoriのねこ
kouzhudong on github
Kovalkov Dmitrii
-kpcyrd
+kpcyrd on github
kreshano on github
Kris Kennaway
Krishnendu Majumdar
@@ -1709,6 +1732,7 @@ Luca Niccoli
Lucas Adamski
Lucas Clemente Vella
Lucas Holt
+Lucas Nussbaum
Lucas Pardue
Lucas Servén Marín
Lucas Severo
@@ -1740,6 +1764,7 @@ Maciej Puzio
Maciej W. Rozycki
madblobfish on github
MaeIsBad on github
+magisterquis on hackerone
Mahmoud Samir Fayed
Maks Naumov
Maksim Arhipov
@@ -1917,6 +1942,7 @@ Median Median Stride
mehatzri on github
Mehmet Bozkurt
Mekonikum
+Mel Zuser
Melissa Mears
Melroy van den Berg
Mert Yazıcıoğlu
@@ -1948,6 +1974,7 @@ Michael Kolechkin
Michael Kujawa
Michael König
Michael Lee
+Michael Litwak
Michael Maltese
Michael Mealling
Michael Mueller
@@ -2203,6 +2230,7 @@ Pau Garcia i Quiles
Paul B. Omta
Paul Donohue
Paul Dreik
+Paul Gilmartin
Paul Groke
Paul Harrington
Paul Harris
@@ -2224,6 +2252,7 @@ Paulo Roberto Tomasi
Pavel Cenek
Pavel Gushchin
Pavel Kalyugin
+Pavel Kropachev
Pavel Löbl
Pavel Mayorov
Pavel Orehov
@@ -2352,6 +2381,7 @@ Rafael Sagula
Rafayel Mkrtchyan
Rafaël Carré
Rafał Mikrut
+Rahul Krishna M
Rainer Canavan
Rainer Jung
Rainer Koenig
@@ -2398,10 +2428,12 @@ Renaud Guillard
Renaud Lehoux
Rene Bernhardt
Rene Rebe
+renovate[bot]
Reuven Wachtfogel
RevaliQaQ on github
Reza Arbab
Rianov Viacheslav
+riastradh on github
Ricardo Cadime
Ricardo Gomes
Ricardo M. Correia
@@ -2572,6 +2604,7 @@ SandakovMM on github
Sander Gates
Sandor Feldi
Sandro Jaeckel
+Sanjay Pujare
Santhana Todatry
Santino Keupp
Saqib Ali
@@ -2683,6 +2716,7 @@ Sohom Datta
Somnath Kundu
Song Ma
Sonia Subramanian
+southernedge on github
Spacen Jasset
Spezifant on github
Spiridonoff A.V
@@ -2730,6 +2764,7 @@ Stephane Pellegrino
Stephen Boost
Stephen Brokenshire
Stephen Collyer
+Stephen Farrell
Stephen Kick
Stephen M. Coakley
Stephen More
@@ -2915,6 +2950,7 @@ Ton Voon
Toni Moreno
Tony Kelman
tonystz on Github
+Toon Claes
Toon Verwaest
Tor Arntsen
Torben Dannhauer
@@ -2931,6 +2967,8 @@ Trivikram Kamat
Troels Walsted Hansen
Troy Engel
trrui-huawei
+Trumeet on github
+Trzik on github
Tseng Jun
Tuomas Siipola
Tuomo Rinne
@@ -3117,6 +3155,7 @@ zhihaoy on github
Zhouyihai Ding
ZimCodes on github
zloi-user on github
+zmcx16 on github
Zmey Petroff
Zvi Har'El
zzq1015 on github
diff --git a/libs/libcurl/include/curl/curl.h b/libs/libcurl/include/curl/curl.h
index 3775ac8af9..48e28f543b 100644
--- a/libs/libcurl/include/curl/curl.h
+++ b/libs/libcurl/include/curl/curl.h
@@ -632,6 +632,7 @@ typedef enum {
CURLE_SSL_CLIENTCERT, /* 98 - client-side certificate required */
CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */
CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */
+ CURLE_ECH_REQUIRED, /* 101 - ECH tried but failed */
CURL_LAST /* never use! */
} CURLcode;
@@ -811,7 +812,10 @@ typedef enum {
#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE
#define CURLAUTH_NTLM (((unsigned long)1)<<3)
#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4)
+#ifndef CURL_NO_OLDIES
+ /* functionality removed since 8.8.0 */
#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5)
+#endif
#define CURLAUTH_BEARER (((unsigned long)1)<<6)
#define CURLAUTH_AWS_SIGV4 (((unsigned long)1)<<7)
#define CURLAUTH_ONLY (((unsigned long)1)<<31)
@@ -2206,6 +2210,9 @@ typedef enum {
/* millisecond version */
CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324),
+ /* set ECH configuration */
+ CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 325),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
@@ -2311,30 +2318,26 @@ enum CURL_NETRC_OPTION {
CURL_NETRC_LAST
};
-enum {
- CURL_SSLVERSION_DEFAULT,
- CURL_SSLVERSION_TLSv1, /* TLS 1.x */
- CURL_SSLVERSION_SSLv2,
- CURL_SSLVERSION_SSLv3,
- CURL_SSLVERSION_TLSv1_0,
- CURL_SSLVERSION_TLSv1_1,
- CURL_SSLVERSION_TLSv1_2,
- CURL_SSLVERSION_TLSv1_3,
-
- CURL_SSLVERSION_LAST /* never use, keep last */
-};
+#define CURL_SSLVERSION_DEFAULT 0
+#define CURL_SSLVERSION_TLSv1 1 /* TLS 1.x */
+#define CURL_SSLVERSION_SSLv2 2
+#define CURL_SSLVERSION_SSLv3 3
+#define CURL_SSLVERSION_TLSv1_0 4
+#define CURL_SSLVERSION_TLSv1_1 5
+#define CURL_SSLVERSION_TLSv1_2 6
+#define CURL_SSLVERSION_TLSv1_3 7
-enum {
- CURL_SSLVERSION_MAX_NONE = 0,
- CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16),
- CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16),
- CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16),
- CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16),
- CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16),
+#define CURL_SSLVERSION_LAST 8 /* never use, keep last */
+
+#define CURL_SSLVERSION_MAX_NONE 0
+#define CURL_SSLVERSION_MAX_DEFAULT (CURL_SSLVERSION_TLSv1 << 16)
+#define CURL_SSLVERSION_MAX_TLSv1_0 (CURL_SSLVERSION_TLSv1_0 << 16)
+#define CURL_SSLVERSION_MAX_TLSv1_1 (CURL_SSLVERSION_TLSv1_1 << 16)
+#define CURL_SSLVERSION_MAX_TLSv1_2 (CURL_SSLVERSION_TLSv1_2 << 16)
+#define CURL_SSLVERSION_MAX_TLSv1_3 (CURL_SSLVERSION_TLSv1_3 << 16)
/* never use, keep last */
- CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16)
-};
+#define CURL_SSLVERSION_MAX_LAST (CURL_SSLVERSION_LAST << 16)
enum CURL_TLSAUTH {
CURL_TLSAUTH_NONE,
@@ -3035,17 +3038,18 @@ CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *share);
*/
typedef enum {
- CURLVERSION_FIRST,
- CURLVERSION_SECOND,
- CURLVERSION_THIRD,
- CURLVERSION_FOURTH,
- CURLVERSION_FIFTH,
- CURLVERSION_SIXTH,
- CURLVERSION_SEVENTH,
- CURLVERSION_EIGHTH,
- CURLVERSION_NINTH,
- CURLVERSION_TENTH,
- CURLVERSION_ELEVENTH,
+ CURLVERSION_FIRST, /* 7.10 */
+ CURLVERSION_SECOND, /* 7.11.1 */
+ CURLVERSION_THIRD, /* 7.12.0 */
+ CURLVERSION_FOURTH, /* 7.16.1 */
+ CURLVERSION_FIFTH, /* 7.57.0 */
+ CURLVERSION_SIXTH, /* 7.66.0 */
+ CURLVERSION_SEVENTH, /* 7.70.0 */
+ CURLVERSION_EIGHTH, /* 7.72.0 */
+ CURLVERSION_NINTH, /* 7.75.0 */
+ CURLVERSION_TENTH, /* 7.77.0 */
+ CURLVERSION_ELEVENTH, /* 7.87.0 */
+ CURLVERSION_TWELFTH, /* 8.8.0 */
CURLVERSION_LAST /* never actually use this */
} CURLversion;
@@ -3054,7 +3058,7 @@ typedef enum {
meant to be a built-in version number for what kind of struct the caller
expects. If the struct ever changes, we redefine the NOW to another enum
from above. */
-#define CURLVERSION_NOW CURLVERSION_ELEVENTH
+#define CURLVERSION_NOW CURLVERSION_TWELFTH
struct curl_version_info_data {
CURLversion age; /* age of the returned struct */
@@ -3114,6 +3118,9 @@ struct curl_version_info_data {
/* These fields were added in CURLVERSION_ELEVENTH */
/* feature_names is terminated by an entry with a NULL feature name */
const char * const *feature_names;
+
+ /* These fields were added in CURLVERSION_TWELFTH */
+ const char *rtmp_version; /* human readable string. */
};
typedef struct curl_version_info_data curl_version_info_data;
@@ -3154,7 +3161,7 @@ typedef struct curl_version_info_data curl_version_info_data;
#define CURL_VERSION_GSASL (1<<29) /* libgsasl is supported */
#define CURL_VERSION_THREADSAFE (1<<30) /* libcurl API is thread-safe */
- /*
+/*
* NAME curl_version_info()
*
* DESCRIPTION
diff --git a/libs/libcurl/include/curl/curlver.h b/libs/libcurl/include/curl/curlver.h
index b2ac5a66d6..7faa482afc 100644
--- a/libs/libcurl/include/curl/curlver.h
+++ b/libs/libcurl/include/curl/curlver.h
@@ -32,13 +32,13 @@
/* This is the version number of the libcurl package from which this header
file origins: */
-#define LIBCURL_VERSION "8.7.1"
+#define LIBCURL_VERSION "8.8.0"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 8
-#define LIBCURL_VERSION_MINOR 7
-#define LIBCURL_VERSION_PATCH 1
+#define LIBCURL_VERSION_MINOR 8
+#define LIBCURL_VERSION_PATCH 0
/* This is the numeric version of the libcurl version number, meant for easier
parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
@@ -59,7 +59,7 @@
CURL_VERSION_BITS() macro since curl's own configure script greps for it
and needs it to contain the full number.
*/
-#define LIBCURL_VERSION_NUM 0x080701
+#define LIBCURL_VERSION_NUM 0x080800
/*
* This is the date and time when the full source package was created. The
@@ -70,7 +70,7 @@
*
* "2007-11-23"
*/
-#define LIBCURL_TIMESTAMP "2024-03-27"
+#define LIBCURL_TIMESTAMP "2024-05-22"
#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
#define CURL_AT_LEAST_VERSION(x,y,z) \
diff --git a/libs/libcurl/include/curl/multi.h b/libs/libcurl/include/curl/multi.h
index 9ea91ef7a1..9a808f1f99 100644
--- a/libs/libcurl/include/curl/multi.h
+++ b/libs/libcurl/include/curl/multi.h
@@ -464,6 +464,20 @@ typedef int (*curl_push_callback)(CURL *parent,
struct curl_pushheaders *headers,
void *userp);
+/*
+ * Name: curl_multi_waitfds()
+ *
+ * Desc: Ask curl for fds for polling. The app can use these to poll on.
+ * We want curl_multi_perform() called as soon as one of them are
+ * ready. Passing zero size allows to get just a number of fds.
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_waitfds(CURLM *multi,
+ struct curl_waitfd *ufds,
+ unsigned int size,
+ unsigned int *fd_count);
+
#ifdef __cplusplus
} /* end of extern "C" */
#endif
diff --git a/libs/libcurl/include/curl/typecheck-gcc.h b/libs/libcurl/include/curl/typecheck-gcc.h
index b3fb12b358..8fd0d91e60 100644
--- a/libs/libcurl/include/curl/typecheck-gcc.h
+++ b/libs/libcurl/include/curl/typecheck-gcc.h
@@ -275,6 +275,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_DNS_LOCAL_IP6 || \
(option) == CURLOPT_DNS_SERVERS || \
(option) == CURLOPT_DOH_URL || \
+ (option) == CURLOPT_ECH || \
(option) == CURLOPT_EGDSOCKET || \
(option) == CURLOPT_FTP_ACCOUNT || \
(option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \
diff --git a/libs/libcurl/include/curl/urlapi.h b/libs/libcurl/include/curl/urlapi.h
index f5f2a2b771..b65735cf62 100644
--- a/libs/libcurl/include/curl/urlapi.h
+++ b/libs/libcurl/include/curl/urlapi.h
@@ -99,6 +99,9 @@ typedef enum {
#define CURLU_ALLOW_SPACE (1<<11) /* Allow spaces in the URL */
#define CURLU_PUNYCODE (1<<12) /* get the host name in punycode */
#define CURLU_PUNY2IDN (1<<13) /* punycode => IDN conversion */
+#define CURLU_GET_EMPTY (1<<14) /* allow empty queries and fragments
+ when extracting the URL or the
+ components */
typedef struct Curl_URL CURLU;
diff --git a/libs/libcurl/libcurl.vcxproj b/libs/libcurl/libcurl.vcxproj
index d4e3f36ede..f5d856fa6e 100644
--- a/libs/libcurl/libcurl.vcxproj
+++ b/libs/libcurl/libcurl.vcxproj
@@ -110,9 +110,6 @@
<ClCompile Include="src\curl_ntlm_core.c">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
- <ClCompile Include="src\curl_ntlm_wb.c">
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- </ClCompile>
<ClCompile Include="src\curl_path.c">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
@@ -143,6 +140,9 @@
<ClCompile Include="src\dict.c">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
+ <ClCompile Include="src\dllmain.c">
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
<ClCompile Include="src\doh.c">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
@@ -443,6 +443,9 @@
<ClCompile Include="src\vtls\bearssl.c">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
+ <ClCompile Include="src\vtls\cipher_suite.c">
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
<ClCompile Include="src\vtls\gtls.c">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
@@ -529,7 +532,6 @@
<ClInclude Include="src\curl_memrchr.h" />
<ClInclude Include="src\curl_multibyte.h" />
<ClInclude Include="src\curl_ntlm_core.h" />
- <ClInclude Include="src\curl_ntlm_wb.h" />
<ClInclude Include="src\curl_path.h" />
<ClInclude Include="src\curl_printf.h" />
<ClInclude Include="src\curl_range.h" />
diff --git a/libs/libcurl/libcurl.vcxproj.filters b/libs/libcurl/libcurl.vcxproj.filters
index e5c1ab0b62..21b78bd068 100644
--- a/libs/libcurl/libcurl.vcxproj.filters
+++ b/libs/libcurl/libcurl.vcxproj.filters
@@ -86,9 +86,6 @@
<ClCompile Include="src\curl_ntlm_core.c">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="src\curl_ntlm_wb.c">
- <Filter>Source Files</Filter>
- </ClCompile>
<ClCompile Include="src\curl_path.c">
<Filter>Source Files</Filter>
</ClCompile>
@@ -119,6 +116,9 @@
<ClCompile Include="src\dict.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\dllmain.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="src\doh.c">
<Filter>Source Files</Filter>
</ClCompile>
@@ -416,6 +416,9 @@
<ClCompile Include="src\vtls\bearssl.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\vtls\cipher_suite.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="src\vtls\gtls.c">
<Filter>Source Files</Filter>
</ClCompile>
@@ -628,9 +631,6 @@
<ClInclude Include="src\curl_ntlm_core.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="src\curl_ntlm_wb.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="src\curl_path.h">
<Filter>Header Files</Filter>
</ClInclude>
diff --git a/libs/libcurl/src/CMakeLists.txt b/libs/libcurl/src/CMakeLists.txt
index dd0e8dfe1a..47392ca79e 100644
--- a/libs/libcurl/src/CMakeLists.txt
+++ b/libs/libcurl/src/CMakeLists.txt
@@ -31,9 +31,10 @@ configure_file(curl_config.h.cmake
transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
-list(APPEND HHEADERS
- ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
- )
+# DllMain is added later for DLL builds only.
+list(REMOVE_ITEM CSOURCES dllmain.c)
+
+list(APPEND HHEADERS ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
# The rest of the build
@@ -55,6 +56,7 @@ if(BUILD_TESTING)
${HHEADERS} ${CSOURCES}
)
target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB)
+ target_link_libraries(curlu PRIVATE ${CURL_LIBS})
endif()
if(ENABLE_CURLDEBUG)
@@ -63,10 +65,6 @@ if(ENABLE_CURLDEBUG)
set_source_files_properties(memdebug.c curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
endif()
-if(BUILD_TESTING)
- target_link_libraries(curlu PRIVATE ${CURL_LIBS})
-endif()
-
transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)
@@ -114,17 +112,17 @@ if(NOT DEFINED SHARE_LIB_OBJECT)
endif()
endif()
-if(WIN32)
- # Define CURL_STATICLIB always, to disable __declspec(dllexport) for exported
- # libcurl symbols. We handle exports via libcurl.def instead. Except with
- # symbol hiding disabled or debug mode enabled, when we export _all_ symbols
- # from libcurl DLL, without using libcurl.def.
- add_definitions("-DCURL_STATICLIB")
-endif()
-
if(SHARE_LIB_OBJECT)
set(LIB_OBJECT "libcurl_object")
add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES})
+ if(WIN32)
+ # Define CURL_STATICLIB always, to disable __declspec(dllexport) for
+ # exported libcurl symbols. We handle exports via libcurl.def instead.
+ # Except with symbol hiding disabled or debug mode enabled, when we export
+ # _all_ symbols from libcurl DLL, without using libcurl.def.
+ set_property(TARGET ${LIB_OBJECT} APPEND
+ PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
+ endif()
target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS})
set_target_properties(${LIB_OBJECT} PROPERTIES
POSITION_INDEPENDENT_CODE ON)
@@ -152,6 +150,10 @@ if(BUILD_STATIC_LIBS)
list(APPEND libcurl_export ${LIB_STATIC})
add_library(${LIB_STATIC} STATIC ${LIB_SOURCE})
add_library(${PROJECT_NAME}::${LIB_STATIC} ALIAS ${LIB_STATIC})
+ if(WIN32)
+ set_property(TARGET ${LIB_OBJECT} APPEND
+ PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
+ endif()
target_link_libraries(${LIB_STATIC} PRIVATE ${CURL_LIBS})
# Remove the "lib" prefix since the library is already named "libcurl".
set_target_properties(${LIB_STATIC} PROPERTIES
@@ -181,6 +183,15 @@ if(BUILD_SHARED_LIBS)
list(APPEND libcurl_export ${LIB_SHARED})
add_library(${LIB_SHARED} SHARED ${LIB_SOURCE})
add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
+ if(WIN32 OR CYGWIN)
+ if(CYGWIN)
+ # For cygwin always compile dllmain.c as a separate unit since it
+ # includes windows.h, which shouldn't be included in other units.
+ set_source_files_properties(dllmain.c PROPERTIES
+ SKIP_UNITY_BUILD_INCLUSION ON)
+ endif()
+ set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES dllmain.c)
+ endif()
if(WIN32)
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
if(HIDES_CURL_PRIVATE_SYMBOLS)
diff --git a/libs/libcurl/src/Makefile.am b/libs/libcurl/src/Makefile.am
index 5cab1cc00f..4fe1ef7f74 100644
--- a/libs/libcurl/src/Makefile.am
+++ b/libs/libcurl/src/Makefile.am
@@ -25,11 +25,10 @@ AUTOMAKE_OPTIONS = foreign nostdinc
CMAKE_DIST = CMakeLists.txt curl_config.h.cmake
-EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h \
- config-riscos.h config-mac.h curl_config.h.in config-dos.h \
- libcurl.plist libcurl.rc config-amigaos.h config-win32ce.h \
- config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc \
- Makefile.soname
+EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h \
+ config-riscos.h config-mac.h curl_config.h.in config-dos.h libcurl.rc \
+ config-amigaos.h config-win32ce.h config-os400.h setup-os400.h \
+ $(CMAKE_DIST) setup-win32.h .checksrc Makefile.soname
lib_LTLIBRARIES = libcurl.la
diff --git a/libs/libcurl/src/Makefile.in b/libs/libcurl/src/Makefile.in
index 7940068ba5..4f0c9d1651 100644
--- a/libs/libcurl/src/Makefile.in
+++ b/libs/libcurl/src/Makefile.in
@@ -179,7 +179,7 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = curl_config.h
-CONFIG_CLEAN_FILES = libcurl.vers libcurl.plist
+CONFIG_CLEAN_FILES = libcurl.vers
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
@@ -217,45 +217,44 @@ am__libcurl_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \
cfilters.c conncache.c connect.c content_encoding.c cookie.c \
curl_addrinfo.c curl_des.c curl_endian.c curl_fnmatch.c \
curl_get_line.c curl_gethostname.c curl_gssapi.c \
- curl_memrchr.c curl_multibyte.c curl_ntlm_core.c \
- curl_ntlm_wb.c curl_path.c curl_range.c curl_rtmp.c \
- curl_sasl.c curl_sha512_256.c curl_sspi.c curl_threads.c \
- curl_trc.c cw-out.c dict.c doh.c dynbuf.c dynhds.c easy.c \
- easygetopt.c easyoptions.c escape.c file.c fileinfo.c fopen.c \
- formdata.c ftp.c ftplistparser.c getenv.c getinfo.c gopher.c \
- hash.c headers.c hmac.c hostasyn.c hostip.c hostip4.c \
- hostip6.c hostsyn.c hsts.c http.c http1.c http2.c \
- http_aws_sigv4.c http_chunks.c http_digest.c http_negotiate.c \
- http_ntlm.c http_proxy.c idn.c if2ip.c imap.c inet_ntop.c \
- inet_pton.c krb5.c ldap.c llist.c macos.c md4.c md5.c \
- memdebug.c mime.c mprintf.c mqtt.c multi.c netrc.c nonblock.c \
- noproxy.c openldap.c parsedate.c pingpong.c pop3.c progress.c \
- psl.c rand.c rename.c request.c rtsp.c select.c sendf.c \
- setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c \
- socks.c socks_gssapi.c socks_sspi.c speedcheck.c splay.c \
- strcase.c strdup.c strerror.c strtok.c strtoofft.c \
- system_win32.c telnet.c tftp.c timediff.c timeval.c transfer.c \
- url.c urlapi.c version.c version_win32.c warnless.c ws.c \
- vauth/cleartext.c vauth/cram.c vauth/digest.c \
- vauth/digest_sspi.c vauth/gsasl.c vauth/krb5_gssapi.c \
- vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c \
- vauth/oauth2.c vauth/spnego_gssapi.c vauth/spnego_sspi.c \
- vauth/vauth.c vtls/bearssl.c vtls/gtls.c vtls/hostcheck.c \
- vtls/keylog.c vtls/mbedtls.c vtls/mbedtls_threadlock.c \
- vtls/openssl.c vtls/rustls.c vtls/schannel.c \
- vtls/schannel_verify.c vtls/sectransp.c vtls/vtls.c \
- vtls/wolfssl.c vtls/x509asn1.c vquic/curl_msh3.c \
- vquic/curl_ngtcp2.c vquic/curl_osslq.c vquic/curl_quiche.c \
- vquic/vquic.c vquic/vquic-tls.c vssh/libssh.c vssh/libssh2.c \
- vssh/wolfssh.c altsvc.h amigaos.h arpa_telnet.h asyn.h bufq.h \
- bufref.h c-hyper.h cf-h1-proxy.h cf-h2-proxy.h cf-haproxy.h \
- cf-https-connect.h cf-socket.h cfilters.h conncache.h \
- connect.h content_encoding.h cookie.h curl_addrinfo.h \
- curl_base64.h curl_ctype.h curl_des.h curl_endian.h \
- curl_fnmatch.h curl_get_line.h curl_gethostname.h \
- curl_gssapi.h curl_hmac.h curl_krb5.h curl_ldap.h curl_md4.h \
- curl_md5.h curl_memory.h curl_memrchr.h curl_multibyte.h \
- curl_ntlm_core.h curl_ntlm_wb.h curl_path.h curl_printf.h \
+ curl_memrchr.c curl_multibyte.c curl_ntlm_core.c curl_path.c \
+ curl_range.c curl_rtmp.c curl_sasl.c curl_sha512_256.c \
+ curl_sspi.c curl_threads.c curl_trc.c cw-out.c dict.c \
+ dllmain.c doh.c dynbuf.c dynhds.c easy.c easygetopt.c \
+ easyoptions.c escape.c file.c fileinfo.c fopen.c formdata.c \
+ ftp.c ftplistparser.c getenv.c getinfo.c gopher.c hash.c \
+ headers.c hmac.c hostasyn.c hostip.c hostip4.c hostip6.c \
+ hostsyn.c hsts.c http.c http1.c http2.c http_aws_sigv4.c \
+ http_chunks.c http_digest.c http_negotiate.c http_ntlm.c \
+ http_proxy.c idn.c if2ip.c imap.c inet_ntop.c inet_pton.c \
+ krb5.c ldap.c llist.c macos.c md4.c md5.c memdebug.c mime.c \
+ mprintf.c mqtt.c multi.c netrc.c nonblock.c noproxy.c \
+ openldap.c parsedate.c pingpong.c pop3.c progress.c psl.c \
+ rand.c rename.c request.c rtsp.c select.c sendf.c setopt.c \
+ sha256.c share.c slist.c smb.c smtp.c socketpair.c socks.c \
+ socks_gssapi.c socks_sspi.c speedcheck.c splay.c strcase.c \
+ strdup.c strerror.c strtok.c strtoofft.c system_win32.c \
+ telnet.c tftp.c timediff.c timeval.c transfer.c url.c urlapi.c \
+ version.c version_win32.c warnless.c ws.c vauth/cleartext.c \
+ vauth/cram.c vauth/digest.c vauth/digest_sspi.c vauth/gsasl.c \
+ vauth/krb5_gssapi.c vauth/krb5_sspi.c vauth/ntlm.c \
+ vauth/ntlm_sspi.c vauth/oauth2.c vauth/spnego_gssapi.c \
+ vauth/spnego_sspi.c vauth/vauth.c vtls/bearssl.c \
+ vtls/cipher_suite.c vtls/gtls.c vtls/hostcheck.c vtls/keylog.c \
+ vtls/mbedtls.c vtls/mbedtls_threadlock.c vtls/openssl.c \
+ vtls/rustls.c vtls/schannel.c vtls/schannel_verify.c \
+ vtls/sectransp.c vtls/vtls.c vtls/wolfssl.c vtls/x509asn1.c \
+ vquic/curl_msh3.c vquic/curl_ngtcp2.c vquic/curl_osslq.c \
+ vquic/curl_quiche.c vquic/vquic.c vquic/vquic-tls.c \
+ vssh/libssh.c vssh/libssh2.c vssh/wolfssh.c altsvc.h amigaos.h \
+ arpa_telnet.h asyn.h bufq.h bufref.h c-hyper.h cf-h1-proxy.h \
+ cf-h2-proxy.h cf-haproxy.h cf-https-connect.h cf-socket.h \
+ cfilters.h conncache.h connect.h content_encoding.h cookie.h \
+ curl_addrinfo.h curl_base64.h curl_ctype.h curl_des.h \
+ curl_endian.h curl_fnmatch.h curl_get_line.h \
+ curl_gethostname.h curl_gssapi.h curl_hmac.h curl_krb5.h \
+ curl_ldap.h curl_md4.h curl_md5.h curl_memory.h curl_memrchr.h \
+ curl_multibyte.h curl_ntlm_core.h curl_path.h curl_printf.h \
curl_range.h curl_rtmp.h curl_sasl.h curl_setup.h \
curl_setup_once.h curl_sha256.h curl_sha512_256.h curl_sspi.h \
curl_threads.h curl_trc.h curlx.h cw-out.h dict.h doh.h \
@@ -274,13 +273,13 @@ am__libcurl_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \
telnet.h tftp.h timediff.h timeval.h transfer.h url.h \
urlapi-int.h urldata.h version_win32.h warnless.h ws.h \
vauth/digest.h vauth/ntlm.h vauth/vauth.h vtls/bearssl.h \
- vtls/gtls.h vtls/hostcheck.h vtls/keylog.h vtls/mbedtls.h \
- vtls/mbedtls_threadlock.h vtls/openssl.h vtls/rustls.h \
- vtls/schannel.h vtls/schannel_int.h vtls/sectransp.h \
- vtls/vtls.h vtls/vtls_int.h vtls/wolfssl.h vtls/x509asn1.h \
- vquic/curl_msh3.h vquic/curl_ngtcp2.h vquic/curl_osslq.h \
- vquic/curl_quiche.h vquic/vquic.h vquic/vquic_int.h \
- vquic/vquic-tls.h vssh/ssh.h libcurl.rc
+ vtls/cipher_suite.h vtls/gtls.h vtls/hostcheck.h vtls/keylog.h \
+ vtls/mbedtls.h vtls/mbedtls_threadlock.h vtls/openssl.h \
+ vtls/rustls.h vtls/schannel.h vtls/schannel_int.h \
+ vtls/sectransp.h vtls/vtls.h vtls/vtls_int.h vtls/wolfssl.h \
+ vtls/x509asn1.h vquic/curl_msh3.h vquic/curl_ngtcp2.h \
+ vquic/curl_osslq.h vquic/curl_quiche.h vquic/vquic.h \
+ vquic/vquic_int.h vquic/vquic-tls.h vssh/ssh.h libcurl.rc
am__objects_1 = libcurl_la-altsvc.lo libcurl_la-amigaos.lo \
libcurl_la-asyn-ares.lo libcurl_la-asyn-thread.lo \
libcurl_la-base64.lo libcurl_la-bufq.lo libcurl_la-bufref.lo \
@@ -294,13 +293,13 @@ am__objects_1 = libcurl_la-altsvc.lo libcurl_la-amigaos.lo \
libcurl_la-curl_fnmatch.lo libcurl_la-curl_get_line.lo \
libcurl_la-curl_gethostname.lo libcurl_la-curl_gssapi.lo \
libcurl_la-curl_memrchr.lo libcurl_la-curl_multibyte.lo \
- libcurl_la-curl_ntlm_core.lo libcurl_la-curl_ntlm_wb.lo \
- libcurl_la-curl_path.lo libcurl_la-curl_range.lo \
- libcurl_la-curl_rtmp.lo libcurl_la-curl_sasl.lo \
- libcurl_la-curl_sha512_256.lo libcurl_la-curl_sspi.lo \
- libcurl_la-curl_threads.lo libcurl_la-curl_trc.lo \
- libcurl_la-cw-out.lo libcurl_la-dict.lo libcurl_la-doh.lo \
- libcurl_la-dynbuf.lo libcurl_la-dynhds.lo libcurl_la-easy.lo \
+ libcurl_la-curl_ntlm_core.lo libcurl_la-curl_path.lo \
+ libcurl_la-curl_range.lo libcurl_la-curl_rtmp.lo \
+ libcurl_la-curl_sasl.lo libcurl_la-curl_sha512_256.lo \
+ libcurl_la-curl_sspi.lo libcurl_la-curl_threads.lo \
+ libcurl_la-curl_trc.lo libcurl_la-cw-out.lo libcurl_la-dict.lo \
+ libcurl_la-dllmain.lo libcurl_la-doh.lo libcurl_la-dynbuf.lo \
+ libcurl_la-dynhds.lo libcurl_la-easy.lo \
libcurl_la-easygetopt.lo libcurl_la-easyoptions.lo \
libcurl_la-escape.lo libcurl_la-file.lo libcurl_la-fileinfo.lo \
libcurl_la-fopen.lo libcurl_la-formdata.lo libcurl_la-ftp.lo \
@@ -347,7 +346,8 @@ am__objects_2 = vauth/libcurl_la-cleartext.lo vauth/libcurl_la-cram.lo \
vauth/libcurl_la-ntlm_sspi.lo vauth/libcurl_la-oauth2.lo \
vauth/libcurl_la-spnego_gssapi.lo \
vauth/libcurl_la-spnego_sspi.lo vauth/libcurl_la-vauth.lo
-am__objects_3 = vtls/libcurl_la-bearssl.lo vtls/libcurl_la-gtls.lo \
+am__objects_3 = vtls/libcurl_la-bearssl.lo \
+ vtls/libcurl_la-cipher_suite.lo vtls/libcurl_la-gtls.lo \
vtls/libcurl_la-hostcheck.lo vtls/libcurl_la-keylog.lo \
vtls/libcurl_la-mbedtls.lo \
vtls/libcurl_la-mbedtls_threadlock.lo \
@@ -393,20 +393,21 @@ am__objects_11 = libcurlu_la-altsvc.lo libcurlu_la-amigaos.lo \
libcurlu_la-curl_get_line.lo libcurlu_la-curl_gethostname.lo \
libcurlu_la-curl_gssapi.lo libcurlu_la-curl_memrchr.lo \
libcurlu_la-curl_multibyte.lo libcurlu_la-curl_ntlm_core.lo \
- libcurlu_la-curl_ntlm_wb.lo libcurlu_la-curl_path.lo \
- libcurlu_la-curl_range.lo libcurlu_la-curl_rtmp.lo \
- libcurlu_la-curl_sasl.lo libcurlu_la-curl_sha512_256.lo \
- libcurlu_la-curl_sspi.lo libcurlu_la-curl_threads.lo \
- libcurlu_la-curl_trc.lo libcurlu_la-cw-out.lo \
- libcurlu_la-dict.lo libcurlu_la-doh.lo libcurlu_la-dynbuf.lo \
- libcurlu_la-dynhds.lo libcurlu_la-easy.lo \
- libcurlu_la-easygetopt.lo libcurlu_la-easyoptions.lo \
- libcurlu_la-escape.lo libcurlu_la-file.lo \
- libcurlu_la-fileinfo.lo libcurlu_la-fopen.lo \
- libcurlu_la-formdata.lo libcurlu_la-ftp.lo \
- libcurlu_la-ftplistparser.lo libcurlu_la-getenv.lo \
- libcurlu_la-getinfo.lo libcurlu_la-gopher.lo \
- libcurlu_la-hash.lo libcurlu_la-headers.lo libcurlu_la-hmac.lo \
+ libcurlu_la-curl_path.lo libcurlu_la-curl_range.lo \
+ libcurlu_la-curl_rtmp.lo libcurlu_la-curl_sasl.lo \
+ libcurlu_la-curl_sha512_256.lo libcurlu_la-curl_sspi.lo \
+ libcurlu_la-curl_threads.lo libcurlu_la-curl_trc.lo \
+ libcurlu_la-cw-out.lo libcurlu_la-dict.lo \
+ libcurlu_la-dllmain.lo libcurlu_la-doh.lo \
+ libcurlu_la-dynbuf.lo libcurlu_la-dynhds.lo \
+ libcurlu_la-easy.lo libcurlu_la-easygetopt.lo \
+ libcurlu_la-easyoptions.lo libcurlu_la-escape.lo \
+ libcurlu_la-file.lo libcurlu_la-fileinfo.lo \
+ libcurlu_la-fopen.lo libcurlu_la-formdata.lo \
+ libcurlu_la-ftp.lo libcurlu_la-ftplistparser.lo \
+ libcurlu_la-getenv.lo libcurlu_la-getinfo.lo \
+ libcurlu_la-gopher.lo libcurlu_la-hash.lo \
+ libcurlu_la-headers.lo libcurlu_la-hmac.lo \
libcurlu_la-hostasyn.lo libcurlu_la-hostip.lo \
libcurlu_la-hostip4.lo libcurlu_la-hostip6.lo \
libcurlu_la-hostsyn.lo libcurlu_la-hsts.lo libcurlu_la-http.lo \
@@ -449,7 +450,8 @@ am__objects_12 = vauth/libcurlu_la-cleartext.lo \
vauth/libcurlu_la-ntlm_sspi.lo vauth/libcurlu_la-oauth2.lo \
vauth/libcurlu_la-spnego_gssapi.lo \
vauth/libcurlu_la-spnego_sspi.lo vauth/libcurlu_la-vauth.lo
-am__objects_13 = vtls/libcurlu_la-bearssl.lo vtls/libcurlu_la-gtls.lo \
+am__objects_13 = vtls/libcurlu_la-bearssl.lo \
+ vtls/libcurlu_la-cipher_suite.lo vtls/libcurlu_la-gtls.lo \
vtls/libcurlu_la-hostcheck.lo vtls/libcurlu_la-keylog.lo \
vtls/libcurlu_la-mbedtls.lo \
vtls/libcurlu_la-mbedtls_threadlock.lo \
@@ -516,7 +518,6 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurl_la-curl_memrchr.Plo \
./$(DEPDIR)/libcurl_la-curl_multibyte.Plo \
./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo \
- ./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo \
./$(DEPDIR)/libcurl_la-curl_path.Plo \
./$(DEPDIR)/libcurl_la-curl_range.Plo \
./$(DEPDIR)/libcurl_la-curl_rtmp.Plo \
@@ -526,7 +527,9 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurl_la-curl_threads.Plo \
./$(DEPDIR)/libcurl_la-curl_trc.Plo \
./$(DEPDIR)/libcurl_la-cw-out.Plo \
- ./$(DEPDIR)/libcurl_la-dict.Plo ./$(DEPDIR)/libcurl_la-doh.Plo \
+ ./$(DEPDIR)/libcurl_la-dict.Plo \
+ ./$(DEPDIR)/libcurl_la-dllmain.Plo \
+ ./$(DEPDIR)/libcurl_la-doh.Plo \
./$(DEPDIR)/libcurl_la-dynbuf.Plo \
./$(DEPDIR)/libcurl_la-dynhds.Plo \
./$(DEPDIR)/libcurl_la-easy.Plo \
@@ -645,7 +648,6 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo \
./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo \
./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo \
- ./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo \
./$(DEPDIR)/libcurlu_la-curl_path.Plo \
./$(DEPDIR)/libcurlu_la-curl_range.Plo \
./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo \
@@ -656,6 +658,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurlu_la-curl_trc.Plo \
./$(DEPDIR)/libcurlu_la-cw-out.Plo \
./$(DEPDIR)/libcurlu_la-dict.Plo \
+ ./$(DEPDIR)/libcurlu_la-dllmain.Plo \
./$(DEPDIR)/libcurlu_la-doh.Plo \
./$(DEPDIR)/libcurlu_la-dynbuf.Plo \
./$(DEPDIR)/libcurlu_la-dynhds.Plo \
@@ -795,6 +798,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo \
vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo \
vtls/$(DEPDIR)/libcurl_la-bearssl.Plo \
+ vtls/$(DEPDIR)/libcurl_la-cipher_suite.Plo \
vtls/$(DEPDIR)/libcurl_la-gtls.Plo \
vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo \
vtls/$(DEPDIR)/libcurl_la-keylog.Plo \
@@ -809,6 +813,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo \
vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo \
vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo \
+ vtls/$(DEPDIR)/libcurlu_la-cipher_suite.Plo \
vtls/$(DEPDIR)/libcurlu_la-gtls.Plo \
vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo \
vtls/$(DEPDIR)/libcurlu_la-keylog.Plo \
@@ -868,8 +873,7 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.inc \
$(srcdir)/Makefile.soname $(srcdir)/curl_config.h.in \
- $(srcdir)/libcurl.plist.in $(srcdir)/libcurl.vers.in \
- $(top_srcdir)/depcomp
+ $(srcdir)/libcurl.vers.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@@ -919,7 +923,6 @@ CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@
CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@
CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@
CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@
-CURL_PLIST_VERSION = @CURL_PLIST_VERSION@
CURL_WITH_MULTI_SSL = @CURL_WITH_MULTI_SSL@
CYGPATH_W = @CYGPATH_W@
DEFAULT_SSL_BACKEND = @DEFAULT_SSL_BACKEND@
@@ -1043,6 +1046,7 @@ USE_WOLFSSH = @USE_WOLFSSH@
USE_WOLFSSL = @USE_WOLFSSL@
VERSION = @VERSION@
VERSIONNUM = @VERSIONNUM@
+VSFTPD = @VSFTPD@
ZLIB_LIBS = @ZLIB_LIBS@
ZSH_FUNCTIONS_DIR = @ZSH_FUNCTIONS_DIR@
abs_builddir = @abs_builddir@
@@ -1125,11 +1129,10 @@ top_srcdir = @top_srcdir@
###########################################################################
AUTOMAKE_OPTIONS = foreign nostdinc
CMAKE_DIST = CMakeLists.txt curl_config.h.cmake
-EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h \
- config-riscos.h config-mac.h curl_config.h.in config-dos.h \
- libcurl.plist libcurl.rc config-amigaos.h config-win32ce.h \
- config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc \
- Makefile.soname
+EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h \
+ config-riscos.h config-mac.h curl_config.h.in config-dos.h libcurl.rc \
+ config-amigaos.h config-win32ce.h config-os400.h setup-os400.h \
+ $(CMAKE_DIST) setup-win32.h .checksrc Makefile.soname
lib_LTLIBRARIES = libcurl.la
@BUILD_UNITTESTS_FALSE@noinst_LTLIBRARIES =
@@ -1175,6 +1178,7 @@ LIB_VAUTH_HFILES = \
LIB_VTLS_CFILES = \
vtls/bearssl.c \
+ vtls/cipher_suite.c \
vtls/gtls.c \
vtls/hostcheck.c \
vtls/keylog.c \
@@ -1191,6 +1195,7 @@ LIB_VTLS_CFILES = \
LIB_VTLS_HFILES = \
vtls/bearssl.h \
+ vtls/cipher_suite.h \
vtls/gtls.h \
vtls/hostcheck.h \
vtls/keylog.h \
@@ -1260,7 +1265,6 @@ LIB_CFILES = \
curl_memrchr.c \
curl_multibyte.c \
curl_ntlm_core.c \
- curl_ntlm_wb.c \
curl_path.c \
curl_range.c \
curl_rtmp.c \
@@ -1271,6 +1275,7 @@ LIB_CFILES = \
curl_trc.c \
cw-out.c \
dict.c \
+ dllmain.c \
doh.c \
dynbuf.c \
dynhds.c \
@@ -1402,7 +1407,6 @@ LIB_HFILES = \
curl_memrchr.h \
curl_multibyte.h \
curl_ntlm_core.h \
- curl_ntlm_wb.h \
curl_path.h \
curl_printf.h \
curl_range.h \
@@ -1584,8 +1588,6 @@ distclean-hdr:
-rm -f curl_config.h stamp-h1
libcurl.vers: $(top_builddir)/config.status $(srcdir)/libcurl.vers.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
-libcurl.plist: $(top_builddir)/config.status $(srcdir)/libcurl.plist.in
- cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@@ -1672,6 +1674,8 @@ vtls/$(DEPDIR)/$(am__dirstamp):
@: > vtls/$(DEPDIR)/$(am__dirstamp)
vtls/libcurl_la-bearssl.lo: vtls/$(am__dirstamp) \
vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurl_la-cipher_suite.lo: vtls/$(am__dirstamp) \
+ vtls/$(DEPDIR)/$(am__dirstamp)
vtls/libcurl_la-gtls.lo: vtls/$(am__dirstamp) \
vtls/$(DEPDIR)/$(am__dirstamp)
vtls/libcurl_la-hostcheck.lo: vtls/$(am__dirstamp) \
@@ -1759,6 +1763,8 @@ vauth/libcurlu_la-vauth.lo: vauth/$(am__dirstamp) \
vauth/$(DEPDIR)/$(am__dirstamp)
vtls/libcurlu_la-bearssl.lo: vtls/$(am__dirstamp) \
vtls/$(DEPDIR)/$(am__dirstamp)
+vtls/libcurlu_la-cipher_suite.lo: vtls/$(am__dirstamp) \
+ vtls/$(DEPDIR)/$(am__dirstamp)
vtls/libcurlu_la-gtls.lo: vtls/$(am__dirstamp) \
vtls/$(DEPDIR)/$(am__dirstamp)
vtls/libcurlu_la-hostcheck.lo: vtls/$(am__dirstamp) \
@@ -1849,7 +1855,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_memrchr.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_multibyte.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_path.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_range.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_rtmp.Plo@am__quote@ # am--include-marker
@@ -1860,6 +1865,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_trc.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cw-out.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dict.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dllmain.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-doh.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dynbuf.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dynhds.Plo@am__quote@ # am--include-marker
@@ -1982,7 +1988,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_path.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_range.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo@am__quote@ # am--include-marker
@@ -1993,6 +1998,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_trc.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cw-out.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dict.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dllmain.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-doh.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dynbuf.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dynhds.Plo@am__quote@ # am--include-marker
@@ -2132,6 +2138,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-bearssl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-cipher_suite.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-gtls.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-keylog.Plo@am__quote@ # am--include-marker
@@ -2146,6 +2153,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-cipher_suite.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-gtls.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@vtls/$(DEPDIR)/libcurlu_la-keylog.Plo@am__quote@ # am--include-marker
@@ -2386,13 +2394,6 @@ libcurl_la-curl_ntlm_core.lo: curl_ntlm_core.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_ntlm_core.lo `test -f 'curl_ntlm_core.c' || echo '$(srcdir)/'`curl_ntlm_core.c
-libcurl_la-curl_ntlm_wb.lo: curl_ntlm_wb.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_ntlm_wb.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_ntlm_wb.Tpo -c -o libcurl_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_ntlm_wb.Tpo $(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_ntlm_wb.c' object='libcurl_la-curl_ntlm_wb.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c
-
libcurl_la-curl_path.lo: curl_path.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-curl_path.lo -MD -MP -MF $(DEPDIR)/libcurl_la-curl_path.Tpo -c -o libcurl_la-curl_path.lo `test -f 'curl_path.c' || echo '$(srcdir)/'`curl_path.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-curl_path.Tpo $(DEPDIR)/libcurl_la-curl_path.Plo
@@ -2463,6 +2464,13 @@ libcurl_la-dict.lo: dict.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
+libcurl_la-dllmain.lo: dllmain.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-dllmain.lo -MD -MP -MF $(DEPDIR)/libcurl_la-dllmain.Tpo -c -o libcurl_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-dllmain.Tpo $(DEPDIR)/libcurl_la-dllmain.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dllmain.c' object='libcurl_la-dllmain.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
+
libcurl_la-doh.lo: doh.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-doh.lo -MD -MP -MF $(DEPDIR)/libcurl_la-doh.Tpo -c -o libcurl_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-doh.Tpo $(DEPDIR)/libcurl_la-doh.Plo
@@ -3219,6 +3227,13 @@ vtls/libcurl_la-bearssl.lo: vtls/bearssl.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-bearssl.lo `test -f 'vtls/bearssl.c' || echo '$(srcdir)/'`vtls/bearssl.c
+vtls/libcurl_la-cipher_suite.lo: vtls/cipher_suite.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-cipher_suite.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-cipher_suite.Tpo -c -o vtls/libcurl_la-cipher_suite.lo `test -f 'vtls/cipher_suite.c' || echo '$(srcdir)/'`vtls/cipher_suite.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-cipher_suite.Tpo vtls/$(DEPDIR)/libcurl_la-cipher_suite.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/cipher_suite.c' object='vtls/libcurl_la-cipher_suite.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-cipher_suite.lo `test -f 'vtls/cipher_suite.c' || echo '$(srcdir)/'`vtls/cipher_suite.c
+
vtls/libcurl_la-gtls.lo: vtls/gtls.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vtls/libcurl_la-gtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurl_la-gtls.Tpo -c -o vtls/libcurl_la-gtls.lo `test -f 'vtls/gtls.c' || echo '$(srcdir)/'`vtls/gtls.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurl_la-gtls.Tpo vtls/$(DEPDIR)/libcurl_la-gtls.Plo
@@ -3569,13 +3584,6 @@ libcurlu_la-curl_ntlm_core.lo: curl_ntlm_core.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_ntlm_core.lo `test -f 'curl_ntlm_core.c' || echo '$(srcdir)/'`curl_ntlm_core.c
-libcurlu_la-curl_ntlm_wb.lo: curl_ntlm_wb.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_ntlm_wb.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_ntlm_wb.Tpo -c -o libcurlu_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_ntlm_wb.Tpo $(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='curl_ntlm_wb.c' object='libcurlu_la-curl_ntlm_wb.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-curl_ntlm_wb.lo `test -f 'curl_ntlm_wb.c' || echo '$(srcdir)/'`curl_ntlm_wb.c
-
libcurlu_la-curl_path.lo: curl_path.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-curl_path.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-curl_path.Tpo -c -o libcurlu_la-curl_path.lo `test -f 'curl_path.c' || echo '$(srcdir)/'`curl_path.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-curl_path.Tpo $(DEPDIR)/libcurlu_la-curl_path.Plo
@@ -3646,6 +3654,13 @@ libcurlu_la-dict.lo: dict.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
+libcurlu_la-dllmain.lo: dllmain.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-dllmain.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-dllmain.Tpo -c -o libcurlu_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-dllmain.Tpo $(DEPDIR)/libcurlu_la-dllmain.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dllmain.c' object='libcurlu_la-dllmain.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
+
libcurlu_la-doh.lo: doh.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-doh.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-doh.Tpo -c -o libcurlu_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-doh.Tpo $(DEPDIR)/libcurlu_la-doh.Plo
@@ -4402,6 +4417,13 @@ vtls/libcurlu_la-bearssl.lo: vtls/bearssl.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-bearssl.lo `test -f 'vtls/bearssl.c' || echo '$(srcdir)/'`vtls/bearssl.c
+vtls/libcurlu_la-cipher_suite.lo: vtls/cipher_suite.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-cipher_suite.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-cipher_suite.Tpo -c -o vtls/libcurlu_la-cipher_suite.lo `test -f 'vtls/cipher_suite.c' || echo '$(srcdir)/'`vtls/cipher_suite.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-cipher_suite.Tpo vtls/$(DEPDIR)/libcurlu_la-cipher_suite.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vtls/cipher_suite.c' object='vtls/libcurlu_la-cipher_suite.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-cipher_suite.lo `test -f 'vtls/cipher_suite.c' || echo '$(srcdir)/'`vtls/cipher_suite.c
+
vtls/libcurlu_la-gtls.lo: vtls/gtls.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vtls/libcurlu_la-gtls.lo -MD -MP -MF vtls/$(DEPDIR)/libcurlu_la-gtls.Tpo -c -o vtls/libcurlu_la-gtls.lo `test -f 'vtls/gtls.c' || echo '$(srcdir)/'`vtls/gtls.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vtls/$(DEPDIR)/libcurlu_la-gtls.Tpo vtls/$(DEPDIR)/libcurlu_la-gtls.Plo
@@ -4730,7 +4752,6 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurl_la-curl_memrchr.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_multibyte.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo
- -rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_path.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_range.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_rtmp.Plo
@@ -4741,6 +4762,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurl_la-curl_trc.Plo
-rm -f ./$(DEPDIR)/libcurl_la-cw-out.Plo
-rm -f ./$(DEPDIR)/libcurl_la-dict.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-dllmain.Plo
-rm -f ./$(DEPDIR)/libcurl_la-doh.Plo
-rm -f ./$(DEPDIR)/libcurl_la-dynbuf.Plo
-rm -f ./$(DEPDIR)/libcurl_la-dynhds.Plo
@@ -4863,7 +4885,6 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo
- -rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_path.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_range.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo
@@ -4874,6 +4895,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurlu_la-curl_trc.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-cw-out.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-dict.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-dllmain.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-doh.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-dynbuf.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-dynhds.Plo
@@ -5013,6 +5035,7 @@ distclean: distclean-am
-rm -f vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo
-rm -f vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo
-rm -f vtls/$(DEPDIR)/libcurl_la-bearssl.Plo
+ -rm -f vtls/$(DEPDIR)/libcurl_la-cipher_suite.Plo
-rm -f vtls/$(DEPDIR)/libcurl_la-gtls.Plo
-rm -f vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo
-rm -f vtls/$(DEPDIR)/libcurl_la-keylog.Plo
@@ -5027,6 +5050,7 @@ distclean: distclean-am
-rm -f vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo
-rm -f vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo
-rm -f vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo
+ -rm -f vtls/$(DEPDIR)/libcurlu_la-cipher_suite.Plo
-rm -f vtls/$(DEPDIR)/libcurlu_la-gtls.Plo
-rm -f vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo
-rm -f vtls/$(DEPDIR)/libcurlu_la-keylog.Plo
@@ -5113,7 +5137,6 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurl_la-curl_memrchr.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_multibyte.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_core.Plo
- -rm -f ./$(DEPDIR)/libcurl_la-curl_ntlm_wb.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_path.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_range.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_rtmp.Plo
@@ -5124,6 +5147,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurl_la-curl_trc.Plo
-rm -f ./$(DEPDIR)/libcurl_la-cw-out.Plo
-rm -f ./$(DEPDIR)/libcurl_la-dict.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-dllmain.Plo
-rm -f ./$(DEPDIR)/libcurl_la-doh.Plo
-rm -f ./$(DEPDIR)/libcurl_la-dynbuf.Plo
-rm -f ./$(DEPDIR)/libcurl_la-dynhds.Plo
@@ -5246,7 +5270,6 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurlu_la-curl_memrchr.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_multibyte.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_core.Plo
- -rm -f ./$(DEPDIR)/libcurlu_la-curl_ntlm_wb.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_path.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_range.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_rtmp.Plo
@@ -5257,6 +5280,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurlu_la-curl_trc.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-cw-out.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-dict.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-dllmain.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-doh.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-dynbuf.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-dynhds.Plo
@@ -5396,6 +5420,7 @@ maintainer-clean: maintainer-clean-am
-rm -f vssh/$(DEPDIR)/libcurlu_la-libssh2.Plo
-rm -f vssh/$(DEPDIR)/libcurlu_la-wolfssh.Plo
-rm -f vtls/$(DEPDIR)/libcurl_la-bearssl.Plo
+ -rm -f vtls/$(DEPDIR)/libcurl_la-cipher_suite.Plo
-rm -f vtls/$(DEPDIR)/libcurl_la-gtls.Plo
-rm -f vtls/$(DEPDIR)/libcurl_la-hostcheck.Plo
-rm -f vtls/$(DEPDIR)/libcurl_la-keylog.Plo
@@ -5410,6 +5435,7 @@ maintainer-clean: maintainer-clean-am
-rm -f vtls/$(DEPDIR)/libcurl_la-wolfssl.Plo
-rm -f vtls/$(DEPDIR)/libcurl_la-x509asn1.Plo
-rm -f vtls/$(DEPDIR)/libcurlu_la-bearssl.Plo
+ -rm -f vtls/$(DEPDIR)/libcurlu_la-cipher_suite.Plo
-rm -f vtls/$(DEPDIR)/libcurlu_la-gtls.Plo
-rm -f vtls/$(DEPDIR)/libcurlu_la-hostcheck.Plo
-rm -f vtls/$(DEPDIR)/libcurlu_la-keylog.Plo
diff --git a/libs/libcurl/src/Makefile.inc b/libs/libcurl/src/Makefile.inc
index a6393054b7..0a7537f498 100644
--- a/libs/libcurl/src/Makefile.inc
+++ b/libs/libcurl/src/Makefile.inc
@@ -44,6 +44,7 @@ LIB_VAUTH_HFILES = \
LIB_VTLS_CFILES = \
vtls/bearssl.c \
+ vtls/cipher_suite.c \
vtls/gtls.c \
vtls/hostcheck.c \
vtls/keylog.c \
@@ -60,6 +61,7 @@ LIB_VTLS_CFILES = \
LIB_VTLS_HFILES = \
vtls/bearssl.h \
+ vtls/cipher_suite.h \
vtls/gtls.h \
vtls/hostcheck.h \
vtls/keylog.h \
@@ -129,7 +131,6 @@ LIB_CFILES = \
curl_memrchr.c \
curl_multibyte.c \
curl_ntlm_core.c \
- curl_ntlm_wb.c \
curl_path.c \
curl_range.c \
curl_rtmp.c \
@@ -140,6 +141,7 @@ LIB_CFILES = \
curl_trc.c \
cw-out.c \
dict.c \
+ dllmain.c \
doh.c \
dynbuf.c \
dynhds.c \
@@ -271,7 +273,6 @@ LIB_HFILES = \
curl_memrchr.h \
curl_multibyte.h \
curl_ntlm_core.h \
- curl_ntlm_wb.h \
curl_path.h \
curl_printf.h \
curl_range.h \
diff --git a/libs/libcurl/src/altsvc.c b/libs/libcurl/src/altsvc.c
index 0414ab1150..590c580087 100644
--- a/libs/libcurl/src/altsvc.c
+++ b/libs/libcurl/src/altsvc.c
@@ -191,7 +191,7 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
as->expires = expires;
as->prio = prio;
as->persist = persist ? 1 : 0;
- Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
+ Curl_llist_append(&asi->list, as, &as->node);
}
}
@@ -252,7 +252,7 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
CURLcode result = Curl_gmtime(as->expires, &stamp);
if(result)
return result;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else {
char ipv6_unused[16];
if(1 == Curl_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
@@ -303,7 +303,7 @@ struct altsvcinfo *Curl_altsvc_init(void)
#ifdef USE_HTTP2
| CURLALTSVC_H2
#endif
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
| CURLALTSVC_H3
#endif
;
@@ -643,7 +643,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
account. [See RFC 7838 section 3.1] */
as->expires = maxage + time(NULL);
as->persist = persist;
- Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
+ Curl_llist_append(&asi->list, as, &as->node);
infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
Curl_alpnid2str(dstalpnid));
}
diff --git a/libs/libcurl/src/asyn-ares.c b/libs/libcurl/src/asyn-ares.c
index baae83218f..1504377335 100644
--- a/libs/libcurl/src/asyn-ares.c
+++ b/libs/libcurl/src/asyn-ares.c
@@ -539,7 +539,7 @@ static void compound_results(struct thread_data *res,
if(!ai)
return;
-#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+#ifdef USE_IPV6 /* CURLRES_IPV6 */
if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) {
/* We have results already, put the new IPv6 entries at the head of the
list. */
@@ -684,7 +684,7 @@ static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node)
/* settle family-specific sockaddr structure size. */
if(ai->ai_family == AF_INET)
ss_size = sizeof(struct sockaddr_in);
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else if(ai->ai_family == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
#endif
@@ -932,7 +932,7 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
const char *local_ip6)
{
-#if defined(HAVE_CARES_SET_LOCAL) && defined(ENABLE_IPV6)
+#if defined(HAVE_CARES_SET_LOCAL) && defined(USE_IPV6)
unsigned char a6[INET6_ADDRSTRLEN];
if((!local_ip6) || (local_ip6[0] == 0)) {
diff --git a/libs/libcurl/src/asyn-thread.c b/libs/libcurl/src/asyn-thread.c
index fe5e10ebc1..779f285283 100644
--- a/libs/libcurl/src/asyn-thread.c
+++ b/libs/libcurl/src/asyn-thread.c
@@ -325,7 +325,7 @@ query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
/* settle family-specific sockaddr structure size. */
if(ai->ai_family == AF_INET)
ss_size = sizeof(struct sockaddr_in);
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else if(ai->ai_family == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
#endif
@@ -444,7 +444,7 @@ query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
/*
* getaddrinfo_thread() resolves a name and then exits.
*
- * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
+ * For builds without ARES, but with USE_IPV6, create a resolver thread
* and wait on it.
*/
static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
@@ -554,11 +554,15 @@ static void destroy_async_data(struct Curl_async *async)
if(!done) {
#ifdef _WIN32
- if(td->complete_ev)
+ if(td->complete_ev) {
CloseHandle(td->complete_ev);
- else
+ td->complete_ev = NULL;
+ }
#endif
- Curl_thread_destroy(td->thread_hnd);
+ if(td->thread_hnd != curl_thread_t_null) {
+ Curl_thread_destroy(td->thread_hnd);
+ td->thread_hnd = curl_thread_t_null;
+ }
}
else {
#ifdef _WIN32
@@ -566,6 +570,7 @@ static void destroy_async_data(struct Curl_async *async)
Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
WaitForSingleObject(td->complete_ev, INFINITE);
CloseHandle(td->complete_ev);
+ td->complete_ev = NULL;
}
#endif
if(td->thread_hnd != curl_thread_t_null)
@@ -672,7 +677,7 @@ static bool init_resolve_thread(struct Curl_easy *data,
td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
#endif
- if(!td->thread_hnd) {
+ if(td->thread_hnd == curl_thread_t_null) {
/* The thread never started, so mark it as done here for proper cleanup. */
td->tsd.done = 1;
err = errno;
@@ -713,6 +718,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
if(td->complete_ev) {
WaitForSingleObject(td->complete_ev, INFINITE);
CloseHandle(td->complete_ev);
+ td->complete_ev = NULL;
if(entry)
result = getaddrinfo_complete(data);
}
@@ -754,6 +760,13 @@ void Curl_resolver_kill(struct Curl_easy *data)
/* If we're still resolving, we must wait for the threads to fully clean up,
unfortunately. Otherwise, we can simply cancel to clean up any resolver
data. */
+#ifdef _WIN32
+ if(td && td->complete_ev) {
+ Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
+ (void)thread_wait_resolv(data, NULL, FALSE);
+ }
+ else
+#endif
if(td && td->thread_hnd != curl_thread_t_null
&& (data->set.quick_exit != 1L))
(void)thread_wait_resolv(data, NULL, FALSE);
diff --git a/libs/libcurl/src/base64.c b/libs/libcurl/src/base64.c
index 739c26f24b..a60d4542b7 100644
--- a/libs/libcurl/src/base64.c
+++ b/libs/libcurl/src/base64.c
@@ -243,7 +243,7 @@ static CURLcode base64_encode(const char *table64,
*outptr = base64data;
/* Return the length of the new data */
- *outlen = output - base64data;
+ *outlen = (size_t)(output - base64data);
return CURLE_OK;
}
diff --git a/libs/libcurl/src/bufq.h b/libs/libcurl/src/bufq.h
index c7aa10a75d..dc803bd9dc 100644
--- a/libs/libcurl/src/bufq.h
+++ b/libs/libcurl/src/bufq.h
@@ -85,7 +85,7 @@ void Curl_bufcp_free(struct bufc_pool *pool);
* preferably never fail (except for memory exhaustion).
*
* By default and without a pool, a bufq will keep chunks that read
- * read empty in its `spare` list. Option `BUFQ_OPT_NO_SPARES` will
+ * empty in its `spare` list. Option `BUFQ_OPT_NO_SPARES` will
* disable that and free chunks once they become empty.
*
* When providing a pool to a bufq, all chunk creation and spare handling
diff --git a/libs/libcurl/src/c-hyper.c b/libs/libcurl/src/c-hyper.c
index 72619006b6..d2523718f4 100644
--- a/libs/libcurl/src/c-hyper.c
+++ b/libs/libcurl/src/c-hyper.c
@@ -171,7 +171,7 @@ static int hyper_each_header(void *userdata,
len = Curl_dyn_len(&data->state.headerb);
headp = Curl_dyn_ptr(&data->state.headerb);
- result = Curl_http_header(data, data->conn, headp, len);
+ result = Curl_http_header(data, headp, len);
if(result) {
data->state.hresult = result;
return HYPER_ITER_BREAK;
@@ -980,11 +980,13 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
goto error;
}
+#ifndef CURL_DISABLE_PROXY
if(data->state.aptr.proxyuserpwd) {
result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
if(result)
goto error;
}
+#endif
if(data->state.aptr.userpwd) {
result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
@@ -1137,7 +1139,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* clear userpwd and proxyuserpwd to avoid reusing old credentials
* from reused connections */
Curl_safefree(data->state.aptr.userpwd);
+#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
+#endif
return CURLE_OK;
error:
DEBUGASSERT(result);
diff --git a/libs/libcurl/src/cf-h1-proxy.c b/libs/libcurl/src/cf-h1-proxy.c
index 5c359e7ddc..085a343475 100644
--- a/libs/libcurl/src/cf-h1-proxy.c
+++ b/libs/libcurl/src/cf-h1-proxy.c
@@ -195,14 +195,16 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
static void tunnel_free(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct h1_tunnel_state *ts = cf->ctx;
- if(ts) {
- h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
- Curl_dyn_free(&ts->rcvbuf);
- Curl_dyn_free(&ts->request_data);
- Curl_httpchunk_free(data, &ts->ch);
- free(ts);
- cf->ctx = NULL;
+ if(cf) {
+ struct h1_tunnel_state *ts = cf->ctx;
+ if(ts) {
+ h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
+ Curl_dyn_free(&ts->rcvbuf);
+ Curl_dyn_free(&ts->request_data);
+ Curl_httpchunk_free(data, &ts->ch);
+ free(ts);
+ cf->ctx = NULL;
+ }
}
}
@@ -1057,18 +1059,20 @@ static void cf_h1_proxy_close(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
CURL_TRC_CF(data, cf, "close");
- cf->connected = FALSE;
- if(cf->ctx) {
- h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data);
+ if(cf) {
+ cf->connected = FALSE;
+ if(cf->ctx) {
+ h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data);
+ }
+ if(cf->next)
+ cf->next->cft->do_close(cf->next, data);
}
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
}
struct Curl_cftype Curl_cft_h1_proxy = {
"H1-PROXY",
- CF_TYPE_IP_CONNECT,
+ CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
0,
cf_h1_proxy_destroy,
cf_h1_proxy_connect,
diff --git a/libs/libcurl/src/cf-h2-proxy.c b/libs/libcurl/src/cf-h2-proxy.c
index c302f603d9..be9f932ecf 100644
--- a/libs/libcurl/src/cf-h2-proxy.c
+++ b/libs/libcurl/src/cf-h2-proxy.c
@@ -1532,7 +1532,7 @@ static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_h2_proxy = {
"H2-PROXY",
- CF_TYPE_IP_CONNECT,
+ CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
CURL_LOG_LVL_NONE,
cf_h2_proxy_destroy,
cf_h2_proxy_connect,
diff --git a/libs/libcurl/src/cf-haproxy.c b/libs/libcurl/src/cf-haproxy.c
index a6e1499d8a..c9a0102eab 100644
--- a/libs/libcurl/src/cf-haproxy.c
+++ b/libs/libcurl/src/cf-haproxy.c
@@ -189,7 +189,7 @@ static void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_haproxy = {
"HAPROXY",
- 0,
+ CF_TYPE_PROXY,
0,
cf_haproxy_destroy,
cf_haproxy_connect,
diff --git a/libs/libcurl/src/cf-https-connect.c b/libs/libcurl/src/cf-https-connect.c
index 05e6bdf044..681159f178 100644
--- a/libs/libcurl/src/cf-https-connect.c
+++ b/libs/libcurl/src/cf-https-connect.c
@@ -102,8 +102,8 @@ struct cf_hc_ctx {
CURLcode result; /* overall result */
struct cf_hc_baller h3_baller;
struct cf_hc_baller h21_baller;
- int soft_eyeballs_timeout_ms;
- int hard_eyeballs_timeout_ms;
+ unsigned int soft_eyeballs_timeout_ms;
+ unsigned int hard_eyeballs_timeout_ms;
};
static void cf_hc_baller_init(struct cf_hc_baller *b,
diff --git a/libs/libcurl/src/cf-socket.c b/libs/libcurl/src/cf-socket.c
index 20ea147875..713499a2e8 100644
--- a/libs/libcurl/src/cf-socket.c
+++ b/libs/libcurl/src/cf-socket.c
@@ -81,7 +81,7 @@
#include "memdebug.h"
-#if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
+#if defined(USE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
/* It makes support for IPv4-mapped IPv6 addresses.
* Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
* Windows Vista and later: default is on;
@@ -287,7 +287,7 @@ static CURLcode socket_open(struct Curl_easy *data,
/* no socket, no connection */
return CURLE_COULDNT_CONNECT;
-#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
+#if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
if(data->conn->scope_id && (addr->family == AF_INET6)) {
struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
sa6->sin6_scope_id = data->conn->scope_id;
@@ -405,7 +405,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
#endif
@@ -419,7 +419,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
#ifdef IP_BIND_ADDRESS_NO_PORT
int on = 1;
#endif
-#ifndef ENABLE_IPV6
+#ifndef USE_IPV6
(void)scope;
#endif
@@ -475,7 +475,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
#endif
switch(Curl_if2ip(af,
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
scope, conn->scope_id,
#endif
dev, myhost, sizeof(myhost))) {
@@ -514,7 +514,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
if(af == AF_INET)
conn->ip_version = CURL_IPRESOLVE_V4;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else if(af == AF_INET6)
conn->ip_version = CURL_IPRESOLVE_V6;
#endif
@@ -547,7 +547,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
}
if(done > 0) {
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
/* IPv6 address */
if(af == AF_INET6) {
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
@@ -596,7 +596,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
}
else {
/* no device was given, prepare sa to match af's needs */
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if(af == AF_INET6) {
si6->sin6_family = AF_INET6;
si6->sin6_port = htons(port);
@@ -616,16 +616,6 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
for(;;) {
if(bind(sockfd, sock, sizeof_sa) >= 0) {
/* we succeeded to bind */
- struct Curl_sockaddr_storage add;
- curl_socklen_t size = sizeof(add);
- memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
- if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
- char buffer[STRERROR_LEN];
- data->state.os_errno = error = SOCKERRNO;
- failf(data, "getsockname() failed with errno %d: %s",
- error, Curl_strerror(error, buffer, sizeof(buffer)));
- return CURLE_INTERFACE_FAILED;
- }
infof(data, "Local port: %hu", port);
conn->bits.bound = TRUE;
return CURLE_OK;
@@ -639,7 +629,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
/* We reuse/clobber the port variable here below */
if(sock->sa_family == AF_INET)
si4->sin_port = ntohs(port);
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else
si6->sin6_port = ntohs(port);
#endif
@@ -923,7 +913,8 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf,
struct cf_socket_ctx *ctx = cf->ctx;
#ifdef HAVE_GETSOCKNAME
- if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
+ if((ctx->sock != CURL_SOCKET_BAD) &&
+ !(data->conn->handler->protocol & CURLPROTO_TFTP)) {
/* TFTP does not connect, so it cannot get the IP like this */
char buffer[STRERROR_LEN];
@@ -946,8 +937,8 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf,
}
#else
(void)data;
- ctx->l_ip[0] = 0;
- ctx->l_port = -1;
+ ctx->ip.local_ip[0] = 0;
+ ctx->ip.local_port = -1;
#endif
return CURLE_OK;
}
@@ -991,7 +982,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
if(result)
goto out;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if(ctx->addr.family == AF_INET6) {
set_ipv6_v6only(ctx->sock, 0);
infof(data, " Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
@@ -1000,7 +991,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
#endif
infof(data, " Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
is_tcp = (ctx->addr.family == AF_INET
|| ctx->addr.family == AF_INET6) &&
ctx->addr.socktype == SOCK_STREAM;
@@ -1037,7 +1028,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
#ifndef CURL_DISABLE_BINDLOCAL
/* possibly bind the local end to an IP, interface or port */
if(ctx->addr.family == AF_INET
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
|| ctx->addr.family == AF_INET6
#endif
) {
@@ -1288,7 +1279,7 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
#ifdef DEBUGBUILD
/* simulate network blocking/partial writes */
if(ctx->wblock_percent > 0) {
- unsigned char c;
+ unsigned char c = 0;
Curl_rand(data, &c, 1);
if(c >= ((100-ctx->wblock_percent)*256/100)) {
CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
@@ -1366,7 +1357,7 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
#ifdef DEBUGBUILD
/* simulate network blocking/partial reads */
if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
- unsigned char c;
+ unsigned char c = 0;
Curl_rand(data, &c, 1);
if(c >= ((100-ctx->rblock_percent)*256/100)) {
CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
@@ -1449,7 +1440,7 @@ static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
/* the first socket info gets some specials */
if(cf->sockindex == FIRSTSOCKET) {
cf->conn->remote_addr = &ctx->addr;
- #ifdef ENABLE_IPV6
+ #ifdef USE_IPV6
cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
#endif
Curl_persistconninfo(data, cf->conn, &ctx->ip);
diff --git a/libs/libcurl/src/cfilters.c b/libs/libcurl/src/cfilters.c
index 2d1fbe1b1d..4bb958cf3a 100644
--- a/libs/libcurl/src/cfilters.c
+++ b/libs/libcurl/src/cfilters.c
@@ -590,7 +590,7 @@ CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
/**
* Notify connection filters that the transfer represented by `data`
- * is donw with sending data (e.g. has uploaded everything).
+ * is done with sending data (e.g. has uploaded everything).
*/
void Curl_conn_ev_data_done_send(struct Curl_easy *data)
{
@@ -670,6 +670,19 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
return (result || n <= 0)? 1 : (size_t)n;
}
+int Curl_conn_get_stream_error(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode result;
+ int n = 0;
+
+ struct Curl_cfilter *cf = conn->cfilter[sockindex];
+ result = cf? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR,
+ &n, NULL) : CURLE_UNKNOWN_OPTION;
+ return (result || n < 0)? 0 : n;
+}
+
int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
{
if(data && data->conn &&
diff --git a/libs/libcurl/src/cfilters.h b/libs/libcurl/src/cfilters.h
index 016b05ea71..040c9e88ee 100644
--- a/libs/libcurl/src/cfilters.h
+++ b/libs/libcurl/src/cfilters.h
@@ -160,6 +160,7 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
#define CF_QUERY_SOCKET 3 /* - curl_socket_t */
#define CF_QUERY_TIMER_CONNECT 4 /* - struct curltime */
#define CF_QUERY_TIMER_APPCONNECT 5 /* - struct curltime */
+#define CF_QUERY_STREAM_ERROR 6 /* error code - */
/**
* Query the cfilter for properties. Filters ignorant of a query will
@@ -178,10 +179,12 @@ typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
* connection, etc.
* CF_TYPE_SSL: provide SSL/TLS
* CF_TYPE_MULTIPLEX: provides multiplexing of easy handles
+ * CF_TYPE_PROXY provides proxying
*/
#define CF_TYPE_IP_CONNECT (1 << 0)
#define CF_TYPE_SSL (1 << 1)
#define CF_TYPE_MULTIPLEX (1 << 2)
+#define CF_TYPE_PROXY (1 << 3)
/* A connection filter type, e.g. specific implementation. */
struct Curl_cftype {
@@ -449,7 +452,7 @@ CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data);
/**
* Notify connection filters that the transfer represented by `data`
- * is donw with sending data (e.g. has uploaded everything).
+ * is done with sending data (e.g. has uploaded everything).
*/
void Curl_conn_ev_data_done_send(struct Curl_easy *data);
@@ -496,6 +499,12 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
+/**
+ * Get the underlying error code for a transfer stream or 0 if not known.
+ */
+int Curl_conn_get_stream_error(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
/**
* Get the index of the given socket in the connection's sockets.
diff --git a/libs/libcurl/src/config-os400.h b/libs/libcurl/src/config-os400.h
index af97f64947..d33185a390 100644
--- a/libs/libcurl/src/config-os400.h
+++ b/libs/libcurl/src/config-os400.h
@@ -57,7 +57,7 @@
#undef NEED_REENTRANT
/* Define if you want to enable IPv6 support */
-#define ENABLE_IPV6
+#define USE_IPV6
/* Define if struct sockaddr_in6 has the sin6_scope_id member */
#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
@@ -237,7 +237,7 @@
/* Define to enable HTTP3 support (experimental, requires NGTCP2, QUICHE or
MSH3) */
-#undef ENABLE_QUIC
+#undef USE_HTTP3
/* Version number of package */
#undef VERSION
diff --git a/libs/libcurl/src/config-plan9.h b/libs/libcurl/src/config-plan9.h
index be30f883c6..ca095df3a8 100644
--- a/libs/libcurl/src/config-plan9.h
+++ b/libs/libcurl/src/config-plan9.h
@@ -28,7 +28,7 @@
#define CURL_CA_BUNDLE "/sys/lib/tls/ca.pem"
#define CURL_CA_PATH "/sys/lib/tls"
#define CURL_STATICLIB 1
-#define ENABLE_IPV6 1
+#define USE_IPV6 1
#define CURL_DISABLE_LDAP 1
#define NEED_REENTRANT 1
diff --git a/libs/libcurl/src/config-riscos.h b/libs/libcurl/src/config-riscos.h
index 7add4d42d5..fd3f67e59f 100644
--- a/libs/libcurl/src/config-riscos.h
+++ b/libs/libcurl/src/config-riscos.h
@@ -55,7 +55,7 @@
#undef NEED_REENTRANT
/* Define if you want to enable IPv6 support */
-#undef ENABLE_IPV6
+#undef USE_IPV6
/* Define if struct sockaddr_in6 has the sin6_scope_id member */
#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
@@ -66,9 +66,6 @@
/* Define this as a suitable file to read random data from */
#undef RANDOM_FILE
-/* Define if you want to enable IPv6 support */
-#undef ENABLE_IPV6
-
/* Define if you have the alarm function. */
#define HAVE_ALARM
diff --git a/libs/libcurl/src/config-win32.h b/libs/libcurl/src/config-win32.h
index ce440ddda3..17924e3dec 100644
--- a/libs/libcurl/src/config-win32.h
+++ b/libs/libcurl/src/config-win32.h
@@ -158,10 +158,6 @@
/* Define if you have the socket function. */
#define HAVE_SOCKET 1
-/* Define if libSSH2 is in use */
-#define USE_LIBSSH2 1
-#define HAVE_LIBSSH2_H 1
-
/* Define if you have the strcasecmp function. */
#if defined(__MINGW32__)
#define HAVE_STRCASECMP 1
@@ -478,9 +474,6 @@ Vista
#define USE_WIN32_LDAP 1
#endif
-/* if SSL is enabled */
-#define USE_OPENSSL 1
-
/* Define to use the Windows crypto library. */
#if !defined(CURL_WINDOWS_APP)
#define USE_WIN32_CRYPTO
@@ -516,8 +509,4 @@ Vista
/* If you want to build curl with the built-in manual */
#define USE_MANUAL 1
-#if defined(USE_IPV6)
-# define ENABLE_IPV6 1
-#endif
-
#endif /* HEADER_CURL_CONFIG_WIN32_H */
diff --git a/libs/libcurl/src/conncache.c b/libs/libcurl/src/conncache.c
index c3212450a4..00bb601cab 100644
--- a/libs/libcurl/src/conncache.c
+++ b/libs/libcurl/src/conncache.c
@@ -68,8 +68,7 @@ static void bundle_destroy(struct connectbundle *bundle)
static void bundle_add_conn(struct connectbundle *bundle,
struct connectdata *conn)
{
- Curl_llist_insert_next(&bundle->conn_list, bundle->conn_list.tail, conn,
- &conn->bundle_node);
+ Curl_llist_append(&bundle->conn_list, conn, &conn->bundle_node);
conn->bundle = bundle;
bundle->num_connections++;
}
@@ -101,7 +100,7 @@ static void free_bundle_hash_entry(void *freethis)
bundle_destroy(b);
}
-int Curl_conncache_init(struct conncache *connc, int size)
+int Curl_conncache_init(struct conncache *connc, size_t size)
{
/* allocate a new easy handle to use when closing cached connections */
connc->closure_handle = curl_easy_init();
@@ -141,7 +140,7 @@ static void hashkey(struct connectdata *conn, char *buf, size_t len)
hostname = conn->host.name;
/* put the numbers first so that the hostname gets cut off if too long */
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
msnprintf(buf, len, "%u/%ld/%s", conn->scope_id, port, hostname);
#else
msnprintf(buf, len, "%ld/%s", port, hostname);
diff --git a/libs/libcurl/src/conncache.h b/libs/libcurl/src/conncache.h
index 90a2bb917c..fe51706b56 100644
--- a/libs/libcurl/src/conncache.h
+++ b/libs/libcurl/src/conncache.h
@@ -85,7 +85,7 @@ struct connectbundle {
};
/* returns 1 on error, 0 is fine */
-int Curl_conncache_init(struct conncache *, int size);
+int Curl_conncache_init(struct conncache *, size_t size);
void Curl_conncache_destroy(struct conncache *connc);
/* return the correct bundle, to a host or a proxy */
diff --git a/libs/libcurl/src/connect.c b/libs/libcurl/src/connect.c
index c391b0d99b..7ca66eaea1 100644
--- a/libs/libcurl/src/connect.c
+++ b/libs/libcurl/src/connect.c
@@ -195,7 +195,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, int *port)
{
struct sockaddr_in *si = NULL;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct sockaddr_in6 *si6 = NULL;
#endif
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
@@ -214,7 +214,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
return TRUE;
}
break;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case AF_INET6:
si6 = (struct sockaddr_in6 *)(void *) sa;
if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
@@ -401,7 +401,7 @@ static CURLcode eyeballer_new(struct eyeballer **pballer,
return CURLE_OUT_OF_MEMORY;
baller->name = ((ai_family == AF_INET)? "ipv4" : (
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
(ai_family == AF_INET6)? "ipv6" :
#endif
"ip"));
@@ -779,7 +779,7 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
/* any IP version is allowed */
ai_family0 = remotehost->addr?
remotehost->addr->ai_family : 0;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
ai_family1 = ai_family0 == AF_INET6 ?
AF_INET : AF_INET6;
#else
@@ -790,7 +790,7 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
/* only one IP version is allowed */
ai_family0 = (conn->ip_version == CURL_IPRESOLVE_V4) ?
AF_INET :
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
AF_INET6;
#else
AF_UNSPEC;
@@ -1117,7 +1117,7 @@ const
#endif
struct transport_provider transport_providers[] = {
{ TRNSPRT_TCP, Curl_cf_tcp_create },
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
{ TRNSPRT_QUIC, Curl_cf_quic_create },
#endif
#ifndef CURL_DISABLE_TFTP
diff --git a/libs/libcurl/src/content_encoding.c b/libs/libcurl/src/content_encoding.c
index cccf027489..2e8ec147e6 100644
--- a/libs/libcurl/src/content_encoding.c
+++ b/libs/libcurl/src/content_encoding.c
@@ -300,7 +300,7 @@ static CURLcode deflate_do_write(struct Curl_easy *data,
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
- if(!(type & CLIENTWRITE_BODY))
+ if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
/* Set the compressed input when this function is called */
@@ -457,7 +457,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
- if(!(type & CLIENTWRITE_BODY))
+ if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(zp->zlib_init == ZLIB_INIT_GZIP) {
@@ -669,7 +669,7 @@ static CURLcode brotli_do_write(struct Curl_easy *data,
CURLcode result = CURLE_OK;
BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
- if(!(type & CLIENTWRITE_BODY))
+ if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(!bp->br)
@@ -762,7 +762,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data,
ZSTD_outBuffer out;
size_t errorCode;
- if(!(type & CLIENTWRITE_BODY))
+ if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(!zp->decomp) {
@@ -916,7 +916,7 @@ static CURLcode error_do_write(struct Curl_easy *data,
(void) buf;
(void) nbytes;
- if(!(type & CLIENTWRITE_BODY))
+ if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
failf(data, "Unrecognized content encoding type. "
@@ -978,6 +978,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
do {
const char *name;
size_t namelen;
+ bool is_chunked = FALSE;
/* Parse a single encoding name. */
while(ISBLANK(*enclist) || *enclist == ',')
@@ -993,10 +994,11 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
const struct Curl_cwtype *cwt;
struct Curl_cwriter *writer;
+ is_chunked = (is_transfer && (namelen == 7) &&
+ strncasecompare(name, "chunked", 7));
/* if we skip the decoding in this phase, do not look further.
* Exception is "chunked" transfer-encoding which always must happen */
- if((is_transfer && !data->set.http_transfer_encoding &&
- (namelen != 7 || !strncasecompare(name, "chunked", 7))) ||
+ if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) ||
(!is_transfer && data->set.http_ce_skip)) {
/* not requested, ignore */
return CURLE_OK;
@@ -1009,6 +1011,31 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
}
cwt = find_unencode_writer(name, namelen, phase);
+ if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) {
+ /* A 'chunked' transfer encoding has already been added.
+ * Ignore duplicates. See #13451.
+ * Also RFC 9112, ch. 6.1:
+ * "A sender MUST NOT apply the chunked transfer coding more than
+ * once to a message body."
+ */
+ return CURLE_OK;
+ }
+
+ if(is_transfer && !is_chunked &&
+ Curl_cwriter_get_by_name(data, "chunked")) {
+ /* RFC 9112, ch. 6.1:
+ * "If any transfer coding other than chunked is applied to a
+ * response's content, the sender MUST either apply chunked as the
+ * final transfer coding or terminate the message by closing the
+ * connection."
+ * "chunked" must be the last added to be the first in its phase,
+ * reject this.
+ */
+ failf(data, "Reject response due to 'chunked' not being the last "
+ "Transfer-Encoding");
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
if(!cwt)
cwt = &error_writer; /* Defer error at use. */
diff --git a/libs/libcurl/src/cookie.c b/libs/libcurl/src/cookie.c
index 1689f7fa41..020fa529ab 100644
--- a/libs/libcurl/src/cookie.c
+++ b/libs/libcurl/src/cookie.c
@@ -886,7 +886,8 @@ Curl_cookie_add(struct Curl_easy *data,
* Now loop through the fields and init the struct we already have
* allocated
*/
- for(ptr = firstptr, fields = 0; ptr && !badcookie;
+ fields = 0;
+ for(ptr = firstptr; ptr && !badcookie;
ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
switch(fields) {
case 0:
diff --git a/libs/libcurl/src/curl_addrinfo.c b/libs/libcurl/src/curl_addrinfo.c
index 2dd0edcede..949482ff54 100644
--- a/libs/libcurl/src/curl_addrinfo.c
+++ b/libs/libcurl/src/curl_addrinfo.c
@@ -130,7 +130,7 @@ Curl_getaddrinfo_ex(const char *nodename,
/* settle family-specific sockaddr structure size. */
if(ai->ai_family == AF_INET)
ss_size = sizeof(struct sockaddr_in);
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else if(ai->ai_family == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
#endif
@@ -259,7 +259,7 @@ Curl_he2ai(const struct hostent *he, int port)
struct Curl_addrinfo *prevai = NULL;
struct Curl_addrinfo *firstai = NULL;
struct sockaddr_in *addr;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct sockaddr_in6 *addr6;
#endif
CURLcode result = CURLE_OK;
@@ -275,7 +275,7 @@ Curl_he2ai(const struct hostent *he, int port)
for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
size_t ss_size;
size_t namelen = strlen(he->h_name) + 1; /* include null-terminator */
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if(he->h_addrtype == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
else
@@ -321,7 +321,7 @@ Curl_he2ai(const struct hostent *he, int port)
addr->sin_port = htons((unsigned short)port);
break;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case AF_INET6:
addr6 = (void *)ai->ai_addr; /* storage area for this info */
@@ -348,7 +348,7 @@ struct namebuff {
struct hostent hostentry;
union {
struct in_addr ina4;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct in6_addr ina6;
#endif
} addrentry;
@@ -401,7 +401,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
addrentry = (void *)&buf->addrentry.ina4;
memcpy(addrentry, inaddr, sizeof(struct in_addr));
break;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case AF_INET6:
addrsize = sizeof(struct in6_addr);
addrentry = (void *)&buf->addrentry.ina6;
@@ -447,7 +447,7 @@ struct Curl_addrinfo *Curl_str2addr(char *address, int port)
if(Curl_inet_pton(AF_INET, address, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
return Curl_ip2addr(AF_INET, &in, address, port);
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
{
struct in6_addr in6;
if(Curl_inet_pton(AF_INET6, address, &in6) > 0)
@@ -570,7 +570,7 @@ void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
{
struct Curl_addrinfo *ca;
struct sockaddr_in *addr;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct sockaddr_in6 *addr6;
#endif
for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
@@ -580,7 +580,7 @@ void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
addr->sin_port = htons((unsigned short)port);
break;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case AF_INET6:
addr6 = (void *)ca->ai_addr; /* storage area for this info */
addr6->sin6_port = htons((unsigned short)port);
diff --git a/libs/libcurl/src/curl_config.h.cmake b/libs/libcurl/src/curl_config.h.cmake
index d88710fed3..ef7e308e0d 100644
--- a/libs/libcurl/src/curl_config.h.cmake
+++ b/libs/libcurl/src/curl_config.h.cmake
@@ -163,7 +163,7 @@
#cmakedefine USE_WIN32_LDAP 1
/* Define if you want to enable IPv6 support */
-#cmakedefine ENABLE_IPV6 1
+#cmakedefine USE_IPV6 1
/* Define to 1 if you have the alarm function. */
#cmakedefine HAVE_ALARM 1
@@ -199,6 +199,12 @@
/* Define to 1 if you have the `closesocket' function. */
#cmakedefine HAVE_CLOSESOCKET 1
+/* Define to 1 if you have the <dirent.h> header file. */
+#cmakedefine HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the `opendir' function. */
+#cmakedefine HAVE_OPENDIR 1
+
/* Define to 1 if you have the fcntl function. */
#cmakedefine HAVE_FCNTL 1
@@ -704,6 +710,9 @@ ${SIZEOF_TIME_T_CODE}
/* if OpenSSL is in use */
#cmakedefine USE_OPENSSL 1
+/* if librtmp/rtmpdump is in use */
+#cmakedefine USE_LIBRTMP 1
+
/* Define to 1 if you don't want the OpenSSL configuration to be loaded
automatically */
#cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1
@@ -767,12 +776,6 @@ ${SIZEOF_TIME_T_CODE}
/* Type to use in place of in_addr_t when system does not provide it. */
#cmakedefine in_addr_t ${in_addr_t}
-/* Define to `__inline__' or `__inline' if that's what the C compiler
- calls it, or to nothing if 'inline' is not supported under any name. */
-#ifndef __cplusplus
-#undef inline
-#endif
-
/* Define to `unsigned int' if <sys/types.h> does not define. */
#cmakedefine size_t ${size_t}
@@ -785,6 +788,9 @@ ${SIZEOF_TIME_T_CODE}
/* to enable Windows IDN */
#cmakedefine USE_WIN32_IDN 1
+/* to enable Apple IDN */
+#cmakedefine USE_APPLE_IDN 1
+
/* Define to 1 to enable websocket support. */
#cmakedefine USE_WEBSOCKETS 1
@@ -796,3 +802,9 @@ ${SIZEOF_TIME_T_CODE}
/* Define to 1 to enable TLS-SRP support. */
#cmakedefine USE_TLS_SRP 1
+
+/* Define to 1 to query for HTTPSRR when using DoH */
+#cmakedefine USE_HTTPSRR 1
+
+/* if ECH support is available */
+#cmakedefine USE_ECH 1
diff --git a/libs/libcurl/src/curl_config.h.in b/libs/libcurl/src/curl_config.h.in
index 47ac9ec690..c85b2f1b25 100644
--- a/libs/libcurl/src/curl_config.h.in
+++ b/libs/libcurl/src/curl_config.h.in
@@ -1,5 +1,8 @@
/* lib/curl_config.h.in. Generated from configure.ac by autoheader. */
+/* Ignore c-ares deprecation warnings */
+#undef CARES_NO_DEPRECATED
+
/* to enable curl debug memory tracking */
#undef CURLDEBUG
@@ -150,9 +153,6 @@
/* enable debug build options */
#undef DEBUGBUILD
-/* Define if you want to enable IPv6 support */
-#undef ENABLE_IPV6
-
/* Define to the type of arg 2 for gethostname. */
#undef GETHOSTNAME_TYPE_ARG2
@@ -209,6 +209,9 @@
/* "Set if getpwuid_r() declaration is missing" */
#undef HAVE_DECL_GETPWUID_R_MISSING
+/* if you have <dirent.h> */
+#undef HAVE_DIRENT_H
+
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
@@ -478,6 +481,9 @@
*/
#undef HAVE_OLD_GSSMIT
+/* if you have opendir */
+#undef HAVE_OPENDIR
+
/* Define to 1 if using OpenSSL 3 or later. */
#undef HAVE_OPENSSL3
@@ -593,8 +599,8 @@
/* Define to 1 if you have the <socket.h> header file. */
#undef HAVE_SOCKET_H
-/* Define to 1 if you have the `SSL_get_ech_status' function. */
-#undef HAVE_SSL_GET_ECH_STATUS
+/* Define to 1 if you have the `SSL_ech_set1_echconfig' function. */
+#undef HAVE_SSL_ECH_SET1_ECHCONFIG
/* Define to 1 if you have the <ssl.h> header file. */
#undef HAVE_SSL_H
@@ -602,6 +608,9 @@
/* Define to 1 if you have the `SSL_set0_wbio' function. */
#undef HAVE_SSL_SET0_WBIO
+/* Define to 1 if you have the `SSL_set1_ech_config_list' function. */
+#undef HAVE_SSL_SET1_ECH_CONFIG_LIST
+
/* Define to 1 if you have the `SSL_set_quic_use_legacy_codepoint' function.
*/
#undef HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT
@@ -729,6 +738,9 @@
/* Define to 1 if you have the <wolfssh/ssh.h> header file. */
#undef HAVE_WOLFSSH_SSH_H
+/* Define to 1 if you have the `wolfSSL_CTX_GenerateEchConfig' function. */
+#undef HAVE_WOLFSSL_CTX_GENERATEECHCONFIG
+
/* if you have wolfSSL_DES_ecb_encrypt */
#undef HAVE_WOLFSSL_DES_ECB_ENCRYPT
@@ -768,12 +780,6 @@
/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
#undef NEED_THREAD_SAFE
-/* Define to enable NTLM delegation to winbind's ntlm_auth helper. */
-#undef NTLM_WB_ENABLED
-
-/* Define absolute filename for winbind's ntlm_auth helper. */
-#undef NTLM_WB_FILE
-
/* cpu-machine-OS */
#undef OS
@@ -848,9 +854,15 @@
/* GSASL support enabled */
#undef USE_GSASL
+/* force HTTPS RR support for ECH */
+#undef USE_HTTPSRR
+
/* if hyper is in use */
#undef USE_HYPER
+/* Define if you want to enable IPv6 support */
+#undef USE_IPV6
+
/* if libpsl is in use */
#undef USE_LIBPSL
@@ -982,12 +994,6 @@
/* Type to use in place of in_addr_t when system does not provide it. */
#undef in_addr_t
-/* Define to `__inline__' or `__inline' if that's what the C compiler
- calls it, or to nothing if 'inline' is not supported under any name. */
-#ifndef __cplusplus
-#undef inline
-#endif
-
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
diff --git a/libs/libcurl/src/curl_gethostname.c b/libs/libcurl/src/curl_gethostname.c
index 3f3c09f0bc..c42482e478 100644
--- a/libs/libcurl/src/curl_gethostname.c
+++ b/libs/libcurl/src/curl_gethostname.c
@@ -68,7 +68,7 @@ int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
/* Override host name when environment variable CURL_GETHOSTNAME is set */
const char *force_hostname = getenv("CURL_GETHOSTNAME");
if(force_hostname) {
- strncpy(name, force_hostname, namelen);
+ strncpy(name, force_hostname, namelen - 1);
err = 0;
}
else {
diff --git a/libs/libcurl/src/curl_multibyte.c b/libs/libcurl/src/curl_multibyte.c
index 7448f51f3a..a991df2906 100644
--- a/libs/libcurl/src/curl_multibyte.c
+++ b/libs/libcurl/src/curl_multibyte.c
@@ -159,21 +159,4 @@ int curlx_win32_stat(const char *path, struct_stat *buffer)
#endif
}
-int curlx_win32_access(const char *path, int mode)
-{
-#if defined(_UNICODE)
- int result = -1;
- wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
- if(path_w) {
- result = _waccess(path_w, mode);
- curlx_unicodefree(path_w);
- }
- else
- errno = EINVAL;
- return result;
-#else
- return _access(path, mode);
-#endif
-}
-
#endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */
diff --git a/libs/libcurl/src/curl_ntlm_wb.c b/libs/libcurl/src/curl_ntlm_wb.c
deleted file mode 100644
index 5afdb310d6..0000000000
--- a/libs/libcurl/src/curl_ntlm_wb.c
+++ /dev/null
@@ -1,500 +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"
-
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
- defined(NTLM_WB_ENABLED)
-
-/*
- * NTLM details:
- *
- * https://davenport.sourceforge.net/ntlm.html
- * https://www.innovation.ch/java/ntlm.html
- */
-
-#define DEBUG_ME 0
-
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-#include <signal.h>
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "select.h"
-#include "vauth/ntlm.h"
-#include "curl_ntlm_core.h"
-#include "curl_ntlm_wb.h"
-#include "url.h"
-#include "strerror.h"
-#include "strdup.h"
-#include "strcase.h"
-
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-#if DEBUG_ME
-# define DEBUG_OUT(x) x
-#else
-# define DEBUG_OUT(x) Curl_nop_stmt
-#endif
-
-/* Portable 'sclose_nolog' used only in child process instead of 'sclose'
- to avoid fooling the socket leak detector */
-#ifdef HAVE_PIPE
-# define sclose_nolog(x) close((x))
-#elif defined(HAVE_CLOSESOCKET)
-# define sclose_nolog(x) closesocket((x))
-#elif defined(HAVE_CLOSESOCKET_CAMEL)
-# define sclose_nolog(x) CloseSocket((x))
-#else
-# define sclose_nolog(x) close((x))
-#endif
-
-static void ntlm_wb_cleanup(struct ntlmdata *ntlm)
-{
- if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
- sclose(ntlm->ntlm_auth_hlpr_socket);
- ntlm->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
- }
-
- if(ntlm->ntlm_auth_hlpr_pid) {
- int i;
- for(i = 0; i < 4; i++) {
- pid_t ret = waitpid(ntlm->ntlm_auth_hlpr_pid, NULL, WNOHANG);
- if(ret == ntlm->ntlm_auth_hlpr_pid || errno == ECHILD)
- break;
- switch(i) {
- case 0:
- kill(ntlm->ntlm_auth_hlpr_pid, SIGTERM);
- break;
- case 1:
- /* Give the process another moment to shut down cleanly before
- bringing down the axe */
- Curl_wait_ms(1);
- break;
- case 2:
- kill(ntlm->ntlm_auth_hlpr_pid, SIGKILL);
- break;
- case 3:
- break;
- }
- }
- ntlm->ntlm_auth_hlpr_pid = 0;
- }
-
- Curl_safefree(ntlm->challenge);
- Curl_safefree(ntlm->response);
-}
-
-static CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm,
- const char *userp)
-{
- curl_socket_t sockfds[2];
- pid_t child_pid;
- const char *username;
- char *slash, *domain = NULL;
- const char *ntlm_auth = NULL;
- char *ntlm_auth_alloc = NULL;
-#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
- struct passwd pw, *pw_res;
- char pwbuf[1024];
-#endif
- char buffer[STRERROR_LEN];
-
-#if defined(CURL_DISABLE_VERBOSE_STRINGS)
- (void) data;
-#endif
-
- /* Return if communication with ntlm_auth already set up */
- if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
- ntlm->ntlm_auth_hlpr_pid)
- return CURLE_OK;
-
- username = userp;
- /* The real ntlm_auth really doesn't like being invoked with an
- empty username. It won't make inferences for itself, and expects
- the client to do so (mostly because it's really designed for
- servers like squid to use for auth, and client support is an
- afterthought for it). So try hard to provide a suitable username
- if we don't already have one. But if we can't, provide the
- empty one anyway. Perhaps they have an implementation of the
- ntlm_auth helper which *doesn't* need it so we might as well try */
- if(!username || !username[0]) {
- username = getenv("NTLMUSER");
- if(!username || !username[0])
- username = getenv("LOGNAME");
- if(!username || !username[0])
- username = getenv("USER");
-#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
- if((!username || !username[0]) &&
- !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) &&
- pw_res) {
- username = pw.pw_name;
- }
-#endif
- if(!username || !username[0])
- username = userp;
- }
- slash = strpbrk(username, "\\/");
- if(slash) {
- domain = strdup(username);
- if(!domain)
- return CURLE_OUT_OF_MEMORY;
- slash = domain + (slash - username);
- *slash = '\0';
- username = username + (slash - domain) + 1;
- }
-
- /* For testing purposes, when DEBUGBUILD is defined and environment
- variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform
- NTLM challenge/response which only accepts commands and output
- strings pre-written in test case definitions */
-#ifdef DEBUGBUILD
- ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE");
- if(ntlm_auth_alloc)
- ntlm_auth = ntlm_auth_alloc;
- else
-#endif
- ntlm_auth = NTLM_WB_FILE;
-
- if(access(ntlm_auth, X_OK) != 0) {
- failf(data, "Could not access ntlm_auth: %s errno %d: %s",
- ntlm_auth, errno, Curl_strerror(errno, buffer, sizeof(buffer)));
- goto done;
- }
-
- if(wakeup_create(sockfds)) {
- failf(data, "Could not open socket pair. errno %d: %s",
- errno, Curl_strerror(errno, buffer, sizeof(buffer)));
- goto done;
- }
-
- child_pid = fork();
- if(child_pid == -1) {
- wakeup_close(sockfds[0]);
- wakeup_close(sockfds[1]);
- failf(data, "Could not fork. errno %d: %s",
- errno, Curl_strerror(errno, buffer, sizeof(buffer)));
- goto done;
- }
- else if(!child_pid) {
- /*
- * child process
- */
-
- /* Don't use sclose in the child since it fools the socket leak detector */
- sclose_nolog(sockfds[0]);
- if(dup2(sockfds[1], STDIN_FILENO) == -1) {
- failf(data, "Could not redirect child stdin. errno %d: %s",
- errno, Curl_strerror(errno, buffer, sizeof(buffer)));
- exit(1);
- }
-
- if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
- failf(data, "Could not redirect child stdout. errno %d: %s",
- errno, Curl_strerror(errno, buffer, sizeof(buffer)));
- exit(1);
- }
-
- if(domain)
- execl(ntlm_auth, ntlm_auth,
- "--helper-protocol", "ntlmssp-client-1",
- "--use-cached-creds",
- "--username", username,
- "--domain", domain,
- NULL);
- else
- execl(ntlm_auth, ntlm_auth,
- "--helper-protocol", "ntlmssp-client-1",
- "--use-cached-creds",
- "--username", username,
- NULL);
-
- sclose_nolog(sockfds[1]);
- failf(data, "Could not execl(). errno %d: %s",
- errno, Curl_strerror(errno, buffer, sizeof(buffer)));
- exit(1);
- }
-
- sclose(sockfds[1]);
- ntlm->ntlm_auth_hlpr_socket = sockfds[0];
- ntlm->ntlm_auth_hlpr_pid = child_pid;
- free(domain);
- free(ntlm_auth_alloc);
- return CURLE_OK;
-
-done:
- free(domain);
- free(ntlm_auth_alloc);
- return CURLE_REMOTE_ACCESS_DENIED;
-}
-
-/* if larger than this, something is seriously wrong */
-#define MAX_NTLM_WB_RESPONSE 100000
-
-static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
- const char *input, curlntlm state)
-{
- size_t len_in = strlen(input), len_out = 0;
- struct dynbuf b;
- char *ptr = NULL;
- unsigned char buf[1024];
- Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE);
-
- while(len_in > 0) {
- ssize_t written = wakeup_write(ntlm->ntlm_auth_hlpr_socket, input, len_in);
- if(written == -1) {
- /* Interrupted by a signal, retry it */
- if(errno == EINTR)
- continue;
- /* write failed if other errors happen */
- goto done;
- }
- input += written;
- len_in -= written;
- }
- /* Read one line */
- while(1) {
- ssize_t size =
- wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, sizeof(buf));
- if(size == -1) {
- if(errno == EINTR)
- continue;
- goto done;
- }
- else if(size == 0)
- goto done;
-
- if(Curl_dyn_addn(&b, buf, size))
- goto done;
-
- len_out = Curl_dyn_len(&b);
- ptr = Curl_dyn_ptr(&b);
- if(len_out && ptr[len_out - 1] == '\n') {
- ptr[len_out - 1] = '\0';
- break; /* done! */
- }
- /* loop */
- }
-
- /* Samba/winbind installed but not configured */
- if(state == NTLMSTATE_TYPE1 &&
- len_out == 3 &&
- ptr[0] == 'P' && ptr[1] == 'W')
- goto done;
- /* invalid response */
- if(len_out < 4)
- goto done;
- if(state == NTLMSTATE_TYPE1 &&
- (ptr[0]!='Y' || ptr[1]!='R' || ptr[2]!=' '))
- goto done;
- if(state == NTLMSTATE_TYPE2 &&
- (ptr[0]!='K' || ptr[1]!='K' || ptr[2]!=' ') &&
- (ptr[0]!='A' || ptr[1]!='F' || ptr[2]!=' '))
- goto done;
-
- ntlm->response = strdup(ptr + 3);
- Curl_dyn_free(&b);
- if(!ntlm->response)
- return CURLE_OUT_OF_MEMORY;
- return CURLE_OK;
-done:
- Curl_dyn_free(&b);
- return CURLE_REMOTE_ACCESS_DENIED;
-}
-
-CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
- struct connectdata *conn,
- bool proxy,
- const char *header)
-{
- struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
- curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
-
- (void) data; /* In case it gets unused by nop log macros. */
-
- if(!checkprefix("NTLM", header))
- return CURLE_BAD_CONTENT_ENCODING;
-
- header += strlen("NTLM");
- while(*header && ISSPACE(*header))
- header++;
-
- if(*header) {
- ntlm->challenge = strdup(header);
- if(!ntlm->challenge)
- return CURLE_OUT_OF_MEMORY;
-
- *state = NTLMSTATE_TYPE2; /* We got a type-2 message */
- }
- else {
- if(*state == NTLMSTATE_LAST) {
- infof(data, "NTLM auth restarted");
- Curl_http_auth_cleanup_ntlm_wb(conn);
- }
- else if(*state == NTLMSTATE_TYPE3) {
- infof(data, "NTLM handshake rejected");
- Curl_http_auth_cleanup_ntlm_wb(conn);
- *state = NTLMSTATE_NONE;
- return CURLE_REMOTE_ACCESS_DENIED;
- }
- else if(*state >= NTLMSTATE_TYPE1) {
- infof(data, "NTLM handshake failure (internal error)");
- return CURLE_REMOTE_ACCESS_DENIED;
- }
-
- *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
- }
-
- return CURLE_OK;
-}
-
-/*
- * This is for creating ntlm header output by delegating challenge/response
- * to Samba's winbind daemon helper ntlm_auth.
- */
-CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
- bool proxy)
-{
- /* point to the address of the pointer that holds the string to send to the
- server, which is for a plain host or for an HTTP proxy */
- char **allocuserpwd;
- /* point to the name and password for this */
- const char *userp;
- struct ntlmdata *ntlm;
- curlntlm *state;
- struct auth *authp;
-
- CURLcode res = CURLE_OK;
-
- DEBUGASSERT(conn);
- DEBUGASSERT(data);
-
- if(proxy) {
-#ifndef CURL_DISABLE_PROXY
- allocuserpwd = &data->state.aptr.proxyuserpwd;
- userp = conn->http_proxy.user;
- ntlm = &conn->proxyntlm;
- state = &conn->proxy_ntlm_state;
- authp = &data->state.authproxy;
-#else
- return CURLE_NOT_BUILT_IN;
-#endif
- }
- else {
- allocuserpwd = &data->state.aptr.userpwd;
- userp = conn->user;
- ntlm = &conn->ntlm;
- state = &conn->http_ntlm_state;
- authp = &data->state.authhost;
- }
- authp->done = FALSE;
-
- /* not set means empty */
- if(!userp)
- userp = "";
-
- switch(*state) {
- case NTLMSTATE_TYPE1:
- default:
- /* Use Samba's 'winbind' daemon to support NTLM authentication,
- * by delegating the NTLM challenge/response protocol to a helper
- * in ntlm_auth.
- * https://web.archive.org/web/20190925164737
- * /devel.squid-cache.org/ntlm/squid_helper_protocol.html
- * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
- * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
- * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this
- * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute
- * filename of ntlm_auth helper.
- * If NTLM authentication using winbind fails, go back to original
- * request handling process.
- */
- /* Create communication with ntlm_auth */
- res = ntlm_wb_init(data, ntlm, userp);
- if(res)
- return res;
- res = ntlm_wb_response(data, ntlm, "YR\n", *state);
- if(res)
- return res;
-
- free(*allocuserpwd);
- *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
- proxy ? "Proxy-" : "",
- ntlm->response);
- DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
- Curl_safefree(ntlm->response);
- if(!*allocuserpwd)
- return CURLE_OUT_OF_MEMORY;
- break;
-
- case NTLMSTATE_TYPE2: {
- char *input = aprintf("TT %s\n", ntlm->challenge);
- if(!input)
- return CURLE_OUT_OF_MEMORY;
- res = ntlm_wb_response(data, ntlm, input, *state);
- free(input);
- if(res)
- return res;
-
- free(*allocuserpwd);
- *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
- proxy ? "Proxy-" : "",
- ntlm->response);
- DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
- *state = NTLMSTATE_TYPE3; /* we sent a type-3 */
- authp->done = TRUE;
- Curl_http_auth_cleanup_ntlm_wb(conn);
- if(!*allocuserpwd)
- return CURLE_OUT_OF_MEMORY;
- break;
- }
- case NTLMSTATE_TYPE3:
- /* connection is already authenticated,
- * don't send a header in future requests */
- *state = NTLMSTATE_LAST;
- FALLTHROUGH();
- case NTLMSTATE_LAST:
- Curl_safefree(*allocuserpwd);
- authp->done = TRUE;
- break;
- }
-
- return CURLE_OK;
-}
-
-void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn)
-{
- ntlm_wb_cleanup(&conn->ntlm);
- ntlm_wb_cleanup(&conn->proxyntlm);
-}
-
-#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */
diff --git a/libs/libcurl/src/curl_path.c b/libs/libcurl/src/curl_path.c
index 7adc040a22..f2b23fecc2 100644
--- a/libs/libcurl/src/curl_path.c
+++ b/libs/libcurl/src/curl_path.c
@@ -98,8 +98,8 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
return CURLE_OK;
}
-/* The get_pathname() function is being borrowed from OpenSSH sftp.c
- version 4.6p1. */
+/* The original get_pathname() function came from OpenSSH sftp.c version
+ 4.6p1. */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -115,38 +115,37 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
+
+#define MAX_PATHLENGTH 65535 /* arbitrary long */
+
+CURLcode Curl_get_pathname(const char **cpp, char **path, const char *homedir)
{
const char *cp = *cpp, *end;
char quot;
- unsigned int i, j;
- size_t fullPathLength, pathLength;
- bool relativePath = false;
+ unsigned int i;
static const char WHITESPACE[] = " \t\r\n";
+ struct dynbuf out;
+ CURLcode result;
DEBUGASSERT(homedir);
- if(!*cp || !homedir) {
- *cpp = NULL;
- *path = NULL;
+ *path = NULL;
+ *cpp = NULL;
+ if(!*cp || !homedir)
return CURLE_QUOTE_ERROR;
- }
+
+ Curl_dyn_init(&out, MAX_PATHLENGTH);
+
/* Ignore leading whitespace */
cp += strspn(cp, WHITESPACE);
- /* Allocate enough space for home directory and filename + separator */
- fullPathLength = strlen(cp) + strlen(homedir) + 2;
- *path = malloc(fullPathLength);
- if(!*path)
- return CURLE_OUT_OF_MEMORY;
/* Check for quoted filenames */
if(*cp == '\"' || *cp == '\'') {
quot = *cp++;
/* Search for terminating quote, unescape some chars */
- for(i = j = 0; i <= strlen(cp); i++) {
+ for(i = 0; i <= strlen(cp); i++) {
if(cp[i] == quot) { /* Found quote */
i++;
- (*path)[j] = '\0';
break;
}
if(cp[i] == '\0') { /* End of string */
@@ -159,40 +158,45 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
goto fail;
}
}
- (*path)[j++] = cp[i];
+ result = Curl_dyn_addn(&out, &cp[i], 1);
+ if(result)
+ return result;
}
- if(j == 0) {
+ if(!Curl_dyn_len(&out))
goto fail;
- }
- *cpp = cp + i + strspn(cp + i, WHITESPACE);
+
+ /* return pointer to second parameter if it exists */
+ *cpp = &cp[i] + strspn(&cp[i], WHITESPACE);
}
else {
/* Read to end of filename - either to whitespace or terminator */
end = strpbrk(cp, WHITESPACE);
if(!end)
end = strchr(cp, '\0');
+
/* return pointer to second parameter if it exists */
*cpp = end + strspn(end, WHITESPACE);
- pathLength = 0;
- relativePath = (cp[0] == '/' && cp[1] == '~' && cp[2] == '/');
+
/* Handling for relative path - prepend home directory */
- if(relativePath) {
- strcpy(*path, homedir);
- pathLength = strlen(homedir);
- (*path)[pathLength++] = '/';
- (*path)[pathLength] = '\0';
+ if(cp[0] == '/' && cp[1] == '~' && cp[2] == '/') {
+ result = Curl_dyn_add(&out, homedir);
+ if(!result)
+ result = Curl_dyn_addn(&out, "/", 1);
+ if(result)
+ return result;
cp += 3;
}
/* Copy path name up until first "whitespace" */
- memcpy(&(*path)[pathLength], cp, (int)(end - cp));
- pathLength += (int)(end - cp);
- (*path)[pathLength] = '\0';
+ result = Curl_dyn_addn(&out, cp, (end - cp));
+ if(result)
+ return result;
}
+ *path = Curl_dyn_ptr(&out);
return CURLE_OK;
fail:
- Curl_safefree(*path);
+ Curl_dyn_free(&out);
return CURLE_QUOTE_ERROR;
}
diff --git a/libs/libcurl/src/curl_path.h b/libs/libcurl/src/curl_path.h
index 3c0d0b7480..ea56d20eba 100644
--- a/libs/libcurl/src/curl_path.h
+++ b/libs/libcurl/src/curl_path.h
@@ -45,5 +45,5 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
char *homedir,
char **path);
-CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir);
+CURLcode Curl_get_pathname(const char **cpp, char **path, const char *homedir);
#endif /* HEADER_CURL_PATH_H */
diff --git a/libs/libcurl/src/curl_rtmp.c b/libs/libcurl/src/curl_rtmp.c
index 467bde6002..38b6646404 100644
--- a/libs/libcurl/src/curl_rtmp.c
+++ b/libs/libcurl/src/curl_rtmp.c
@@ -35,8 +35,10 @@
#include "warnless.h"
#include <curl/curl.h>
#include <librtmp/rtmp.h>
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
#include "curl_memory.h"
-/* The last #include file should be: */
#include "memdebug.h"
#if defined(_WIN32) && !defined(USE_LWIPSOCK)
@@ -66,7 +68,7 @@ static Curl_send rtmp_send;
*/
const struct Curl_handler Curl_handler_rtmp = {
- "RTMP", /* scheme */
+ "rtmp", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -80,6 +82,7 @@ const struct Curl_handler Curl_handler_rtmp = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMP, /* defport */
@@ -89,7 +92,7 @@ const struct Curl_handler Curl_handler_rtmp = {
};
const struct Curl_handler Curl_handler_rtmpt = {
- "RTMPT", /* scheme */
+ "rtmpt", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -103,6 +106,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPT, /* defport */
@@ -112,7 +116,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
};
const struct Curl_handler Curl_handler_rtmpe = {
- "RTMPE", /* scheme */
+ "rtmpe", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -126,6 +130,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMP, /* defport */
@@ -135,7 +140,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
};
const struct Curl_handler Curl_handler_rtmpte = {
- "RTMPTE", /* scheme */
+ "rtmpte", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -149,6 +154,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPT, /* defport */
@@ -158,7 +164,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
};
const struct Curl_handler Curl_handler_rtmps = {
- "RTMPS", /* scheme */
+ "rtmps", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -172,6 +178,7 @@ const struct Curl_handler Curl_handler_rtmps = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPS, /* defport */
@@ -181,7 +188,7 @@ const struct Curl_handler Curl_handler_rtmps = {
};
const struct Curl_handler Curl_handler_rtmpts = {
- "RTMPTS", /* scheme */
+ "rtmpts", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -195,6 +202,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPS, /* defport */
@@ -335,4 +343,20 @@ static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
return num;
}
+
+void Curl_rtmp_version(char *version, size_t len)
+{
+ char suff[2];
+ if(RTMP_LIB_VERSION & 0xff) {
+ suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1;
+ suff[1] = '\0';
+ }
+ else
+ suff[0] = '\0';
+
+ msnprintf(version, len, "librtmp/%d.%d%s",
+ RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
+ suff);
+}
+
#endif /* USE_LIBRTMP */
diff --git a/libs/libcurl/src/curl_rtmp.h b/libs/libcurl/src/curl_rtmp.h
index c526153b9c..29521a2d33 100644
--- a/libs/libcurl/src/curl_rtmp.h
+++ b/libs/libcurl/src/curl_rtmp.h
@@ -30,6 +30,8 @@ extern const struct Curl_handler Curl_handler_rtmpe;
extern const struct Curl_handler Curl_handler_rtmpte;
extern const struct Curl_handler Curl_handler_rtmps;
extern const struct Curl_handler Curl_handler_rtmpts;
+
+void Curl_rtmp_version(char *version, size_t len);
#endif
#endif /* HEADER_CURL_RTMP_H */
diff --git a/libs/libcurl/src/curl_sasl.c b/libs/libcurl/src/curl_sasl.c
index 8ec942cd1c..c03fc0863d 100644
--- a/libs/libcurl/src/curl_sasl.c
+++ b/libs/libcurl/src/curl_sasl.c
@@ -376,7 +376,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_EXTERNAL;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_external_message(conn->user, &resp);
+ Curl_auth_create_external_message(conn->user, &resp);
}
else if(data->state.aptr.user) {
#if defined(USE_KERBEROS5)
@@ -498,7 +498,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_LOGIN;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_login_message(conn->user, &resp);
+ Curl_auth_create_login_message(conn->user, &resp);
}
}
@@ -576,14 +576,14 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
conn->user, conn->passwd, &resp);
break;
case SASL_LOGIN:
- result = Curl_auth_create_login_message(conn->user, &resp);
+ Curl_auth_create_login_message(conn->user, &resp);
newstate = SASL_LOGIN_PASSWD;
break;
case SASL_LOGIN_PASSWD:
- result = Curl_auth_create_login_message(conn->passwd, &resp);
+ Curl_auth_create_login_message(conn->passwd, &resp);
break;
case SASL_EXTERNAL:
- result = Curl_auth_create_external_message(conn->user, &resp);
+ Curl_auth_create_external_message(conn->user, &resp);
break;
#ifdef USE_GSASL
case SASL_GSASL:
diff --git a/libs/libcurl/src/curl_setup.h b/libs/libcurl/src/curl_setup.h
index 37436a4459..a6731c4f6a 100644
--- a/libs/libcurl/src/curl_setup.h
+++ b/libs/libcurl/src/curl_setup.h
@@ -60,6 +60,21 @@
# ifndef NOGDI
# define NOGDI
# endif
+/* Detect Windows App environment which has a restricted access
+ * to the Win32 APIs. */
+# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
+ defined(WINAPI_FAMILY)
+# include <winapifamily.h>
+# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+ !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# define CURL_WINDOWS_APP
+# endif
+# endif
+#endif
+
+/* Compatibility */
+#if defined(ENABLE_IPV6)
+# define USE_IPV6 1
#endif
/*
@@ -276,7 +291,8 @@
/* based on logic in "curl/mprintf.h" */
-#if (defined(__GNUC__) || defined(__clang__)) && \
+#if (defined(__GNUC__) || defined(__clang__) || \
+ defined(__IAR_SYSTEMS_ICC__)) && \
defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
!defined(CURL_NO_FMT_CHECKS)
#if defined(__MINGW32__) && !defined(__clang__)
@@ -299,7 +315,7 @@
#include <TargetConditionals.h>
#define USE_RESOLVE_ON_IPS 1
# if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && \
- defined(ENABLE_IPV6)
+ defined(USE_IPV6)
# define CURL_MACOS_CALL_COPYPROXIES 1
# endif
#endif
@@ -394,11 +410,9 @@
# define LSEEK_ERROR (__int64)-1
# define open curlx_win32_open
# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
-# define access(fname,mode) curlx_win32_access(fname, mode)
int curlx_win32_open(const char *filename, int oflag, ...);
int curlx_win32_stat(const char *path, struct_stat *buffer);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
- int curlx_win32_access(const char *path, int mode);
#endif
/*
@@ -417,11 +431,9 @@
# define struct_stat struct _stat
# define open curlx_win32_open
# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
-# define access(fname,mode) curlx_win32_access(fname, mode)
int curlx_win32_stat(const char *path, struct_stat *buffer);
int curlx_win32_open(const char *filename, int oflag, ...);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
- int curlx_win32_access(const char *path, int mode);
# endif
# define LSEEK_ERROR (long)-1
#endif
@@ -496,11 +508,14 @@
# error "curl_off_t must be exactly 64 bits"
#else
typedef unsigned CURL_TYPEOF_CURL_OFF_T curl_uint64_t;
+ typedef CURL_TYPEOF_CURL_OFF_T curl_int64_t;
# ifndef CURL_SUFFIX_CURL_OFF_TU
# error "CURL_SUFFIX_CURL_OFF_TU must be defined"
# endif
# define CURL_UINT64_SUFFIX CURL_SUFFIX_CURL_OFF_TU
# define CURL_UINT64_C(val) CURL_CONC_MACROS(val,CURL_UINT64_SUFFIX)
+# define CURL_PRId64 CURL_FORMAT_CURL_OFF_T
+# define CURL_PRIu64 CURL_FORMAT_CURL_OFF_TU
#endif
#if (SIZEOF_TIME_T == 4)
@@ -607,9 +622,9 @@
* Mutually exclusive CURLRES_* definitions.
*/
-#if defined(ENABLE_IPV6) && defined(HAVE_GETADDRINFO)
+#if defined(USE_IPV6) && defined(HAVE_GETADDRINFO)
# define CURLRES_IPV6
-#elif defined(ENABLE_IPV6) && (defined(_WIN32) || defined(__CYGWIN__))
+#elif defined(USE_IPV6) && (defined(_WIN32) || defined(__CYGWIN__))
/* assume on Windows that IPv6 without getaddrinfo is a broken build */
# error "Unexpected build: IPv6 is enabled but getaddrinfo was not found."
#else
@@ -631,13 +646,14 @@
/* ---------------------------------------------------------------- */
-#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN)
+#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && \
+ !defined(USE_WIN32_IDN) && !defined(USE_APPLE_IDN)
/* The lib and header are present */
#define USE_LIBIDN2
#endif
-#if defined(USE_LIBIDN2) && defined(USE_WIN32_IDN)
-#error "Both libidn2 and WinIDN are enabled, choose one."
+#if defined(USE_LIBIDN2) && (defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN))
+#error "libidn2 cannot be enabled with WinIDN or AppleIDN, choose one."
#endif
#define LIBIDN_REQUIRED_VERSION "0.4.1"
@@ -691,6 +707,13 @@
((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7)))
# define UNUSED_PARAM __attribute__((__unused__))
# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#elif defined(__IAR_SYSTEMS_ICC__)
+# define UNUSED_PARAM __attribute__((__unused__))
+# if (__VER__ >= 9040001)
+# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+# else
+# define WARN_UNUSED_RESULT
+# endif
#else
# define UNUSED_PARAM /* NOTHING */
# define WARN_UNUSED_RESULT
@@ -699,7 +722,8 @@
/* noreturn attribute */
#if !defined(CURL_NORETURN)
-#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__)
+#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) || \
+ defined(__IAR_SYSTEMS_ICC__)
# define CURL_NORETURN __attribute__((__noreturn__))
#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
# define CURL_NORETURN __declspec(noreturn)
@@ -842,7 +866,6 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#error "Multi-SSL combined with QUIC is not supported"
#endif
-#define ENABLE_QUIC
#define USE_HTTP3
#endif
@@ -873,4 +896,26 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#define OPENSSL_SUPPRESS_DEPRECATED
#endif
+#if defined(inline)
+ /* 'inline' is defined as macro and assumed to be correct */
+ /* No need for 'inline' replacement */
+#elif defined(__cplusplus)
+ /* The code is compiled with C++ compiler.
+ C++ always supports 'inline'. */
+ /* No need for 'inline' replacement */
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
+ /* C99 (and later) supports 'inline' keyword */
+ /* No need for 'inline' replacement */
+#elif defined(__GNUC__) && __GNUC__ >= 3
+ /* GCC supports '__inline__' as an extension */
+# define inline __inline__
+#elif defined(_MSC_VER) && _MSC_VER >= 1400
+ /* MSC supports '__inline' from VS 2005 (or even earlier) */
+# define inline __inline
+#else
+ /* Probably 'inline' is not supported by compiler.
+ Define to the empty string to be on the safe side. */
+# define inline /* empty */
+#endif
+
#endif /* HEADER_CURL_SETUP_H */
diff --git a/libs/libcurl/src/curl_setup_once.h b/libs/libcurl/src/curl_setup_once.h
index 2d92332eed..ed72008f58 100644
--- a/libs/libcurl/src/curl_setup_once.h
+++ b/libs/libcurl/src/curl_setup_once.h
@@ -164,9 +164,7 @@ struct timeval {
(RECV_TYPE_ARG4)(0))
#else /* HAVE_RECV */
#ifndef sread
- /* */
- Error Missing_definition_of_macro_sread
- /* */
+#error "Missing definition of macro sread!"
#endif
#endif /* HAVE_RECV */
@@ -184,9 +182,7 @@ struct timeval {
(SEND_TYPE_ARG4)(SEND_4TH_ARG))
#else /* HAVE_SEND */
#ifndef swrite
- /* */
- Error Missing_definition_of_macro_swrite
- /* */
+#error "Missing definition of macro swrite!"
#endif
#endif /* HAVE_SEND */
diff --git a/libs/libcurl/src/curl_sha512_256.c b/libs/libcurl/src/curl_sha512_256.c
index e1d6c4bc99..bd96af1c4e 100644
--- a/libs/libcurl/src/curl_sha512_256.c
+++ b/libs/libcurl/src/curl_sha512_256.c
@@ -44,7 +44,7 @@
# include <openssl/opensslv.h>
# if (!defined(LIBRESSL_VERSION_NUMBER) && \
defined(OPENSSL_VERSION_NUMBER) && \
- (OPENSSL_VERSION_NUMBER >= 0x10100010L)) || \
+ (OPENSSL_VERSION_NUMBER >= 0x10101000L)) || \
(defined(LIBRESSL_VERSION_NUMBER) && \
(LIBRESSL_VERSION_NUMBER >= 0x3080000fL))
# include <openssl/opensslconf.h>
@@ -52,6 +52,27 @@
# include <openssl/evp.h>
# define USE_OPENSSL_SHA512_256 1
# define HAS_SHA512_256_IMPLEMENTATION 1
+# ifdef __NetBSD__
+/* Some NetBSD versions has a bug in SHA-512/256.
+ * See https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=58039
+ * The problematic versions:
+ * - NetBSD before 9.4
+ * - NetBSD 9 all development versions (9.99.x)
+ * - NetBSD 10 development versions (10.99.x) before 10.99.11
+ * The bug was fixed in NetBSD 9.4 release, NetBSD 10.0 release,
+ * NetBSD 10.99.11 development.
+ * It is safe to apply the workaround even if the bug is not present, as
+ * the workaround just reduces performance slightly. */
+# include <sys/param.h>
+# if __NetBSD_Version__ < 904000000 || \
+ (__NetBSD_Version__ >= 999000000 && \
+ __NetBSD_Version__ < 1000000000) || \
+ (__NetBSD_Version__ >= 1099000000 && \
+ __NetBSD_Version__ < 1099001100)
+# define NEED_NETBSD_SHA512_256_WORKAROUND 1
+# include <string.h>
+# endif
+# endif
# endif
# endif
#endif /* USE_OPENSSL */
@@ -153,7 +174,7 @@ Curl_sha512_256_finish(unsigned char *digest,
CURLcode ret;
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
-#ifdef __NetBSD__
+#ifdef NEED_NETBSD_SHA512_256_WORKAROUND
/* Use a larger buffer to work around a bug in NetBSD:
https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=58039 */
unsigned char tmp_digest[SHA512_256_DIGEST_SIZE * 2];
@@ -161,9 +182,10 @@ Curl_sha512_256_finish(unsigned char *digest,
tmp_digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
if(ret == CURLE_OK)
memcpy(digest, tmp_digest, SHA512_256_DIGEST_SIZE);
-#else /* ! __NetBSD__ */
+ explicit_memset(tmp_digest, 0, sizeof(tmp_digest));
+#else /* ! NEED_NETBSD_SHA512_256_WORKAROUND */
ret = EVP_DigestFinal_ex(*ctx, digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
-#endif /* ! __NetBSD__ */
+#endif /* ! NEED_NETBSD_SHA512_256_WORKAROUND */
EVP_MD_CTX_destroy(*ctx);
*ctx = NULL;
@@ -264,29 +286,13 @@ Curl_sha512_256_finish(unsigned char *digest,
defined(_MSC_VER) && !defined(__GNUC__) && !defined(__clang__)
# if _MSC_VER >= 1400
# define MHDX_INLINE __forceinline
-# else
-# define MHDX_INLINE /* empty */
# endif
#endif
#if !defined(MHDX_INLINE)
-# if defined(inline)
- /* Assume that 'inline' macro was already defined correctly by
- * the build system. */
-# define MHDX_INLINE inline
-# elif defined(__cplusplus)
- /* The code is compiled with C++ compiler.
- * C++ always supports 'inline'. */
-# define MHDX_INLINE inline
-# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
- /* C99 (and later) supports 'inline' keyword */
-# define MHDX_INLINE inline
-# elif defined(__GNUC__) && __GNUC__ >= 3
- /* GCC supports '__inline__' as an extension */
-# define MHDX_INLINE __inline__
-# else
-# define MHDX_INLINE /* empty */
-# endif
+ /* Assume that 'inline' keyword works or the
+ * macro was already defined correctly. */
+# define MHDX_INLINE inline
#endif
/* Bits manipulation macros and functions.
diff --git a/libs/libcurl/src/curl_threads.c b/libs/libcurl/src/curl_threads.c
index 41bcdbc91e..ea343a1e23 100644
--- a/libs/libcurl/src/curl_threads.c
+++ b/libs/libcurl/src/curl_threads.c
@@ -131,7 +131,8 @@ curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
void Curl_thread_destroy(curl_thread_t hnd)
{
- CloseHandle(hnd);
+ if(hnd != curl_thread_t_null)
+ CloseHandle(hnd);
}
int Curl_thread_join(curl_thread_t *hnd)
diff --git a/libs/libcurl/src/curl_trc.c b/libs/libcurl/src/curl_trc.c
index 9dc9fddea8..eba9d57d52 100644
--- a/libs/libcurl/src/curl_trc.c
+++ b/libs/libcurl/src/curl_trc.c
@@ -111,21 +111,30 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
/* 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 * const fmt, va_list ap) CURL_PRINTF(3, 0);
+
+static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
+ const char * const fmt, va_list ap)
+{
+ int len = 0;
+ char buffer[MAXINFO + 2];
+ if(feat)
+ len = msnprintf(buffer, MAXINFO, "[%s] ", feat->name);
+ len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
+ buffer[len++] = '\n';
+ buffer[len] = '\0';
+ Curl_debug(data, CURLINFO_TEXT, buffer, len);
+}
+
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
{
DEBUGASSERT(!strchr(fmt, '\n'));
if(Curl_trc_is_verbose(data)) {
va_list ap;
- int len = 0;
- char buffer[MAXINFO + 2];
- if(data->state.feat)
- len = msnprintf(buffer, MAXINFO, "[%s] ", data->state.feat->name);
va_start(ap, fmt);
- len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
+ trc_infof(data, data->state.feat, fmt, ap);
va_end(ap);
- buffer[len++] = '\n';
- buffer[len] = '\0';
- Curl_debug(data, CURLINFO_TEXT, buffer, len);
}
}
@@ -154,7 +163,61 @@ void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
}
}
+struct curl_trc_feat Curl_trc_feat_read = {
+ "READ",
+ CURL_LOG_LVL_NONE,
+};
+struct curl_trc_feat Curl_trc_feat_write = {
+ "WRITE",
+ CURL_LOG_LVL_NONE,
+};
+
+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, fmt, ap);
+ va_end(ap);
+ }
+}
+
+void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
+{
+ DEBUGASSERT(!strchr(fmt, '\n'));
+ 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, fmt, ap);
+ va_end(ap);
+ }
+}
+
+#ifndef CURL_DISABLE_FTP
+struct curl_trc_feat Curl_trc_feat_ftp = {
+ "FTP",
+ CURL_LOG_LVL_NONE,
+};
+
+void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
+{
+ DEBUGASSERT(!strchr(fmt, '\n'));
+ 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, fmt, ap);
+ va_end(ap);
+ }
+}
+#endif /* !CURL_DISABLE_FTP */
+
static struct curl_trc_feat *trc_feats[] = {
+ &Curl_trc_feat_read,
+ &Curl_trc_feat_write,
+#ifndef CURL_DISABLE_FTP
+ &Curl_trc_feat_ftp,
+#endif
#ifndef CURL_DISABLE_DOH
&Curl_doh_trc,
#endif
@@ -188,7 +251,7 @@ static struct Curl_cftype *cf_types[] = {
&Curl_cft_haproxy,
&Curl_cft_socks_proxy,
#endif /* !CURL_DISABLE_PROXY */
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
&Curl_cft_http3,
#endif
#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
diff --git a/libs/libcurl/src/curl_trc.h b/libs/libcurl/src/curl_trc.h
index 3949c5027f..437e54cb30 100644
--- a/libs/libcurl/src/curl_trc.h
+++ b/libs/libcurl/src/curl_trc.h
@@ -77,12 +77,32 @@ void Curl_failf(struct Curl_easy *data,
#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)
+#define CURL_TRC_WRITE(data, ...) \
+ do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) \
+ Curl_trc_write(data, __VA_ARGS__); } while(0)
+#define CURL_TRC_READ(data, ...) \
+ do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) \
+ Curl_trc_read(data, __VA_ARGS__); } while(0)
+
+#ifndef CURL_DISABLE_FTP
+#define CURL_TRC_FTP(data, ...) \
+ do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) \
+ Curl_trc_ftp(data, __VA_ARGS__); } while(0)
+#endif /* !CURL_DISABLE_FTP */
+
+#else /* CURL_HAVE_C99 */
-#else
#define infof Curl_infof
#define CURL_TRC_CF Curl_trc_cf_infof
+#define CURL_TRC_WRITE Curl_trc_write
+#define CURL_TRC_READ Curl_trc_read
+
+#ifndef CURL_DISABLE_FTP
+#define CURL_TRC_FTP Curl_trc_ftp
#endif
+#endif /* !CURL_HAVE_C99 */
+
#ifndef CURL_DISABLE_VERBOSE_STRINGS
/* informational messages enabled */
@@ -90,6 +110,8 @@ struct curl_trc_feat {
const char *name;
int log_level;
};
+extern struct curl_trc_feat Curl_trc_feat_read;
+extern struct curl_trc_feat Curl_trc_feat_write;
#define Curl_trc_is_verbose(data) \
((data) && (data)->set.verbose && \
@@ -97,10 +119,10 @@ struct curl_trc_feat {
((data)->state.feat->log_level >= CURL_LOG_LVL_INFO)))
#define Curl_trc_cf_is_verbose(cf, data) \
(Curl_trc_is_verbose(data) && \
- (cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
+ (cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
#define Curl_trc_ft_is_verbose(data, ft) \
- (Curl_trc_is_verbose(data) && \
- (ft)->log_level >= CURL_LOG_LVL_INFO)
+ (Curl_trc_is_verbose(data) && \
+ (ft)->log_level >= CURL_LOG_LVL_INFO)
/**
* Output an informational message when transfer's verbose logging is enabled.
@@ -114,13 +136,26 @@ 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_ft_infof(struct Curl_easy *data, struct curl_trc_feat *ft,
+ const char *fmt, ...) CURL_PRINTF(3, 4);
+void Curl_trc_write(struct Curl_easy *data,
+ const char *fmt, ...) CURL_PRINTF(2, 3);
+void Curl_trc_read(struct Curl_easy *data,
+ const char *fmt, ...) CURL_PRINTF(2, 3);
+
+#ifndef CURL_DISABLE_FTP
+extern struct curl_trc_feat Curl_trc_feat_ftp;
+void Curl_trc_ftp(struct Curl_easy *data,
+ const char *fmt, ...) CURL_PRINTF(2, 3);
+#endif
+
#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
/* All informational messages are not compiled in for size savings */
-#define Curl_trc_is_verbose(d) ((void)(d), FALSE)
-#define Curl_trc_cf_is_verbose(x,y) ((void)(x), (void)(y), FALSE)
-#define Curl_trc_ft_is_verbose(x,y) ((void)(x), (void)(y), FALSE)
+#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)
static void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
{
@@ -134,6 +169,32 @@ static void Curl_trc_cf_infof(struct Curl_easy *data,
(void)data; (void)cf; (void)fmt;
}
+struct curl_trc_feat;
+
+static void Curl_trc_ft_infof(struct Curl_easy *data,
+ struct curl_trc_feat *ft,
+ const char *fmt, ...)
+{
+ (void)data; (void)ft; (void)fmt;
+}
+
+static void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
+{
+ (void)data; (void)fmt;
+}
+
+static void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
+{
+ (void)data; (void)fmt;
+}
+
+#ifndef CURL_DISABLE_FTP
+static void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
+{
+ (void)data; (void)fmt;
+}
+#endif
+
#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
#endif /* HEADER_CURL_TRC_H */
diff --git a/libs/libcurl/src/curlx.h b/libs/libcurl/src/curlx.h
index 0b8dcb44cc..daa46f46af 100644
--- a/libs/libcurl/src/curlx.h
+++ b/libs/libcurl/src/curlx.h
@@ -77,7 +77,6 @@
*/
-#define curlx_getenv curl_getenv
#define curlx_mvsnprintf curl_mvsnprintf
#define curlx_msnprintf curl_msnprintf
#define curlx_maprintf curl_maprintf
diff --git a/libs/libcurl/src/cw-out.c b/libs/libcurl/src/cw-out.c
index a2f6904051..bf6250c519 100644
--- a/libs/libcurl/src/cw-out.c
+++ b/libs/libcurl/src/cw-out.c
@@ -102,6 +102,8 @@ static void cw_out_buf_free(struct cw_out_buf *cwbuf)
struct cw_out_ctx {
struct Curl_cwriter super;
struct cw_out_buf *buf;
+ BIT(paused);
+ BIT(errored);
};
static CURLcode cw_out_write(struct Curl_easy *data,
@@ -201,7 +203,10 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
size_t max_write, min_write;
size_t wlen, nwritten;
- (void)ctx;
+ /* If we errored once, we do not invoke the client callback again */
+ if(ctx->errored)
+ return CURLE_WRITE_ERROR;
+
/* write callbacks may get NULLed by the client between calls. */
cw_get_writefunc(data, otype, &wcb, &wcb_data, &max_write, &min_write);
if(!wcb) {
@@ -210,13 +215,16 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
}
*pconsumed = 0;
- while(blen && !(data->req.keepon & KEEP_RECV_PAUSE)) {
+ while(blen && !ctx->paused) {
if(!flush_all && blen < min_write)
break;
wlen = max_write? CURLMIN(blen, max_write) : blen;
Curl_set_in_callback(data, TRUE);
nwritten = wcb((char *)buf, 1, wlen, wcb_data);
Curl_set_in_callback(data, FALSE);
+ CURL_TRC_WRITE(data, "cw_out, wrote %zu %s bytes -> %zu",
+ wlen, (otype == CW_OUT_BODY)? "body" : "header",
+ nwritten);
if(CURL_WRITEFUNC_PAUSE == nwritten) {
if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) {
/* Protocols that work without network cannot be paused. This is
@@ -227,9 +235,15 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
}
/* mark the connection as RECV paused */
data->req.keepon |= KEEP_RECV_PAUSE;
+ ctx->paused = TRUE;
+ CURL_TRC_WRITE(data, "cw_out, PAUSE requested by client");
break;
}
- if(nwritten != wlen) {
+ else if(CURL_WRITEFUNC_ERROR == nwritten) {
+ failf(data, "client returned ERROR on write of %zu bytes", wlen);
+ return CURLE_WRITE_ERROR;
+ }
+ else if(nwritten != wlen) {
failf(data, "Failure writing output to destination, "
"passed %zu returned %zd", wlen, nwritten);
return CURLE_WRITE_ERROR;
@@ -283,7 +297,7 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
if(!cwbuf)
return CURLE_OK;
- if(data->req.keepon & KEEP_RECV_PAUSE)
+ if(ctx->paused)
return CURLE_OK;
/* write the end of the chain until it blocks or gets empty */
@@ -296,7 +310,7 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
return result;
if(*plast) {
/* could not write last, paused again? */
- DEBUGASSERT(data->req.keepon & KEEP_RECV_PAUSE);
+ DEBUGASSERT(ctx->paused);
return CURLE_OK;
}
}
@@ -338,14 +352,14 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
bool flush_all,
const char *buf, size_t blen)
{
- CURLcode result;
+ CURLcode result = CURLE_OK;
/* if we have buffered data and it is a different type than what
* we are writing now, try to flush all */
if(ctx->buf && ctx->buf->type != otype) {
result = cw_out_flush_chain(ctx, data, &ctx->buf, TRUE);
if(result)
- return result;
+ goto out;
}
if(ctx->buf) {
@@ -355,7 +369,7 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
return result;
result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
if(result)
- return result;
+ goto out;
}
else {
/* nothing buffered, try direct write */
@@ -368,10 +382,18 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
/* did not write all, append the rest */
result = cw_out_append(ctx, otype, buf + consumed, blen - consumed);
if(result)
- return result;
+ goto out;
}
}
- return CURLE_OK;
+
+out:
+ if(result) {
+ /* We do not want to invoked client callbacks a second time after
+ * encountering an error. See issue #13337 */
+ ctx->errored = TRUE;
+ cw_out_bufs_free(ctx);
+ }
+ return result;
}
static CURLcode cw_out_write(struct Curl_easy *data,
@@ -409,10 +431,12 @@ bool Curl_cw_out_is_paused(struct Curl_easy *data)
return FALSE;
ctx = (struct cw_out_ctx *)cw_out;
- return cw_out_bufs_len(ctx) > 0;
+ CURL_TRC_WRITE(data, "cw-out is%spaused", ctx->paused? "" : " not");
+ return ctx->paused;
}
-static CURLcode cw_out_flush(struct Curl_easy *data, bool flush_all)
+static CURLcode cw_out_flush(struct Curl_easy *data,
+ bool unpause, bool flush_all)
{
struct Curl_cwriter *cw_out;
CURLcode result = CURLE_OK;
@@ -420,18 +444,31 @@ static CURLcode cw_out_flush(struct Curl_easy *data, bool flush_all)
cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
if(cw_out) {
struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
+ if(ctx->errored)
+ return CURLE_WRITE_ERROR;
+ if(unpause && ctx->paused)
+ ctx->paused = FALSE;
+ if(ctx->paused)
+ return CURLE_OK; /* not doing it */
result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
+ if(result) {
+ ctx->errored = TRUE;
+ cw_out_bufs_free(ctx);
+ return result;
+ }
}
return result;
}
-CURLcode Curl_cw_out_flush(struct Curl_easy *data)
+CURLcode Curl_cw_out_unpause(struct Curl_easy *data)
{
- return cw_out_flush(data, FALSE);
+ CURL_TRC_WRITE(data, "cw-out unpause");
+ return cw_out_flush(data, TRUE, FALSE);
}
CURLcode Curl_cw_out_done(struct Curl_easy *data)
{
- return cw_out_flush(data, TRUE);
+ CURL_TRC_WRITE(data, "cw-out done");
+ return cw_out_flush(data, FALSE, TRUE);
}
diff --git a/libs/libcurl/src/cw-out.h b/libs/libcurl/src/cw-out.h
index ecdd8d4ce6..e5afe097a0 100644
--- a/libs/libcurl/src/cw-out.h
+++ b/libs/libcurl/src/cw-out.h
@@ -43,7 +43,7 @@ bool Curl_cw_out_is_paused(struct Curl_easy *data);
/**
* Flush any buffered date to the client, chunk collation still applies.
*/
-CURLcode Curl_cw_out_flush(struct Curl_easy *data);
+CURLcode Curl_cw_out_unpause(struct Curl_easy *data);
/**
* Mark EndOfStream reached and flush ALL data to the client.
diff --git a/libs/libcurl/src/dict.c b/libs/libcurl/src/dict.c
index 75649398f8..5e79b1cf3f 100644
--- a/libs/libcurl/src/dict.c
+++ b/libs/libcurl/src/dict.c
@@ -76,7 +76,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done);
*/
const struct Curl_handler Curl_handler_dict = {
- "DICT", /* scheme */
+ "dict", /* scheme */
ZERO_NULL, /* setup_connection */
dict_do, /* do_it */
ZERO_NULL, /* done */
@@ -90,6 +90,7 @@ const struct Curl_handler Curl_handler_dict = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_DICT, /* defport */
diff --git a/libs/libcurl/src/dllmain.c b/libs/libcurl/src/dllmain.c
new file mode 100644
index 0000000000..ad064c8b9d
--- /dev/null
+++ b/libs/libcurl/src/dllmain.c
@@ -0,0 +1,81 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#ifdef USE_OPENSSL
+#include <openssl/crypto.h>
+#endif
+
+/* The fourth-to-last include */
+#ifdef __CYGWIN__
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#ifdef _WIN32
+#undef _WIN32
+#endif
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* DllMain() must only be defined for Windows and Cygwin DLL builds. */
+#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(CURL_STATICLIB)
+
+#if defined(USE_OPENSSL) && \
+ !defined(OPENSSL_IS_AWSLC) && \
+ !defined(OPENSSL_IS_BORINGSSL) && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#define PREVENT_OPENSSL_MEMLEAK
+#endif
+
+#ifdef PREVENT_OPENSSL_MEMLEAK
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ (void)hinstDLL;
+ (void)lpvReserved;
+
+ switch(fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ /* Call OPENSSL_thread_stop to prevent a memory leak in case OpenSSL is
+ linked statically.
+ https://github.com/curl/curl/issues/12327#issuecomment-1826405944 */
+ OPENSSL_thread_stop();
+ break;
+ }
+ return TRUE;
+}
+#endif /* OpenSSL */
+
+#endif /* DLL build */
diff --git a/libs/libcurl/src/doh.c b/libs/libcurl/src/doh.c
index f63710b09d..8164cf5b78 100644
--- a/libs/libcurl/src/doh.c
+++ b/libs/libcurl/src/doh.c
@@ -42,9 +42,13 @@
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
+#include "escape.h"
#define DNS_CLASS_IN 0x01
+/* local_print_buf truncates if the hex string will be more than this */
+#define LOCAL_PB_HEXMAX 400
+
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char * const errors[]={
"",
@@ -187,6 +191,26 @@ doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
return realsize;
}
+#if defined(USE_HTTPSRR) && defined(CURLDEBUG)
+static void local_print_buf(struct Curl_easy *data,
+ const char *prefix,
+ unsigned char *buf, size_t len)
+{
+ unsigned char hexstr[LOCAL_PB_HEXMAX];
+ size_t hlen = LOCAL_PB_HEXMAX;
+ bool truncated = false;
+
+ if(len > (LOCAL_PB_HEXMAX / 2))
+ truncated = true;
+ Curl_hexencode(buf, len, hexstr, hlen);
+ if(!truncated)
+ infof(data, "%s: len=%d, val=%s", prefix, (int)len, hexstr);
+ else
+ infof(data, "%s: len=%d (truncated)val=%s", prefix, (int)len, hexstr);
+ return;
+}
+#endif
+
/* called from multi.c when this DoH transfer is complete */
static int doh_done(struct Curl_easy *doh, CURLcode result)
{
@@ -379,6 +403,12 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
int slot;
struct dohdata *dohp;
struct connectdata *conn = data->conn;
+#ifdef USE_HTTPSRR
+ /* for now, this is only used when ECH is enabled */
+# ifdef USE_ECH
+ char *qname = NULL;
+# endif
+#endif
*waitp = FALSE;
(void)hostname;
(void)port;
@@ -408,7 +438,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
goto error;
dohp->pending++;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if((conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
/* create IPv6 DoH request */
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
@@ -419,6 +449,37 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
dohp->pending++;
}
#endif
+
+#ifdef USE_HTTPSRR
+ /*
+ * TODO: Figure out the conditions under which we want to make
+ * a request for an HTTPS RR when we are not doing ECH. For now,
+ * making this request breaks a bunch of DoH tests, e.g. test2100,
+ * where the additional request doesn't match the pre-cooked data
+ * files, so there's a bit of work attached to making the request
+ * in a non-ECH use-case. For the present, we'll only make the
+ * request when ECH is enabled in the build and is being used for
+ * the curl operation.
+ */
+# ifdef USE_ECH
+ if(data->set.tls_ech & CURLECH_ENABLE
+ || data->set.tls_ech & CURLECH_HARD) {
+ if(port == 443)
+ qname = strdup(hostname);
+ else
+ qname = aprintf("_%d._https.%s", port, hostname);
+ if(!qname)
+ goto error;
+ result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_HTTPS],
+ DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
+ data->multi, dohp->headers);
+ free(qname);
+ if(result)
+ goto error;
+ dohp->pending++;
+ }
+# endif
+#endif
*waitp = TRUE; /* this never returns synchronously */
return NULL;
@@ -501,6 +562,25 @@ static DOHcode store_aaaa(const unsigned char *doh,
return DOH_OK;
}
+#ifdef USE_HTTPSRR
+static DOHcode store_https(const unsigned char *doh,
+ int index,
+ struct dohentry *d,
+ uint16_t len)
+{
+ /* silently ignore RRs over the limit */
+ if(d->numhttps_rrs < DOH_MAX_HTTPS) {
+ struct dohhttps_rr *h = &d->https_rrs[d->numhttps_rrs];
+ h->val = Curl_memdup(&doh[index], len);
+ if(!h->val)
+ return DOH_OUT_OF_MEM;
+ h->len = len;
+ d->numhttps_rrs++;
+ }
+ return DOH_OK;
+}
+#endif
+
static DOHcode store_cname(const unsigned char *doh,
size_t dohlen,
unsigned int index,
@@ -563,7 +643,8 @@ static DOHcode rdata(const unsigned char *doh,
/* RDATA
- A (TYPE 1): 4 bytes
- AAAA (TYPE 28): 16 bytes
- - NS (TYPE 2): N bytes */
+ - NS (TYPE 2): N bytes
+ - HTTPS (TYPE 65): N bytes */
DOHcode rc;
switch(type) {
@@ -581,6 +662,13 @@ static DOHcode rdata(const unsigned char *doh,
if(rc)
return rc;
break;
+#ifdef USE_HTTPSRR
+ case DNS_TYPE_HTTPS:
+ rc = store_https(doh, index, d, rdlength);
+ if(rc)
+ return rc;
+ break;
+#endif
case DNS_TYPE_CNAME:
rc = store_cname(doh, dohlen, index, d);
if(rc)
@@ -737,7 +825,11 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
if(index != dohlen)
return DOH_DNS_MALFORMAT; /* something is wrong */
+#ifdef USE_HTTTPS
+ if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr && !d->numhttps_rrs)
+#else
if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr)
+#endif
/* nothing stored! */
return DOH_NO_CONTENT;
@@ -776,6 +868,16 @@ static void showdoh(struct Curl_easy *data,
infof(data, "%s", buffer);
}
}
+#ifdef USE_HTTPSRR
+ for(i = 0; i < d->numhttps_rrs; i++) {
+# ifdef CURLDEBUG
+ local_print_buf(data, "DoH HTTPS",
+ d->https_rrs[i].val, d->https_rrs[i].len);
+# else
+ infof(data, "DoH HTTPS RR: length %d", d->https_rrs[i].len);
+# endif
+ }
+#endif
for(i = 0; i < d->numcname; i++) {
infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i]));
}
@@ -804,7 +906,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
struct Curl_addrinfo *prevai = NULL;
struct Curl_addrinfo *firstai = NULL;
struct sockaddr_in *addr;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct sockaddr_in6 *addr6;
#endif
CURLcode result = CURLE_OK;
@@ -820,7 +922,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
size_t ss_size;
CURL_SA_FAMILY_T addrtype;
if(de->addr[i].type == DNS_TYPE_AAAA) {
-#ifndef ENABLE_IPV6
+#ifndef USE_IPV6
/* we can't handle IPv6 addresses */
continue;
#else
@@ -869,7 +971,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
addr->sin_port = htons((unsigned short)port);
break;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case AF_INET6:
addr6 = (void *)ai->ai_addr; /* storage area for this info */
DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
@@ -895,7 +997,18 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char *type2name(DNStype dnstype)
{
- return (dnstype == DNS_TYPE_A)?"A":"AAAA";
+ switch(dnstype) {
+ case DNS_TYPE_A:
+ return "A";
+ case DNS_TYPE_AAAA:
+ return "AAAA";
+#ifdef USE_HTTPSRR
+ case DNS_TYPE_HTTPS:
+ return "HTTPS";
+#endif
+ default:
+ return "unknown";
+ }
}
#endif
@@ -905,8 +1018,270 @@ UNITTEST void de_cleanup(struct dohentry *d)
for(i = 0; i < d->numcname; i++) {
Curl_dyn_free(&d->cname[i]);
}
+#ifdef USE_HTTPSRR
+ for(i = 0; i < d->numhttps_rrs; i++)
+ free(d->https_rrs[i].val);
+#endif
+}
+
+#ifdef USE_HTTPSRR
+
+/*
+ * @brief decode the DNS name in a binary RRData
+ * @param buf points to the buffer (in/out)
+ * @param remaining points to the remaining buffer length (in/out)
+ * @param dnsname returns the string form name on success
+ * @return is 1 for success, error otherwise
+ *
+ * The encoding here is defined in
+ * https://tools.ietf.org/html/rfc1035#section-3.1
+ *
+ * The input buffer pointer will be modified so it points to
+ * just after the end of the DNS name encoding on output. (And
+ * that's why it's an "unsigned char **" :-)
+ */
+static CURLcode local_decode_rdata_name(unsigned char **buf, size_t *remaining,
+ char **dnsname)
+{
+ unsigned char *cp = NULL;
+ int rem = 0;
+ unsigned char clen = 0; /* chunk len */
+ struct dynbuf thename;
+
+ DEBUGASSERT(buf && remaining && dnsname);
+ if(!buf || !remaining || !dnsname)
+ return CURLE_OUT_OF_MEMORY;
+ rem = (int)*remaining;
+ if(rem <= 0) {
+ Curl_dyn_free(&thename);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ Curl_dyn_init(&thename, CURL_MAXLEN_host_name);
+ cp = *buf;
+ clen = *cp++;
+ if(clen == 0) {
+ /* special case - return "." as name */
+ if(Curl_dyn_addn(&thename, ".", 1))
+ return CURLE_OUT_OF_MEMORY;
+ }
+ while(clen) {
+ if(clen >= rem) {
+ Curl_dyn_free(&thename);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if(Curl_dyn_addn(&thename, cp, clen) ||
+ Curl_dyn_addn(&thename, ".", 1))
+ return CURLE_TOO_LARGE;
+
+ cp += clen;
+ rem -= (clen + 1);
+ if(rem <= 0) {
+ Curl_dyn_free(&thename);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ clen = *cp++;
+ }
+ *buf = cp;
+ *remaining = rem - 1;
+ *dnsname = Curl_dyn_ptr(&thename);
+ return CURLE_OK;
}
+static CURLcode local_decode_rdata_alpn(unsigned char *rrval, size_t len,
+ char **alpns)
+{
+ /*
+ * spec here is as per draft-ietf-dnsop-svcb-https, section-7.1.1
+ * encoding is catenated list of strings each preceded by a one
+ * octet length
+ * output is comma-sep list of the strings
+ * implementations may or may not handle quoting of comma within
+ * string values, so we might see a comma within the wire format
+ * version of a string, in which case we'll precede that by a
+ * backslash - same goes for a backslash character, and of course
+ * we need to use two backslashes in strings when we mean one;-)
+ */
+ int remaining = (int) len;
+ char *oval;
+ size_t i;
+ unsigned char *cp = rrval;
+ struct dynbuf dval;
+
+ if(!alpns)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_dyn_init(&dval, DYN_DOH_RESPONSE);
+ remaining = (int)len;
+ cp = rrval;
+ while(remaining > 0) {
+ size_t tlen = (size_t) *cp++;
+
+ /* if not 1st time, add comma */
+ if(remaining != (int)len && Curl_dyn_addn(&dval, ",", 1))
+ goto err;
+ remaining--;
+ if(tlen > (size_t)remaining)
+ goto err;
+ /* add escape char if needed, clunky but easier to read */
+ for(i = 0; i != tlen; i++) {
+ if('\\' == *cp || ',' == *cp) {
+ if(Curl_dyn_addn(&dval, "\\", 1))
+ goto err;
+ }
+ if(Curl_dyn_addn(&dval, cp++, 1))
+ goto err;
+ }
+ remaining -= (int)tlen;
+ }
+ /* this string is always null terminated */
+ oval = Curl_dyn_ptr(&dval);
+ if(!oval)
+ goto err;
+ *alpns = oval;
+ return CURLE_OK;
+err:
+ Curl_dyn_free(&dval);
+ return CURLE_BAD_CONTENT_ENCODING;
+}
+
+#ifdef CURLDEBUG
+static CURLcode test_alpn_escapes(void)
+{
+ /* we'll use an example from draft-ietf-dnsop-svcb, figure 10 */
+ static unsigned char example[] = {
+ 0x08, /* length 8 */
+ 0x66, 0x5c, 0x6f, 0x6f, 0x2c, 0x62, 0x61, 0x72, /* value "f\\oo,bar" */
+ 0x02, /* length 2 */
+ 0x68, 0x32 /* value "h2" */
+ };
+ size_t example_len = sizeof(example);
+ char *aval = NULL;
+ static const char *expected = "f\\\\oo\\,bar,h2";
+
+ if(local_decode_rdata_alpn(example, example_len, &aval) != CURLE_OK)
+ return CURLE_BAD_CONTENT_ENCODING;
+ if(strlen(aval) != strlen(expected))
+ return CURLE_BAD_CONTENT_ENCODING;
+ if(memcmp(aval, expected, strlen(aval)))
+ return CURLE_BAD_CONTENT_ENCODING;
+ return CURLE_OK;
+}
+#endif
+
+static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
+ struct Curl_https_rrinfo **hrr)
+{
+ size_t remaining = len;
+ unsigned char *cp = rrval;
+ uint16_t pcode = 0, plen = 0;
+ struct Curl_https_rrinfo *lhrr = NULL;
+ char *dnsname = NULL;
+
+#ifdef CURLDEBUG
+ /* a few tests of escaping, shouldn't be here but ok for now */
+ if(test_alpn_escapes() != CURLE_OK)
+ return CURLE_OUT_OF_MEMORY;
+#endif
+ lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
+ if(!lhrr)
+ return CURLE_OUT_OF_MEMORY;
+ lhrr->val = Curl_memdup(rrval, len);
+ if(!lhrr->val)
+ goto err;
+ lhrr->len = len;
+ if(remaining <= 2)
+ goto err;
+ lhrr->priority = (uint16_t)((cp[0] << 8) + cp[1]);
+ cp += 2;
+ remaining -= (uint16_t)2;
+ if(local_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
+ goto err;
+ lhrr->target = dnsname;
+ while(remaining >= 4) {
+ pcode = (uint16_t)((*cp << 8) + (*(cp + 1)));
+ cp += 2;
+ plen = (uint16_t)((*cp << 8) + (*(cp + 1)));
+ cp += 2;
+ remaining -= 4;
+ if(pcode == HTTPS_RR_CODE_ALPN) {
+ if(local_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
+ goto err;
+ }
+ if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
+ lhrr->no_def_alpn = TRUE;
+ else if(pcode == HTTPS_RR_CODE_IPV4) {
+ lhrr->ipv4hints = Curl_memdup(cp, plen);
+ if(!lhrr->ipv4hints)
+ goto err;
+ lhrr->ipv4hints_len = (size_t)plen;
+ }
+ else if(pcode == HTTPS_RR_CODE_ECH) {
+ lhrr->echconfiglist = Curl_memdup(cp, plen);
+ if(!lhrr->echconfiglist)
+ goto err;
+ lhrr->echconfiglist_len = (size_t)plen;
+ }
+ else if(pcode == HTTPS_RR_CODE_IPV6) {
+ lhrr->ipv6hints = Curl_memdup(cp, plen);
+ if(!lhrr->ipv6hints)
+ goto err;
+ lhrr->ipv6hints_len = (size_t)plen;
+ }
+ if(plen > 0 && plen <= remaining) {
+ cp += plen;
+ remaining -= plen;
+ }
+ }
+ DEBUGASSERT(!remaining);
+ *hrr = lhrr;
+ return CURLE_OK;
+err:
+ if(lhrr) {
+ free(lhrr->target);
+ free(lhrr->echconfiglist);
+ free(lhrr->val);
+ free(lhrr);
+ }
+ return CURLE_OUT_OF_MEMORY;
+}
+
+# ifdef CURLDEBUG
+static void local_print_httpsrr(struct Curl_easy *data,
+ struct Curl_https_rrinfo *hrr)
+{
+ DEBUGASSERT(hrr);
+ infof(data, "HTTPS RR: priority %d, target: %s",
+ hrr->priority, hrr->target);
+ if(hrr->alpns)
+ infof(data, "HTTPS RR: alpns %s", hrr->alpns);
+ else
+ infof(data, "HTTPS RR: no alpns");
+ if(hrr->no_def_alpn)
+ infof(data, "HTTPS RR: no_def_alpn set");
+ else
+ infof(data, "HTTPS RR: no_def_alpn not set");
+ if(hrr->ipv4hints) {
+ local_print_buf(data, "HTTPS RR: ipv4hints",
+ hrr->ipv4hints, hrr->ipv4hints_len);
+ }
+ else
+ infof(data, "HTTPS RR: no ipv4hints");
+ if(hrr->echconfiglist) {
+ local_print_buf(data, "HTTPS RR: ECHConfigList",
+ hrr->echconfiglist, hrr->echconfiglist_len);
+ }
+ else
+ infof(data, "HTTPS RR: no ECHConfigList");
+ if(hrr->ipv6hints) {
+ local_print_buf(data, "HTTPS RR: ipv6hint",
+ hrr->ipv6hints, hrr->ipv6hints_len);
+ }
+ else
+ infof(data, "HTTPS RR: no ipv6hints");
+ return;
+}
+# endif
+#endif
+
CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dnsp)
{
@@ -923,9 +1298,15 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
CURLE_COULDNT_RESOLVE_HOST;
}
else if(!dohp->pending) {
+#ifndef USE_HTTPSRR
DOHcode rc[DOH_PROBE_SLOTS] = {
DOH_OK, DOH_OK
};
+#else
+ DOHcode rc[DOH_PROBE_SLOTS] = {
+ DOH_OK, DOH_OK, DOH_OK
+ };
+#endif
struct dohentry de;
int slot;
/* remove DoH handles from multi handle and close them */
@@ -991,6 +1372,22 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
} /* address processing done */
/* Now process any build-specific attributes retrieved from DNS */
+#ifdef USE_HTTPSRR
+ if(de.numhttps_rrs > 0 && result == CURLE_OK && *dnsp) {
+ struct Curl_https_rrinfo *hrr = NULL;
+ result = Curl_doh_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
+ &hrr);
+ if(result) {
+ infof(data, "Failed to decode HTTPS RR");
+ return result;
+ }
+ infof(data, "Some HTTPS RR to process");
+# ifdef CURLDEBUG
+ local_print_httpsrr(data, hrr);
+# endif
+ (*dnsp)->hinfo = hrr;
+ }
+#endif
/* All done */
de_cleanup(&de);
diff --git a/libs/libcurl/src/doh.h b/libs/libcurl/src/doh.h
index d83e7b9a4a..b8b8a18ebe 100644
--- a/libs/libcurl/src/doh.h
+++ b/libs/libcurl/src/doh.h
@@ -26,6 +26,9 @@
#include "urldata.h"
#include "curl_addrinfo.h"
+#ifdef USE_HTTPSRR
+# include <stdint.h>
+#endif
#ifndef CURL_DISABLE_DOH
@@ -51,7 +54,8 @@ typedef enum {
DNS_TYPE_NS = 2,
DNS_TYPE_CNAME = 5,
DNS_TYPE_AAAA = 28,
- DNS_TYPE_DNAME = 39 /* RFC6672 */
+ DNS_TYPE_DNAME = 39, /* RFC6672 */
+ DNS_TYPE_HTTPS = 65
} DNStype;
/* one of these for each DoH request */
@@ -84,10 +88,9 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dns);
-int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks);
-
#define DOH_MAX_ADDR 24
#define DOH_MAX_CNAME 4
+#define DOH_MAX_HTTPS 4
struct dohaddr {
int type;
@@ -97,12 +100,44 @@ struct dohaddr {
} ip;
};
+#ifdef USE_HTTPSRR
+
+/*
+ * These are the code points for DNS wire format SvcParams as
+ * per draft-ietf-dnsop-svcb-https
+ * Not all are supported now, and even those that are may need
+ * more work in future to fully support the spec.
+ */
+#define HTTPS_RR_CODE_ALPN 0x01
+#define HTTPS_RR_CODE_NO_DEF_ALPN 0x02
+#define HTTPS_RR_CODE_PORT 0x03
+#define HTTPS_RR_CODE_IPV4 0x04
+#define HTTPS_RR_CODE_ECH 0x05
+#define HTTPS_RR_CODE_IPV6 0x06
+
+/*
+ * These may need escaping when found within an alpn string
+ * value.
+ */
+#define COMMA_CHAR ','
+#define BACKSLASH_CHAR '\\'
+
+struct dohhttps_rr {
+ uint16_t len; /* raw encoded length */
+ unsigned char *val; /* raw encoded octets */
+};
+#endif
+
struct dohentry {
struct dynbuf cname[DOH_MAX_CNAME];
struct dohaddr addr[DOH_MAX_ADDR];
int numaddr;
unsigned int ttl;
int numcname;
+#ifdef USE_HTTPSRR
+ struct dohhttps_rr https_rrs[DOH_MAX_HTTPS];
+ int numhttps_rrs;
+#endif
};
diff --git a/libs/libcurl/src/dynbuf.c b/libs/libcurl/src/dynbuf.c
index 16a47108ca..78ef1039df 100644
--- a/libs/libcurl/src/dynbuf.c
+++ b/libs/libcurl/src/dynbuf.c
@@ -213,7 +213,7 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
}
/* If we failed, we cleanup the whole buffer and return error */
Curl_dyn_free(s);
- return CURLE_OK;
+ return CURLE_OUT_OF_MEMORY;
#endif
}
diff --git a/libs/libcurl/src/easy.c b/libs/libcurl/src/easy.c
index ff2cb6bd06..8dfeea825f 100644
--- a/libs/libcurl/src/easy.c
+++ b/libs/libcurl/src/easy.c
@@ -58,7 +58,6 @@
#include "multiif.h"
#include "select.h"
#include "cfilters.h"
-#include "cw-out.h"
#include "sendf.h" /* for failf function prototype */
#include "connect.h" /* for Curl_getconnectinfo */
#include "slist.h"
@@ -729,6 +728,8 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
/* clear this as early as possible */
data->set.errorbuffer[0] = 0;
+ data->state.os_errno = 0;
+
if(data->multi) {
failf(data, "easy handle already used in multi handle");
return CURLE_FAILED_INIT;
@@ -1086,6 +1087,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
int oldstate;
int newstate;
bool recursive = FALSE;
+ bool keep_changed, unpause_read, not_all_paused;
if(!GOOD_EASY_HANDLE(data) || !data->conn)
/* crazy input, don't continue */
@@ -1101,51 +1103,47 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
- if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) {
- /* Not changing any pause state, return */
- DEBUGF(infof(data, "pause: no change, early return"));
- return CURLE_OK;
- }
-
- /* Unpause parts in active mime tree. */
- if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
- (data->mstate == MSTATE_PERFORMING ||
- data->mstate == MSTATE_RATELIMITING)) {
- result = Curl_creader_unpause(data);
- if(result)
- return result;
- }
-
- /* put it back in the keepon */
+ keep_changed = ((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) != oldstate);
+ not_all_paused = (newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
+ (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE);
+ unpause_read = ((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
+ (data->mstate == MSTATE_PERFORMING ||
+ data->mstate == MSTATE_RATELIMITING));
+ /* Unpausing writes is detected on the next run in
+ * transfer.c:Curl_readwrite(). This is because this may result
+ * in a transfer error if the application's callbacks fail */
+
+ /* Set the new keepon state, so it takes effect no matter what error
+ * may happen afterwards. */
k->keepon = newstate;
- if(!(newstate & KEEP_RECV_PAUSE)) {
- Curl_conn_ev_data_pause(data, FALSE);
- result = Curl_cw_out_flush(data);
- if(result)
- return result;
- }
-
- /* if there's no error and we're not pausing both directions, we want
- to have this handle checked soon */
- if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
- (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) {
- Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
-
+ /* If not completely pausing both directions now, run again in any case. */
+ if(not_all_paused) {
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
/* reset the too-slow time keeper */
data->state.keeps_speed.tv_sec = 0;
-
- if(!Curl_cw_out_is_paused(data))
- /* if not pausing again, force a recv/send check of this connection as
- the data might've been read off the socket already */
- data->state.select_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
- if(data->multi) {
- if(Curl_update_timer(data->multi))
- return CURLE_ABORTED_BY_CALLBACK;
+ /* Simulate socket events on next run for unpaused directions */
+ if(!(newstate & KEEP_SEND_PAUSE))
+ data->state.select_bits |= CURL_CSELECT_OUT;
+ if(!(newstate & KEEP_RECV_PAUSE))
+ data->state.select_bits |= CURL_CSELECT_IN;
+ /* On changes, tell application to update its timers. */
+ if(keep_changed && data->multi) {
+ if(Curl_update_timer(data->multi)) {
+ result = CURLE_ABORTED_BY_CALLBACK;
+ goto out;
+ }
}
}
- if(!data->state.done)
+ if(unpause_read) {
+ result = Curl_creader_unpause(data);
+ if(result)
+ goto out;
+ }
+
+out:
+ 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);
@@ -1305,7 +1303,7 @@ static int conn_upkeep(struct Curl_easy *data,
conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
}
else {
- /* Do the generic action on the FIRSTSOCKE filter chain */
+ /* Do the generic action on the FIRSTSOCKET filter chain */
Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
}
Curl_detach_connection(data);
diff --git a/libs/libcurl/src/easyoptions.c b/libs/libcurl/src/easyoptions.c
index e111406bc4..ad80e253d2 100644
--- a/libs/libcurl/src/easyoptions.c
+++ b/libs/libcurl/src/easyoptions.c
@@ -86,6 +86,7 @@ struct curl_easyoption Curl_easyopts[] = {
{"DOH_SSL_VERIFYPEER", CURLOPT_DOH_SSL_VERIFYPEER, CURLOT_LONG, 0},
{"DOH_SSL_VERIFYSTATUS", CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOT_LONG, 0},
{"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0},
+ {"ECH", CURLOPT_ECH, CURLOT_STRING, 0},
{"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0},
{"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS},
{"ERRORBUFFER", CURLOPT_ERRORBUFFER, CURLOT_OBJECT, 0},
@@ -375,6 +376,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
- return ((CURLOPT_LASTENTRY%10000) != (324 + 1));
+ return ((CURLOPT_LASTENTRY%10000) != (325 + 1));
}
#endif
diff --git a/libs/libcurl/src/file.c b/libs/libcurl/src/file.c
index 640968a1a7..fa71856471 100644
--- a/libs/libcurl/src/file.c
+++ b/libs/libcurl/src/file.c
@@ -50,6 +50,14 @@
#include <fcntl.h>
#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
#include "strtoofft.h"
#include "urldata.h"
#include <curl/curl.h>
@@ -101,7 +109,7 @@ static CURLcode file_setup_connection(struct Curl_easy *data,
*/
const struct Curl_handler Curl_handler_file = {
- "FILE", /* scheme */
+ "file", /* scheme */
file_setup_connection, /* setup_connection */
file_do, /* do_it */
file_done, /* done */
@@ -115,6 +123,7 @@ const struct Curl_handler Curl_handler_file = {
ZERO_NULL, /* perform_getsock */
file_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
0, /* defport */
@@ -446,12 +455,9 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
fstated = TRUE;
}
- if(fstated && !data->state.range && data->set.timecondition) {
- if(!Curl_meets_timecondition(data, data->info.filetime)) {
- *done = TRUE;
- return CURLE_OK;
- }
- }
+ if(fstated && !data->state.range && data->set.timecondition &&
+ !Curl_meets_timecondition(data, data->info.filetime))
+ return CURLE_OK;
if(fstated) {
time_t filetime;
@@ -543,49 +549,85 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
Curl_pgrsSetDownloadSize(data, expected_size);
if(data->state.resume_from) {
- if(data->state.resume_from !=
- lseek(fd, data->state.resume_from, SEEK_SET))
+ if(!S_ISDIR(statbuf.st_mode)) {
+ if(data->state.resume_from !=
+ lseek(fd, data->state.resume_from, SEEK_SET))
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ else {
return CURLE_BAD_DOWNLOAD_RESUME;
+ }
}
result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
if(result)
goto out;
- while(!result) {
- ssize_t nread;
- /* Don't fill a whole buffer if we want less than all data */
- size_t bytestoread;
+ if(!S_ISDIR(statbuf.st_mode)) {
+ while(!result) {
+ ssize_t nread;
+ /* Don't fill a whole buffer if we want less than all data */
+ size_t bytestoread;
- if(size_known) {
- bytestoread = (expected_size < (curl_off_t)(xfer_blen-1)) ?
- curlx_sotouz(expected_size) : (xfer_blen-1);
- }
- else
- bytestoread = xfer_blen-1;
+ if(size_known) {
+ bytestoread = (expected_size < (curl_off_t)(xfer_blen-1)) ?
+ curlx_sotouz(expected_size) : (xfer_blen-1);
+ }
+ else
+ bytestoread = xfer_blen-1;
- nread = read(fd, xfer_buf, bytestoread);
+ nread = read(fd, xfer_buf, bytestoread);
- if(nread > 0)
- xfer_buf[nread] = 0;
+ if(nread > 0)
+ xfer_buf[nread] = 0;
- if(nread <= 0 || (size_known && (expected_size == 0)))
- break;
+ if(nread <= 0 || (size_known && (expected_size == 0)))
+ break;
- if(size_known)
- expected_size -= nread;
+ if(size_known)
+ expected_size -= nread;
- result = Curl_client_write(data, CLIENTWRITE_BODY, xfer_buf, nread);
- if(result)
- goto out;
+ result = Curl_client_write(data, CLIENTWRITE_BODY, xfer_buf, nread);
+ if(result)
+ goto out;
- if(Curl_pgrsUpdate(data))
- result = CURLE_ABORTED_BY_CALLBACK;
- else
- result = Curl_speedcheck(data, Curl_now());
- if(result)
+ if(Curl_pgrsUpdate(data))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(data, Curl_now());
+ if(result)
+ goto out;
+ }
+ }
+ else {
+#ifdef HAVE_OPENDIR
+ DIR *dir = opendir(file->path);
+ struct dirent *entry;
+
+ if(!dir) {
+ result = CURLE_READ_ERROR;
goto out;
+ }
+ else {
+ while((entry = readdir(dir))) {
+ if(entry->d_name[0] != '.') {
+ result = Curl_client_write(data, CLIENTWRITE_BODY,
+ entry->d_name, strlen(entry->d_name));
+ if(result)
+ break;
+ result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1);
+ if(result)
+ break;
+ }
+ }
+ closedir(dir);
+ }
+#else
+ failf(data, "Directory listing not yet implemented on this platform.");
+ result = CURLE_READ_ERROR;
+#endif
}
+
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
diff --git a/libs/libcurl/src/ftp.c b/libs/libcurl/src/ftp.c
index 7ec0ed9247..6b1f2a31f6 100644
--- a/libs/libcurl/src/ftp.c
+++ b/libs/libcurl/src/ftp.c
@@ -95,19 +95,89 @@
#ifdef CURL_DISABLE_VERBOSE_STRINGS
#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
+#define FTP_CSTATE(c) ""
+#define FTP_DSTATE(d) ""
+#else /* CURL_DISABLE_VERBOSE_STRINGS */
+ /* for tracing purposes */
+static const char * const ftp_state_names[]={
+ "STOP",
+ "WAIT220",
+ "AUTH",
+ "USER",
+ "PASS",
+ "ACCT",
+ "PBSZ",
+ "PROT",
+ "CCC",
+ "PWD",
+ "SYST",
+ "NAMEFMT",
+ "QUOTE",
+ "RETR_PREQUOTE",
+ "STOR_PREQUOTE",
+ "POSTQUOTE",
+ "CWD",
+ "MKD",
+ "MDTM",
+ "TYPE",
+ "LIST_TYPE",
+ "RETR_TYPE",
+ "STOR_TYPE",
+ "SIZE",
+ "RETR_SIZE",
+ "STOR_SIZE",
+ "REST",
+ "RETR_REST",
+ "PORT",
+ "PRET",
+ "PASV",
+ "LIST",
+ "RETR",
+ "STOR",
+ "QUIT"
+};
+#define FTP_CSTATE(c) ((c)? ftp_state_names[(c)->proto.ftpc.state] : "???")
+#define FTP_DSTATE(d) (((d) && (d)->conn)? \
+ ftp_state_names[(d)->conn->proto.ftpc.state] : "???")
+
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
+/* This is the ONLY way to change FTP state! */
+static void _ftp_state(struct Curl_easy *data,
+ ftpstate newstate
+#ifdef DEBUGBUILD
+ , int lineno
+#endif
+ )
+{
+ struct connectdata *conn = data->conn;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+#ifdef DEBUGBUILD
+ (void)lineno;
+#endif
+#else /* CURL_DISABLE_VERBOSE_STRINGS */
+ if(ftpc->state != newstate)
+#ifdef DEBUGBUILD
+ CURL_TRC_FTP(data, "[%s] -> [%s] (line %d)", FTP_DSTATE(data),
+ ftp_state_names[newstate], lineno);
+#else
+ CURL_TRC_FTP(data, "[%s] -> [%s]", FTP_DSTATE(data),
+ ftp_state_names[newstate]);
#endif
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
+ ftpc->state = newstate;
+}
+
/* Local API functions */
#ifndef DEBUGBUILD
-static void _ftp_state(struct Curl_easy *data,
- ftpstate newstate);
#define ftp_state(x,y) _ftp_state(x,y)
-#else
-static void _ftp_state(struct Curl_easy *data,
- ftpstate newstate,
- int lineno);
+#else /* !DEBUGBUILD */
#define ftp_state(x,y) _ftp_state(x,y,__LINE__)
-#endif
+#endif /* DEBUGBUILD */
static CURLcode ftp_sendquote(struct Curl_easy *data,
struct connectdata *conn,
@@ -163,7 +233,7 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data,
*/
const struct Curl_handler Curl_handler_ftp = {
- "FTP", /* scheme */
+ "ftp", /* scheme */
ftp_setup_connection, /* setup_connection */
ftp_do, /* do_it */
ftp_done, /* done */
@@ -177,6 +247,7 @@ const struct Curl_handler Curl_handler_ftp = {
ZERO_NULL, /* perform_getsock */
ftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_FTP, /* defport */
@@ -194,7 +265,7 @@ const struct Curl_handler Curl_handler_ftp = {
*/
const struct Curl_handler Curl_handler_ftps = {
- "FTPS", /* scheme */
+ "ftps", /* scheme */
ftp_setup_connection, /* setup_connection */
ftp_do, /* do_it */
ftp_done, /* done */
@@ -208,6 +279,7 @@ const struct Curl_handler Curl_handler_ftps = {
ZERO_NULL, /* perform_getsock */
ftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_FTPS, /* defport */
@@ -221,6 +293,7 @@ const struct Curl_handler Curl_handler_ftps = {
static void close_secondarysocket(struct Curl_easy *data,
struct connectdata *conn)
{
+ CURL_TRC_FTP(data, "[%s] closing DATA connection", FTP_DSTATE(data));
Curl_conn_close(data, SECONDARYSOCKET);
Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET);
}
@@ -360,7 +433,7 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
struct connectdata *conn = data->conn;
curl_socket_t sock = conn->sock[SECONDARYSOCKET];
curl_socket_t s = CURL_SOCKET_BAD;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct Curl_sockaddr_storage add;
#else
struct sockaddr_in add;
@@ -386,8 +459,10 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
(void)curlx_nonblock(s, TRUE); /* enable non-blocking */
/* Replace any filter on SECONDARY with one listening on this socket */
result = Curl_conn_tcp_accepted_set(data, conn, SECONDARYSOCKET, &s);
- if(result)
+ if(result) {
+ sclose(s);
return result;
+ }
if(data->set.fsockopt) {
int error = 0;
@@ -562,7 +637,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
struct connectdata *conn = data->conn;
bool connected;
- DEBUGF(infof(data, "ftp InitiateTransfer()"));
+ CURL_TRC_FTP(data, "InitiateTransfer()");
if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port &&
!Curl_conn_is_ssl(conn, SECONDARYSOCKET)) {
result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET);
@@ -645,7 +720,7 @@ static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
}
out:
- DEBUGF(infof(data, "ftp AllowServerConnect() -> %d", result));
+ CURL_TRC_FTP(data, "AllowServerConnect() -> %d", result);
return result;
}
@@ -827,73 +902,6 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
return result;
}
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- /* for debug purposes */
-static const char * const ftp_state_names[]={
- "STOP",
- "WAIT220",
- "AUTH",
- "USER",
- "PASS",
- "ACCT",
- "PBSZ",
- "PROT",
- "CCC",
- "PWD",
- "SYST",
- "NAMEFMT",
- "QUOTE",
- "RETR_PREQUOTE",
- "STOR_PREQUOTE",
- "POSTQUOTE",
- "CWD",
- "MKD",
- "MDTM",
- "TYPE",
- "LIST_TYPE",
- "RETR_TYPE",
- "STOR_TYPE",
- "SIZE",
- "RETR_SIZE",
- "STOR_SIZE",
- "REST",
- "RETR_REST",
- "PORT",
- "PRET",
- "PASV",
- "LIST",
- "RETR",
- "STOR",
- "QUIT"
-};
-#endif
-
-/* This is the ONLY way to change FTP state! */
-static void _ftp_state(struct Curl_easy *data,
- ftpstate newstate
-#ifdef DEBUGBUILD
- , int lineno
-#endif
- )
-{
- struct connectdata *conn = data->conn;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
-#if defined(DEBUGBUILD)
-
-#if defined(CURL_DISABLE_VERBOSE_STRINGS)
- (void) lineno;
-#else
- if(ftpc->state != newstate)
- infof(data, "FTP %p (line %d) state change from %s to %s",
- (void *)ftpc, lineno, ftp_state_names[ftpc->state],
- ftp_state_names[newstate]);
-#endif
-#endif
-
- ftpc->state = newstate;
-}
-
static CURLcode ftp_state_user(struct Curl_easy *data,
struct connectdata *conn)
{
@@ -937,7 +945,7 @@ static int ftp_domore_getsock(struct Curl_easy *data,
* remote site, or we could wait for that site to connect to us. Or just
* handle ordinary commands.
*/
- DEBUGF(infof(data, "ftp_domore_getsock()"));
+ CURL_TRC_FTP(data, "[%s] ftp_domore_getsock()", FTP_DSTATE(data));
if(FTP_STOP == ftpc->state) {
/* if stopped and still in this state, then we're also waiting for a
@@ -1027,7 +1035,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
char hbuf[NI_MAXHOST];
struct sockaddr *sa = (struct sockaddr *)&ss;
struct sockaddr_in * const sa4 = (void *)sa;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct sockaddr_in6 * const sa6 = (void *)sa;
#endif
static const char mode[][5] = { "EPRT", "PORT" };
@@ -1054,7 +1062,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
(strlen(data->set.str[STRING_FTPPORT]) > 1)) {
char *ip_end = NULL;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if(*string_ftpport == '[') {
/* [ipv6]:port(-range) */
char *ip_start = string_ftpport + 1;
@@ -1076,7 +1084,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(ip_end) {
/* either ipv6 or (ipv4|domain|interface):port(-range) */
addrlen = ip_end - string_ftpport;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if(Curl_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) {
/* ipv6 */
port_min = port_max = 0;
@@ -1122,7 +1130,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
/* attempt to get the address of the given interface name */
switch(Curl_if2ip(conn->remote_addr->family,
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
Curl_ipv6_scope(&conn->remote_addr->sa_addr),
conn->scope_id,
#endif
@@ -1154,7 +1162,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
goto out;
}
switch(sa->sa_family) {
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case AF_INET6:
r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
break;
@@ -1204,7 +1212,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
Curl_strerror(error, buffer, sizeof(buffer)));
goto out;
}
- DEBUGF(infof(data, "ftp_state_use_port(), opened socket"));
+ CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), opened socket",
+ FTP_DSTATE(data));
/* step 3, bind to a suitable local address */
@@ -1214,7 +1223,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
for(port = port_min; port <= port_max;) {
if(sa->sa_family == AF_INET)
sa4->sin_port = htons(port);
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else
sa6->sin6_port = htons(port);
#endif
@@ -1265,7 +1274,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
goto out;
}
- DEBUGF(infof(data, "ftp_state_use_port(), socket bound to port %d", port));
+ CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), socket bound to port %d",
+ FTP_DSTATE(data), port);
/* step 4, listen on the socket */
@@ -1274,7 +1284,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
goto out;
}
- DEBUGF(infof(data, "ftp_state_use_port(), listening on %d", port));
+ CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), listening on %d",
+ FTP_DSTATE(data), port);
/* step 5, send the proper FTP command */
@@ -1282,7 +1293,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
below */
Curl_printable_address(ai, myhost, sizeof(myhost));
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
/* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
request and enable EPRT again! */
@@ -1309,7 +1320,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
case AF_INET:
port = ntohs(sa4->sin_port);
break;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case AF_INET6:
port = ntohs(sa6->sin6_port);
break;
@@ -2349,7 +2360,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
struct connectdata *conn = data->conn;
struct ftp_conn *ftpc = &conn->proto.ftpc;
- DEBUGF(infof(data, "ftp_state_retr()"));
+ CURL_TRC_FTP(data, "[%s] ftp_state_retr()", FTP_DSTATE(data));
if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
failf(data, "Maximum file size exceeded");
return CURLE_FILESIZE_EXCEEDED;
@@ -3064,7 +3075,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
}
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
- DEBUGF(infof(data, "protocol connect phase DONE"));
+ CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
break;
case FTP_SYST:
@@ -3109,7 +3120,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
- DEBUGF(infof(data, "protocol connect phase DONE"));
+ CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
break;
case FTP_NAMEFMT:
@@ -3120,7 +3131,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
- DEBUGF(infof(data, "protocol connect phase DONE"));
+ CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
break;
case FTP_QUOTE:
@@ -3549,6 +3560,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
/* Send any post-transfer QUOTE strings? */
if(!status && !result && !premature && data->set.postquote)
result = ftp_sendquote(data, conn, data->set.postquote);
+ CURL_TRC_FTP(data, "[%s] done, result=%d", FTP_DSTATE(data), result);
Curl_safefree(ftp->pathalloc);
return result;
}
@@ -3817,7 +3829,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
if(!ftpc->wait_data_conn) {
/* no waiting for the data connection so this is now complete */
*completep = 1;
- DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result));
+ CURL_TRC_FTP(data, "[%s] DO-MORE phase ends with %d", FTP_DSTATE(data),
+ (int)result);
}
return result;
@@ -3841,7 +3854,7 @@ CURLcode ftp_perform(struct Curl_easy *data,
/* this is FTP and no proxy */
CURLcode result = CURLE_OK;
- DEBUGF(infof(data, "DO phase starts"));
+ CURL_TRC_FTP(data, "[%s] DO phase starts", FTP_DSTATE(data));
if(data->req.no_body) {
/* requested no body means no transfer... */
@@ -3861,10 +3874,15 @@ CURLcode ftp_perform(struct Curl_easy *data,
*connected = Curl_conn_is_connected(data->conn, SECONDARYSOCKET);
- infof(data, "ftp_perform ends with SECONDARY: %d", *connected);
+ if(*connected)
+ infof(data, "[FTP] [%s] perform, DATA connection established",
+ FTP_DSTATE(data));
+ else
+ CURL_TRC_FTP(data, "[%s] perform, awaiting DATA connect",
+ FTP_DSTATE(data));
if(*dophase_done)
- DEBUGF(infof(data, "DO phase is complete1"));
+ CURL_TRC_FTP(data, "[%s] DO phase is complete1", FTP_DSTATE(data));
return result;
}
@@ -4431,11 +4449,11 @@ static CURLcode ftp_doing(struct Curl_easy *data,
CURLcode result = ftp_multi_statemach(data, dophase_done);
if(result)
- DEBUGF(infof(data, "DO phase failed"));
+ CURL_TRC_FTP(data, "[%s] DO phase failed", FTP_DSTATE(data));
else if(*dophase_done) {
result = ftp_dophase_done(data, FALSE /* not connected */);
- DEBUGF(infof(data, "DO phase is complete2"));
+ CURL_TRC_FTP(data, "[%s] DO phase is complete2", FTP_DSTATE(data));
}
return result;
}
@@ -4559,6 +4577,7 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
ftpc->use_ssl = data->set.use_ssl;
ftpc->ccc = data->set.ftp_ccc;
+ CURL_TRC_FTP(data, "[%s] setup connection -> %d", FTP_CSTATE(conn), result);
return result;
}
diff --git a/libs/libcurl/src/ftplistparser.c b/libs/libcurl/src/ftplistparser.c
index 403a019b21..c59544cfd3 100644
--- a/libs/libcurl/src/ftplistparser.c
+++ b/libs/libcurl/src/ftplistparser.c
@@ -349,7 +349,7 @@ static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
Curl_set_in_callback(data, false);
if(add) {
- Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
+ Curl_llist_append(llist, finfo, &infop->list);
}
else {
Curl_fileinfo_cleanup(infop);
diff --git a/libs/libcurl/src/getinfo.c b/libs/libcurl/src/getinfo.c
index e7162b3a9f..689e65b939 100644
--- a/libs/libcurl/src/getinfo.c
+++ b/libs/libcurl/src/getinfo.c
@@ -161,7 +161,11 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
*param_charp = data->info.primary.local_ip;
break;
case CURLINFO_RTSP_SESSION_ID:
+#ifndef CURL_DISABLE_RTSP
*param_charp = data->set.str[STRING_RTSP_SESSION_ID];
+#else
+ *param_charp = NULL;
+#endif
break;
case CURLINFO_SCHEME:
*param_charp = data->info.conn_scheme;
diff --git a/libs/libcurl/src/gopher.c b/libs/libcurl/src/gopher.c
index 2c8bd18914..5d01eb0046 100644
--- a/libs/libcurl/src/gopher.c
+++ b/libs/libcurl/src/gopher.c
@@ -62,7 +62,7 @@ static CURLcode gopher_connecting(struct Curl_easy *data, bool *done);
*/
const struct Curl_handler Curl_handler_gopher = {
- "GOPHER", /* scheme */
+ "gopher", /* scheme */
ZERO_NULL, /* setup_connection */
gopher_do, /* do_it */
ZERO_NULL, /* done */
@@ -76,6 +76,7 @@ const struct Curl_handler Curl_handler_gopher = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_GOPHER, /* defport */
@@ -86,7 +87,7 @@ const struct Curl_handler Curl_handler_gopher = {
#ifdef USE_SSL
const struct Curl_handler Curl_handler_gophers = {
- "GOPHERS", /* scheme */
+ "gophers", /* scheme */
ZERO_NULL, /* setup_connection */
gopher_do, /* do_it */
ZERO_NULL, /* done */
@@ -100,6 +101,7 @@ const struct Curl_handler Curl_handler_gophers = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_GOPHER, /* defport */
diff --git a/libs/libcurl/src/hash.c b/libs/libcurl/src/hash.c
index 8a1aadfda4..dc0fb62e1e 100644
--- a/libs/libcurl/src/hash.c
+++ b/libs/libcurl/src/hash.c
@@ -57,7 +57,7 @@ hash_element_dtor(void *user, void *element)
*/
void
Curl_hash_init(struct Curl_hash *h,
- int slots,
+ size_t slots,
hash_function hfunc,
comp_function comparator,
Curl_hash_dtor dtor)
@@ -111,7 +111,7 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
DEBUGASSERT(h);
DEBUGASSERT(h->slots);
if(!h->table) {
- int i;
+ size_t i;
h->table = malloc(h->slots * sizeof(struct Curl_llist));
if(!h->table)
return NULL; /* OOM */
@@ -132,7 +132,7 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
he = mk_hash_element(key, key_len, p);
if(he) {
- Curl_llist_insert_next(l, l->tail, he, &he->list);
+ Curl_llist_append(l, he, &he->list);
++h->size;
return p; /* return the new entry */
}
@@ -192,25 +192,6 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
return NULL;
}
-#if defined(DEBUGBUILD) && defined(AGGRESSIVE_TEST)
-void
-Curl_hash_apply(Curl_hash *h, void *user,
- void (*cb)(void *user, void *ptr))
-{
- struct Curl_llist_element *le;
- int i;
-
- for(i = 0; i < h->slots; ++i) {
- for(le = (h->table[i])->head;
- le;
- le = le->next) {
- Curl_hash_element *el = le->ptr;
- cb(user, el->ptr);
- }
- }
-}
-#endif
-
/* Destroys all the entries in the given hash and resets its attributes,
* prepping the given hash for [static|dynamic] deallocation.
*
@@ -222,7 +203,7 @@ void
Curl_hash_destroy(struct Curl_hash *h)
{
if(h->table) {
- int i;
+ size_t i;
for(i = 0; i < h->slots; ++i) {
Curl_llist_destroy(&h->table[i], (void *) h);
}
@@ -250,7 +231,7 @@ Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
struct Curl_llist_element *le;
struct Curl_llist_element *lnext;
struct Curl_llist *list;
- int i;
+ size_t i;
if(!h || !h->table)
return;
@@ -316,7 +297,7 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter)
/* If we have reached the end of the list, find the next one */
if(!iter->current_element) {
- int i;
+ size_t i;
for(i = iter->slot_index; i < h->slots; i++) {
if(h->table[i].head) {
iter->current_element = h->table[i].head;
@@ -339,7 +320,7 @@ void Curl_hash_print(struct Curl_hash *h,
{
struct Curl_hash_iterator iter;
struct Curl_hash_element *he;
- int last_index = -1;
+ size_t last_index = ~0;
if(!h)
return;
@@ -352,7 +333,7 @@ void Curl_hash_print(struct Curl_hash *h,
while(he) {
if(iter.slot_index != last_index) {
fprintf(stderr, "index %d:", iter.slot_index);
- if(last_index >= 0) {
+ if(last_index != ~0) {
fprintf(stderr, "\n");
}
last_index = iter.slot_index;
@@ -368,3 +349,25 @@ void Curl_hash_print(struct Curl_hash *h,
fprintf(stderr, "\n");
}
#endif
+
+void Curl_hash_offt_init(struct Curl_hash *h,
+ size_t slots,
+ Curl_hash_dtor dtor)
+{
+ Curl_hash_init(h, slots, Curl_hash_str, Curl_str_key_compare, dtor);
+}
+
+void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem)
+{
+ return Curl_hash_add(h, &id, sizeof(id), elem);
+}
+
+int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id)
+{
+ return Curl_hash_delete(h, &id, sizeof(id));
+}
+
+void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id)
+{
+ return Curl_hash_pick(h, &id, sizeof(id));
+}
diff --git a/libs/libcurl/src/hash.h b/libs/libcurl/src/hash.h
index 5b82d824d0..a6e05cae57 100644
--- a/libs/libcurl/src/hash.h
+++ b/libs/libcurl/src/hash.h
@@ -54,7 +54,7 @@ struct Curl_hash {
/* Comparator function to compare keys */
comp_function comp_func;
Curl_hash_dtor dtor;
- int slots;
+ size_t slots;
size_t size;
};
@@ -67,12 +67,12 @@ struct Curl_hash_element {
struct Curl_hash_iterator {
struct Curl_hash *hash;
- int slot_index;
+ size_t slot_index;
struct Curl_llist_element *current_element;
};
void Curl_hash_init(struct Curl_hash *h,
- int slots,
+ size_t slots,
hash_function hfunc,
comp_function comparator,
Curl_hash_dtor dtor);
@@ -80,8 +80,6 @@ void Curl_hash_init(struct Curl_hash *h,
void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p);
int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
void *Curl_hash_pick(struct Curl_hash *, void *key, size_t key_len);
-void Curl_hash_apply(struct Curl_hash *h, void *user,
- void (*cb)(void *user, void *ptr));
#define Curl_hash_count(h) ((h)->size)
void Curl_hash_destroy(struct Curl_hash *h);
void Curl_hash_clean(struct Curl_hash *h);
@@ -98,5 +96,13 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter);
void Curl_hash_print(struct Curl_hash *h,
void (*func)(void *));
+/* Hash for `curl_off_t` as key */
+void Curl_hash_offt_init(struct Curl_hash *h, size_t slots,
+ Curl_hash_dtor dtor);
+
+void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem);
+int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id);
+void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id);
+
#endif /* HEADER_CURL_HASH_H */
diff --git a/libs/libcurl/src/headers.c b/libs/libcurl/src/headers.c
index 35e27d6503..3a4ce3adfe 100644
--- a/libs/libcurl/src/headers.c
+++ b/libs/libcurl/src/headers.c
@@ -253,7 +253,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value,
newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1);
if(!newhs)
return CURLE_OUT_OF_MEMORY;
- /* ->name' and ->value point into ->buffer (to keep the header allocation
+ /* ->name and ->value point into ->buffer (to keep the header allocation
in a single memory block), which now potentially have moved. Adjust
them. */
newhs->name = newhs->buffer;
@@ -264,8 +264,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value,
newhs->value[olen + vlen] = 0; /* null-terminate at newline */
/* insert this node into the list of headers */
- Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
- newhs, &newhs->node);
+ Curl_llist_append(&data->state.httphdrs, newhs, &newhs->node);
data->state.prevhead = newhs;
return CURLE_OK;
}
@@ -328,8 +327,7 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
hs->request = data->state.requests;
/* insert this node into the list of headers */
- Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
- hs, &hs->node);
+ Curl_llist_append(&data->state.httphdrs, hs, &hs->node);
data->state.prevhead = hs;
}
else
@@ -361,6 +359,8 @@ static CURLcode hds_cw_collect_write(struct Curl_easy *data,
(type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
CURLH_HEADER)));
CURLcode result = Curl_headers_push(data, buf, htype);
+ CURL_TRC_WRITE(data, "header_collect pushed(type=%x, len=%zu) -> %d",
+ htype, blen, result);
if(result)
return result;
}
diff --git a/libs/libcurl/src/hostip.c b/libs/libcurl/src/hostip.c
index c7cc068606..d22eb4120b 100644
--- a/libs/libcurl/src/hostip.c
+++ b/libs/libcurl/src/hostip.c
@@ -144,7 +144,7 @@ void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf,
(void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
break;
}
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case AF_INET6: {
const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr;
const struct in6_addr *ipaddr6 = &sa6->sin6_addr;
@@ -167,17 +167,12 @@ create_hostcache_id(const char *name,
int port, char *ptr, size_t buflen)
{
size_t len = nlen ? nlen : strlen(name);
- size_t olen = 0;
DEBUGASSERT(buflen >= MAX_HOSTCACHE_LEN);
if(len > (buflen - 7))
len = buflen - 7;
/* store and lower case the name */
- while(len--) {
- *ptr++ = Curl_raw_tolower(*name++);
- olen++;
- }
- olen += msnprintf(ptr, 7, ":%u", port);
- return olen;
+ Curl_strntolower(ptr, name, len);
+ return msnprintf(&ptr[len], 7, ":%u", port) + len;
}
struct hostcache_prune_data {
@@ -249,7 +244,7 @@ void Curl_hostcache_prune(struct Curl_easy *data)
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- time(&now);
+ now = time(NULL);
do {
/* Remove outdated and unused entries from the hostcache */
@@ -303,7 +298,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
/* See whether the returned entry is stale. Done before we release lock */
struct hostcache_prune_data user;
- time(&user.now);
+ user.now = time(NULL);
user.cache_timeout = data->set.dns_cache_timeout;
user.oldest = 0;
@@ -523,7 +518,7 @@ Curl_cache_addr(struct Curl_easy *data,
return dns;
}
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
/* return a static IPv6 ::1 for the name */
static struct Curl_addrinfo *get_localhost6(int port, const char *name)
{
@@ -600,7 +595,7 @@ static struct Curl_addrinfo *get_localhost(int port, const char *name)
return ca6;
}
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
/*
* Curl_ipv6works() returns TRUE if IPv6 seems to work.
*/
@@ -632,7 +627,7 @@ bool Curl_ipv6works(struct Curl_easy *data)
return (ipv6_works>0)?TRUE:FALSE;
}
}
-#endif /* ENABLE_IPV6 */
+#endif /* USE_IPV6 */
/*
* Curl_host_is_ipnum() returns TRUE if the given string is a numerical IPv4
@@ -641,11 +636,11 @@ bool Curl_ipv6works(struct Curl_easy *data)
bool Curl_host_is_ipnum(const char *hostname)
{
struct in_addr in;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct in6_addr in6;
#endif
if(Curl_inet_pton(AF_INET, hostname, &in) > 0
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
|| Curl_inet_pton(AF_INET6, hostname, &in6) > 0
#endif
)
@@ -760,7 +755,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
if(!addr)
return CURLRESOLV_ERROR;
}
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else {
struct in6_addr in6;
/* check if this is an IPv6 address string */
@@ -771,7 +766,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
return CURLRESOLV_ERROR;
}
}
-#endif /* ENABLE_IPV6 */
+#endif /* USE_IPV6 */
#else /* if USE_RESOLVE_ON_IPS */
#ifndef CURL_DISABLE_DOH
@@ -779,7 +774,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
ipnum = TRUE;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else {
struct in6_addr in6;
/* check if this is an IPv6 address string */
@@ -787,7 +782,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
/* This is an IPv6 address literal */
ipnum = TRUE;
}
-#endif /* ENABLE_IPV6 */
+#endif /* USE_IPV6 */
#endif /* CURL_DISABLE_DOH */
#endif /* !USE_RESOLVE_ON_IPS */
@@ -1070,6 +1065,23 @@ static void freednsentry(void *freethis)
dns->inuse--;
if(dns->inuse == 0) {
Curl_freeaddrinfo(dns->addr);
+#ifdef USE_HTTPSRR
+ if(dns->hinfo) {
+ if(dns->hinfo->target)
+ free(dns->hinfo->target);
+ if(dns->hinfo->alpns)
+ free(dns->hinfo->alpns);
+ if(dns->hinfo->ipv4hints)
+ free(dns->hinfo->ipv4hints);
+ if(dns->hinfo->echconfiglist)
+ free(dns->hinfo->echconfiglist);
+ if(dns->hinfo->ipv6hints)
+ free(dns->hinfo->ipv6hints);
+ if(dns->hinfo->val)
+ free(dns->hinfo->val);
+ free(dns->hinfo);
+ }
+#endif
free(dns);
}
}
@@ -1077,7 +1089,7 @@ static void freednsentry(void *freethis)
/*
* Curl_init_dnscache() inits a new DNS cache.
*/
-void Curl_init_dnscache(struct Curl_hash *hash, int size)
+void Curl_init_dnscache(struct Curl_hash *hash, size_t size)
{
Curl_hash_init(hash, size, Curl_hash_str, Curl_str_key_compare,
freednsentry);
@@ -1210,7 +1222,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
memcpy(address, addr_begin, alen);
address[alen] = '\0';
-#ifndef ENABLE_IPV6
+#ifndef USE_IPV6
if(strchr(address, ':')) {
infof(data, "Ignoring resolve address '%s', missing IPv6 support.",
address);
diff --git a/libs/libcurl/src/hostip.h b/libs/libcurl/src/hostip.h
index f47e3abaf9..e1a7615bea 100644
--- a/libs/libcurl/src/hostip.h
+++ b/libs/libcurl/src/hostip.h
@@ -32,6 +32,10 @@
#include <setjmp.h>
+#ifdef USE_HTTPSRR
+# include <stdint.h>
+#endif
+
/* Allocate enough memory to hold the full name information structs and
* everything. OSF1 is known to require at least 8872 bytes. The buffer
* required for storing all possible aliases and IP numbers is according to
@@ -58,8 +62,41 @@ struct connectdata;
*/
struct Curl_hash *Curl_global_host_cache_init(void);
+#ifdef USE_HTTPSRR
+
+#define CURL_MAXLEN_host_name 253
+
+struct Curl_https_rrinfo {
+ size_t len; /* raw encoded length */
+ unsigned char *val; /* raw encoded octets */
+ /*
+ * fields from HTTPS RR, with the mandatory fields
+ * first (priority, target), then the others in the
+ * order of the keytag numbers defined at
+ * https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
+ */
+ uint16_t priority;
+ char *target;
+ char *alpns; /* keytag = 1 */
+ bool no_def_alpn; /* keytag = 2 */
+ /*
+ * we don't support ports (keytag = 3) as we don't support
+ * port-switching yet
+ */
+ unsigned char *ipv4hints; /* keytag = 4 */
+ size_t ipv4hints_len;
+ unsigned char *echconfiglist; /* keytag = 5 */
+ size_t echconfiglist_len;
+ unsigned char *ipv6hints; /* keytag = 6 */
+ size_t ipv6hints_len;
+};
+#endif
+
struct Curl_dns_entry {
struct Curl_addrinfo *addr;
+#ifdef USE_HTTPSRR
+ struct Curl_https_rrinfo *hinfo;
+#endif
/* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */
time_t timestamp;
/* use-counter, use Curl_resolv_unlock to release reference */
@@ -96,7 +133,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
struct Curl_dns_entry **dnsentry,
timediff_t timeoutms);
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
/*
* Curl_ipv6works() returns TRUE if IPv6 seems to work.
*/
@@ -129,7 +166,7 @@ void Curl_resolv_unlock(struct Curl_easy *data,
struct Curl_dns_entry *dns);
/* init a new dns cache */
-void Curl_init_dnscache(struct Curl_hash *hash, int hashsize);
+void Curl_init_dnscache(struct Curl_hash *hash, size_t hashsize);
/* prune old entries from the DNS cache */
void Curl_hostcache_prune(struct Curl_easy *data);
diff --git a/libs/libcurl/src/hsts.c b/libs/libcurl/src/hsts.c
index 6166bbdcb3..8a871f77a4 100644
--- a/libs/libcurl/src/hsts.c
+++ b/libs/libcurl/src/hsts.c
@@ -107,11 +107,6 @@ void Curl_hsts_cleanup(struct hsts **hp)
}
}
-static struct stsentry *hsts_entry(void)
-{
- return calloc(1, sizeof(struct stsentry));
-}
-
static CURLcode hsts_create(struct hsts *h,
const char *hostname,
bool subdomains,
@@ -127,7 +122,7 @@ static CURLcode hsts_create(struct hsts *h,
--hlen;
if(hlen) {
char *duphost;
- struct stsentry *sts = hsts_entry();
+ struct stsentry *sts = calloc(1, sizeof(struct stsentry));
if(!sts)
return CURLE_OUT_OF_MEMORY;
@@ -140,7 +135,7 @@ static CURLcode hsts_create(struct hsts *h,
sts->host = duphost;
sts->expires = expires;
sts->includeSubDomains = subdomains;
- Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node);
+ Curl_llist_append(&h->list, sts, &sts->node);
}
return CURLE_OK;
}
@@ -528,8 +523,11 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
char *lineptr = Curl_dyn_ptr(&buf);
while(*lineptr && ISBLANK(*lineptr))
lineptr++;
- if(*lineptr == '#')
- /* skip commented lines */
+ /*
+ * Skip empty or commented lines, since we know the line will have a
+ * trailing newline from Curl_get_line we can treat length 1 as empty.
+ */
+ if((*lineptr == '#') || strlen(lineptr) <= 1)
continue;
hsts_add(h, lineptr);
diff --git a/libs/libcurl/src/http.c b/libs/libcurl/src/http.c
index 3d3a641f20..e56550a09b 100644
--- a/libs/libcurl/src/http.c
+++ b/libs/libcurl/src/http.c
@@ -65,7 +65,6 @@
#include "vquic/vquic.h"
#include "http_digest.h"
#include "http_ntlm.h"
-#include "curl_ntlm_wb.h"
#include "http_negotiate.h"
#include "http_aws_sigv4.h"
#include "url.h"
@@ -101,7 +100,7 @@
* Forward declarations.
*/
-static bool http_should_fail(struct Curl_easy *data);
+static bool http_should_fail(struct Curl_easy *data, int httpcode);
static bool http_exp100_is_waiting(struct Curl_easy *data);
static CURLcode http_exp100_add_reader(struct Curl_easy *data);
static void http_exp100_send_anyway(struct Curl_easy *data);
@@ -110,7 +109,7 @@ static void http_exp100_send_anyway(struct Curl_easy *data);
* HTTP handler interface.
*/
const struct Curl_handler Curl_handler_http = {
- "HTTP", /* scheme */
+ "http", /* scheme */
Curl_http_setup_conn, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
@@ -124,6 +123,7 @@ const struct Curl_handler Curl_handler_http = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
Curl_http_write_resp, /* write_resp */
+ Curl_http_write_resp_hd, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_HTTP, /* defport */
@@ -138,7 +138,7 @@ const struct Curl_handler Curl_handler_http = {
* HTTPS handler interface.
*/
const struct Curl_handler Curl_handler_https = {
- "HTTPS", /* scheme */
+ "https", /* scheme */
Curl_http_setup_conn, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
@@ -152,6 +152,7 @@ const struct Curl_handler Curl_handler_https = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
Curl_http_write_resp, /* write_resp */
+ Curl_http_write_resp_hd, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_HTTPS, /* defport */
@@ -244,8 +245,6 @@ char *Curl_copy_header_value(const char *header)
while(*start && ISSPACE(*start))
start++;
- /* data is in the host encoding so
- use '\r' and '\n' instead of 0x0d and 0x0a */
end = strchr(start, '\r');
if(!end)
end = strchr(start, '\n');
@@ -386,8 +385,6 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
#endif
else if(avail & CURLAUTH_NTLM)
pick->picked = CURLAUTH_NTLM;
- else if(avail & CURLAUTH_NTLM_WB)
- pick->picked = CURLAUTH_NTLM_WB;
#ifndef CURL_DISABLE_BASIC_AUTH
else if(avail & CURLAUTH_BASIC)
pick->picked = CURLAUTH_BASIC;
@@ -446,9 +443,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
/* We'd like to abort the upload - but should we? */
#if defined(USE_NTLM)
if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
- (data->state.authhost.picked == CURLAUTH_NTLM) ||
- (data->state.authproxy.picked == CURLAUTH_NTLM_WB) ||
- (data->state.authhost.picked == CURLAUTH_NTLM_WB)) {
+ (data->state.authhost.picked == CURLAUTH_NTLM)) {
ongoing_auth = "NTML";
if((conn->http_ntlm_state != NTLMSTATE_NONE) ||
(conn->proxy_ntlm_state != NTLMSTATE_NONE)) {
@@ -570,7 +565,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
data->state.authhost.done = TRUE;
}
}
- if(http_should_fail(data)) {
+ if(http_should_fail(data, data->req.httpcode)) {
failf(data, "The requested URL returned error: %d",
data->req.httpcode);
result = CURLE_HTTP_RETURNED_ERROR;
@@ -627,15 +622,6 @@ output_auth_headers(struct Curl_easy *data,
}
else
#endif
-#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
- if(authstatus->picked == CURLAUTH_NTLM_WB) {
- auth = "NTLM_WB";
- result = Curl_output_ntlm_wb(data, conn, proxy);
- if(result)
- return result;
- }
- else
-#endif
#ifndef CURL_DISABLE_DIGEST_AUTH
if(authstatus->picked == CURLAUTH_DIGEST) {
auth = "Digest";
@@ -925,31 +911,15 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
/* NTLM support requires the SSL crypto libs */
if(checkprefix("NTLM", auth) && is_valid_auth_separator(auth[4])) {
if((authp->avail & CURLAUTH_NTLM) ||
- (authp->avail & CURLAUTH_NTLM_WB) ||
Curl_auth_is_ntlm_supported()) {
*availp |= CURLAUTH_NTLM;
authp->avail |= CURLAUTH_NTLM;
- if(authp->picked == CURLAUTH_NTLM ||
- authp->picked == CURLAUTH_NTLM_WB) {
+ if(authp->picked == CURLAUTH_NTLM) {
/* NTLM authentication is picked and activated */
CURLcode result = Curl_input_ntlm(data, proxy, auth);
if(!result) {
data->state.authproblem = FALSE;
-#ifdef NTLM_WB_ENABLED
- if(authp->picked == CURLAUTH_NTLM_WB) {
- *availp &= ~CURLAUTH_NTLM;
- authp->avail &= ~CURLAUTH_NTLM;
- *availp |= CURLAUTH_NTLM_WB;
- authp->avail |= CURLAUTH_NTLM_WB;
-
- result = Curl_input_ntlm_wb(data, conn, proxy, auth);
- if(result) {
- infof(data, "Authentication problem. Ignoring this.");
- data->state.authproblem = TRUE;
- }
- }
-#endif
}
else {
infof(data, "Authentication problem. Ignoring this.");
@@ -1036,21 +1006,18 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
}
/**
- * http_should_fail() determines whether an HTTP response has gotten us
+ * http_should_fail() determines whether an HTTP response code has gotten us
* into an error state or not.
*
* @retval FALSE communications should continue
*
* @retval TRUE communications should not continue
*/
-static bool http_should_fail(struct Curl_easy *data)
+static bool http_should_fail(struct Curl_easy *data, int httpcode)
{
- int httpcode;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
- httpcode = data->req.httpcode;
-
/*
** If we haven't been asked to fail on error,
** don't fail.
@@ -2046,8 +2013,19 @@ static CURLcode set_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
else
result = Curl_creader_set_null(data);
}
- else { /* we read the bytes from the callback */
- result = Curl_creader_set_fread(data, postsize);
+ else {
+ /* we read the bytes from the callback. In case "chunked" encoding
+ * is forced by the application, we disregard `postsize`. This is
+ * a backward compatibility decision to earlier versions where
+ * chunking disregarded this. See issue #13229. */
+ bool chunked = FALSE;
+ char *ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
+ if(ptr) {
+ /* Some kind of TE is requested, check if 'chunked' is chosen */
+ chunked = Curl_compareheader(ptr, STRCONST("Transfer-Encoding:"),
+ STRCONST("chunked"));
+ }
+ result = Curl_creader_set_fread(data, chunked? -1 : postsize);
}
return result;
@@ -2115,6 +2093,13 @@ CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
data->req.upload_chunky =
Curl_compareheader(ptr,
STRCONST("Transfer-Encoding:"), STRCONST("chunked"));
+ if(data->req.upload_chunky &&
+ Curl_use_http_1_1plus(data, data->conn) &&
+ (data->conn->httpversion >= 20)) {
+ infof(data, "suppressing chunked transfer encoding on connection "
+ "using HTTP version 2 or higher");
+ data->req.upload_chunky = FALSE;
+ }
}
else {
curl_off_t req_clen = Curl_creader_total_length(data);
@@ -2253,9 +2238,11 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
/* end of headers */
result = Curl_dyn_addn(r, STRCONST("\r\n"));
- Curl_pgrsSetUploadSize(data, req_clen);
- if(announced_exp100)
- result = http_exp100_add_reader(data);
+ if(!result) {
+ Curl_pgrsSetUploadSize(data, req_clen);
+ if(announced_exp100)
+ result = http_exp100_add_reader(data);
+ }
out:
if(!result) {
@@ -2666,8 +2653,12 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
httpstring,
(data->state.aptr.host?data->state.aptr.host:""),
+#ifndef CURL_DISABLE_PROXY
data->state.aptr.proxyuserpwd?
data->state.aptr.proxyuserpwd:"",
+#else
+ "",
+#endif
data->state.aptr.userpwd?data->state.aptr.userpwd:"",
(data->state.use_range && data->state.aptr.rangeline)?
data->state.aptr.rangeline:"",
@@ -2701,7 +2692,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* clear userpwd and proxyuserpwd to avoid reusing old credentials
* from reused connections */
Curl_safefree(data->state.aptr.userpwd);
+#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
+#endif
free(altused);
if(result) {
@@ -2842,9 +2835,10 @@ checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
/*
* Curl_http_header() parses a single response header.
*/
-CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
- char *hd, size_t hdlen)
+CURLcode Curl_http_header(struct Curl_easy *data,
+ const char *hd, size_t hdlen)
{
+ struct connectdata *conn = data->conn;
CURLcode result;
struct SingleRequest *k = &data->req;
const char *v;
@@ -2854,7 +2848,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
case 'A':
#ifndef CURL_DISABLE_ALTSVC
v = (data->asi &&
- ((conn->handler->flags & PROTOPT_SSL) ||
+ ((data->conn->handler->flags & PROTOPT_SSL) ||
#ifdef CURLDEBUG
/* allow debug builds to circumvent the HTTPS restriction */
getenv("CURL_ALTSVC_HTTP")
@@ -3145,19 +3139,23 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
break;
case 't':
case 'T':
- v = !k->http_bodyless? HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
+ /* RFC 9112, ch. 6.1
+ * "Transfer-Encoding MAY be sent in a response to a HEAD request or
+ * in a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) to a
+ * GET request, neither of which includes a message body, to indicate
+ * that the origin server would have applied a transfer coding to the
+ * message body if the request had been an unconditional GET."
+ *
+ * Read: in these cases the 'Transfer-Encoding' does not apply
+ * to any data following the response headers. Do not add any decoders.
+ */
+ v = (!k->http_bodyless &&
+ (data->state.httpreq != HTTPREQ_HEAD) &&
+ (k->httpcode != 304))?
+ HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
if(v) {
/* One or more encodings. We check for chunked and/or a compression
algorithm. */
- /*
- * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
- * means that the server will send a series of "chunks". Each
- * chunk starts with line with info (including size of the
- * coming block) (terminated with CRLF), then a block of data
- * with the previously mentioned size. There can be any amount
- * of chunks, and a chunk-data set to zero signals the
- * end-of-chunks. */
-
result = Curl_build_unencoding_stack(data, v, TRUE);
if(result)
return result;
@@ -3207,13 +3205,16 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
#ifdef USE_HTTP2
case 20:
#endif
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
case 30:
#endif
- /* TODO: we should verify that responses do not switch major
- * HTTP version of the connection. Now, it seems we might accept
- * a HTTP/2 response on a HTTP/1.1 connection, which is wrong. */
- conn->httpversion = (unsigned char)k->httpversion;
+ /* no major version switch mid-connection */
+ if(conn->httpversion &&
+ (k->httpversion/10 != conn->httpversion/10)) {
+ failf(data, "Version mismatch (from HTTP/%u to HTTP/%u)",
+ conn->httpversion/10, k->httpversion/10);
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
break;
default:
failf(data, "Unsupported HTTP version (%u.%d) in response",
@@ -3258,10 +3259,6 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
of the protocol */
conn->bundle->multiuse = BUNDLE_MULTIPLEX;
}
- else if(k->httpversion >= 11 && !conn->bits.close) {
- /* If HTTP version is >= 1.1 and connection is persistent */
- DEBUGF(infof(data, "HTTP 1.1 or later with persistent connection"));
- }
k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
switch(k->httpcode) {
@@ -3312,12 +3309,11 @@ CURLcode Curl_http_size(struct Curl_easy *data)
return CURLE_OK;
}
-static CURLcode verify_header(struct Curl_easy *data)
+static CURLcode verify_header(struct Curl_easy *data,
+ const char *hd, size_t hdlen)
{
struct SingleRequest *k = &data->req;
- const char *header = Curl_dyn_ptr(&data->state.headerb);
- size_t hlen = Curl_dyn_len(&data->state.headerb);
- char *ptr = memchr(header, 0x00, hlen);
+ char *ptr = memchr(hd, 0x00, hdlen);
if(ptr) {
/* this is bad, bail out */
failf(data, "Nul byte in header");
@@ -3326,11 +3322,11 @@ static CURLcode verify_header(struct Curl_easy *data)
if(k->headerline < 2)
/* the first "header" is the status-line and it has no colon */
return CURLE_OK;
- if(((header[0] == ' ') || (header[0] == '\t')) && k->headerline > 2)
+ if(((hd[0] == ' ') || (hd[0] == '\t')) && k->headerline > 2)
/* line folding, can't happen on line 2 */
;
else {
- ptr = memchr(header, ':', hlen);
+ ptr = memchr(hd, ':', hdlen);
if(!ptr) {
/* this is bad, bail out */
failf(data, "Header without colon");
@@ -3375,7 +3371,6 @@ static CURLcode http_on_response(struct Curl_easy *data,
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
struct SingleRequest *k = &data->req;
- bool switch_to_h2 = FALSE;
(void)buf; /* not used without HTTP2 enabled */
*pconsumed = 0;
@@ -3394,96 +3389,92 @@ static CURLcode http_on_response(struct Curl_easy *data,
return CURLE_UNSUPPORTED_PROTOCOL;
}
else if(k->httpcode < 200) {
- /* "A user agent MAY ignore unexpected 1xx status responses." */
+ /* "A user agent MAY ignore unexpected 1xx status responses."
+ * By default, we expect to get more responses after this one. */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+
switch(k->httpcode) {
case 100:
/*
* We have made an HTTP PUT or POST and this is 1.1-lingo
* that tells us that the server is OK with this and ready
* to receive the data.
- * However, we'll get more headers now so we must get
- * back into the header-parsing state!
*/
- k->header = TRUE;
- k->headerline = 0; /* restart the header line counter */
-
- /* if we did wait for this do enable write now! */
Curl_http_exp100_got100(data);
break;
case 101:
- if(conn->httpversion == 11) {
- /* Switching Protocols only allowed from HTTP/1.1 */
- if(k->upgr101 == UPGR101_H2) {
- /* Switching to HTTP/2 */
- infof(data, "Received 101, Switching to HTTP/2");
- k->upgr101 = UPGR101_RECEIVED;
-
- /* we'll get more headers (HTTP/2 response) */
- k->header = TRUE;
- k->headerline = 0; /* restart the header line counter */
- switch_to_h2 = TRUE;
- }
-#ifdef USE_WEBSOCKETS
- else if(k->upgr101 == UPGR101_WS) {
- /* verify the response */
- result = Curl_ws_accept(data, buf, blen);
- if(result)
- return result;
- k->header = FALSE; /* no more header to parse! */
- *pconsumed += blen; /* ws accept handled the data */
- blen = 0;
- if(data->set.connect_only)
- k->keepon &= ~KEEP_RECV; /* read no more content */
- }
-#endif
- else {
- /* Not switching to another protocol */
- k->header = FALSE; /* no more header to parse! */
- }
- }
- else {
+ /* Switching Protocols only allowed from HTTP/1.1 */
+ if(conn->httpversion != 11) {
/* invalid for other HTTP versions */
failf(data, "unexpected 101 response code");
return CURLE_WEIRD_SERVER_REPLY;
}
+ if(k->upgr101 == UPGR101_H2) {
+ /* Switching to HTTP/2, where we will get more responses */
+ infof(data, "Received 101, Switching to HTTP/2");
+ k->upgr101 = UPGR101_RECEIVED;
+ /* We expect more response from HTTP/2 later */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+ /* Any remaining `buf` bytes are already HTTP/2 and passed to
+ * be processed. */
+ result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
+ if(result)
+ return result;
+ *pconsumed += blen;
+ }
+#ifdef USE_WEBSOCKETS
+ else if(k->upgr101 == UPGR101_WS) {
+ /* verify the response. Any passed `buf` bytes are already in
+ * WebSockets format and taken in by the protocol handler. */
+ result = Curl_ws_accept(data, buf, blen);
+ if(result)
+ return result;
+ *pconsumed += blen; /* ws accept handled the data */
+ k->header = FALSE; /* we will not get more responses */
+ if(data->set.connect_only)
+ k->keepon &= ~KEEP_RECV; /* read no more content */
+ }
+#endif
+ else {
+ /* We silently accept this as the final response.
+ * TODO: this looks, uhm, wrong. What are we switching to if we
+ * did not ask for an Upgrade? Maybe the application provided an
+ * `Upgrade: xxx` header? */
+ k->header = FALSE;
+ }
break;
default:
- /* the status code 1xx indicates a provisional response, so
- we'll get another set of headers */
- k->header = TRUE;
- k->headerline = 0; /* restart the header line counter */
+ /* The server may send us other 1xx responses, like informative
+ * 103. This have no influence on request processing and we expect
+ * to receive a final response eventually. */
break;
}
+ return result;
}
- else {
- /* k->httpcode >= 200, final response */
- k->header = FALSE;
- if(k->upgr101 == UPGR101_H2) {
- /* A requested upgrade was denied, poke the multi handle to possibly
- allow a pending pipewait to continue */
- Curl_multi_connchanged(data->multi);
- }
+ /* k->httpcode >= 200, final response */
+ k->header = FALSE;
- if((k->size == -1) && !k->chunk && !conn->bits.close &&
- (conn->httpversion == 11) &&
- !(conn->handler->protocol & CURLPROTO_RTSP) &&
- data->state.httpreq != HTTPREQ_HEAD) {
- /* On HTTP 1.1, when connection is not to get closed, but no
- Content-Length nor Transfer-Encoding chunked have been
- received, according to RFC2616 section 4.4 point 5, we
- assume that the server will close the connection to
- signal the end of the document. */
- infof(data, "no chunk, no close, no size. Assume close to "
- "signal end");
- streamclose(conn, "HTTP: No end-of-message indicator");
- }
+ if(k->upgr101 == UPGR101_H2) {
+ /* A requested upgrade was denied, poke the multi handle to possibly
+ allow a pending pipewait to continue */
+ Curl_multi_connchanged(data->multi);
}
- if(!k->header) {
- result = Curl_http_size(data);
- if(result)
- return result;
+ if((k->size == -1) && !k->chunk && !conn->bits.close &&
+ (conn->httpversion == 11) &&
+ !(conn->handler->protocol & CURLPROTO_RTSP) &&
+ data->state.httpreq != HTTPREQ_HEAD) {
+ /* On HTTP 1.1, when connection is not to get closed, but no
+ Content-Length nor Transfer-Encoding chunked have been
+ received, according to RFC2616 section 4.4 point 5, we
+ assume that the server will close the connection to
+ signal the end of the document. */
+ infof(data, "no chunk, no close, no size. Assume close to "
+ "signal end");
+ streamclose(conn, "HTTP: No end-of-message indicator");
}
/* At this point we have some idea about the fate of the connection.
@@ -3517,31 +3508,25 @@ static CURLcode http_on_response(struct Curl_easy *data,
}
#endif
- /*
- * When all the headers have been parsed, see if we should give
- * up and return an error.
- */
- if(http_should_fail(data)) {
- failf(data, "The requested URL returned error: %d",
- k->httpcode);
- return CURLE_HTTP_RETURNED_ERROR;
- }
-
#ifdef USE_WEBSOCKETS
- /* All non-101 HTTP status codes are bad when wanting to upgrade to
- websockets */
+ /* All >=200 HTTP status codes are errors when wanting websockets */
if(data->req.upgr101 == UPGR101_WS) {
failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
return CURLE_HTTP_RETURNED_ERROR;
}
#endif
+ /* Check if this response means the transfer errored. */
+ if(http_should_fail(data, data->req.httpcode)) {
+ failf(data, "The requested URL returned error: %d",
+ k->httpcode);
+ return CURLE_HTTP_RETURNED_ERROR;
+ }
/* Curl_http_auth_act() checks what authentication methods
* that are available and decides which one (if any) to
* use. It will set 'newurl' if an auth method was picked. */
result = Curl_http_auth_act(data);
-
if(result)
return result;
@@ -3612,65 +3597,244 @@ static CURLcode http_on_response(struct Curl_easy *data,
infof(data, "Keep sending data to get tossed away");
k->keepon |= KEEP_SEND;
}
+
}
- if(!k->header) {
- /*
- * really end-of-headers.
- *
- * If we requested a "no body", this is a good time to get
- * out and return home.
+ /* This is the last response that we will got for the current request.
+ * Check on the body size and determine if the response is complete.
+ */
+ result = Curl_http_size(data);
+ if(result)
+ return result;
+
+ /* If we requested a "no body", this is a good time to get
+ * out and return home.
+ */
+ if(data->req.no_body)
+ k->download_done = TRUE;
+
+ /* If max download size is *zero* (nothing) we already have
+ nothing and can safely return ok now! But for HTTP/2, we'd
+ like to call http2_handle_stream_close to properly close a
+ stream. In order to do this, we keep reading until we
+ close the stream. */
+ if(0 == k->maxdownload
+ && !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
+ && !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
+ k->download_done = TRUE;
+
+ /* final response without error, prepare to receive the body */
+ return Curl_http_firstwrite(data);
+}
+
+static CURLcode http_rw_hd(struct Curl_easy *data,
+ const char *hd, size_t hdlen,
+ const char *buf_remain, size_t blen,
+ size_t *pconsumed)
+{
+ CURLcode result = CURLE_OK;
+ struct SingleRequest *k = &data->req;
+ int writetype;
+
+ *pconsumed = 0;
+ if((0x0a == *hd) || (0x0d == *hd)) {
+ /* Empty header line means end of headers! */
+ size_t consumed;
+
+ /* now, only output this if the header AND body are requested:
*/
- if(data->req.no_body)
- k->download_done = TRUE;
-
- /* If max download size is *zero* (nothing) we already have
- nothing and can safely return ok now! But for HTTP/2, we'd
- like to call http2_handle_stream_close to properly close a
- stream. In order to do this, we keep reading until we
- close the stream. */
- if(0 == k->maxdownload
- && !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
- && !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
- k->download_done = TRUE;
- }
-
- if(switch_to_h2) {
- /* Having handled the headers, we can do the HTTP/2 switch.
- * Any remaining `buf` bytes are already HTTP/2 and passed to
- * be processed. */
- result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
+ Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
+
+ writetype = CLIENTWRITE_HEADER |
+ ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
+
+ result = Curl_client_write(data, writetype, hd, hdlen);
+ if(result)
+ return result;
+
+ result = Curl_bump_headersize(data, hdlen, FALSE);
if(result)
return result;
- *pconsumed += blen;
+
+ data->req.deductheadercount =
+ (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
+
+ /* analyze the response to find out what to do. */
+ /* Caveat: we clear anything in the header brigade, because a
+ * response might switch HTTP version which may call use recursively.
+ * Not nice, but that is currently the way of things. */
+ Curl_dyn_reset(&data->state.headerb);
+ result = http_on_response(data, buf_remain, blen, &consumed);
+ if(result)
+ return result;
+ *pconsumed += consumed;
+ return CURLE_OK;
+ }
+
+ /*
+ * Checks for special headers coming up.
+ */
+
+ writetype = CLIENTWRITE_HEADER;
+ if(!k->headerline++) {
+ /* This is the first header, it MUST be the error code line
+ or else we consider this to be the body right away! */
+ bool fine_statusline = FALSE;
+
+ k->httpversion = 0; /* Don't know yet */
+ if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
+ /*
+ * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
+ *
+ * The response code is always a three-digit number in HTTP as the spec
+ * says. We allow any three-digit number here, but we cannot make
+ * guarantees on future behaviors since it isn't within the protocol.
+ */
+ const char *p = hd;
+
+ while(*p && ISBLANK(*p))
+ p++;
+ if(!strncmp(p, "HTTP/", 5)) {
+ p += 5;
+ switch(*p) {
+ case '1':
+ p++;
+ if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
+ if(ISBLANK(p[2])) {
+ k->httpversion = 10 + (p[1] - '0');
+ 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;
+ }
+ }
+ }
+ if(!fine_statusline) {
+ failf(data, "Unsupported HTTP/1 subversion in response");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+ break;
+ case '2':
+ case '3':
+ if(!ISBLANK(p[1]))
+ break;
+ k->httpversion = (*p - '0') * 10;
+ p += 2;
+ 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))
+ break;
+ fine_statusline = TRUE;
+ }
+ break;
+ default: /* unsupported */
+ failf(data, "Unsupported HTTP version in response");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+ }
+
+ if(!fine_statusline) {
+ /* If user has set option HTTP200ALIASES,
+ compare header line against list of aliases
+ */
+ statusline check = checkhttpprefix(data, hd, hdlen);
+ if(check == STATUS_DONE) {
+ fine_statusline = TRUE;
+ k->httpcode = 200;
+ k->httpversion = 10;
+ }
+ }
+ }
+ else if(data->conn->handler->protocol & CURLPROTO_RTSP) {
+ const char *p = hd;
+ while(*p && 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) {
+ result = Curl_http_statusline(data, data->conn);
+ if(result)
+ return result;
+ writetype |= CLIENTWRITE_STATUS;
+ }
+ else {
+ k->header = FALSE; /* this is not a header line */
+ return CURLE_WEIRD_SERVER_REPLY;
+ }
}
+ result = verify_header(data, hd, hdlen);
+ if(result)
+ return result;
+
+ result = Curl_http_header(data, hd, hdlen);
+ if(result)
+ return result;
+
+ /*
+ * Taken in one (more) header. Write it to the client.
+ */
+ Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
+
+ if(k->httpcode/100 == 1)
+ writetype |= CLIENTWRITE_1XX;
+ result = Curl_client_write(data, writetype, hd, hdlen);
+ if(result)
+ return result;
+
+ result = Curl_bump_headersize(data, hdlen, FALSE);
+ if(result)
+ return result;
+
return CURLE_OK;
}
+
/*
* Read any HTTP header lines from the server and pass them to the client app.
*/
-static CURLcode http_rw_headers(struct Curl_easy *data,
- const char *buf, size_t blen,
- size_t *pconsumed)
+static CURLcode http_parse_headers(struct Curl_easy *data,
+ const char *buf, size_t blen,
+ size_t *pconsumed)
{
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
struct SingleRequest *k = &data->req;
- char *hd;
- size_t hdlen;
char *end_ptr;
bool leftover_body = FALSE;
/* header line within buffer loop */
*pconsumed = 0;
- do {
- size_t line_length;
- int writetype;
-
- /* data is in network encoding so use 0x0a instead of '\n' */
- end_ptr = memchr(buf, 0x0a, blen);
+ while(blen && k->header) {
+ size_t consumed;
+ end_ptr = memchr(buf, '\n', blen);
if(!end_ptr) {
/* Not a complete header line within buffer, append the data to
the end of the headerbuff. */
@@ -3706,14 +3870,13 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
}
/* decrease the size of the remaining (supposed) header line */
- line_length = (end_ptr - buf) + 1;
- result = Curl_dyn_addn(&data->state.headerb, buf, line_length);
+ consumed = (end_ptr - buf) + 1;
+ result = Curl_dyn_addn(&data->state.headerb, buf, consumed);
if(result)
return result;
-
- blen -= line_length;
- buf += line_length;
- *pconsumed += line_length;
+ blen -= consumed;
+ buf += consumed;
+ *pconsumed += consumed;
/****
* We now have a FULL header line in 'headerb'.
@@ -3741,195 +3904,21 @@ static CURLcode http_rw_headers(struct Curl_easy *data,
}
}
- /* headers are in network encoding so use 0x0a and 0x0d instead of '\n'
- and '\r' */
- hd = Curl_dyn_ptr(&data->state.headerb);
- hdlen = Curl_dyn_len(&data->state.headerb);
- if((0x0a == *hd) || (0x0d == *hd)) {
- /* Empty header line means end of headers! */
- size_t consumed;
-
- /* now, only output this if the header AND body are requested:
- */
- Curl_debug(data, CURLINFO_HEADER_IN, hd, hdlen);
-
- writetype = CLIENTWRITE_HEADER |
- ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
-
- result = Curl_client_write(data, writetype, hd, hdlen);
- if(result)
- return result;
-
- result = Curl_bump_headersize(data, hdlen, FALSE);
- if(result)
- return result;
- /* We are done with this line. We reset because response
- * processing might switch to HTTP/2 and that might call us
- * directly again. */
- Curl_dyn_reset(&data->state.headerb);
-
- data->req.deductheadercount =
- (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
-
- /* analyze the response to find out what to do */
- result = http_on_response(data, buf, blen, &consumed);
- if(result)
- return result;
- *pconsumed += consumed;
+ result = http_rw_hd(data, Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb),
+ buf, blen, &consumed);
+ /* We are done with this line. We reset because response
+ * processing might switch to HTTP/2 and that might call us
+ * directly again. */
+ Curl_dyn_reset(&data->state.headerb);
+ if(consumed) {
blen -= consumed;
buf += consumed;
-
- if(!k->header || !blen)
- goto out; /* exit header line loop */
-
- continue;
- }
-
- /*
- * Checks for special headers coming up.
- */
-
- writetype = CLIENTWRITE_HEADER;
- if(!k->headerline++) {
- /* This is the first header, it MUST be the error code line
- or else we consider this to be the body right away! */
- bool fine_statusline = FALSE;
-
- k->httpversion = 0; /* Don't know yet */
- if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
- /*
- * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
- *
- * The response code is always a three-digit number in HTTP as the spec
- * says. We allow any three-digit number here, but we cannot make
- * guarantees on future behaviors since it isn't within the protocol.
- */
- char *p = hd;
-
- while(*p && ISBLANK(*p))
- p++;
- if(!strncmp(p, "HTTP/", 5)) {
- p += 5;
- switch(*p) {
- case '1':
- p++;
- if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
- if(ISBLANK(p[2])) {
- k->httpversion = 10 + (p[1] - '0');
- 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;
- }
- }
- }
- if(!fine_statusline) {
- failf(data, "Unsupported HTTP/1 subversion in response");
- return CURLE_UNSUPPORTED_PROTOCOL;
- }
- break;
- case '2':
- case '3':
- if(!ISBLANK(p[1]))
- break;
- k->httpversion = (*p - '0') * 10;
- p += 2;
- 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))
- break;
- fine_statusline = TRUE;
- }
- break;
- default: /* unsupported */
- failf(data, "Unsupported HTTP version in response");
- return CURLE_UNSUPPORTED_PROTOCOL;
- }
- }
-
- if(!fine_statusline) {
- /* If user has set option HTTP200ALIASES,
- compare header line against list of aliases
- */
- statusline check = checkhttpprefix(data, hd, hdlen);
- if(check == STATUS_DONE) {
- fine_statusline = TRUE;
- k->httpcode = 200;
- k->httpversion = 10;
- }
- }
- }
- else if(conn->handler->protocol & CURLPROTO_RTSP) {
- char *p = hd;
- while(*p && 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) {
- result = Curl_http_statusline(data, conn);
- if(result)
- return result;
- writetype |= CLIENTWRITE_STATUS;
- }
- else {
- k->header = FALSE; /* this is not a header line */
- break;
- }
+ *pconsumed += consumed;
}
-
- result = verify_header(data);
- if(result)
- return result;
-
- result = Curl_http_header(data, conn, hd, hdlen);
- if(result)
- return result;
-
- /*
- * Taken in one (more) header. Write it to the client.
- */
- Curl_debug(data, CURLINFO_HEADER_IN, hd, hdlen);
-
- if(k->httpcode/100 == 1)
- writetype |= CLIENTWRITE_1XX;
- result = Curl_client_write(data, writetype, hd, hdlen);
if(result)
return result;
-
- result = Curl_bump_headersize(data, hdlen, FALSE);
- if(result)
- return result;
-
- Curl_dyn_reset(&data->state.headerb);
}
- while(blen);
/* We might have reached the end of the header part here, but
there might be a non-header part left in the end of the read
@@ -3941,6 +3930,22 @@ out:
return CURLE_OK;
}
+CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
+ const char *hd, size_t hdlen,
+ bool is_eos)
+{
+ CURLcode result;
+ size_t consumed;
+ char tmp = 0;
+
+ result = http_rw_hd(data, hd, hdlen, &tmp, 0, &consumed);
+ if(!result && is_eos) {
+ result = Curl_client_write(data, (CLIENTWRITE_BODY|CLIENTWRITE_EOS),
+ &tmp, 0);
+ }
+ return result;
+}
+
/*
* HTTP protocol `write_resp` implementation. Will parse headers
* when not done yet and otherwise return without consuming data.
@@ -3956,11 +3961,8 @@ CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
else {
CURLcode result;
- result = http_rw_headers(data, buf, blen, pconsumed);
+ result = http_parse_headers(data, buf, blen, pconsumed);
if(!result && !data->req.header) {
- /* we have successfully finished parsing the HEADERs */
- result = Curl_http_firstwrite(data);
-
if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) {
/* leftover from parsing something that turned out not
* to be a header, only happens if we allow for
diff --git a/libs/libcurl/src/http.h b/libs/libcurl/src/http.h
index 86763d5ad5..c56758be23 100644
--- a/libs/libcurl/src/http.h
+++ b/libs/libcurl/src/http.h
@@ -44,7 +44,7 @@ typedef enum {
#ifndef CURL_DISABLE_HTTP
-#if defined(ENABLE_QUIC)
+#if defined(USE_HTTP3)
#include <stdint.h>
#endif
@@ -102,8 +102,8 @@ CURLcode Curl_http_target(struct Curl_easy *data, struct connectdata *conn,
struct dynbuf *req);
CURLcode Curl_http_statusline(struct Curl_easy *data,
struct connectdata *conn);
-CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
- char *headp, size_t hdlen);
+CURLcode Curl_http_header(struct Curl_easy *data,
+ const char *hd, size_t hdlen);
CURLcode Curl_transferencode(struct Curl_easy *data);
CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
Curl_HttpReq httpreq,
@@ -134,6 +134,9 @@ int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn,
CURLcode Curl_http_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
bool is_eos);
+CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
+ const char *hd, size_t hdlen,
+ bool is_eos);
/* These functions are in http.c */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
@@ -185,12 +188,8 @@ void Curl_http_exp100_got100(struct Curl_easy *data);
* HTTP unique setup
***************************************************************************/
struct HTTP {
-#ifndef CURL_DISABLE_HTTP
- void *h2_ctx; /* HTTP/2 implementation context */
- void *h3_ctx; /* HTTP/3 implementation context */
-#else
+ /* TODO: no longer used, we should remove it from SingleRequest */
char unused;
-#endif
};
CURLcode Curl_http_size(struct Curl_easy *data);
diff --git a/libs/libcurl/src/http2.c b/libs/libcurl/src/http2.c
index c7f369e1cb..261c9fbb8a 100644
--- a/libs/libcurl/src/http2.c
+++ b/libs/libcurl/src/http2.c
@@ -29,6 +29,7 @@
#include <nghttp2/nghttp2.h>
#include "urldata.h"
#include "bufq.h"
+#include "hash.h"
#include "http1.h"
#include "http2.h"
#include "http.h"
@@ -127,7 +128,9 @@ struct cf_h2_ctx {
struct bufq inbufq; /* network input */
struct bufq outbufq; /* network output */
struct bufc_pool stream_bufcp; /* spares for stream buffers */
+ struct dynbuf scratch; /* scratch buffer for temp use */
+ struct Curl_hash streams; /* hash of `data->id` to `h2_stream_ctx` */
size_t drain_total; /* sum of all stream's UrlState drain */
uint32_t max_concurrent_streams;
int32_t goaway_error;
@@ -153,6 +156,9 @@ static void cf_h2_ctx_clear(struct cf_h2_ctx *ctx)
Curl_bufq_free(&ctx->inbufq);
Curl_bufq_free(&ctx->outbufq);
Curl_bufcp_free(&ctx->stream_bufcp);
+ Curl_dyn_free(&ctx->scratch);
+ Curl_hash_clean(&ctx->streams);
+ Curl_hash_destroy(&ctx->streams);
memset(ctx, 0, sizeof(*ctx));
ctx->call_data = save;
}
@@ -187,6 +193,7 @@ struct h2_stream_ctx {
int status_code; /* HTTP response status code */
uint32_t error; /* stream error code */
+ CURLcode xfer_result; /* Result of writing out response */
uint32_t local_window_size; /* the local recv window size */
int32_t id; /* HTTP/2 protocol identifier for stream */
BIT(resp_hds_complete); /* we have a complete, final response */
@@ -198,13 +205,58 @@ struct h2_stream_ctx {
buffered data in stream->sendbuf to upload. */
};
-#define H2_STREAM_CTX(d) ((struct h2_stream_ctx *)(((d) && \
- (d)->req.p.http)? \
- ((struct HTTP *)(d)->req.p.http)->h2_ctx \
- : NULL))
-#define H2_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h2_ctx
-#define H2_STREAM_ID(d) (H2_STREAM_CTX(d)? \
- H2_STREAM_CTX(d)->id : -2)
+#define H2_STREAM_CTX(ctx,data) ((struct h2_stream_ctx *)(\
+ data? Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
+
+static struct h2_stream_ctx *h2_stream_ctx_create(struct cf_h2_ctx *ctx)
+{
+ struct h2_stream_ctx *stream;
+
+ (void)ctx;
+ stream = calloc(1, sizeof(*stream));
+ if(!stream)
+ return NULL;
+
+ stream->id = -1;
+ Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
+ H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
+ Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
+ Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
+ stream->resp_hds_len = 0;
+ stream->bodystarted = FALSE;
+ stream->status_code = -1;
+ stream->closed = FALSE;
+ stream->close_handled = FALSE;
+ stream->error = NGHTTP2_NO_ERROR;
+ stream->local_window_size = H2_STREAM_WINDOW_SIZE;
+ stream->upload_left = 0;
+ stream->nrcvd_data = 0;
+ return stream;
+}
+
+static void free_push_headers(struct h2_stream_ctx *stream)
+{
+ size_t i;
+ for(i = 0; i<stream->push_headers_used; i++)
+ free(stream->push_headers[i]);
+ Curl_safefree(stream->push_headers);
+ stream->push_headers_used = 0;
+}
+
+static void h2_stream_ctx_free(struct h2_stream_ctx *stream)
+{
+ Curl_bufq_free(&stream->sendbuf);
+ Curl_h1_req_parse_free(&stream->h1);
+ Curl_dynhds_free(&stream->resp_trailers);
+ free_push_headers(stream);
+ free(stream);
+}
+
+static void h2_stream_hash_free(void *stream)
+{
+ DEBUGASSERT(stream);
+ h2_stream_ctx_free((struct h2_stream_ctx *)stream);
+}
/*
* Mark this transfer to get "drained".
@@ -241,49 +293,29 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf,
failf(data, "initialization failure, transfer not http initialized");
return CURLE_FAILED_INIT;
}
- stream = H2_STREAM_CTX(data);
+ stream = H2_STREAM_CTX(ctx, data);
if(stream) {
*pstream = stream;
return CURLE_OK;
}
- stream = calloc(1, sizeof(*stream));
+ stream = h2_stream_ctx_create(ctx);
if(!stream)
return CURLE_OUT_OF_MEMORY;
- stream->id = -1;
- Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
- H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
- Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
- Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
- stream->resp_hds_len = 0;
- stream->bodystarted = FALSE;
- stream->status_code = -1;
- stream->closed = FALSE;
- stream->close_handled = FALSE;
- stream->error = NGHTTP2_NO_ERROR;
- stream->local_window_size = H2_STREAM_WINDOW_SIZE;
- stream->upload_left = 0;
- stream->nrcvd_data = 0;
+ if(!Curl_hash_offt_set(&ctx->streams, data->id, stream)) {
+ h2_stream_ctx_free(stream);
+ return CURLE_OUT_OF_MEMORY;
+ }
- H2_STREAM_LCTX(data) = stream;
*pstream = stream;
return CURLE_OK;
}
-static void free_push_headers(struct h2_stream_ctx *stream)
-{
- size_t i;
- for(i = 0; i<stream->push_headers_used; i++)
- free(stream->push_headers[i]);
- Curl_safefree(stream->push_headers);
- stream->push_headers_used = 0;
-}
-
static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
DEBUGASSERT(ctx);
if(!stream)
@@ -310,12 +342,7 @@ static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
nghttp2_session_send(ctx->h2);
}
- Curl_bufq_free(&stream->sendbuf);
- Curl_h1_req_parse_free(&stream->h1);
- Curl_dynhds_free(&stream->resp_trailers);
- free_push_headers(stream);
- free(stream);
- H2_STREAM_LCTX(data) = NULL;
+ Curl_hash_offt_remove(&ctx->streams, data->id);
}
static int h2_client_new(struct Curl_cfilter *cf,
@@ -408,6 +435,8 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf,
Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES);
Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0);
Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0);
+ Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
+ Curl_hash_offt_init(&ctx->streams, 63, h2_stream_hash_free);
ctx->last_stream_id = 2147483647;
rc = nghttp2_session_callbacks_new(&cbs);
@@ -706,6 +735,7 @@ static ssize_t send_callback(nghttp2_session *h2,
the struct are hidden from the user. */
struct curl_pushheaders {
struct Curl_easy *data;
+ struct h2_stream_ctx *stream;
const nghttp2_push_promise *frame;
};
@@ -719,9 +749,8 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
if(!h || !GOOD_EASY_HANDLE(h->data))
return NULL;
else {
- struct h2_stream_ctx *stream = H2_STREAM_CTX(h->data);
- if(stream && num < stream->push_headers_used)
- return stream->push_headers[num];
+ if(h->stream && num < h->stream->push_headers_used)
+ return h->stream->push_headers[num];
}
return NULL;
}
@@ -744,7 +773,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
!strcmp(header, ":") || strchr(header + 1, ':'))
return NULL;
- stream = H2_STREAM_CTX(h->data);
+ stream = h->stream;
if(!stream)
return NULL;
@@ -804,7 +833,7 @@ static int set_transfer_url(struct Curl_easy *data,
v = curl_pushheader_byname(hp, HTTP_PSEUDO_AUTHORITY);
if(v) {
- uc = Curl_url_set_authority(u, v, CURLU_DISALLOW_USER);
+ uc = Curl_url_set_authority(u, v);
if(uc) {
rc = 2;
goto fail;
@@ -867,12 +896,10 @@ static int push_promise(struct Curl_cfilter *cf,
goto fail;
}
- heads.data = data;
- heads.frame = frame;
/* ask the application */
CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ask application");
- stream = H2_STREAM_CTX(data);
+ stream = H2_STREAM_CTX(ctx, data);
if(!stream) {
failf(data, "Internal NULL stream");
discard_newhandle(cf, newhandle);
@@ -880,6 +907,10 @@ static int push_promise(struct Curl_cfilter *cf,
goto fail;
}
+ heads.data = data;
+ heads.stream = stream;
+ heads.frame = frame;
+
rv = set_transfer_url(newhandle, &heads);
if(rv) {
discard_newhandle(cf, newhandle);
@@ -945,12 +976,39 @@ fail:
return rv;
}
-static CURLcode recvbuf_write_hds(struct Curl_cfilter *cf,
+static void h2_xfer_write_resp_hd(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const char *buf, size_t blen)
+ struct h2_stream_ctx *stream,
+ const char *buf, size_t blen, bool eos)
{
- (void)cf;
- return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
+
+ /* If we already encountered an error, skip further writes */
+ if(!stream->xfer_result) {
+ stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos);
+ if(stream->xfer_result)
+ CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of headers",
+ stream->id, stream->xfer_result, blen);
+ }
+}
+
+static void h2_xfer_write_resp(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct h2_stream_ctx *stream,
+ const char *buf, size_t blen, bool eos)
+{
+
+ /* If we already encountered an error, skip further writes */
+ if(!stream->xfer_result)
+ stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos);
+ /* If the transfer write is errored, we do not want any more data */
+ if(stream->xfer_result) {
+ struct cf_h2_ctx *ctx = cf->ctx;
+ CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of data, "
+ "RST-ing stream",
+ stream->id, stream->xfer_result, blen);
+ nghttp2_submit_rst_stream(ctx->h2, 0, stream->id,
+ NGHTTP2_ERR_CALLBACK_FAILURE);
+ }
}
static CURLcode on_stream_frame(struct Curl_cfilter *cf,
@@ -958,9 +1016,8 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
const nghttp2_frame *frame)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
int32_t stream_id = frame->hd.stream_id;
- CURLcode result;
int rv;
if(!stream) {
@@ -1008,9 +1065,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
stream->status_code = -1;
}
- result = recvbuf_write_hds(cf, data, STRCONST("\r\n"));
- if(result)
- return result;
+ h2_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);
if(stream->status_code / 100 != 1) {
stream->resp_hds_complete = TRUE;
@@ -1189,7 +1244,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
* servers send an explicit WINDOW_UPDATE, but not all seem to do that.
* To be safe, we UNHOLD a stream in order not to stall. */
if(CURL_WANT_SEND(data)) {
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
if(stream)
drain_stream(cf, data, stream);
}
@@ -1229,7 +1284,6 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream;
struct Curl_easy *data_s;
- CURLcode result;
(void)flags;
DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
@@ -1248,13 +1302,11 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
return 0;
}
- stream = H2_STREAM_CTX(data_s);
+ stream = H2_STREAM_CTX(ctx, data_s);
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = Curl_xfer_write_resp(data_s, (char *)mem, len, FALSE);
- if(result && result != CURLE_AGAIN)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
+ h2_xfer_write_resp(cf, data_s, stream, (char *)mem, len, FALSE);
nghttp2_session_consume(ctx->h2, stream_id, len);
stream->nrcvd_data += (curl_off_t)len;
@@ -1268,6 +1320,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
uint32_t error_code, void *userp)
{
struct Curl_cfilter *cf = userp;
+ struct cf_h2_ctx *ctx = cf->ctx;
struct Curl_easy *data_s, *call_data = CF_DATA_CURRENT(cf);
struct h2_stream_ctx *stream;
int rv;
@@ -1292,7 +1345,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
(void)nghttp2_session_set_stream_user_data(session, stream_id, 0);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
- stream = H2_STREAM_CTX(data_s);
+ stream = H2_STREAM_CTX(ctx, data_s);
if(!stream) {
CURL_TRC_CF(data_s, cf,
"[%d] on_stream_close, GOOD easy but no stream", stream_id);
@@ -1327,6 +1380,7 @@ static int on_begin_headers(nghttp2_session *session,
const nghttp2_frame *frame, void *userp)
{
struct Curl_cfilter *cf = userp;
+ struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream;
struct Curl_easy *data_s = NULL;
@@ -1340,7 +1394,7 @@ static int on_begin_headers(nghttp2_session *session,
return 0;
}
- stream = H2_STREAM_CTX(data_s);
+ stream = H2_STREAM_CTX(ctx, data_s);
if(!stream || !stream->bodystarted) {
return 0;
}
@@ -1356,6 +1410,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
void *userp)
{
struct Curl_cfilter *cf = userp;
+ struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream;
struct Curl_easy *data_s;
int32_t stream_id = frame->hd.stream_id;
@@ -1371,7 +1426,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
internal error more than anything else! */
return NGHTTP2_ERR_CALLBACK_FAILURE;
- stream = H2_STREAM_CTX(data_s);
+ stream = H2_STREAM_CTX(ctx, data_s);
if(!stream) {
failf(data_s, "Internal NULL stream");
return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -1465,14 +1520,15 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = recvbuf_write_hds(cf, data_s, STRCONST("HTTP/2 "));
- if(result)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen);
- if(result)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
- /* the space character after the status code is mandatory */
- result = recvbuf_write_hds(cf, data_s, STRCONST(" \r\n"));
+ Curl_dyn_reset(&ctx->scratch);
+ result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/2 "));
+ if(!result)
+ result = Curl_dyn_addn(&ctx->scratch, value, valuelen);
+ if(!result)
+ result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
+ if(!result)
+ h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
+ Curl_dyn_len(&ctx->scratch), FALSE);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
@@ -1487,16 +1543,17 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
/* nghttp2 guarantees that namelen > 0, and :status was already
received, and this is not pseudo-header field . */
/* convert to an HTTP1-style header */
- result = recvbuf_write_hds(cf, data_s, (const char *)name, namelen);
- if(result)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = recvbuf_write_hds(cf, data_s, STRCONST(": "));
- if(result)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen);
- if(result)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = recvbuf_write_hds(cf, data_s, STRCONST("\r\n"));
+ Curl_dyn_reset(&ctx->scratch);
+ result = Curl_dyn_addn(&ctx->scratch, (const char *)name, namelen);
+ if(!result)
+ result = Curl_dyn_addn(&ctx->scratch, STRCONST(": "));
+ if(!result)
+ result = Curl_dyn_addn(&ctx->scratch, (const char *)value, valuelen);
+ if(!result)
+ result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
+ if(!result)
+ h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
+ Curl_dyn_len(&ctx->scratch), FALSE);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
@@ -1517,6 +1574,7 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
void *userp)
{
struct Curl_cfilter *cf = userp;
+ struct cf_h2_ctx *ctx = cf->ctx;
struct Curl_easy *data_s;
struct h2_stream_ctx *stream = NULL;
CURLcode result;
@@ -1533,7 +1591,7 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
internal error more than anything else! */
return NGHTTP2_ERR_CALLBACK_FAILURE;
- stream = H2_STREAM_CTX(data_s);
+ stream = H2_STREAM_CTX(ctx, data_s);
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
@@ -1620,7 +1678,7 @@ static CURLcode http2_data_done_send(struct Curl_cfilter *cf,
{
struct cf_h2_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
if(!ctx || !ctx->h2 || !stream)
goto out;
@@ -1658,6 +1716,15 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
return -1;
}
else if(stream->error != NGHTTP2_NO_ERROR) {
+ if(stream->resp_hds_complete && data->req.no_body) {
+ CURL_TRC_CF(data, cf, "[%d] error after response headers, but we did "
+ "not want a body anyway, ignore: %s (err %u)",
+ stream->id, nghttp2_http2_strerror(stream->error),
+ stream->error);
+ stream->close_handled = TRUE;
+ *err = CURLE_OK;
+ goto out;
+ }
failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
stream->id, nghttp2_http2_strerror(stream->error),
stream->error);
@@ -1736,11 +1803,12 @@ static int sweight_in_effect(const struct Curl_easy *data)
* struct.
*/
-static void h2_pri_spec(struct Curl_easy *data,
+static void h2_pri_spec(struct cf_h2_ctx *ctx,
+ struct Curl_easy *data,
nghttp2_priority_spec *pri_spec)
{
struct Curl_data_priority *prio = &data->set.priority;
- struct h2_stream_ctx *depstream = H2_STREAM_CTX(prio->parent);
+ struct h2_stream_ctx *depstream = H2_STREAM_CTX(ctx, prio->parent);
int32_t depstream_id = depstream? depstream->id:0;
nghttp2_priority_spec_init(pri_spec, depstream_id,
sweight_wanted(data),
@@ -1758,7 +1826,7 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
int rv = 0;
if(stream && stream->id > 0 &&
@@ -1768,7 +1836,7 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
/* send new weight and/or dependency */
nghttp2_priority_spec pri_spec;
- h2_pri_spec(data, &pri_spec);
+ h2_pri_spec(ctx, data, &pri_spec);
CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id);
DEBUGASSERT(stream->id != -1);
rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE,
@@ -1799,7 +1867,12 @@ static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
(void)buf;
*err = CURLE_AGAIN;
- if(stream->closed) {
+ if(stream->xfer_result) {
+ CURL_TRC_CF(data, cf, "[%d] xfer write failed", stream->id);
+ *err = stream->xfer_result;
+ nread = -1;
+ }
+ else if(stream->closed) {
CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
nread = http2_handle_stream_close(cf, data, stream, err);
}
@@ -1838,7 +1911,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
* it is time to stop due to connection close or us not processing
* all network input */
while(!ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
- stream = H2_STREAM_CTX(data);
+ stream = H2_STREAM_CTX(ctx, data);
if(stream && (stream->closed || !data_max_bytes)) {
/* We would like to abort here and stop processing, so that
* the transfer loop can handle the data/close here. However,
@@ -1884,7 +1957,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
ssize_t nread = -1;
CURLcode result;
struct cf_call_data save;
@@ -2016,7 +2089,7 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream,
goto out;
}
- h2_pri_spec(data, &pri_spec);
+ h2_pri_spec(ctx, data, &pri_spec);
if(!nghttp2_session_check_request_allowed(ctx->h2))
CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)");
@@ -2113,7 +2186,7 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
struct cf_call_data save;
int rv;
ssize_t nwritten;
@@ -2294,7 +2367,7 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
sock = Curl_conn_cf_get_socket(cf, data);
Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
if(want_recv || want_send) {
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
struct cf_call_data save;
bool c_exhaust, s_exhaust;
@@ -2395,7 +2468,7 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf,
{
#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
DEBUGASSERT(data);
if(ctx && ctx->h2 && stream) {
@@ -2480,7 +2553,7 @@ static bool cf_h2_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
if(ctx && (!Curl_bufq_is_empty(&ctx->inbufq)
|| (stream && !Curl_bufq_is_empty(&stream->sendbuf))))
@@ -2539,6 +2612,11 @@ static CURLcode cf_h2_query(struct Curl_cfilter *cf,
*pres1 = (effective_max > INT_MAX)? INT_MAX : (int)effective_max;
CF_DATA_RESTORE(cf, save);
return CURLE_OK;
+ case CF_QUERY_STREAM_ERROR: {
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
+ *pres1 = stream? (int)stream->error : 0;
+ return CURLE_OK;
+ }
default:
break;
}
@@ -2768,8 +2846,11 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
CURLE_HTTP2_STREAM error! */
bool Curl_h2_http_1_1_error(struct Curl_easy *data)
{
- struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
- return (stream && stream->error == NGHTTP2_HTTP_1_1_REQUIRED);
+ if(Curl_conn_is_http2(data, data->conn, FIRSTSOCKET)) {
+ int err = Curl_conn_get_stream_error(data, data->conn, FIRSTSOCKET);
+ return (err == NGHTTP2_HTTP_1_1_REQUIRED);
+ }
+ return FALSE;
}
#else /* !USE_NGHTTP2 */
diff --git a/libs/libcurl/src/http_aws_sigv4.c b/libs/libcurl/src/http_aws_sigv4.c
index deea1d4b00..0faa386652 100644
--- a/libs/libcurl/src/http_aws_sigv4.c
+++ b/libs/libcurl/src/http_aws_sigv4.c
@@ -158,10 +158,7 @@ static CURLcode make_headers(struct Curl_easy *data,
msnprintf(date_full_hdr, DATE_FULL_HDR_LEN,
"x-%s-date:%s", provider1, timestamp);
- if(Curl_checkheaders(data, STRCONST("Host"))) {
- head = NULL;
- }
- else {
+ if(!Curl_checkheaders(data, STRCONST("Host"))) {
char full_host[FULL_HOST_LEN + 1];
if(data->state.aptr.host) {
diff --git a/libs/libcurl/src/http_chunks.c b/libs/libcurl/src/http_chunks.c
index eb05ea9190..f9c7ad3bab 100644
--- a/libs/libcurl/src/http_chunks.c
+++ b/libs/libcurl/src/http_chunks.c
@@ -28,6 +28,7 @@
#include "urldata.h" /* it includes http_chunks.h */
#include "curl_printf.h"
+#include "curl_trc.h"
#include "sendf.h" /* for the client write stuff */
#include "dynbuf.h"
#include "content_encoding.h"
@@ -185,8 +186,11 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
if(0 == ch->datasize) {
ch->state = CHUNK_TRAILER; /* now check for trailers */
}
- else
+ else {
ch->state = CHUNK_DATA;
+ CURL_TRC_WRITE(data, "http_chunked, chunk start of %"
+ CURL_FORMAT_CURL_OFF_T " bytes", ch->datasize);
+ }
}
buf++;
@@ -221,6 +225,9 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
ch->datasize -= piece; /* decrease amount left to expect */
buf += piece; /* move read pointer forward */
blen -= piece; /* decrease space left in this round */
+ CURL_TRC_WRITE(data, "http_chunked, write %zu body bytes, %"
+ CURL_FORMAT_CURL_OFF_T " bytes in chunk remain",
+ piece, ch->datasize);
if(0 == ch->datasize)
/* end of data this round, we now expect a trailing CRLF */
@@ -340,11 +347,14 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
even if there's no more chunks to read */
ch->datasize = blen;
ch->state = CHUNK_DONE;
+ CURL_TRC_WRITE(data, "http_chunk, response complete");
return CURLE_OK;
}
else {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_BAD_CHUNK;
+ CURL_TRC_WRITE(data, "http_chunk error, expected 0x0a, seeing 0x%ux",
+ (unsigned int)*buf);
return CURLE_RECV_ERROR;
}
case CHUNK_DONE:
@@ -498,6 +508,7 @@ static CURLcode add_last_chunk(struct Curl_easy *data,
int rc;
if(!data->set.trailer_callback) {
+ CURL_TRC_READ(data, "http_chunk, added last, empty chunk");
return Curl_bufq_cwrite(&ctx->chunkbuf, STRCONST("0\r\n\r\n"), &n);
}
@@ -535,6 +546,8 @@ static CURLcode add_last_chunk(struct Curl_easy *data,
out:
curl_slist_free_all(trailers);
+ CURL_TRC_READ(data, "http_chunk, added last chunk with trailers "
+ "from client -> %d", result);
return result;
}
@@ -581,6 +594,8 @@ static CURLcode add_chunk(struct Curl_easy *data,
result = Curl_bufq_cwrite(&ctx->chunkbuf, buf, nread, &n);
if(!result)
result = Curl_bufq_cwrite(&ctx->chunkbuf, "\r\n", 2, &n);
+ CURL_TRC_READ(data, "http_chunk, made chunk of %zu bytes -> %d",
+ nread, result);
if(result)
return result;
}
diff --git a/libs/libcurl/src/http_negotiate.c b/libs/libcurl/src/http_negotiate.c
index 1207ffb14b..545e703f71 100644
--- a/libs/libcurl/src/http_negotiate.c
+++ b/libs/libcurl/src/http_negotiate.c
@@ -120,16 +120,29 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
CURLcode Curl_output_negotiate(struct Curl_easy *data,
struct connectdata *conn, bool proxy)
{
- struct negotiatedata *neg_ctx = proxy ? &conn->proxyneg :
- &conn->negotiate;
- struct auth *authp = proxy ? &data->state.authproxy : &data->state.authhost;
- curlnegotiate *state = proxy ? &conn->proxy_negotiate_state :
- &conn->http_negotiate_state;
+ struct negotiatedata *neg_ctx;
+ struct auth *authp;
+ curlnegotiate *state;
char *base64 = NULL;
size_t len = 0;
char *userp;
CURLcode result;
+ if(proxy) {
+#ifndef CURL_DISABLE_PROXY
+ neg_ctx = &conn->proxyneg;
+ authp = &data->state.authproxy;
+ state = &conn->proxy_negotiate_state;
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
+ }
+ else {
+ neg_ctx = &conn->negotiate;
+ authp = &data->state.authhost;
+ state = &conn->http_negotiate_state;
+ }
+
authp->done = FALSE;
if(*state == GSS_AUTHRECV) {
@@ -171,8 +184,10 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
base64);
if(proxy) {
+#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
data->state.aptr.proxyuserpwd = userp;
+#endif
}
else {
Curl_safefree(data->state.aptr.userpwd);
diff --git a/libs/libcurl/src/http_ntlm.c b/libs/libcurl/src/http_ntlm.c
index 50feeb91ee..83cd435fdc 100644
--- a/libs/libcurl/src/http_ntlm.c
+++ b/libs/libcurl/src/http_ntlm.c
@@ -40,7 +40,6 @@
#include "strcase.h"
#include "http_ntlm.h"
#include "curl_ntlm_core.h"
-#include "curl_ntlm_wb.h"
#include "curl_base64.h"
#include "vauth/vauth.h"
#include "url.h"
@@ -266,10 +265,6 @@ void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)
{
Curl_auth_cleanup_ntlm(&conn->ntlm);
Curl_auth_cleanup_ntlm(&conn->proxyntlm);
-
-#if defined(NTLM_WB_ENABLED)
- Curl_http_auth_cleanup_ntlm_wb(conn);
-#endif
}
#endif /* !CURL_DISABLE_HTTP && USE_NTLM */
diff --git a/libs/libcurl/src/http_proxy.c b/libs/libcurl/src/http_proxy.c
index bf0f3ff87d..be595ab3f7 100644
--- a/libs/libcurl/src/http_proxy.c
+++ b/libs/libcurl/src/http_proxy.c
@@ -293,7 +293,7 @@ static void http_proxy_cf_close(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_http_proxy = {
"HTTP-PROXY",
- CF_TYPE_IP_CONNECT,
+ CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
0,
http_proxy_cf_destroy,
http_proxy_cf_connect,
diff --git a/libs/libcurl/src/idn.c b/libs/libcurl/src/idn.c
index 493cc59c1c..bc1a6a7b38 100644
--- a/libs/libcurl/src/idn.c
+++ b/libs/libcurl/src/idn.c
@@ -50,6 +50,63 @@
#include "curl_memory.h"
#include "memdebug.h"
+/* for macOS and iOS targets */
+#if defined(USE_APPLE_IDN)
+#include <unicode/uidna.h>
+
+static CURLcode mac_idn_to_ascii(const char *in, char **out)
+{
+ UErrorCode err = U_ZERO_ERROR;
+ UIDNA* idna = uidna_openUTS46(UIDNA_CHECK_BIDI, &err);
+ if(U_FAILURE(err)) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ UIDNAInfo info = UIDNA_INFO_INITIALIZER;
+ char buffer[256] = {0};
+ (void)uidna_nameToASCII_UTF8(idna, in, -1, buffer,
+ sizeof(buffer), &info, &err);
+ uidna_close(idna);
+ if(U_FAILURE(err)) {
+ return CURLE_URL_MALFORMAT;
+ }
+ else {
+ *out = strdup(buffer);
+ if(*out)
+ return CURLE_OK;
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+}
+
+static CURLcode mac_ascii_to_idn(const char *in, char **out)
+{
+ UErrorCode err = U_ZERO_ERROR;
+ UIDNA* idna = uidna_openUTS46(UIDNA_CHECK_BIDI, &err);
+ if(U_FAILURE(err)) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ UIDNAInfo info = UIDNA_INFO_INITIALIZER;
+ char buffer[256] = {0};
+ (void)uidna_nameToUnicodeUTF8(idna, in, -1, buffer,
+ sizeof(buffer), &info, &err);
+ uidna_close(idna);
+ if(U_FAILURE(err)) {
+ return CURLE_URL_MALFORMAT;
+ }
+ else {
+ *out = strdup(buffer);
+ if(*out)
+ return CURLE_OK;
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+}
+#endif
+
#ifdef USE_WIN32_IDN
/* using Windows kernel32 and normaliz libraries. */
@@ -181,6 +238,8 @@ static CURLcode idn_decode(const char *input, char **output)
result = CURLE_NOT_BUILT_IN;
#elif defined(USE_WIN32_IDN)
result = win32_idn_to_ascii(input, &decoded);
+#elif defined(USE_APPLE_IDN)
+ result = mac_idn_to_ascii(input, &decoded);
#endif
if(!result)
*output = decoded;
@@ -198,6 +257,10 @@ static CURLcode idn_encode(const char *puny, char **output)
CURLcode result = win32_ascii_to_idn(puny, &enc);
if(result)
return result;
+#elif defined(USE_APPLE_IDN)
+ CURLcode result = mac_ascii_to_idn(puny, &enc);
+ if(result)
+ return result;
#endif
*output = enc;
return CURLE_OK;
@@ -246,11 +309,7 @@ CURLcode Curl_idn_encode(const char *puny, char **output)
*/
void Curl_free_idnconverted_hostname(struct hostname *host)
{
- if(host->encalloc) {
- /* must be freed with idn2_free() if allocated by libidn */
- Curl_idn_free(host->encalloc);
- host->encalloc = NULL;
- }
+ Curl_safefree(host->encalloc);
}
#endif /* USE_IDN */
@@ -267,20 +326,11 @@ CURLcode Curl_idnconvert_hostname(struct hostname *host)
/* Check name for non-ASCII and convert hostname if we can */
if(!Curl_is_ASCII_name(host->name)) {
char *decoded;
- CURLcode result = idn_decode(host->name, &decoded);
- if(!result) {
- if(!*decoded) {
- /* zero length is a bad host name */
- Curl_idn_free(decoded);
- return CURLE_URL_MALFORMAT;
- }
- /* successful */
- host->encalloc = decoded;
- /* change the name pointer to point to the encoded hostname */
- host->name = host->encalloc;
- }
- else
+ CURLcode result = Curl_idn_decode(host->name, &decoded);
+ if(result)
return result;
+ /* successful */
+ host->name = host->encalloc = decoded;
}
#endif
return CURLE_OK;
diff --git a/libs/libcurl/src/idn.h b/libs/libcurl/src/idn.h
index 5f5e527479..0fe61f0947 100644
--- a/libs/libcurl/src/idn.h
+++ b/libs/libcurl/src/idn.h
@@ -26,16 +26,11 @@
bool Curl_is_ASCII_name(const char *hostname);
CURLcode Curl_idnconvert_hostname(struct hostname *host);
-#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
#define USE_IDN
void Curl_free_idnconverted_hostname(struct hostname *host);
CURLcode Curl_idn_decode(const char *input, char **output);
CURLcode Curl_idn_encode(const char *input, char **output);
-#ifdef USE_LIBIDN2
-#define Curl_idn_free(x) idn2_free(x)
-#else
-#define Curl_idn_free(x) free(x)
-#endif
#else
#define Curl_free_idnconverted_hostname(x)
diff --git a/libs/libcurl/src/if2ip.c b/libs/libcurl/src/if2ip.c
index 3e9b87cb55..25948b9edf 100644
--- a/libs/libcurl/src/if2ip.c
+++ b/libs/libcurl/src/if2ip.c
@@ -62,7 +62,7 @@
/* ------------------------------------------------------------------ */
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
/* Return the scope of the given address. */
unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
{
@@ -97,17 +97,17 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
#if defined(HAVE_GETIFADDRS)
if2ip_result_t Curl_if2ip(int af,
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
- char *buf, int buf_size)
+ char *buf, size_t buf_size)
{
struct ifaddrs *iface, *head;
if2ip_result_t res = IF2IP_NOT_FOUND;
-#if defined(ENABLE_IPV6) && \
+#if defined(USE_IPV6) && \
!defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
(void) local_scope_id;
#endif
@@ -121,7 +121,7 @@ if2ip_result_t Curl_if2ip(int af,
const char *ip;
char scope[12] = "";
char ipstr[64];
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if(af == AF_INET6) {
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
unsigned int scopeid = 0;
@@ -182,12 +182,12 @@ if2ip_result_t Curl_if2ip(int af,
#elif defined(HAVE_IOCTL_SIOCGIFADDR)
if2ip_result_t Curl_if2ip(int af,
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
- char *buf, int buf_size)
+ char *buf, size_t buf_size)
{
struct ifreq req;
struct in_addr in;
@@ -196,7 +196,7 @@ if2ip_result_t Curl_if2ip(int af,
size_t len;
const char *r;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
(void)remote_scope;
(void)local_scope_id;
#endif
@@ -237,15 +237,15 @@ if2ip_result_t Curl_if2ip(int af,
#else
if2ip_result_t Curl_if2ip(int af,
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
- char *buf, int buf_size)
+ char *buf, size_t buf_size)
{
(void) af;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
(void) remote_scope;
(void) local_scope_id;
#endif
diff --git a/libs/libcurl/src/if2ip.h b/libs/libcurl/src/if2ip.h
index f82269532a..fc57aa087b 100644
--- a/libs/libcurl/src/if2ip.h
+++ b/libs/libcurl/src/if2ip.h
@@ -32,7 +32,7 @@
#define IPV6_SCOPE_UNIQUELOCAL 3 /* Unique local */
#define IPV6_SCOPE_NODELOCAL 4 /* Loopback. */
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
unsigned int Curl_ipv6_scope(const struct sockaddr *sa);
#else
#define Curl_ipv6_scope(x) 0
@@ -45,12 +45,12 @@ typedef enum {
} if2ip_result_t;
if2ip_result_t Curl_if2ip(int af,
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
- char *buf, int buf_size);
+ char *buf, size_t buf_size);
#ifdef __INTERIX
diff --git a/libs/libcurl/src/imap.c b/libs/libcurl/src/imap.c
index 404b101591..0f67d5c71c 100644
--- a/libs/libcurl/src/imap.c
+++ b/libs/libcurl/src/imap.c
@@ -117,7 +117,7 @@ static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out);
*/
const struct Curl_handler Curl_handler_imap = {
- "IMAP", /* scheme */
+ "imap", /* scheme */
imap_setup_connection, /* setup_connection */
imap_do, /* do_it */
imap_done, /* done */
@@ -131,6 +131,7 @@ const struct Curl_handler Curl_handler_imap = {
ZERO_NULL, /* perform_getsock */
imap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_IMAP, /* defport */
@@ -146,7 +147,7 @@ const struct Curl_handler Curl_handler_imap = {
*/
const struct Curl_handler Curl_handler_imaps = {
- "IMAPS", /* scheme */
+ "imaps", /* scheme */
imap_setup_connection, /* setup_connection */
imap_do, /* do_it */
imap_done, /* done */
@@ -160,6 +161,7 @@ const struct Curl_handler Curl_handler_imaps = {
ZERO_NULL, /* perform_getsock */
imap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_IMAPS, /* defport */
diff --git a/libs/libcurl/src/inet_ntop.c b/libs/libcurl/src/inet_ntop.c
index cf07b888dc..776e7d397b 100644
--- a/libs/libcurl/src/inet_ntop.c
+++ b/libs/libcurl/src/inet_ntop.c
@@ -42,11 +42,11 @@
#define INT16SZ 2
/*
- * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * If USE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
* sure we have _some_ value for AF_INET6 without polluting our fake value
* everywhere.
*/
-#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#if !defined(USE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif
diff --git a/libs/libcurl/src/inet_pton.c b/libs/libcurl/src/inet_pton.c
index 04ccd2e97d..923b1cccd7 100644
--- a/libs/libcurl/src/inet_pton.c
+++ b/libs/libcurl/src/inet_pton.c
@@ -39,11 +39,11 @@
#define INT16SZ 2
/*
- * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * If USE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
* sure we have _some_ value for AF_INET6 without polluting our fake value
* everywhere.
*/
-#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#if !defined(USE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif
diff --git a/libs/libcurl/src/krb5.c b/libs/libcurl/src/krb5.c
index e04c2042f0..a635966d51 100644
--- a/libs/libcurl/src/krb5.c
+++ b/libs/libcurl/src/krb5.c
@@ -524,24 +524,33 @@ static CURLcode read_data(struct Curl_easy *data, int sockindex,
return result;
if(len) {
- /* only realloc if there was a length */
len = ntohl(len);
if(len > CURL_MAX_INPUT_LENGTH)
- len = 0;
- else
- buf->data = Curl_saferealloc(buf->data, len);
+ return CURLE_TOO_LARGE;
+
+ Curl_dyn_reset(&buf->buf);
}
- if(!len || !buf->data)
- return CURLE_OUT_OF_MEMORY;
+ else
+ return CURLE_RECV_ERROR;
- result = socket_read(data, sockindex, buf->data, len);
- if(result)
- return result;
- nread = conn->mech->decode(conn->app_data, buf->data, len,
- conn->data_prot, conn);
+ do {
+ char buffer[1024];
+ nread = CURLMIN(len, (int)sizeof(buffer));
+ result = socket_read(data, sockindex, buffer, nread);
+ if(result)
+ return result;
+ result = Curl_dyn_addn(&buf->buf, buffer, nread);
+ if(result)
+ return result;
+ len -= nread;
+ } while(len);
+ /* this decodes the dynbuf *in place* */
+ nread = conn->mech->decode(conn->app_data,
+ Curl_dyn_ptr(&buf->buf),
+ len, conn->data_prot, conn);
if(nread < 0)
return CURLE_RECV_ERROR;
- buf->size = (size_t)nread;
+ Curl_dyn_setlen(&buf->buf, nread);
buf->index = 0;
return CURLE_OK;
}
@@ -549,9 +558,10 @@ static CURLcode read_data(struct Curl_easy *data, int sockindex,
static size_t
buffer_read(struct krb5buffer *buf, void *data, size_t len)
{
- if(buf->size - buf->index < len)
- len = buf->size - buf->index;
- memcpy(data, (char *)buf->data + buf->index, len);
+ size_t size = Curl_dyn_len(&buf->buf);
+ if(size - buf->index < len)
+ len = size - buf->index;
+ memcpy(data, Curl_dyn_ptr(&buf->buf) + buf->index, len);
buf->index += len;
return len;
}
@@ -586,7 +596,7 @@ static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
while(len > 0) {
if(read_data(data, sockindex, &conn->in_buffer))
return -1;
- if(conn->in_buffer.size == 0) {
+ if(Curl_dyn_len(&conn->in_buffer.buf) == 0) {
if(bytes_read > 0)
conn->in_buffer.eof_flag = 1;
return bytes_read;
@@ -835,6 +845,7 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
mech->name);
return CURLE_FAILED_INIT;
}
+ Curl_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH);
}
infof(data, "Trying mechanism %s...", mech->name);
@@ -899,15 +910,10 @@ Curl_sec_end(struct connectdata *conn)
{
if(conn->mech && conn->mech->end)
conn->mech->end(conn->app_data);
- free(conn->app_data);
- conn->app_data = NULL;
- if(conn->in_buffer.data) {
- free(conn->in_buffer.data);
- conn->in_buffer.data = NULL;
- conn->in_buffer.size = 0;
- conn->in_buffer.index = 0;
- conn->in_buffer.eof_flag = 0;
- }
+ Curl_safefree(conn->app_data);
+ Curl_dyn_free(&conn->in_buffer.buf);
+ conn->in_buffer.index = 0;
+ conn->in_buffer.eof_flag = 0;
conn->sec_complete = 0;
conn->data_prot = PROT_CLEAR;
conn->mech = NULL;
diff --git a/libs/libcurl/src/ldap.c b/libs/libcurl/src/ldap.c
index 4d1cfadb36..af01902594 100644
--- a/libs/libcurl/src/ldap.c
+++ b/libs/libcurl/src/ldap.c
@@ -164,7 +164,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done);
*/
const struct Curl_handler Curl_handler_ldap = {
- "LDAP", /* scheme */
+ "ldap", /* scheme */
ZERO_NULL, /* setup_connection */
ldap_do, /* do_it */
ZERO_NULL, /* done */
@@ -178,6 +178,7 @@ const struct Curl_handler Curl_handler_ldap = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAP, /* defport */
@@ -192,7 +193,7 @@ const struct Curl_handler Curl_handler_ldap = {
*/
const struct Curl_handler Curl_handler_ldaps = {
- "LDAPS", /* scheme */
+ "ldaps", /* scheme */
ZERO_NULL, /* setup_connection */
ldap_do, /* do_it */
ZERO_NULL, /* done */
@@ -206,6 +207,7 @@ const struct Curl_handler Curl_handler_ldaps = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAPS, /* defport */
@@ -483,6 +485,8 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
}
*/
#else
+ (void)ldap_option;
+ (void)ldap_ca;
/* we should probably never come up to here since configure
should check in first place if we can support LDAP SSL/TLS */
failf(data, "LDAP local: SSL/TLS not supported with this version "
@@ -544,7 +548,8 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
- for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg);
+ num = 0;
+ for(entryIterator = ldap_first_entry(server, ldapmsg);
entryIterator;
entryIterator = ldap_next_entry(server, entryIterator), num++) {
BerElement *ber = NULL;
diff --git a/libs/libcurl/src/libcurl.plist b/libs/libcurl/src/libcurl.plist
deleted file mode 100644
index 13b1785006..0000000000
--- a/libs/libcurl/src/libcurl.plist
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
-<plist version="0.9">
-<dict>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
-
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
-
- <key>CFBundleExecutable</key>
- <string>curl</string>
-
- <key>CFBundleIdentifier</key>
- <string>se.curl.libcurl</string>
-
- <key>CFBundleVersion</key>
- <string>8.7.1</string>
-
- <key>CFBundleName</key>
- <string>libcurl</string>
-
- <key>CFBundlePackageType</key>
- <string>FMWK</string>
-
- <key>CFBundleSignature</key>
- <string>????</string>
-
- <key>CFBundleShortVersionString</key>
- <string>libcurl 8.7.1</string>
-
- <key>CFBundleGetInfoString</key>
- <string>libcurl.plist 8.7.1</string>
-</dict>
-</plist>
diff --git a/libs/libcurl/src/libcurl.plist.in b/libs/libcurl/src/libcurl.plist.in
deleted file mode 100644
index 37711f9e5b..0000000000
--- a/libs/libcurl/src/libcurl.plist.in
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
-<plist version="0.9">
-<dict>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
-
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
-
- <key>CFBundleExecutable</key>
- <string>curl</string>
-
- <key>CFBundleIdentifier</key>
- <string>se.curl.libcurl</string>
-
- <key>CFBundleVersion</key>
- <string>@CURL_PLIST_VERSION@</string>
-
- <key>CFBundleName</key>
- <string>libcurl</string>
-
- <key>CFBundlePackageType</key>
- <string>FMWK</string>
-
- <key>CFBundleSignature</key>
- <string>????</string>
-
- <key>CFBundleShortVersionString</key>
- <string>libcurl @CURL_PLIST_VERSION@</string>
-
- <key>CFBundleGetInfoString</key>
- <string>libcurl.plist @CURL_PLIST_VERSION@</string>
-</dict>
-</plist>
diff --git a/libs/libcurl/src/llist.c b/libs/libcurl/src/llist.c
index 83a760acfc..39a20f2b8c 100644
--- a/libs/libcurl/src/llist.c
+++ b/libs/libcurl/src/llist.c
@@ -89,6 +89,22 @@ Curl_llist_insert_next(struct Curl_llist *list, struct Curl_llist_element *e,
}
/*
+ * Curl_llist_append()
+ *
+ * Adds a new list element to the end of the list.
+ *
+ * The 'ne' argument should be a pointer into the object to store.
+ *
+ * @unittest: 1300
+ */
+void
+Curl_llist_append(struct Curl_llist *list, const void *p,
+ struct Curl_llist_element *ne)
+{
+ Curl_llist_insert_next(list, list->tail, p, ne);
+}
+
+/*
* @unittest: 1300
*/
void
diff --git a/libs/libcurl/src/llist.h b/libs/libcurl/src/llist.h
index 506756a98b..bff60fe138 100644
--- a/libs/libcurl/src/llist.h
+++ b/libs/libcurl/src/llist.h
@@ -45,6 +45,8 @@ struct Curl_llist {
void Curl_llist_init(struct Curl_llist *, Curl_llist_dtor);
void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_element *,
const void *, struct Curl_llist_element *node);
+void Curl_llist_append(struct Curl_llist *,
+ const void *, struct Curl_llist_element *node);
void Curl_llist_remove(struct Curl_llist *, struct Curl_llist_element *,
void *);
size_t Curl_llist_count(struct Curl_llist *);
diff --git a/libs/libcurl/src/md4.c b/libs/libcurl/src/md4.c
index e13577088c..73ad24e33b 100644
--- a/libs/libcurl/src/md4.c
+++ b/libs/libcurl/src/md4.c
@@ -55,7 +55,8 @@
#else
#include <mbedtls/config.h>
#endif
-#if(MBEDTLS_VERSION_NUMBER >= 0x02070000)
+#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \
+ (MBEDTLS_VERSION_NUMBER < 0x03000000)
#define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
#endif
#endif /* USE_MBEDTLS */
diff --git a/libs/libcurl/src/mime.c b/libs/libcurl/src/mime.c
index 94930eba73..c52fee5207 100644
--- a/libs/libcurl/src/mime.c
+++ b/libs/libcurl/src/mime.c
@@ -1413,36 +1413,35 @@ CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
char *base;
struct_stat sbuf;
- if(stat(filename, &sbuf) || access(filename, R_OK))
+ if(stat(filename, &sbuf))
result = CURLE_READ_ERROR;
-
- part->data = strdup(filename);
- if(!part->data)
- result = CURLE_OUT_OF_MEMORY;
-
- part->datasize = -1;
- if(!result && S_ISREG(sbuf.st_mode)) {
- part->datasize = filesize(filename, sbuf);
- part->seekfunc = mime_file_seek;
- }
-
- part->readfunc = mime_file_read;
- part->freefunc = mime_file_free;
- part->kind = MIMEKIND_FILE;
-
- /* As a side effect, set the filename to the current file's base name.
- It is possible to withdraw this by explicitly calling
- curl_mime_filename() with a NULL filename argument after the current
- call. */
- base = strippath(filename);
- if(!base)
- result = CURLE_OUT_OF_MEMORY;
else {
- CURLcode res = curl_mime_filename(part, base);
+ part->data = strdup(filename);
+ if(!part->data)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ part->datasize = -1;
+ if(S_ISREG(sbuf.st_mode)) {
+ part->datasize = filesize(filename, sbuf);
+ part->seekfunc = mime_file_seek;
+ }
- if(res)
- result = res;
- free(base);
+ part->readfunc = mime_file_read;
+ part->freefunc = mime_file_free;
+ part->kind = MIMEKIND_FILE;
+
+ /* As a side effect, set the filename to the current file's base name.
+ It is possible to withdraw this by explicitly calling
+ curl_mime_filename() with a NULL filename argument after the current
+ call. */
+ base = strippath(filename);
+ if(!base)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ result = curl_mime_filename(part, base);
+ free(base);
+ }
+ }
}
}
return result;
@@ -1971,7 +1970,7 @@ static CURLcode cr_mime_read(struct Curl_easy *data,
switch(nread) {
case 0:
if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
- failf(data, "client mime read EOF fail, only "
+ failf(data, "client mime read EOF fail, "
"only %"CURL_FORMAT_CURL_OFF_T"/%"CURL_FORMAT_CURL_OFF_T
" of needed bytes read", ctx->read_len, ctx->total_len);
return CURLE_READ_ERROR;
diff --git a/libs/libcurl/src/mprintf.c b/libs/libcurl/src/mprintf.c
index 9b9e6ed56a..21d62fa654 100644
--- a/libs/libcurl/src/mprintf.c
+++ b/libs/libcurl/src/mprintf.c
@@ -77,7 +77,7 @@ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
#define OUTCHAR(x) \
do { \
- if(!stream(x, userp)) \
+ if(!stream((unsigned char)x, userp)) \
done++; \
else \
return done; /* return on failure */ \
@@ -243,7 +243,7 @@ static int parsefmt(const char *format,
struct va_input *iptr;
bool loopit = TRUE;
fmt++;
- outlen = fmt - start - 1;
+ outlen = (size_t)(fmt - start - 1);
if(*fmt == '%') {
/* this means a %% that should be output only as %. Create an output
segment. */
@@ -261,7 +261,8 @@ static int parsefmt(const char *format,
continue; /* while */
}
- flags = width = precision = 0;
+ flags = 0;
+ width = precision = 0;
if(use_dollar != DOLLAR_NOPE) {
param = dollarstring(fmt, &fmt);
@@ -291,7 +292,7 @@ static int parsefmt(const char *format,
break;
case '-':
flags |= FLAGS_LEFT;
- flags &= ~FLAGS_PAD_NIL;
+ flags &= ~(unsigned int)FLAGS_PAD_NIL;
break;
case '#':
flags |= FLAGS_ALT;
@@ -549,7 +550,7 @@ static int parsefmt(const char *format,
optr = &out[ocount++];
if(ocount > MAX_SEGMENTS)
return PFMT_MANYSEGS;
- optr->input = param;
+ optr->input = (unsigned int)param;
optr->flags = flags;
optr->width = width;
optr->precision = precision;
@@ -562,7 +563,7 @@ static int parsefmt(const char *format,
}
/* is there a trailing piece */
- outlen = fmt - start;
+ outlen = (size_t)(fmt - start);
if(outlen) {
optr = &out[ocount++];
if(ocount > MAX_SEGMENTS)
@@ -688,7 +689,7 @@ static int formatf(
mp_intmax_t signed_num; /* Used to convert negative in positive. */
char *w;
size_t outlen = optr->outlen;
- int flags = optr->flags;
+ unsigned int flags = optr->flags;
if(outlen) {
char *str = optr->start;
@@ -710,7 +711,7 @@ static int formatf(
else
width = -width;
flags |= FLAGS_LEFT;
- flags &= ~FLAGS_PAD_NIL;
+ flags &= ~(unsigned int)FLAGS_PAD_NIL;
}
}
else
@@ -867,7 +868,7 @@ number:
str = nilstr;
len = sizeof(nilstr) - 1;
/* Disable quotes around (nil) */
- flags &= (~FLAGS_ALT);
+ flags &= ~(unsigned int)FLAGS_ALT;
}
else {
str = "";
@@ -886,13 +887,13 @@ number:
if(flags & FLAGS_ALT)
OUTCHAR('"');
- if(!(flags&FLAGS_LEFT))
+ if(!(flags & FLAGS_LEFT))
while(width-- > 0)
OUTCHAR(' ');
for(; len && *str; len--)
OUTCHAR(*str++);
- if(flags&FLAGS_LEFT)
+ if(flags & FLAGS_LEFT)
while(width-- > 0)
OUTCHAR(' ');
@@ -952,12 +953,13 @@ number:
*fptr = 0;
if(width >= 0) {
+ size_t dlen;
if(width >= (int)sizeof(work))
width = sizeof(work)-1;
/* RECURSIVE USAGE */
- len = curl_msnprintf(fptr, left, "%d", width);
- fptr += len;
- left -= len;
+ dlen = (size_t)curl_msnprintf(fptr, left, "%d", width);
+ fptr += dlen;
+ left -= dlen;
}
if(prec >= 0) {
/* for each digit in the integer part, we can have one less
@@ -965,7 +967,7 @@ number:
size_t maxprec = sizeof(work) - 2;
double val = iptr->val.dnum;
if(width > 0 && prec <= width)
- maxprec -= width;
+ maxprec -= (size_t)width;
while(val >= 10.0) {
val /= 10;
maxprec--;
@@ -1039,7 +1041,7 @@ static int addbyter(unsigned char outc, void *f)
struct nsprintf *infop = f;
if(infop->length < infop->max) {
/* only do this if we haven't reached max length yet */
- *infop->buffer++ = outc; /* store */
+ *infop->buffer++ = (char)outc; /* store */
infop->length++; /* we are now one byte larger */
return 0; /* fputc() returns like this on success */
}
@@ -1139,7 +1141,7 @@ char *curl_maprintf(const char *format, ...)
static int storebuffer(unsigned char outc, void *f)
{
char **buffer = f;
- **buffer = outc;
+ **buffer = (char)outc;
(*buffer)++;
return 0;
}
@@ -1160,9 +1162,7 @@ static int fputc_wrapper(unsigned char outc, void *f)
int out = outc;
FILE *s = f;
int rc = fputc(out, s);
- if(rc == out)
- return 0;
- return 1;
+ return rc == EOF;
}
int curl_mprintf(const char *format, ...)
diff --git a/libs/libcurl/src/mqtt.c b/libs/libcurl/src/mqtt.c
index 86817bf9bd..9cd56781a5 100644
--- a/libs/libcurl/src/mqtt.c
+++ b/libs/libcurl/src/mqtt.c
@@ -75,7 +75,7 @@ static CURLcode mqtt_setup_conn(struct Curl_easy *data,
*/
const struct Curl_handler Curl_handler_mqtt = {
- "MQTT", /* scheme */
+ "mqtt", /* scheme */
mqtt_setup_conn, /* setup_connection */
mqtt_do, /* do_it */
mqtt_done, /* done */
@@ -89,6 +89,7 @@ const struct Curl_handler Curl_handler_mqtt = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_MQTT, /* defport */
@@ -776,12 +777,12 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
case MQTT_REMAINING_LENGTH:
do {
result = Curl_xfer_recv(data, (char *)&byte, 1, &nread);
- if(!nread)
+ if(result || !nread)
break;
Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
mq->pkt_hd[mq->npacket++] = byte;
} while((byte & 0x80) && (mq->npacket < 4));
- if(nread && (byte & 0x80))
+ if(!result && nread && (byte & 0x80))
/* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
127 * 128^3 bytes. server tried to send more */
result = CURLE_WEIRD_SERVER_REPLY;
diff --git a/libs/libcurl/src/multi.c b/libs/libcurl/src/multi.c
index 78980ba626..c388a3d8d8 100644
--- a/libs/libcurl/src/multi.c
+++ b/libs/libcurl/src/multi.c
@@ -86,6 +86,8 @@
((x) && (x)->magic == CURL_MULTI_HANDLE)
#endif
+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,
@@ -100,6 +102,7 @@ static void multi_xfer_bufs_free(struct Curl_multi *multi);
static const char * const multi_statename[]={
"INIT",
"PENDING",
+ "SETUP",
"CONNECT",
"RESOLVING",
"CONNECTING",
@@ -149,6 +152,7 @@ static void mstate(struct Curl_easy *data, CURLMstate state
static const init_multistate_func finit[MSTATE_LAST] = {
NULL, /* INIT */
NULL, /* PENDING */
+ NULL, /* SETUP */
Curl_init_CONNECT, /* CONNECT */
NULL, /* RESOLVING */
NULL, /* CONNECTING */
@@ -360,7 +364,7 @@ static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
* per call."
*
*/
-static void sh_init(struct Curl_hash *hash, int hashsize)
+static void sh_init(struct Curl_hash *hash, size_t hashsize)
{
Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
sh_freeentry);
@@ -374,13 +378,12 @@ static void sh_init(struct Curl_hash *hash, int hashsize)
*/
static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg)
{
- Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg,
- &msg->list);
+ Curl_llist_append(&multi->msglist, msg, &msg->list);
}
-struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
- int chashsize, /* connection hash */
- int dnssize) /* dns hash */
+struct Curl_multi *Curl_multi_handle(size_t hashsize, /* socket hash */
+ size_t chashsize, /* connection hash */
+ size_t dnssize) /* dns hash */
{
struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
@@ -549,6 +552,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
if(data->set.errorbuffer)
data->set.errorbuffer[0] = 0;
+ data->state.os_errno = 0;
+
/* make the Curl_easy refer back to this multi handle - before Curl_expire()
is called. */
data->multi = multi;
@@ -1002,8 +1007,7 @@ void Curl_attach_connection(struct Curl_easy *data,
DEBUGASSERT(!data->conn);
DEBUGASSERT(conn);
data->conn = conn;
- Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
- &data->conn_queue);
+ Curl_llist_append(&conn->easyq, data, &data->conn_queue);
if(conn->handler && conn->handler->attach)
conn->handler->attach(data, conn);
Curl_conn_ev_data_attach(conn, data);
@@ -1112,6 +1116,7 @@ static void multi_getsock(struct Curl_easy *data,
switch(data->mstate) {
case MSTATE_INIT:
case MSTATE_PENDING:
+ case MSTATE_SETUP:
case MSTATE_CONNECT:
/* nothing to poll for yet */
break;
@@ -1208,6 +1213,68 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
return CURLM_OK;
}
+CURLMcode curl_multi_waitfds(struct Curl_multi *multi,
+ struct curl_waitfd *ufds,
+ unsigned int size,
+ unsigned int *fd_count)
+{
+ struct Curl_easy *data;
+ unsigned int nfds = 0;
+ struct easy_pollset ps;
+ unsigned int i;
+ CURLMcode result = CURLM_OK;
+ struct curl_waitfd *ufd;
+ unsigned int j;
+
+ if(!ufds)
+ return CURLM_BAD_FUNCTION_ARGUMENT;
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ if(multi->in_callback)
+ return CURLM_RECURSIVE_API_CALL;
+
+ memset(&ps, 0, sizeof(ps));
+ for(data = multi->easyp; data; data = data->next) {
+ multi_getsock(data, &ps);
+
+ for(i = 0; i < ps.num; i++) {
+ if(nfds < size) {
+ curl_socket_t fd = ps.sockets[i];
+ int fd_idx = -1;
+
+ /* Simple linear search to skip an already added descriptor */
+ for(j = 0; j < nfds; j++) {
+ if(ufds[j].fd == fd) {
+ fd_idx = (int)j;
+ break;
+ }
+ }
+
+ if(fd_idx < 0) {
+ ufd = &ufds[nfds++];
+ ufd->fd = ps.sockets[i];
+ ufd->events = 0;
+ }
+ else
+ ufd = &ufds[fd_idx];
+
+ if(ps.actions[i] & CURL_POLL_IN)
+ ufd->events |= CURL_WAIT_POLLIN;
+ if(ps.actions[i] & CURL_POLL_OUT)
+ ufd->events |= CURL_WAIT_POLLOUT;
+ }
+ else
+ return CURLM_OUT_OF_MEMORY;
+ }
+ }
+
+ if(fd_count)
+ *fd_count = nfds;
+ return result;
+}
+
#ifdef USE_WINSOCK
/* Reset FD_WRITE for TCP sockets. Nothing is actually sent. UDP sockets can't
* be reset this way because an empty datagram would be sent. #9203
@@ -1224,6 +1291,29 @@ static void reset_socket_fdwrite(curl_socket_t s)
}
#endif
+static CURLMcode ufds_increase(struct pollfd **pfds, unsigned int *pfds_len,
+ unsigned int inc, bool *is_malloced)
+{
+ struct pollfd *new_fds, *old_fds = *pfds;
+ unsigned int new_len = *pfds_len + inc;
+
+ new_fds = calloc(new_len, sizeof(struct pollfd));
+ if(!new_fds) {
+ if(*is_malloced)
+ free(old_fds);
+ *pfds = NULL;
+ *pfds_len = 0;
+ return CURLM_OUT_OF_MEMORY;
+ }
+ memcpy(new_fds, old_fds, (*pfds_len) * sizeof(struct pollfd));
+ if(*is_malloced)
+ free(old_fds);
+ *pfds = new_fds;
+ *pfds_len = new_len;
+ *is_malloced = TRUE;
+ return CURLM_OK;
+}
+
#define NUM_POLLS_ON_STACK 10
static CURLMcode multi_wait(struct Curl_multi *multi,
@@ -1237,12 +1327,12 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
struct Curl_easy *data;
struct easy_pollset ps;
size_t i;
- unsigned int nfds = 0;
- unsigned int curlfds;
long timeout_internal;
int retcode = 0;
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
struct pollfd *ufds = &a_few_on_stack[0];
+ unsigned int ufds_len = NUM_POLLS_ON_STACK;
+ unsigned int nfds = 0, curl_nfds = 0; /* how many ufds are in use */
bool ufds_malloc = FALSE;
#ifdef USE_WINSOCK
WSANETWORKEVENTS wsa_events;
@@ -1261,13 +1351,6 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
if(timeout_ms < 0)
return CURLM_BAD_FUNCTION_ARGUMENT;
- /* Count up how many fds we have from the multi handle */
- memset(&ps, 0, sizeof(ps));
- for(data = multi->easyp; data; data = data->next) {
- multi_getsock(data, &ps);
- nfds += ps.num;
- }
-
/* If the internally desired timeout is actually shorter than requested from
the outside, then use the shorter time! But only if the internal timer
is actually larger than -1! */
@@ -1275,70 +1358,60 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
timeout_ms = (int)timeout_internal;
- curlfds = nfds; /* number of internal file descriptors */
- nfds += extra_nfds; /* add the externally provided ones */
-
-#ifdef ENABLE_WAKEUP
-#ifdef USE_WINSOCK
- if(use_wakeup) {
-#else
- if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
-#endif
- ++nfds;
- }
-#endif
-
- if(nfds > NUM_POLLS_ON_STACK) {
- /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
- big, so at 2^29 sockets this value might wrap. When a process gets
- the capability to actually handle over 500 million sockets this
- calculation needs a integer overflow check. */
- ufds = malloc(nfds * sizeof(struct pollfd));
- if(!ufds)
- return CURLM_OUT_OF_MEMORY;
- ufds_malloc = TRUE;
- }
- nfds = 0;
-
- /* only do the second loop if we found descriptors in the first stage run
- above */
+ memset(ufds, 0, ufds_len * sizeof(struct pollfd));
+ memset(&ps, 0, sizeof(ps));
- if(curlfds) {
- /* Add the curl handles to our pollfds first */
- for(data = multi->easyp; data; data = data->next) {
- multi_getsock(data, &ps);
+ /* Add the curl handles to our pollfds first */
+ for(data = multi->easyp; data; data = data->next) {
+ multi_getsock(data, &ps);
- for(i = 0; i < ps.num; i++) {
- struct pollfd *ufd = &ufds[nfds++];
+ for(i = 0; i < ps.num; i++) {
+ short events = 0;
#ifdef USE_WINSOCK
- long mask = 0;
+ long mask = 0;
#endif
- ufd->fd = ps.sockets[i];
- ufd->events = 0;
- if(ps.actions[i] & CURL_POLL_IN) {
+ if(ps.actions[i] & CURL_POLL_IN) {
#ifdef USE_WINSOCK
- mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
+ mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
#endif
- ufd->events |= POLLIN;
- }
- if(ps.actions[i] & CURL_POLL_OUT) {
+ events |= POLLIN;
+ }
+ if(ps.actions[i] & CURL_POLL_OUT) {
#ifdef USE_WINSOCK
- mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
- reset_socket_fdwrite(ps.sockets[i]);
+ mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
+ reset_socket_fdwrite(ps.sockets[i]);
#endif
- ufd->events |= POLLOUT;
+ events |= POLLOUT;
+ }
+ if(events) {
+ if(nfds && ps.sockets[i] == ufds[nfds-1].fd) {
+ ufds[nfds-1].events |= events;
}
+ else {
+ if(nfds >= ufds_len) {
+ if(ufds_increase(&ufds, &ufds_len, 100, &ufds_malloc))
+ return CURLM_OUT_OF_MEMORY;
+ }
+ DEBUGASSERT(nfds < ufds_len);
+ ufds[nfds].fd = ps.sockets[i];
+ ufds[nfds].events = events;
+ ++nfds;
+ }
+ }
#ifdef USE_WINSOCK
+ if(mask) {
if(WSAEventSelect(ps.sockets[i], multi->wsa_event, mask) != 0) {
if(ufds_malloc)
free(ufds);
return CURLM_INTERNAL_ERROR;
}
-#endif
}
+#endif
}
}
+ curl_nfds = nfds; /* what curl internally used in ufds */
+
/* Add external file descriptions from poll-like struct curl_waitfd */
for(i = 0; i < extra_nfds; i++) {
#ifdef USE_WINSOCK
@@ -1357,6 +1430,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
return CURLM_INTERNAL_ERROR;
}
#endif
+ if(nfds >= ufds_len) {
+ if(ufds_increase(&ufds, &ufds_len, 100, &ufds_malloc))
+ return CURLM_OUT_OF_MEMORY;
+ }
+ DEBUGASSERT(nfds < ufds_len);
ufds[nfds].fd = extra_fds[i].fd;
ufds[nfds].events = 0;
if(extra_fds[i].events & CURL_WAIT_POLLIN)
@@ -1371,6 +1449,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
#ifdef ENABLE_WAKEUP
#ifndef USE_WINSOCK
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
+ if(nfds >= ufds_len) {
+ if(ufds_increase(&ufds, &ufds_len, 100, &ufds_malloc))
+ return CURLM_OUT_OF_MEMORY;
+ }
+ DEBUGASSERT(nfds < ufds_len);
ufds[nfds].fd = multi->wakeup_pair[0];
ufds[nfds].events = POLLIN;
++nfds;
@@ -1410,7 +1493,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
struct, the bit values of the actual underlying poll() implementation
may not be the same as the ones in the public libcurl API! */
for(i = 0; i < extra_nfds; i++) {
- unsigned r = ufds[curlfds + i].revents;
+ unsigned r = ufds[curl_nfds + i].revents;
unsigned short mask = 0;
#ifdef USE_WINSOCK
curl_socket_t s = extra_fds[i].fd;
@@ -1443,7 +1526,7 @@ 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. */
- if(curlfds) {
+ if(curl_nfds) {
for(data = multi->easyp; data; data = data->next) {
multi_getsock(data, &ps);
@@ -1464,7 +1547,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
#else
#ifdef ENABLE_WAKEUP
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
- if(ufds[curlfds + extra_nfds].revents & POLLIN) {
+ if(ufds[curl_nfds + extra_nfds].revents & POLLIN) {
char buf[64];
ssize_t nread;
while(1) {
@@ -1684,47 +1767,47 @@ static bool multi_handle_timeout(struct Curl_easy *data,
CURLcode *result,
bool connect_timeout)
{
- timediff_t timeout_ms;
- timeout_ms = Curl_timeleft(data, now, connect_timeout);
-
+ timediff_t timeout_ms = Curl_timeleft(data, now, connect_timeout);
if(timeout_ms < 0) {
/* Handle timed out */
+ struct curltime since;
+ if(connect_timeout)
+ since = data->progress.t_startsingle;
+ else
+ since = data->progress.t_startop;
if(data->mstate == MSTATE_RESOLVING)
failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds",
- Curl_timediff(*now, data->progress.t_startsingle));
+ " milliseconds", Curl_timediff(*now, since));
else if(data->mstate == MSTATE_CONNECTING)
failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds",
- Curl_timediff(*now, data->progress.t_startsingle));
+ " milliseconds", Curl_timediff(*now, since));
else {
struct SingleRequest *k = &data->req;
if(k->size != -1) {
failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
CURL_FORMAT_CURL_OFF_T " bytes received",
- Curl_timediff(*now, data->progress.t_startsingle),
- k->bytecount, k->size);
+ Curl_timediff(*now, since), k->bytecount, k->size);
}
else {
failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds with %" CURL_FORMAT_CURL_OFF_T
- " bytes received",
- Curl_timediff(*now, data->progress.t_startsingle),
- k->bytecount);
+ " bytes received", Curl_timediff(*now, since), k->bytecount);
}
}
-
- /* Force connection closed if the connection has indeed been used */
- if(data->mstate > MSTATE_DO) {
- streamclose(data->conn, "Disconnected with pending data");
- *stream_error = TRUE;
- }
*result = CURLE_OPERATION_TIMEDOUT;
- (void)multi_done(data, *result, TRUE);
+ if(data->conn) {
+ /* Force connection closed if the connection has indeed been used */
+ if(data->mstate > MSTATE_DO) {
+ streamclose(data->conn, "Disconnect due to timeout");
+ *stream_error = TRUE;
+ }
+ (void)multi_done(data, *result, TRUE);
+ }
+ return TRUE;
}
- return (timeout_ms < 0);
+ return FALSE;
}
/*
@@ -1816,19 +1899,6 @@ static CURLcode protocol_connect(struct Curl_easy *data,
return result; /* pass back status */
}
-/*
- * Curl_preconnect() is called immediately before a connect starts. When a
- * redirect is followed, this is then called multiple times during a single
- * transfer.
- */
-CURLcode Curl_preconnect(struct Curl_easy *data)
-{
- /* this used to do data->state.buffer allocation,
- maybe remove completely now? */
- (void)data;
- return CURLE_OK;
-}
-
static void set_in_callback(struct Curl_multi *multi, bool value)
{
multi->in_callback = value;
@@ -1882,51 +1952,44 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
return CURLM_INTERNAL_ERROR;
}
- if(data->conn &&
- (data->mstate >= MSTATE_CONNECT) &&
- (data->mstate < MSTATE_COMPLETED)) {
- /* Check for overall operation timeout here but defer handling the
- * connection timeout to later, to allow for a connection to be set up
- * in the window since we last checked timeout. This prevents us
- * tearing down a completed connection in the case where we were slow
- * to check the timeout (e.g. process descheduled during this loop).
- * We set connect_timeout=FALSE to do this. */
-
- /* we need to wait for the connect state as only then is the start time
- stored, but we must not check already completed handles */
- if(multi_handle_timeout(data, nowp, &stream_error, &result, FALSE)) {
- /* Skip the statemachine and go directly to error handling section. */
- goto statemachine_end;
- }
- }
+ /* Wait for the connect state as only then is the start time stored, but
+ we must not check already completed handles */
+ if((data->mstate >= MSTATE_CONNECT) && (data->mstate < MSTATE_COMPLETED) &&
+ multi_handle_timeout(data, nowp, &stream_error, &result, FALSE))
+ /* Skip the statemachine and go directly to error handling section. */
+ goto statemachine_end;
switch(data->mstate) {
case MSTATE_INIT:
- /* init this transfer. */
+ /* Transitional state. init this transfer. A handle never comes
+ back to this state. */
result = Curl_pretransfer(data);
-
- if(!result) {
- /* after init, go CONNECT */
- multistate(data, MSTATE_CONNECT);
- *nowp = Curl_pgrsTime(data, TIMER_STARTOP);
- rc = CURLM_CALL_MULTI_PERFORM;
- }
- break;
-
- case MSTATE_CONNECT:
- /* Connect. We want to get a connection identifier filled in. */
- /* init this transfer. */
- result = Curl_preconnect(data);
if(result)
break;
+ /* after init, go SETUP */
+ multistate(data, MSTATE_SETUP);
+ (void)Curl_pgrsTime(data, TIMER_STARTOP);
+ FALLTHROUGH();
+
+ case MSTATE_SETUP:
+ /* Transitional state. Setup things for a new transfer. The handle
+ can come back to this state on a redirect. */
*nowp = Curl_pgrsTime(data, TIMER_STARTSINGLE);
if(data->set.timeout)
Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
-
if(data->set.connecttimeout)
+ /* Since a connection might go to pending and back to CONNECT several
+ times before it actually takes off, we need to set the timeout once
+ in SETUP before we enter CONNECT the first time. */
Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
+ multistate(data, MSTATE_CONNECT);
+ FALLTHROUGH();
+
+ case MSTATE_CONNECT:
+ /* Connect. We want to get a connection identifier filled in. This state
+ can be entered from SETUP and from PENDING. */
result = Curl_connect(data, &async, &connected);
if(CURLE_NO_CONNECTION_AVAILABLE == result) {
/* There was no connection available. We will go to the pending
@@ -1934,18 +1997,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multistate(data, MSTATE_PENDING);
/* add this handle to the list of connect-pending handles */
- Curl_llist_insert_next(&multi->pending, multi->pending.tail, data,
- &data->connect_queue);
+ Curl_llist_append(&multi->pending, data, &data->connect_queue);
/* unlink from the main list */
unlink_easy(multi, data);
result = CURLE_OK;
break;
}
- else if(data->state.previouslypending) {
- /* this transfer comes from the pending queue so try move another */
- infof(data, "Transfer was pending, now try another");
+ else
process_pending_handles(data->multi);
- }
if(!result) {
*nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
@@ -2226,7 +2285,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
follow = FOLLOW_RETRY;
drc = Curl_follow(data, newurl, follow);
if(!drc) {
- multistate(data, MSTATE_CONNECT);
+ multistate(data, MSTATE_SETUP);
rc = CURLM_CALL_MULTI_PERFORM;
result = CURLE_OK;
}
@@ -2463,7 +2522,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_posttransfer(data);
multi_done(data, result, TRUE);
}
- else if(data->req.done) {
+ else if(data->req.done && !Curl_cwriter_is_paused(data)) {
/* call this even if the readwrite function returned error */
Curl_posttransfer(data);
@@ -2486,10 +2545,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* multi_done() might return CURLE_GOT_NOTHING */
result = Curl_follow(data, newurl, follow);
if(!result) {
- multistate(data, MSTATE_CONNECT);
+ multistate(data, MSTATE_SETUP);
rc = CURLM_CALL_MULTI_PERFORM;
}
- free(newurl);
}
else {
/* after the transfer is done, go DONE */
@@ -2501,7 +2559,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
newurl = data->req.location;
data->req.location = NULL;
result = Curl_follow(data, newurl, FOLLOW_FAKE);
- free(newurl);
if(result) {
stream_error = TRUE;
result = multi_done(data, result, TRUE);
@@ -2520,6 +2577,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
transfers */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
+ free(newurl);
break;
}
@@ -2570,8 +2628,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
return CURLM_INTERNAL_ERROR;
}
- if(data->conn &&
- data->mstate >= MSTATE_CONNECT &&
+ if(data->mstate >= MSTATE_CONNECT &&
data->mstate < MSTATE_DO &&
rc != CURLM_CALL_MULTI_PERFORM &&
!multi_ischanged(multi, false)) {
@@ -2581,7 +2638,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
* (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
* declaring the connection timed out as we may almost have a completed
* connection. */
- multi_handle_timeout(data, nowp, &stream_error, &result, TRUE);
+ multi_handle_timeout(data, nowp, &stream_error, &result, FALSE);
}
statemachine_end:
@@ -2658,8 +2715,7 @@ statemachine_end:
multistate(data, MSTATE_MSGSENT);
/* add this handle to the list of msgsent handles */
- Curl_llist_insert_next(&multi->msgsent, multi->msgsent.tail, data,
- &data->connect_queue);
+ Curl_llist_append(&multi->msgsent, data, &data->connect_queue);
/* unlink from the main list */
unlink_easy(multi, data);
return CURLM_OK;
@@ -2721,10 +2777,20 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
*/
do {
multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
- if(t)
+ if(t) {
/* the removed may have another timeout in queue */
+ data = t->payload;
+ if(data->mstate == MSTATE_PENDING) {
+ bool stream_unused;
+ CURLcode result_unused;
+ if(multi_handle_timeout(data, &now, &stream_unused, &result_unused,
+ FALSE)) {
+ infof(data, "PENDING handle timeout");
+ move_pending_to_connect(multi, data);
+ }
+ }
(void)add_next_timeout(now, multi, t->payload);
-
+ }
} while(t);
*running_handles = multi->num_alive;
@@ -3678,47 +3744,55 @@ void Curl_multiuse_state(struct Curl_easy *data,
process_pending_handles(data->multi);
}
-/* process_pending_handles() moves all handles from PENDING
- back into the main list and change state to CONNECT */
-static void process_pending_handles(struct Curl_multi *multi)
+static void move_pending_to_connect(struct Curl_multi *multi,
+ struct Curl_easy *data)
{
- struct Curl_llist_element *e = multi->pending.head;
- if(e) {
- struct Curl_easy *data = e->ptr;
+ DEBUGASSERT(data->mstate == MSTATE_PENDING);
+
+ /* put it back into the main list */
+ link_easy(multi, data);
- DEBUGASSERT(data->mstate == MSTATE_PENDING);
+ multistate(data, MSTATE_CONNECT);
- /* put it back into the main list */
- link_easy(multi, data);
+ /* Remove this node from the pending list */
+ Curl_llist_remove(&multi->pending, &data->connect_queue, NULL);
- multistate(data, MSTATE_CONNECT);
+ /* Make sure that the handle will be processed soonish. */
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+}
- /* Remove this node from the list */
- Curl_llist_remove(&multi->pending, e, NULL);
+/* process_pending_handles() moves a handle from PENDING back into the main
+ list and change state to CONNECT.
- /* Make sure that the handle will be processed soonish. */
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ We do not move all transfers because that can be a significant amount.
+ Since this is tried every now and then doing too many too often becomes a
+ performance problem.
- /* mark this as having been in the pending queue */
- data->state.previouslypending = TRUE;
+ When there is a change for connection limits like max host connections etc,
+ this likely only allows one new transfer. When there is a pipewait change,
+ it can potentially allow hundreds of new transfers.
+
+ We could consider an improvement where we store the queue reason and allow
+ more pipewait rechecks than others.
+*/
+static void process_pending_handles(struct Curl_multi *multi)
+{
+ struct Curl_llist_element *e = multi->pending.head;
+ if(e) {
+ struct Curl_easy *data = e->ptr;
+ move_pending_to_connect(multi, data);
}
}
void Curl_set_in_callback(struct Curl_easy *data, bool value)
{
- /* might get called when there is no data pointer! */
- if(data) {
- if(data->multi_easy)
- data->multi_easy->in_callback = value;
- else if(data->multi)
- data->multi->in_callback = value;
- }
+ if(data && data->multi)
+ data->multi->in_callback = value;
}
-bool Curl_is_in_callback(struct Curl_easy *easy)
+bool Curl_is_in_callback(struct Curl_easy *data)
{
- return ((easy->multi && easy->multi->in_callback) ||
- (easy->multi_easy && easy->multi_easy->in_callback));
+ return (data && data->multi && data->multi->in_callback);
}
unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi)
diff --git a/libs/libcurl/src/multihandle.h b/libs/libcurl/src/multihandle.h
index 6a7a3c62db..44b275858b 100644
--- a/libs/libcurl/src/multihandle.h
+++ b/libs/libcurl/src/multihandle.h
@@ -44,24 +44,25 @@ struct Curl_message {
typedef enum {
MSTATE_INIT, /* 0 - start in this state */
MSTATE_PENDING, /* 1 - no connections, waiting for one */
- MSTATE_CONNECT, /* 2 - resolve/connect has been sent off */
- MSTATE_RESOLVING, /* 3 - awaiting the resolve to finalize */
- MSTATE_CONNECTING, /* 4 - awaiting the TCP connect to finalize */
- MSTATE_TUNNELING, /* 5 - awaiting HTTPS proxy SSL initialization to
+ MSTATE_SETUP, /* 2 - start a new transfer */
+ MSTATE_CONNECT, /* 3 - resolve/connect has been sent off */
+ MSTATE_RESOLVING, /* 4 - awaiting the resolve to finalize */
+ MSTATE_CONNECTING, /* 5 - awaiting the TCP connect to finalize */
+ MSTATE_TUNNELING, /* 6 - awaiting HTTPS proxy SSL initialization to
complete and/or proxy CONNECT to finalize */
- MSTATE_PROTOCONNECT, /* 6 - initiate protocol connect procedure */
- MSTATE_PROTOCONNECTING, /* 7 - completing the protocol-specific connect
+ MSTATE_PROTOCONNECT, /* 7 - initiate protocol connect procedure */
+ MSTATE_PROTOCONNECTING, /* 8 - completing the protocol-specific connect
phase */
- MSTATE_DO, /* 8 - start send off the request (part 1) */
- MSTATE_DOING, /* 9 - sending off the request (part 1) */
- MSTATE_DOING_MORE, /* 10 - send off the request (part 2) */
- MSTATE_DID, /* 11 - done sending off request */
- MSTATE_PERFORMING, /* 12 - transfer data */
- MSTATE_RATELIMITING, /* 13 - wait because limit-rate exceeded */
- MSTATE_DONE, /* 14 - post data transfer operation */
- MSTATE_COMPLETED, /* 15 - operation complete */
- MSTATE_MSGSENT, /* 16 - the operation complete message is sent */
- MSTATE_LAST /* 17 - not a true state, never use this */
+ MSTATE_DO, /* 9 - start send off the request (part 1) */
+ MSTATE_DOING, /* 10 - sending off the request (part 1) */
+ MSTATE_DOING_MORE, /* 11 - send off the request (part 2) */
+ MSTATE_DID, /* 12 - done sending off request */
+ MSTATE_PERFORMING, /* 13 - transfer data */
+ MSTATE_RATELIMITING, /* 14 - wait because limit-rate exceeded */
+ MSTATE_DONE, /* 15 - post data transfer operation */
+ MSTATE_COMPLETED, /* 16 - operation complete */
+ MSTATE_MSGSENT, /* 17 - the operation complete message is sent */
+ MSTATE_LAST /* 18 - not a true state, never use this */
} CURLMstate;
/* we support N sockets per easy handle. Set the corresponding bit to what
@@ -158,7 +159,7 @@ struct Curl_multi {
WSAEVENT wsa_event; /* winsock event used for waits */
#else
#ifdef ENABLE_WAKEUP
- curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup
+ curl_socket_t wakeup_pair[2]; /* pipe()/socketpair() used for wakeup
0 is used for read, 1 is used for write */
#endif
#endif
@@ -179,7 +180,7 @@ struct Curl_multi {
BIT(dead); /* a callback returned error, everything needs to crash and
burn */
BIT(xfer_buf_borrowed); /* xfer_buf is currently being borrowed */
- BIT(xfer_ulbuf_borrowed); /* xfer_buf is currently being borrowed */
+ BIT(xfer_ulbuf_borrowed); /* xfer_ulbuf is currently being borrowed */
#ifdef DEBUGBUILD
BIT(warned); /* true after user warned of DEBUGBUILD */
#endif
diff --git a/libs/libcurl/src/multiif.h b/libs/libcurl/src/multiif.h
index bedec92d1d..ee2b599df2 100644
--- a/libs/libcurl/src/multiif.h
+++ b/libs/libcurl/src/multiif.h
@@ -38,15 +38,16 @@ void Curl_attach_connection(struct Curl_easy *data,
void Curl_detach_connection(struct Curl_easy *data);
bool Curl_multiplex_wanted(const struct Curl_multi *multi);
void Curl_set_in_callback(struct Curl_easy *data, bool value);
-bool Curl_is_in_callback(struct Curl_easy *easy);
+bool Curl_is_in_callback(struct Curl_easy *data);
CURLcode Curl_preconnect(struct Curl_easy *data);
void Curl_multi_connchanged(struct Curl_multi *multi);
/* Internal version of curl_multi_init() accepts size parameters for the
socket, connection and dns hashes */
-struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize,
- int dnssize);
+struct Curl_multi *Curl_multi_handle(size_t hashsize,
+ size_t chashsize,
+ size_t dnssize);
/* the write bits start at bit 16 for the *getsock() bitmap */
#define GETSOCK_WRITEBITSTART 16
diff --git a/libs/libcurl/src/noproxy.c b/libs/libcurl/src/noproxy.c
index db372732f5..dae21245aa 100644
--- a/libs/libcurl/src/noproxy.c
+++ b/libs/libcurl/src/noproxy.c
@@ -78,7 +78,7 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
const char *network,
unsigned int bits)
{
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
int bytes;
int rest;
unsigned char address[16];
diff --git a/libs/libcurl/src/openldap.c b/libs/libcurl/src/openldap.c
index 2a21094b7d..5263d17aec 100644
--- a/libs/libcurl/src/openldap.c
+++ b/libs/libcurl/src/openldap.c
@@ -117,7 +117,7 @@ static Curl_recv oldap_recv;
*/
const struct Curl_handler Curl_handler_ldap = {
- "LDAP", /* scheme */
+ "ldap", /* scheme */
oldap_setup_connection, /* setup_connection */
oldap_do, /* do_it */
oldap_done, /* done */
@@ -131,6 +131,7 @@ const struct Curl_handler Curl_handler_ldap = {
ZERO_NULL, /* perform_getsock */
oldap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAP, /* defport */
@@ -145,7 +146,7 @@ const struct Curl_handler Curl_handler_ldap = {
*/
const struct Curl_handler Curl_handler_ldaps = {
- "LDAPS", /* scheme */
+ "ldaps", /* scheme */
oldap_setup_connection, /* setup_connection */
oldap_do, /* do_it */
oldap_done, /* done */
@@ -159,6 +160,7 @@ const struct Curl_handler Curl_handler_ldaps = {
ZERO_NULL, /* perform_getsock */
oldap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAPS, /* defport */
@@ -548,9 +550,12 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
return result;
}
- hosturl = aprintf("ldap%s://%s:%d",
- conn->handler->flags & PROTOPT_SSL? "s": "",
- conn->host.name, conn->remote_port);
+ hosturl = aprintf("%s://%s%s%s:%d",
+ conn->handler->scheme,
+ conn->bits.ipv6_ip? "[": "",
+ conn->host.name,
+ conn->bits.ipv6_ip? "]": "",
+ conn->remote_port);
if(!hosturl)
return CURLE_OUT_OF_MEMORY;
diff --git a/libs/libcurl/src/pop3.c b/libs/libcurl/src/pop3.c
index 8281b6bcc0..2f113fb246 100644
--- a/libs/libcurl/src/pop3.c
+++ b/libs/libcurl/src/pop3.c
@@ -112,7 +112,7 @@ static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out);
*/
const struct Curl_handler Curl_handler_pop3 = {
- "POP3", /* scheme */
+ "pop3", /* scheme */
pop3_setup_connection, /* setup_connection */
pop3_do, /* do_it */
pop3_done, /* done */
@@ -126,6 +126,7 @@ const struct Curl_handler Curl_handler_pop3 = {
ZERO_NULL, /* perform_getsock */
pop3_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_POP3, /* defport */
@@ -141,7 +142,7 @@ const struct Curl_handler Curl_handler_pop3 = {
*/
const struct Curl_handler Curl_handler_pop3s = {
- "POP3S", /* scheme */
+ "pop3s", /* scheme */
pop3_setup_connection, /* setup_connection */
pop3_do, /* do_it */
pop3_done, /* done */
@@ -155,6 +156,7 @@ const struct Curl_handler Curl_handler_pop3s = {
ZERO_NULL, /* perform_getsock */
pop3_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_POP3S, /* defport */
@@ -1450,7 +1452,7 @@ static CURLcode pop3_parse_custom_request(struct Curl_easy *data)
* This function scans the body after the end-of-body and writes everything
* until the end is found.
*/
-CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread)
+CURLcode Curl_pop3_write(struct Curl_easy *data, const char *str, size_t nread)
{
/* This code could be made into a special function in the handler struct */
CURLcode result = CURLE_OK;
diff --git a/libs/libcurl/src/pop3.h b/libs/libcurl/src/pop3.h
index 49d9d88e8d..408bd0233c 100644
--- a/libs/libcurl/src/pop3.h
+++ b/libs/libcurl/src/pop3.h
@@ -92,6 +92,7 @@ extern const struct Curl_handler Curl_handler_pop3s;
/* This function scans the body after the end-of-body and writes everything
* until the end is found */
-CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread);
+CURLcode Curl_pop3_write(struct Curl_easy *data,
+ const char *str, size_t nread);
#endif /* HEADER_CURL_POP3_H */
diff --git a/libs/libcurl/src/request.c b/libs/libcurl/src/request.c
index a6c69a3dda..54b43e12ce 100644
--- a/libs/libcurl/src/request.c
+++ b/libs/libcurl/src/request.c
@@ -40,10 +40,9 @@
#include "curl_memory.h"
#include "memdebug.h"
-CURLcode Curl_req_init(struct SingleRequest *req)
+void Curl_req_init(struct SingleRequest *req)
{
memset(req, 0, sizeof(*req));
- return CURLE_OK;
}
CURLcode Curl_req_soft_reset(struct SingleRequest *req,
@@ -266,7 +265,7 @@ static CURLcode req_set_upload_done(struct Curl_easy *data)
else if(data->req.writebytecount)
infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
" bytes", data->req.writebytecount);
- else
+ else if(!data->req.download_done)
infof(data, Curl_creader_total_length(data)?
"We are completely uploaded and fine" :
"Request completely sent off");
@@ -395,6 +394,7 @@ CURLcode Curl_req_send_more(struct Curl_easy *data)
result = req_flush(data);
if(result == CURLE_AGAIN)
result = CURLE_OK;
+
return result;
}
diff --git a/libs/libcurl/src/request.h b/libs/libcurl/src/request.h
index 1f87b191c3..570ab4f10c 100644
--- a/libs/libcurl/src/request.h
+++ b/libs/libcurl/src/request.h
@@ -152,7 +152,7 @@ struct SingleRequest {
/**
* Initialize the state of the request for first use.
*/
-CURLcode Curl_req_init(struct SingleRequest *req);
+void Curl_req_init(struct SingleRequest *req);
/**
* The request is about to start. Record time and do a soft reset.
diff --git a/libs/libcurl/src/rtsp.c b/libs/libcurl/src/rtsp.c
index 9e8120373b..b1aad90c75 100644
--- a/libs/libcurl/src/rtsp.c
+++ b/libs/libcurl/src/rtsp.c
@@ -93,14 +93,14 @@ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
static
CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len);
static
-CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport);
+CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport);
/*
* RTSP handler interface.
*/
const struct Curl_handler Curl_handler_rtsp = {
- "RTSP", /* scheme */
+ "rtsp", /* scheme */
rtsp_setup_connection, /* setup_connection */
rtsp_do, /* do_it */
rtsp_done, /* done */
@@ -114,6 +114,7 @@ const struct Curl_handler Curl_handler_rtsp = {
ZERO_NULL, /* perform_getsock */
rtsp_disconnect, /* disconnect */
rtsp_rtp_write_resp, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
rtsp_conncheck, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTSP, /* defport */
@@ -393,7 +394,9 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
if(result)
goto out;
+#ifndef CURL_DISABLE_PROXY
p_proxyuserpwd = data->state.aptr.proxyuserpwd;
+#endif
p_userpwd = data->state.aptr.userpwd;
/* Referrer */
@@ -802,7 +805,7 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, eos=%d)",
blen, rtspc->in_header, is_eos));
- /* If header parsing is not onging, extract RTP messages */
+ /* If header parsing is not ongoing, extract RTP messages */
if(!rtspc->in_header) {
result = rtsp_filter_rtp(data, buf, blen, &consumed);
if(result)
@@ -911,12 +914,12 @@ CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len)
return CURLE_OK;
}
-CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
{
if(checkprefix("CSeq:", header)) {
long CSeq = 0;
char *endp;
- char *p = &header[5];
+ const char *p = &header[5];
while(ISBLANK(*p))
p++;
CSeq = strtol(p, &endp, 10);
@@ -931,8 +934,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
}
}
else if(checkprefix("Session:", header)) {
- char *start;
- char *end;
+ const char *start, *end;
size_t idlen;
/* Find the first non-space letter */
@@ -987,14 +989,13 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
}
static
-CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport)
+CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport)
{
/* If we receive multiple Transport response-headers, the linterleaved
channels of each response header is recorded and used together for
subsequent data validity checks.*/
/* e.g.: ' RTP/AVP/TCP;unicast;interleaved=5-6' */
- char *start;
- char *end;
+ const char *start, *end;
start = transport;
while(start && *start) {
while(*start && ISBLANK(*start) )
@@ -1003,7 +1004,7 @@ CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport)
if(checkprefix("interleaved=", start)) {
long chan1, chan2, chan;
char *endp;
- char *p = start + 12;
+ const char *p = start + 12;
chan1 = strtol(p, &endp, 10);
if(p != endp && chan1 >= 0 && chan1 <= 255) {
unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
diff --git a/libs/libcurl/src/rtsp.h b/libs/libcurl/src/rtsp.h
index 15419e7f9f..0b841765cf 100644
--- a/libs/libcurl/src/rtsp.h
+++ b/libs/libcurl/src/rtsp.h
@@ -31,7 +31,7 @@
extern const struct Curl_handler Curl_handler_rtsp;
-CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header);
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header);
#else
/* disabled */
diff --git a/libs/libcurl/src/sendf.c b/libs/libcurl/src/sendf.c
index ea598b35df..67b431f645 100644
--- a/libs/libcurl/src/sendf.c
+++ b/libs/libcurl/src/sendf.c
@@ -88,7 +88,10 @@ CURLcode Curl_client_write(struct Curl_easy *data,
DEBUGASSERT(data->req.writer_stack);
}
- return Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
+ result = Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
+ CURL_TRC_WRITE(data, "client_write(type=%x, len=%zu) -> %d",
+ type, blen, result);
+ return result;
}
static void cl_reset_writer(struct Curl_easy *data)
@@ -115,7 +118,6 @@ static void cl_reset_reader(struct Curl_easy *data)
void Curl_client_cleanup(struct Curl_easy *data)
{
- DEBUGF(infof(data, "Curl_client_cleanup()"));
cl_reset_reader(data);
cl_reset_writer(data);
@@ -127,10 +129,10 @@ void Curl_client_reset(struct Curl_easy *data)
{
if(data->req.rewind_read) {
/* already requested */
- DEBUGF(infof(data, "Curl_client_reset(), will rewind_read"));
+ CURL_TRC_READ(data, "client_reset, will rewind reader");
}
else {
- DEBUGF(infof(data, "Curl_client_reset(), clear readers"));
+ CURL_TRC_READ(data, "client_reset, clear readers");
cl_reset_reader(data);
}
cl_reset_writer(data);
@@ -145,7 +147,7 @@ CURLcode Curl_client_start(struct Curl_easy *data)
struct Curl_creader *r = data->req.reader_stack;
CURLcode result = CURLE_OK;
- DEBUGF(infof(data, "client start, rewind readers"));
+ CURL_TRC_READ(data, "client start, rewind readers");
while(r) {
result = r->crt->rewind(data, r);
if(result) {
@@ -171,8 +173,7 @@ void Curl_creader_set_rewind(struct Curl_easy *data, bool enable)
data->req.rewind_read = !!enable;
}
-/* Write data using an unencoding writer stack. "nbytes" is not
- allowed to be 0. */
+/* Write data using an unencoding writer stack. */
CURLcode Curl_cwriter_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
@@ -249,7 +250,10 @@ static CURLcode cw_download_write(struct Curl_easy *data,
if(!(type & CLIENTWRITE_BODY)) {
if(is_connect && data->set.suppress_connect_headers)
return CURLE_OK;
- return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+ result = Curl_cwriter_write(data, writer->next, type, buf, nbytes);
+ CURL_TRC_WRITE(data, "download_write header(type=%x, blen=%zu) -> %d",
+ type, nbytes, result);
+ return result;
}
/* Here, we deal with REAL BODY bytes. All filtering and transfer
@@ -261,8 +265,8 @@ static CURLcode cw_download_write(struct Curl_easy *data,
if(data->req.no_body && nbytes > 0) {
/* BODY arrives although we want none, bail out */
streamclose(data->conn, "ignoring body");
- DEBUGF(infof(data, "did not want a BODY, but seeing %zu bytes",
- nbytes));
+ CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu), "
+ "did not want a BODY", type, nbytes);
data->req.download_done = TRUE;
if(data->info.header_size)
/* if headers have been received, this is fine */
@@ -298,6 +302,8 @@ static CURLcode cw_download_write(struct Curl_easy *data,
if(!data->req.ignorebody && (nwrite || (type & CLIENTWRITE_EOS))) {
result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
+ CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu) -> %d",
+ type, nbytes, result);
if(result)
return result;
}
@@ -333,7 +339,7 @@ static CURLcode cw_download_write(struct Curl_easy *data,
}
static const struct Curl_cwtype cw_download = {
- "download",
+ "protocol",
NULL,
Curl_cwriter_def_init,
cw_download_write,
@@ -499,10 +505,22 @@ void Curl_cwriter_remove_by_name(struct Curl_easy *data,
}
}
+bool Curl_cwriter_is_paused(struct Curl_easy *data)
+{
+ return Curl_cw_out_is_paused(data);
+}
+
+CURLcode Curl_cwriter_unpause(struct Curl_easy *data)
+{
+ return Curl_cw_out_unpause(data);
+}
+
CURLcode Curl_creader_read(struct Curl_easy *data,
struct Curl_creader *reader,
char *buf, size_t blen, size_t *nread, bool *eos)
{
+ *nread = 0;
+ *eos = FALSE;
if(!reader)
return CURLE_READ_ERROR;
return reader->crt->do_read(data, reader, buf, blen, nread, eos);
@@ -649,7 +667,7 @@ static CURLcode cr_in_read(struct Curl_easy *data,
switch(nread) {
case 0:
if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
- failf(data, "client read function EOF fail, only "
+ failf(data, "client read function EOF fail, "
"only %"CURL_FORMAT_CURL_OFF_T"/%"CURL_FORMAT_CURL_OFF_T
" of needed bytes read", ctx->read_len, ctx->total_len);
return CURLE_READ_ERROR;
@@ -698,9 +716,10 @@ static CURLcode cr_in_read(struct Curl_easy *data,
*peos = ctx->seen_eos;
break;
}
- DEBUGF(infof(data, "cr_in_read(len=%zu, total=%"CURL_FORMAT_CURL_OFF_T
- ", read=%"CURL_FORMAT_CURL_OFF_T") -> %d, %zu, %d",
- blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos));
+ CURL_TRC_READ(data, "cr_in_read(len=%zu, total=%"CURL_FORMAT_CURL_OFF_T
+ ", read=%"CURL_FORMAT_CURL_OFF_T") -> %d, nread=%zu, eos=%d",
+ blen, ctx->total_len, ctx->read_len, CURLE_OK,
+ *pnread, *peos);
return CURLE_OK;
}
@@ -798,7 +817,7 @@ static CURLcode cr_in_rewind(struct Curl_easy *data,
Curl_set_in_callback(data, true);
err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
Curl_set_in_callback(data, false);
- DEBUGF(infof(data, "cr_in, rewind via set.seek_func -> %d", err));
+ CURL_TRC_READ(data, "cr_in, rewind via set.seek_func -> %d", err);
if(err) {
failf(data, "seek callback returned error %d", (int)err);
return CURLE_SEND_FAIL_REWIND;
@@ -811,7 +830,7 @@ static CURLcode cr_in_rewind(struct Curl_easy *data,
err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
data->set.ioctl_client);
Curl_set_in_callback(data, false);
- DEBUGF(infof(data, "cr_in, rewind via set.ioctl_func -> %d", (int)err));
+ CURL_TRC_READ(data, "cr_in, rewind via set.ioctl_func -> %d", (int)err);
if(err) {
failf(data, "ioctl callback returned error %d", (int)err);
return CURLE_SEND_FAIL_REWIND;
@@ -823,8 +842,8 @@ static CURLcode cr_in_rewind(struct Curl_easy *data,
ourselves with fseek() */
if(data->state.fread_func == (curl_read_callback)fread) {
int err = fseek(data->state.in, 0, SEEK_SET);
- DEBUGF(infof(data, "cr_in, rewind via fseek -> %d(%d)",
- (int)err, (int)errno));
+ CURL_TRC_READ(data, "cr_in, rewind via fseek -> %d(%d)",
+ (int)err, (int)errno);
if(-1 != err)
/* successful rewind */
return CURLE_OK;
@@ -945,7 +964,7 @@ static CURLcode cr_lc_read(struct Curl_easy *data,
ctx->eos = TRUE;
*pnread = nread;
*peos = ctx->eos;
- return CURLE_OK;
+ goto out;
}
/* at least one \n needs conversion to '\r\n', place into ctx->buf */
@@ -977,6 +996,10 @@ static CURLcode cr_lc_read(struct Curl_easy *data,
ctx->eos = TRUE;
*peos = TRUE;
}
+
+out:
+ CURL_TRC_READ(data, "cr_lc_read(len=%zu) -> %d, nread=%zu, eos=%d",
+ blen, result, *pnread, *peos);
return result;
}
@@ -1054,12 +1077,16 @@ CURLcode Curl_creader_set_fread(struct Curl_easy *data, curl_off_t len)
result = Curl_creader_create(&r, data, &cr_in, CURL_CR_CLIENT);
if(result)
- return result;
+ goto out;
ctx = r->ctx;
ctx->total_len = len;
cl_reset_reader(data);
- return do_init_reader_stack(data, r);
+ result = do_init_reader_stack(data, r);
+out:
+ CURL_TRC_READ(data, "add fread reader, len=%"CURL_FORMAT_CURL_OFF_T
+ " -> %d", len, result);
+ return result;
}
CURLcode Curl_creader_add(struct Curl_easy *data,
@@ -1117,6 +1144,8 @@ CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
result = Curl_creader_read(data, data->req.reader_stack, buf, blen,
nread, eos);
+ CURL_TRC_READ(data, "client_read(len=%zu) -> %d, nread=%zu, eos=%d",
+ blen, result, *nread, *eos);
return result;
}
@@ -1124,8 +1153,10 @@ bool Curl_creader_needs_rewind(struct Curl_easy *data)
{
struct Curl_creader *reader = data->req.reader_stack;
while(reader) {
- if(reader->crt->needs_rewind(data, reader))
+ if(reader->crt->needs_rewind(data, reader)) {
+ CURL_TRC_READ(data, "client reader needs rewind before next request");
return TRUE;
+ }
reader = reader->next;
}
return FALSE;
@@ -1209,6 +1240,8 @@ static CURLcode cr_buf_read(struct Curl_easy *data,
ctx->index += nread;
*peos = (ctx->index == ctx->blen);
}
+ CURL_TRC_READ(data, "cr_buf_read(len=%zu) -> 0, nread=%zu, eos=%d",
+ blen, *pnread, *peos);
return CURLE_OK;
}
@@ -1274,14 +1307,17 @@ CURLcode Curl_creader_set_buf(struct Curl_easy *data,
result = Curl_creader_create(&r, data, &cr_buf, CURL_CR_CLIENT);
if(result)
- return result;
+ goto out;
ctx = r->ctx;
ctx->buf = buf;
ctx->blen = blen;
ctx->index = 0;
cl_reset_reader(data);
- return do_init_reader_stack(data, r);
+ result = do_init_reader_stack(data, r);
+out:
+ CURL_TRC_READ(data, "add buf reader, len=%zu -> %d", blen, result);
+ return result;
}
curl_off_t Curl_creader_total_length(struct Curl_easy *data)
diff --git a/libs/libcurl/src/sendf.h b/libs/libcurl/src/sendf.h
index 7225bb4292..699760dccc 100644
--- a/libs/libcurl/src/sendf.h
+++ b/libs/libcurl/src/sendf.h
@@ -181,6 +181,16 @@ CURLcode Curl_cwriter_write(struct Curl_easy *data,
const char *buf, size_t nbytes);
/**
+ * Return TRUE iff client writer is paused.
+ */
+bool Curl_cwriter_is_paused(struct Curl_easy *data);
+
+/**
+ * Unpause client writer and flush any buffered date to the client.
+ */
+CURLcode Curl_cwriter_unpause(struct Curl_easy *data);
+
+/**
* Default implementations for do_init, do_write, do_close that
* do nothing and pass the data through.
*/
@@ -302,7 +312,7 @@ CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r);
/**
* Read at most `blen` bytes at `buf` from the client.
- * @param date the transfer to read client bytes for
+ * @param data the transfer to read client bytes for
* @param buf the memory location to read to
* @param blen the amount of memory at `buf`
* @param nread on return the number of bytes read into `buf`
@@ -350,8 +360,8 @@ curl_off_t Curl_creader_client_length(struct Curl_easy *data);
* Ask the installed reader at phase CURL_CR_CLIENT to start
* reading from the given offset. On success, this will reduce
* the `total_length()` by the amount.
- * @param date the transfer to read client bytes for
- * param offset the offset where to start reads from, negative
+ * @param data the transfer to read client bytes for
+ * @param offset the offset where to start reads from, negative
* values will be ignored.
* @return CURLE_OK if offset could be set
* CURLE_READ_ERROR if not supported by reader or seek/read failed
diff --git a/libs/libcurl/src/setopt.c b/libs/libcurl/src/setopt.c
index 5b8108fb4f..db68910187 100644
--- a/libs/libcurl/src/setopt.c
+++ b/libs/libcurl/src/setopt.c
@@ -52,6 +52,8 @@
#include "hsts.h"
#include "tftp.h"
#include "strdup.h"
+#include "escape.h"
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -109,45 +111,32 @@ CURLcode Curl_setblobopt(struct curl_blob **blobp,
static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
{
- CURLcode result = CURLE_OK;
char *user = NULL;
char *passwd = NULL;
+ DEBUGASSERT(userp);
+ DEBUGASSERT(passwdp);
+
/* Parse the login details if specified. It not then we treat NULL as a hint
to clear the existing data */
if(option) {
size_t len = strlen(option);
+ CURLcode result;
if(len > CURL_MAX_INPUT_LENGTH)
return CURLE_BAD_FUNCTION_ARGUMENT;
- result = Curl_parse_login_details(option, len,
- (userp ? &user : NULL),
- (passwdp ? &passwd : NULL),
- NULL);
+ result = Curl_parse_login_details(option, len, &user, &passwd, NULL);
+ if(result)
+ return result;
}
- if(!result) {
- /* Store the username part of option if required */
- if(userp) {
- if(!user && option && option[0] == ':') {
- /* Allocate an empty string instead of returning NULL as user name */
- user = strdup("");
- if(!user)
- result = CURLE_OUT_OF_MEMORY;
- }
-
- Curl_safefree(*userp);
- *userp = user;
- }
+ free(*userp);
+ *userp = user;
- /* Store the password part of option if required */
- if(passwdp) {
- Curl_safefree(*passwdp);
- *passwdp = passwd;
- }
- }
+ free(*passwdp);
+ *passwdp = passwd;
- return result;
+ return CURLE_OK;
}
#define C_SSLVERSION_VALUE(x) (x & 0xffff)
@@ -518,11 +507,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data.
*/
char *p = Curl_memdup0(argptr, (size_t)data->set.postfieldsize);
- (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
if(!p)
result = CURLE_OUT_OF_MEMORY;
- else
+ else {
+ free(data->set.str[STRING_COPYPOSTFIELDS]);
data->set.str[STRING_COPYPOSTFIELDS] = p;
+ }
}
}
@@ -536,7 +526,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*/
data->set.postfields = va_arg(param, void *);
/* Release old copied data. */
- (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
data->set.method = HTTPREQ_POST;
break;
@@ -552,7 +542,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
if(data->set.postfieldsize < bigsize &&
data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
/* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
- (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
data->set.postfields = NULL;
}
@@ -571,7 +561,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
if(data->set.postfieldsize < bigsize &&
data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
/* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
- (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
data->set.postfields = NULL;
}
@@ -789,22 +779,20 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* Set cookie file name to dump all cookies to when we're done.
*/
- {
- struct CookieInfo *newcookies;
result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR],
va_arg(param, char *));
-
- /*
- * Activate the cookie parser. This may or may not already
- * have been made.
- */
- newcookies = Curl_cookie_init(data, NULL, data->cookies,
- data->set.cookiesession);
- if(!newcookies)
- result = CURLE_OUT_OF_MEMORY;
- data->cookies = newcookies;
- }
- break;
+ if(!result) {
+ /*
+ * Activate the cookie parser. This may or may not already
+ * have been made.
+ */
+ struct CookieInfo *newcookies =
+ Curl_cookie_init(data, NULL, data->cookies, data->set.cookiesession);
+ if(!newcookies)
+ result = CURLE_OUT_OF_MEMORY;
+ data->cookies = newcookies;
+ }
+ break;
case CURLOPT_COOKIESESSION:
/*
@@ -913,7 +901,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* accepted */
break;
#endif
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
case CURL_HTTP_VERSION_3:
case CURL_HTTP_VERSION_3ONLY:
/* accepted */
@@ -1022,9 +1010,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* switch off bits we can't support */
#ifndef USE_NTLM
auth &= ~CURLAUTH_NTLM; /* no NTLM support */
- auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
-#elif !defined(NTLM_WB_ENABLED)
- auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
#endif
#ifndef USE_SPNEGO
auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
@@ -1103,9 +1088,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* switch off bits we can't support */
#ifndef USE_NTLM
auth &= ~CURLAUTH_NTLM; /* no NTLM support */
- auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
-#elif !defined(NTLM_WB_ENABLED)
- auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
#endif
#ifndef USE_SPNEGO
auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
@@ -1318,6 +1300,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.ftpsslauth = (unsigned char)(curl_ftpauth)arg;
break;
+#ifdef HAVE_GSSAPI
case CURLOPT_KRBLEVEL:
/*
* A string that defines the kerberos security level.
@@ -1327,6 +1310,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]);
break;
#endif
+#endif
#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
case CURLOPT_FTP_CREATE_MISSING_DIRS:
/*
@@ -1593,13 +1577,24 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
#ifndef CURL_DISABLE_PROXY
- case CURLOPT_PROXYUSERPWD:
+ case CURLOPT_PROXYUSERPWD: {
/*
* user:password needed to use the proxy
*/
- result = setstropt_userpwd(va_arg(param, char *),
- &data->set.str[STRING_PROXYUSERNAME],
- &data->set.str[STRING_PROXYPASSWORD]);
+ char *u = NULL;
+ char *p = NULL;
+ result = setstropt_userpwd(va_arg(param, char *), &u, &p);
+
+ /* URL decode the components */
+ if(!result && u)
+ result = Curl_urldecode(u, 0, &data->set.str[STRING_PROXYUSERNAME], NULL,
+ REJECT_ZERO);
+ if(!result && p)
+ result = Curl_urldecode(p, 0, &data->set.str[STRING_PROXYPASSWORD], NULL,
+ REJECT_ZERO);
+ free(u);
+ free(p);
+ }
break;
case CURLOPT_PROXYUSERNAME:
/*
@@ -1851,7 +1846,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* flag to set engine as default.
*/
- Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], NULL);
+ Curl_safefree(data->set.str[STRING_SSL_ENGINE]);
result = Curl_ssl_set_engine_default(data);
break;
case CURLOPT_CRLF:
@@ -2315,7 +2310,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
Curl_hsts_cleanup(&data->hsts);
data->hsts = data->share->hsts;
}
-#endif /* CURL_DISABLE_HTTP */
+#endif
#ifdef USE_SSL
if(data->share->sslsession) {
data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
@@ -2625,7 +2620,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
#endif
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case CURLOPT_ADDRESS_SCOPE:
/*
* Use this scope id when using IPv6
@@ -3133,6 +3128,49 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
}
#endif
+#ifdef USE_ECH
+ case CURLOPT_ECH: {
+ size_t plen = 0;
+
+ argptr = va_arg(param, char *);
+ if(!argptr) {
+ data->set.tls_ech = CURLECH_DISABLE;
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ return result;
+ }
+ plen = strlen(argptr);
+ if(plen > CURL_MAX_INPUT_LENGTH) {
+ data->set.tls_ech = CURLECH_DISABLE;
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ return result;
+ }
+ /* set tls_ech flag value, preserving CLA_CFG bit */
+ if(plen == 5 && !strcmp(argptr, "false"))
+ data->set.tls_ech = CURLECH_DISABLE
+ | (data->set.tls_ech & CURLECH_CLA_CFG);
+ else if(plen == 6 && !strcmp(argptr, "grease"))
+ data->set.tls_ech = CURLECH_GREASE
+ | (data->set.tls_ech & CURLECH_CLA_CFG);
+ else if(plen == 4 && !strcmp(argptr, "true"))
+ data->set.tls_ech = CURLECH_ENABLE
+ | (data->set.tls_ech & CURLECH_CLA_CFG);
+ else if(plen == 4 && !strcmp(argptr, "hard"))
+ data->set.tls_ech = CURLECH_HARD
+ | (data->set.tls_ech & CURLECH_CLA_CFG);
+ else if(plen > 5 && !strncmp(argptr, "ecl:", 4)) {
+ result = Curl_setstropt(&data->set.str[STRING_ECH_CONFIG], argptr + 4);
+ if(result)
+ return result;
+ data->set.tls_ech |= CURLECH_CLA_CFG;
+ }
+ else if(plen > 4 && !strncmp(argptr, "pn:", 3)) {
+ result = Curl_setstropt(&data->set.str[STRING_ECH_PUBLIC], argptr + 3);
+ if(result)
+ return result;
+ }
+ break;
+ }
+#endif
case CURLOPT_QUICK_EXIT:
data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L;
break;
diff --git a/libs/libcurl/src/setopt.h b/libs/libcurl/src/setopt.h
index a80b56cac3..f550a09e5f 100644
--- a/libs/libcurl/src/setopt.h
+++ b/libs/libcurl/src/setopt.h
@@ -24,9 +24,10 @@
*
***************************************************************************/
-CURLcode Curl_setstropt(char **charp, const char *s);
+CURLcode Curl_setstropt(char **charp, const char *s) WARN_UNUSED_RESULT;
CURLcode Curl_setblobopt(struct curl_blob **blobp,
- const struct curl_blob *blob);
-CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg);
+ const struct curl_blob *blob) WARN_UNUSED_RESULT;
+CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg)
+ WARN_UNUSED_RESULT;
#endif /* HEADER_CURL_SETOPT_H */
diff --git a/libs/libcurl/src/setup-vms.h b/libs/libcurl/src/setup-vms.h
index ea1cd42294..459331185a 100644
--- a/libs/libcurl/src/setup-vms.h
+++ b/libs/libcurl/src/setup-vms.h
@@ -374,8 +374,8 @@ static struct passwd *vms_getpwuid(uid_t uid)
#ifdef HAVE_NETDB_H
#include <netdb.h>
#ifndef AI_NUMERICHOST
-#ifdef ENABLE_IPV6
-#undef ENABLE_IPV6
+#ifdef USE_IPV6
+#undef USE_IPV6
#endif
#endif
#endif
diff --git a/libs/libcurl/src/smb.c b/libs/libcurl/src/smb.c
index 53d457cd76..a927c7dba3 100644
--- a/libs/libcurl/src/smb.c
+++ b/libs/libcurl/src/smb.c
@@ -259,7 +259,7 @@ static CURLcode smb_parse_url_path(struct Curl_easy *data,
* SMB handler interface
*/
const struct Curl_handler Curl_handler_smb = {
- "SMB", /* scheme */
+ "smb", /* scheme */
smb_setup_connection, /* setup_connection */
smb_do, /* do_it */
ZERO_NULL, /* done */
@@ -273,6 +273,7 @@ const struct Curl_handler Curl_handler_smb = {
ZERO_NULL, /* perform_getsock */
smb_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMB, /* defport */
@@ -286,7 +287,7 @@ const struct Curl_handler Curl_handler_smb = {
* SMBS handler interface
*/
const struct Curl_handler Curl_handler_smbs = {
- "SMBS", /* scheme */
+ "smbs", /* scheme */
smb_setup_connection, /* setup_connection */
smb_do, /* do_it */
ZERO_NULL, /* done */
@@ -300,6 +301,7 @@ const struct Curl_handler Curl_handler_smbs = {
ZERO_NULL, /* perform_getsock */
smb_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMBS, /* defport */
diff --git a/libs/libcurl/src/smtp.c b/libs/libcurl/src/smtp.c
index abb8855cd9..197697bfa4 100644
--- a/libs/libcurl/src/smtp.c
+++ b/libs/libcurl/src/smtp.c
@@ -118,7 +118,7 @@ static CURLcode cr_eob_add(struct Curl_easy *data);
*/
const struct Curl_handler Curl_handler_smtp = {
- "SMTP", /* scheme */
+ "smtp", /* scheme */
smtp_setup_connection, /* setup_connection */
smtp_do, /* do_it */
smtp_done, /* done */
@@ -132,6 +132,7 @@ const struct Curl_handler Curl_handler_smtp = {
ZERO_NULL, /* perform_getsock */
smtp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMTP, /* defport */
@@ -147,7 +148,7 @@ const struct Curl_handler Curl_handler_smtp = {
*/
const struct Curl_handler Curl_handler_smtps = {
- "SMTPS", /* scheme */
+ "smtps", /* scheme */
smtp_setup_connection, /* setup_connection */
smtp_do, /* do_it */
smtp_done, /* done */
@@ -161,6 +162,7 @@ const struct Curl_handler Curl_handler_smtps = {
ZERO_NULL, /* perform_getsock */
smtp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMTPS, /* defport */
@@ -1901,7 +1903,7 @@ static CURLcode cr_eob_read(struct Curl_easy *data,
*peos = ctx->eos;
DEBUGF(infof(data, "cr_eob_read(%zu) -> %d, %zd, %d",
blen, result, *pnread, *peos));
- return CURLE_OK;
+ return result;
}
static curl_off_t cr_eob_total_length(struct Curl_easy *data,
diff --git a/libs/libcurl/src/sockaddr.h b/libs/libcurl/src/sockaddr.h
index 2ec3efe296..81eb8ac3e4 100644
--- a/libs/libcurl/src/sockaddr.h
+++ b/libs/libcurl/src/sockaddr.h
@@ -30,7 +30,7 @@ struct Curl_sockaddr_storage {
union {
struct sockaddr sa;
struct sockaddr_in sa_in;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct sockaddr_in6 sa_in6;
#endif
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
diff --git a/libs/libcurl/src/socketpair.c b/libs/libcurl/src/socketpair.c
index 90b51d9017..06eaa2b5c7 100644
--- a/libs/libcurl/src/socketpair.c
+++ b/libs/libcurl/src/socketpair.c
@@ -27,6 +27,27 @@
#include "urldata.h"
#include "rand.h"
+#if defined(HAVE_PIPE) && defined(HAVE_FCNTL)
+#include <fcntl.h>
+
+int Curl_pipe(curl_socket_t socks[2])
+{
+ if(pipe(socks))
+ return -1;
+
+ if(fcntl(socks[0], F_SETFD, FD_CLOEXEC) ||
+ fcntl(socks[1], F_SETFD, FD_CLOEXEC) ) {
+ close(socks[0]);
+ close(socks[1]);
+ socks[0] = socks[1] = CURL_SOCKET_BAD;
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+
#if !defined(HAVE_SOCKETPAIR) && !defined(CURL_DISABLE_SOCKETPAIR)
#ifdef _WIN32
/*
diff --git a/libs/libcurl/src/socketpair.h b/libs/libcurl/src/socketpair.h
index 08f076d916..b52b8b7d8a 100644
--- a/libs/libcurl/src/socketpair.h
+++ b/libs/libcurl/src/socketpair.h
@@ -31,17 +31,41 @@
#define wakeup_write write
#define wakeup_read read
#define wakeup_close close
-#define wakeup_create pipe
+#define wakeup_create(p) Curl_pipe(p)
+
+#ifdef HAVE_FCNTL
+#include <curl/curl.h>
+int Curl_pipe(curl_socket_t socks[2]);
+#else
+#define Curl_pipe(p) pipe(p)
+#endif
#else /* HAVE_PIPE */
#define wakeup_write swrite
#define wakeup_read sread
#define wakeup_close sclose
-#define wakeup_create(p) Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, p)
+
+#if defined(USE_UNIX_SOCKETS) && defined(HAVE_SOCKETPAIR)
+#define SOCKETPAIR_FAMILY AF_UNIX
+#elif !defined(HAVE_SOCKETPAIR)
+#define SOCKETPAIR_FAMILY 0 /* not used */
+#else
+#error "unsupported unix domain and socketpair build combo"
+#endif
+
+#ifdef SOCK_CLOEXEC
+#define SOCKETPAIR_TYPE (SOCK_STREAM | SOCK_CLOEXEC)
+#else
+#define SOCKETPAIR_TYPE SOCK_STREAM
+#endif
+
+#define wakeup_create(p)\
+Curl_socketpair(SOCKETPAIR_FAMILY, SOCKETPAIR_TYPE, 0, p)
#endif /* HAVE_PIPE */
+
#ifndef HAVE_SOCKETPAIR
#include <curl/curl.h>
diff --git a/libs/libcurl/src/socks.c b/libs/libcurl/src/socks.c
index 89f85666ff..016e9db041 100644
--- a/libs/libcurl/src/socks.c
+++ b/libs/libcurl/src/socks.c
@@ -838,7 +838,7 @@ CONNECT_RESOLVED:
struct Curl_addrinfo *hp = NULL;
if(dns)
hp = dns->addr;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if(data->set.ipver != CURL_IPRESOLVE_WHATEVER) {
int wanted_family = data->set.ipver == CURL_IPRESOLVE_V4 ?
AF_INET : AF_INET6;
@@ -872,7 +872,7 @@ CONNECT_RESOLVED:
infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest,
sx->remote_port);
}
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else if(hp->ai_family == AF_INET6) {
int i;
struct sockaddr_in6 *saddr_in6;
@@ -909,7 +909,7 @@ CONNECT_RESOLVE_REMOTE:
IPv6 == 4,
IPv4 == 1 */
unsigned char ip4[4];
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if(conn->bits.ipv6_ip) {
char ip6[16];
if(1 != Curl_inet_pton(AF_INET6, sx->hostname, ip6))
@@ -1244,7 +1244,7 @@ static void socks_cf_get_host(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_socks_proxy = {
"SOCKS-PROXYY",
- CF_TYPE_IP_CONNECT,
+ CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
0,
socks_proxy_cf_destroy,
socks_proxy_cf_connect,
diff --git a/libs/libcurl/src/strcase.c b/libs/libcurl/src/strcase.c
index 3296cc006e..0a658d0332 100644
--- a/libs/libcurl/src/strcase.c
+++ b/libs/libcurl/src/strcase.c
@@ -71,7 +71,7 @@ static const unsigned char tolowermap[256] = {
altered by the current locale. */
char Curl_raw_toupper(char in)
{
- return touppermap[(unsigned char) in];
+ return (char)touppermap[(unsigned char) in];
}
@@ -79,7 +79,7 @@ char Curl_raw_toupper(char in)
altered by the current locale. */
char Curl_raw_tolower(char in)
{
- return tolowermap[(unsigned char) in];
+ return (char)tolowermap[(unsigned char) in];
}
/*
diff --git a/libs/libcurl/src/strerror.c b/libs/libcurl/src/strerror.c
index 8d4abe4198..95986724e0 100644
--- a/libs/libcurl/src/strerror.c
+++ b/libs/libcurl/src/strerror.c
@@ -322,6 +322,9 @@ curl_easy_strerror(CURLcode error)
case CURLE_TOO_LARGE:
return "A value or data field grew larger than allowed";
+ case CURLE_ECH_REQUIRED:
+ return "ECH attempted but failed";
+
/* error codes not used by current libcurl */
case CURLE_OBSOLETE20:
case CURLE_OBSOLETE24:
diff --git a/libs/libcurl/src/telnet.c b/libs/libcurl/src/telnet.c
index 359cd09b0a..c60398f627 100644
--- a/libs/libcurl/src/telnet.c
+++ b/libs/libcurl/src/telnet.c
@@ -173,7 +173,7 @@ struct TELNET {
*/
const struct Curl_handler Curl_handler_telnet = {
- "TELNET", /* scheme */
+ "telnet", /* scheme */
ZERO_NULL, /* setup_connection */
telnet_do, /* do_it */
telnet_done, /* done */
@@ -187,6 +187,7 @@ const struct Curl_handler Curl_handler_telnet = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_TELNET, /* defport */
@@ -1534,6 +1535,11 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
pfd[1].events = POLLIN;
poll_cnt = 2;
interval_ms = 1 * 1000;
+ if(pfd[1].fd < 0) {
+ failf(data, "cannot read input");
+ result = CURLE_RECV_ERROR;
+ keepon = FALSE;
+ }
}
while(keepon) {
diff --git a/libs/libcurl/src/tftp.c b/libs/libcurl/src/tftp.c
index b31b2c287e..623a2864bc 100644
--- a/libs/libcurl/src/tftp.c
+++ b/libs/libcurl/src/tftp.c
@@ -168,7 +168,7 @@ static CURLcode tftp_translate_code(tftp_error_t error);
*/
const struct Curl_handler Curl_handler_tftp = {
- "TFTP", /* scheme */
+ "tftp", /* scheme */
tftp_setup_connection, /* setup_connection */
tftp_do, /* do_it */
tftp_done, /* done */
@@ -182,6 +182,7 @@ const struct Curl_handler Curl_handler_tftp = {
ZERO_NULL, /* perform_getsock */
tftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_TFTP, /* defport */
@@ -1203,7 +1204,7 @@ static timediff_t tftp_state_timeout(struct Curl_easy *data,
state->state = TFTP_STATE_FIN;
return 0;
}
- time(&current);
+ current = time(NULL);
if(current > state->rx_time + state->retry_time) {
if(event)
*event = TFTP_EVENT_TIMEOUT;
diff --git a/libs/libcurl/src/transfer.c b/libs/libcurl/src/transfer.c
index 566f3da5e8..257932b0fa 100644
--- a/libs/libcurl/src/transfer.c
+++ b/libs/libcurl/src/transfer.c
@@ -198,7 +198,6 @@ static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data,
if(*err)
return -1;
DEBUGASSERT(nread >= 0);
- *err = CURLE_OK;
return nread;
}
@@ -272,10 +271,9 @@ static CURLcode readwrite_data(struct Curl_easy *data,
DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
else
DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
- if(k->eos_written) { /* already did write this to client, leave */
- k->keepon = 0; /* stop sending as well */
+ k->keepon &= ~(KEEP_RECV|KEEP_SEND); /* stop sending as well */
+ if(k->eos_written) /* already did write this to client, leave */
break;
- }
}
total_received += blen;
@@ -410,6 +408,14 @@ CURLcode Curl_readwrite(struct Curl_easy *data)
int didwhat = 0;
int select_bits;
+ /* Check if client writes had been paused and can resume now. */
+ if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) {
+ Curl_conn_ev_data_pause(data, FALSE);
+ result = Curl_cwriter_unpause(data);
+ if(result)
+ goto out;
+ }
+
if(data->state.select_bits) {
if(select_bits_paused(data, data->state.select_bits)) {
/* leave the bits unchanged, so they'll tell us what to do when
@@ -706,12 +712,14 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
if(!result)
result = Curl_setstropt(&data->state.aptr.passwd,
data->set.str[STRING_PASSWORD]);
+#ifndef CURL_DISABLE_PROXY
if(!result)
result = Curl_setstropt(&data->state.aptr.proxyuser,
data->set.str[STRING_PROXYUSERNAME]);
if(!result)
result = Curl_setstropt(&data->state.aptr.proxypasswd,
data->set.str[STRING_PROXYPASSWORD]);
+#endif
data->req.headerbytecount = 0;
Curl_headers_cleanup(data);
@@ -1155,7 +1163,7 @@ void Curl_xfer_setup(
}
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
- char *buf, size_t blen,
+ const char *buf, size_t blen,
bool is_eos)
{
CURLcode result = CURLE_OK;
@@ -1189,9 +1197,23 @@ CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
data->req.eos_written = TRUE;
data->req.download_done = TRUE;
}
+ CURL_TRC_WRITE(data, "xfer_write_resp(len=%zu, eos=%d) -> %d",
+ blen, is_eos, result);
return result;
}
+CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
+ const char *hd0, size_t hdlen, bool is_eos)
+{
+ if(data->conn->handler->write_resp_hd) {
+ /* protocol handlers offering this function take full responsibility
+ * for writing all received download data to the client. */
+ return data->conn->handler->write_resp_hd(data, hd0, hdlen, is_eos);
+ }
+ /* No special handling by protocol handler, write as response bytes */
+ return Curl_xfer_write_resp(data, hd0, hdlen, is_eos);
+}
+
CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature)
{
(void)premature;
@@ -1221,6 +1243,9 @@ CURLcode Curl_xfer_send(struct Curl_easy *data,
result = CURLE_OK;
*pnwritten = 0;
}
+ else if(!result && *pnwritten)
+ data->info.request_size += *pnwritten;
+
return result;
}
diff --git a/libs/libcurl/src/transfer.h b/libs/libcurl/src/transfer.h
index eaae63519c..1e9e1a4d69 100644
--- a/libs/libcurl/src/transfer.h
+++ b/libs/libcurl/src/transfer.h
@@ -62,12 +62,20 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);
* @param blen the amount of bytes in `buf`
* @param is_eos TRUE iff the connection indicates this to be the last
* bytes of the response
- * @param done on returnm, TRUE iff the response is complete
*/
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
- char *buf, size_t blen,
+ const char *buf, size_t blen,
bool is_eos);
+/**
+ * Write a single "header" line from a server response.
+ * @param hd0 the 0-terminated, single header line
+ * @param hdlen the length of the header line
+ * @param is_eos TRUE iff this is the end of the response
+ */
+CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
+ const char *hd0, size_t hdlen, bool is_eos);
+
/* This sets up a forthcoming transfer */
void Curl_xfer_setup(struct Curl_easy *data,
int sockindex, /* socket index to read from or -1 */
diff --git a/libs/libcurl/src/url.c b/libs/libcurl/src/url.c
index 444129578c..aa03c1d676 100644
--- a/libs/libcurl/src/url.c
+++ b/libs/libcurl/src/url.c
@@ -278,10 +278,12 @@ CURLcode Curl_close(struct Curl_easy **datap)
up_free(data);
Curl_dyn_free(&data->state.headerb);
Curl_flush_cookies(data, TRUE);
+#ifndef CURL_DISABLE_ALTSVC
Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
Curl_altsvc_cleanup(&data->asi);
- Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
+#endif
#ifndef CURL_DISABLE_HSTS
+ Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
if(!data->share || !data->share->hsts)
Curl_hsts_cleanup(&data->hsts);
curl_slist_free_all(data->state.hstslist); /* clean up list */
@@ -305,7 +307,9 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
}
+#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
+#endif
Curl_safefree(data->state.aptr.uagent);
Curl_safefree(data->state.aptr.userpwd);
Curl_safefree(data->state.aptr.accept_encoding);
@@ -313,12 +317,18 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->state.aptr.rangeline);
Curl_safefree(data->state.aptr.ref);
Curl_safefree(data->state.aptr.host);
+#ifndef CURL_DISABLE_COOKIES
Curl_safefree(data->state.aptr.cookiehost);
+#endif
+#ifndef CURL_DISABLE_RTSP
Curl_safefree(data->state.aptr.rtsp_transport);
+#endif
Curl_safefree(data->state.aptr.user);
Curl_safefree(data->state.aptr.passwd);
+#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuser);
Curl_safefree(data->state.aptr.proxypasswd);
+#endif
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
Curl_mime_cleanpart(data->state.formp);
@@ -429,21 +439,23 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
if(result)
return result;
-
+#ifndef CURL_DISABLE_PROXY
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
CURL_CA_BUNDLE);
if(result)
return result;
#endif
+#endif
#if defined(CURL_CA_PATH)
result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
if(result)
return result;
-
+#ifndef CURL_DISABLE_PROXY
result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
if(result)
return result;
#endif
+#endif
}
#ifndef CURL_DISABLE_FTP
@@ -504,12 +516,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->magic = CURLEASY_MAGIC_NUMBER;
- result = Curl_req_init(&data->req);
- if(result) {
- DEBUGF(fprintf(stderr, "Error: request init failed\n"));
- free(data);
- return result;
- }
+ Curl_req_init(&data->req);
result = Curl_resolver_init(data, &data->state.async.resolver);
if(result) {
@@ -767,16 +774,16 @@ static bool conn_maxage(struct Curl_easy *data,
}
/*
- * This function checks if the given connection is dead and extracts it from
+ * This function checks if the given connection is dead and prunes it from
* the connection cache if so.
*
* When this is called as a Curl_conncache_foreach() callback, the connection
* cache lock is held!
*
- * Returns TRUE if the connection was dead and extracted.
+ * Returns TRUE if the connection was dead and pruned.
*/
-static bool extract_if_dead(struct connectdata *conn,
- struct Curl_easy *data)
+static bool prune_if_dead(struct connectdata *conn,
+ struct Curl_easy *data)
{
if(!CONN_INUSE(conn)) {
/* The check for a dead socket makes sense only if the connection isn't in
@@ -803,7 +810,7 @@ static bool extract_if_dead(struct connectdata *conn,
}
else {
- bool input_pending;
+ bool input_pending = FALSE;
Curl_attach_connection(data, conn);
dead = !Curl_conn_is_alive(data, conn, &input_pending);
@@ -822,6 +829,7 @@ static bool extract_if_dead(struct connectdata *conn,
}
if(dead) {
+ /* remove connection from cache */
infof(data, "Connection %" CURL_FORMAT_CURL_OFF_T " seems to be dead",
conn->connection_id);
Curl_conncache_remove_conn(data, conn, FALSE);
@@ -831,22 +839,17 @@ static bool extract_if_dead(struct connectdata *conn,
return FALSE;
}
-struct prunedead {
- struct Curl_easy *data;
- struct connectdata *extracted;
-};
-
/*
- * Wrapper to use extract_if_dead() function in Curl_conncache_foreach()
+ * Wrapper to use prune_if_dead() function in Curl_conncache_foreach()
*
*/
-static int call_extract_if_dead(struct Curl_easy *data,
- struct connectdata *conn, void *param)
+static int call_prune_if_dead(struct Curl_easy *data,
+ struct connectdata *conn, void *param)
{
- struct prunedead *p = (struct prunedead *)param;
- if(extract_if_dead(conn, data)) {
- /* stop the iteration here, pass back the connection that was extracted */
- p->extracted = conn;
+ struct connectdata **pruned = (struct connectdata **)param;
+ if(prune_if_dead(conn, data)) {
+ /* stop the iteration here, pass back the connection that was pruned */
+ *pruned = conn;
return 1;
}
return 0; /* continue iteration */
@@ -870,18 +873,15 @@ static void prune_dead_connections(struct Curl_easy *data)
CONNCACHE_UNLOCK(data);
if(elapsed >= 1000L) {
- struct prunedead prune;
- prune.data = data;
- prune.extracted = NULL;
- while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
- call_extract_if_dead)) {
+ struct connectdata *pruned = NULL;
+ while(Curl_conncache_foreach(data, data->state.conn_cache, &pruned,
+ call_prune_if_dead)) {
/* unlocked */
- /* remove connection from cache */
- Curl_conncache_remove_conn(data, prune.extracted, TRUE);
+ /* connection previously removed from cache in prune_if_dead() */
/* disconnect it */
- Curl_disconnect(data, prune.extracted, TRUE);
+ Curl_disconnect(data, pruned, TRUE);
}
CONNCACHE_LOCK(data);
data->state.conn_cache->last_cleanup = now;
@@ -925,13 +925,12 @@ ConnectionExists(struct Curl_easy *data,
struct Curl_llist_element *curr;
#ifdef USE_NTLM
- bool wantNTLMhttp = ((data->state.authhost.want &
- (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ bool wantNTLMhttp = ((data->state.authhost.want & CURLAUTH_NTLM) &&
(needle->handler->protocol & PROTO_FAMILY_HTTP));
#ifndef CURL_DISABLE_PROXY
bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
((data->state.authproxy.want &
- (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ CURLAUTH_NTLM) &&
(needle->handler->protocol & PROTO_FAMILY_HTTP)));
#else
bool wantProxyNTLMhttp = FALSE;
@@ -1293,7 +1292,7 @@ ConnectionExists(struct Curl_easy *data,
/* When not multiplexed, we have a match here! */
infof(data, "Multiplexed connection found");
}
- else if(extract_if_dead(check, data)) {
+ else if(prune_if_dead(check, data)) {
/* disconnect it */
Curl_disconnect(data, check, TRUE);
continue;
@@ -1403,12 +1402,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->connect_only = data->set.connect_only;
conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
- defined(NTLM_WB_ENABLED)
- conn->ntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
- conn->proxyntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
-#endif
-
/* Initialize the easy handle list */
Curl_llist_init(&conn->easyq, NULL);
@@ -1710,7 +1703,7 @@ CURLcode Curl_uc_to_curlcode(CURLUcode uc)
}
}
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
/*
* If the URL was set with an IPv6 numerical address with a zone id part, set
* the scope_id based on that!
@@ -1975,7 +1968,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
(void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
if(data->set.scope_id)
/* Override any scope that was set above. */
conn->scope_id = data->set.scope_id;
@@ -2083,19 +2076,13 @@ static char *detect_proxy(struct Curl_easy *data,
* For compatibility, the all-uppercase versions of these variables are
* checked if the lowercase versions don't exist.
*/
- char proxy_env[128];
- const char *protop = conn->handler->scheme;
+ char proxy_env[20];
char *envp = proxy_env;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
(void)data;
#endif
- /* Now, build <protocol>_proxy and check for such a one to use */
- while(*protop)
- *envp++ = Curl_raw_tolower(*protop++);
-
- /* append _proxy */
- strcpy(envp, "_proxy");
+ msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy", conn->handler->scheme);
/* read the protocol proxy: */
proxy = curl_getenv(proxy_env);
@@ -2118,7 +2105,6 @@ static char *detect_proxy(struct Curl_easy *data,
proxy = curl_getenv(proxy_env);
}
- envp = proxy_env;
if(!proxy) {
#ifdef USE_WEBSOCKETS
/* websocket proxy fallbacks */
@@ -2366,17 +2352,16 @@ static CURLcode parse_proxy_auth(struct Curl_easy *data,
data->state.aptr.proxyuser : "";
const char *proxypasswd = data->state.aptr.proxypasswd ?
data->state.aptr.proxypasswd : "";
- CURLcode result = Curl_urldecode(proxyuser, 0, &conn->http_proxy.user, NULL,
- REJECT_ZERO);
- if(!result)
- result = Curl_setstropt(&data->state.aptr.proxyuser,
- conn->http_proxy.user);
- if(!result)
- result = Curl_urldecode(proxypasswd, 0, &conn->http_proxy.passwd,
- NULL, REJECT_ZERO);
- if(!result)
- result = Curl_setstropt(&data->state.aptr.proxypasswd,
- conn->http_proxy.passwd);
+ CURLcode result = CURLE_OUT_OF_MEMORY;
+
+ conn->http_proxy.user = strdup(proxyuser);
+ if(conn->http_proxy.user) {
+ conn->http_proxy.passwd = strdup(proxypasswd);
+ if(conn->http_proxy.passwd)
+ result = CURLE_OK;
+ else
+ Curl_safefree(conn->http_proxy.user);
+ }
return result;
}
@@ -2576,14 +2561,15 @@ out:
*
* Parameters:
*
- * login [in] - The login string.
- * len [in] - The length of the login string.
- * userp [in/out] - The address where a pointer to newly allocated memory
+ * login [in] - login string.
+ * len [in] - length of the login string.
+ * userp [in/out] - address where a pointer to newly allocated memory
* holding the user will be stored upon completion.
- * passwdp [in/out] - The address where a pointer to newly allocated memory
+ * passwdp [in/out] - address where a pointer to newly allocated memory
* holding the password will be stored upon completion.
- * optionsp [in/out] - The address where a pointer to newly allocated memory
- * holding the options will be stored upon completion.
+ * optionsp [in/out] - OPTIONAL address where a pointer to newly allocated
+ * memory holding the options will be stored upon
+ * completion.
*
* Returns CURLE_OK on success.
*/
@@ -2591,19 +2577,19 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
char **userp, char **passwdp,
char **optionsp)
{
- CURLcode result = CURLE_OK;
char *ubuf = NULL;
char *pbuf = NULL;
- char *obuf = NULL;
const char *psep = NULL;
const char *osep = NULL;
size_t ulen;
size_t plen;
size_t olen;
+ DEBUGASSERT(userp);
+ DEBUGASSERT(passwdp);
+
/* Attempt to find the password separator */
- if(passwdp)
- psep = memchr(login, ':', len);
+ psep = memchr(login, ':', len);
/* Attempt to find the options separator */
if(optionsp)
@@ -2615,64 +2601,40 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
(osep ? (size_t)(osep - login) : len));
plen = (psep ?
(osep && osep > psep ? (size_t)(osep - psep) :
- (size_t)(login + len - psep)) - 1 : 0);
+ (size_t)(login + len - psep)) - 1 : 0);
olen = (osep ?
(psep && psep > osep ? (size_t)(psep - osep) :
- (size_t)(login + len - osep)) - 1 : 0);
+ (size_t)(login + len - osep)) - 1 : 0);
- /* Allocate the user portion buffer, which can be zero length */
- if(userp) {
- ubuf = malloc(ulen + 1);
- if(!ubuf)
- result = CURLE_OUT_OF_MEMORY;
- }
+ /* Clone the user portion buffer, which can be zero length */
+ ubuf = Curl_memdup0(login, ulen);
+ if(!ubuf)
+ goto error;
- /* Allocate the password portion buffer */
- if(!result && passwdp && psep) {
- pbuf = malloc(plen + 1);
- if(!pbuf) {
- free(ubuf);
- result = CURLE_OUT_OF_MEMORY;
- }
+ /* Clone the password portion buffer */
+ if(psep) {
+ pbuf = Curl_memdup0(&psep[1], plen);
+ if(!pbuf)
+ goto error;
}
/* Allocate the options portion buffer */
- if(!result && optionsp && olen) {
- obuf = malloc(olen + 1);
- if(!obuf) {
- free(pbuf);
- free(ubuf);
- result = CURLE_OUT_OF_MEMORY;
- }
- }
-
- if(!result) {
- /* Store the user portion if necessary */
- if(ubuf) {
- memcpy(ubuf, login, ulen);
- ubuf[ulen] = '\0';
- Curl_safefree(*userp);
- *userp = ubuf;
- }
-
- /* Store the password portion if necessary */
- if(pbuf) {
- memcpy(pbuf, psep + 1, plen);
- pbuf[plen] = '\0';
- Curl_safefree(*passwdp);
- *passwdp = pbuf;
- }
-
- /* Store the options portion if necessary */
- if(obuf) {
- memcpy(obuf, osep + 1, olen);
- obuf[olen] = '\0';
- Curl_safefree(*optionsp);
- *optionsp = obuf;
+ if(optionsp) {
+ char *obuf = NULL;
+ if(olen) {
+ obuf = Curl_memdup0(&osep[1], olen);
+ if(!obuf)
+ goto error;
}
+ *optionsp = obuf;
}
-
- return result;
+ *userp = ubuf;
+ *passwdp = pbuf;
+ return CURLE_OK;
+error:
+ free(ubuf);
+ free(pbuf);
+ return CURLE_OUT_OF_MEMORY;
}
/*************************************************************
@@ -2883,7 +2845,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
/* detect and extract RFC6874-style IPv6-addresses */
if(*hostptr == '[') {
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
char *ptr = ++hostptr; /* advance beyond the initial bracket */
while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
ptr++;
@@ -3081,7 +3043,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
#ifdef USE_HTTP2
| ALPN_h2
#endif
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
| ALPN_h3
#endif
) & data->asi->flags;
@@ -3741,14 +3703,14 @@ static CURLcode create_conn(struct Curl_easy *data,
/* If NTLM is requested in a part of this connection, make sure we don't
assume the state is fine as this is a fresh connection and NTLM is
connection based. */
- if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ if((data->state.authhost.picked & CURLAUTH_NTLM) &&
data->state.authhost.done) {
infof(data, "NTLM picked AND auth done set, clear picked");
data->state.authhost.picked = CURLAUTH_NONE;
data->state.authhost.done = FALSE;
}
- if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ if((data->state.authproxy.picked & CURLAUTH_NTLM) &&
data->state.authproxy.done) {
infof(data, "NTLM-proxy picked AND auth done set, clear picked");
data->state.authproxy.picked = CURLAUTH_NONE;
@@ -3884,9 +3846,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
{
/* if this is a pushed stream, we need this: */
- CURLcode result = Curl_preconnect(data);
- if(result)
- return result;
+ CURLcode result;
if(conn) {
conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
@@ -3904,14 +3864,12 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
data->state.httpreq = HTTPREQ_HEAD;
result = Curl_req_start(&data->req, data);
- if(result)
- return result;
-
- Curl_speedinit(data);
- Curl_pgrsSetUploadCounter(data, 0);
- Curl_pgrsSetDownloadCounter(data, 0);
-
- return CURLE_OK;
+ if(!result) {
+ Curl_speedinit(data);
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ }
+ return result;
}
#if defined(USE_HTTP2) || defined(USE_HTTP3)
diff --git a/libs/libcurl/src/urlapi-int.h b/libs/libcurl/src/urlapi-int.h
index bf759382aa..f28157732c 100644
--- a/libs/libcurl/src/urlapi-int.h
+++ b/libs/libcurl/src/urlapi-int.h
@@ -28,8 +28,7 @@
size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
bool guess_scheme);
-CURLUcode Curl_url_set_authority(CURLU *u, const char *authority,
- unsigned int flags);
+CURLUcode Curl_url_set_authority(CURLU *u, const char *authority);
#ifdef DEBUGBUILD
CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
diff --git a/libs/libcurl/src/urlapi.c b/libs/libcurl/src/urlapi.c
index abce1abacf..7a938bbe9c 100644
--- a/libs/libcurl/src/urlapi.c
+++ b/libs/libcurl/src/urlapi.c
@@ -59,11 +59,11 @@
#define MAX_SCHEME_LEN 40
/*
- * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * If USE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
* sure we have _some_ value for AF_INET6 without polluting our fake value
* everywhere.
*/
-#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#if !defined(USE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif
@@ -79,7 +79,9 @@ struct Curl_URL {
char *path;
char *query;
char *fragment;
- long portnum; /* the numerical version */
+ unsigned short portnum; /* the numerical version (if 'port' is set) */
+ BIT(query_present); /* to support blank */
+ BIT(fragment_present); /* to support blank */
};
#define DEFAULT_SCHEME "https"
@@ -232,10 +234,8 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
/* the length of the scheme is the name part only */
size_t len = i;
if(buf) {
+ Curl_strntolower(buf, url, i);
buf[i] = 0;
- while(i--) {
- buf[i] = Curl_raw_tolower(url[i]);
- }
}
return len;
}
@@ -264,6 +264,7 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl)
const char *useurl = relurl;
CURLcode result = CURLE_OK;
CURLUcode uc;
+ bool skip_slash = FALSE;
*newurl = NULL;
/* protsep points to the start of the host name */
@@ -283,48 +284,50 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl)
*pathsep = 0;
/* we have a relative path to append to the last slash if there's one
- available, or if the new URL is just a query string (starts with a
- '?') we append the new one at the end of the entire currently worked
- out URL */
- if(useurl[0] != '?') {
+ available, or the new URL is just a query string (starts with a '?') or
+ a fragment (starts with '#') we append the new one at the end of the
+ current URL */
+ if((useurl[0] != '?') && (useurl[0] != '#')) {
pathsep = strrchr(protsep, '/');
if(pathsep)
*pathsep = 0;
- }
- /* Check if there's any slash after the host name, and if so, remember
- that position instead */
- pathsep = strchr(protsep, '/');
- if(pathsep)
- protsep = pathsep + 1;
- else
- protsep = NULL;
+ /* Check if there's any slash after the host name, and if so, remember
+ that position instead */
+ pathsep = strchr(protsep, '/');
+ if(pathsep)
+ protsep = pathsep + 1;
+ else
+ protsep = NULL;
- /* now deal with one "./" or any amount of "../" in the newurl
- and act accordingly */
+ /* now deal with one "./" or any amount of "../" in the newurl
+ and act accordingly */
- if((useurl[0] == '.') && (useurl[1] == '/'))
- useurl += 2; /* just skip the "./" */
+ if((useurl[0] == '.') && (useurl[1] == '/'))
+ useurl += 2; /* just skip the "./" */
- while((useurl[0] == '.') &&
- (useurl[1] == '.') &&
- (useurl[2] == '/')) {
- level++;
- useurl += 3; /* pass the "../" */
- }
+ while((useurl[0] == '.') &&
+ (useurl[1] == '.') &&
+ (useurl[2] == '/')) {
+ level++;
+ useurl += 3; /* pass the "../" */
+ }
- if(protsep) {
- while(level--) {
- /* cut off one more level from the right of the original URL */
- pathsep = strrchr(protsep, '/');
- if(pathsep)
- *pathsep = 0;
- else {
- *protsep = 0;
- break;
+ if(protsep) {
+ while(level--) {
+ /* cut off one more level from the right of the original URL */
+ pathsep = strrchr(protsep, '/');
+ if(pathsep)
+ *pathsep = 0;
+ else {
+ *protsep = 0;
+ break;
+ }
}
}
}
+ else
+ skip_slash = TRUE;
}
else {
/* We got a new absolute path for this server */
@@ -370,7 +373,7 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl)
return result;
/* check if we need to append a slash */
- if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
+ if(('/' == useurl[0]) || (protsep && !*protsep) || skip_slash)
;
else {
result = Curl_dyn_addn(&newest, "/", 1);
@@ -532,7 +535,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
if(portptr) {
char *rest = NULL;
- long port;
+ unsigned long port;
size_t keep = portptr - hostname;
/* Browser behavior adaptation. If there's a colon with no digits after,
@@ -550,15 +553,13 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
if(!ISDIGIT(*portptr))
return CURLUE_BAD_PORT_NUMBER;
- port = strtol(portptr, &rest, 10); /* Port number must be decimal */
+ errno = 0;
+ port = strtoul(portptr, &rest, 10); /* Port number must be decimal */
- if(port > 0xffff)
+ if(errno || (port > 0xffff) || *rest)
return CURLUE_BAD_PORT_NUMBER;
- if(rest[0])
- return CURLUE_BAD_PORT_NUMBER;
-
- u->portnum = port;
+ u->portnum = (unsigned short) port;
/* generate a new port number string to get rid of leading zeroes etc */
free(u->port);
u->port = aprintf("%ld", port);
@@ -680,6 +681,7 @@ static int ipv4_normalize(struct dynbuf *host)
if(*c == '[')
return HOST_IPV6;
+ errno = 0; /* for strtoul */
while(!done) {
char *endp = NULL;
unsigned long l;
@@ -687,6 +689,13 @@ static int ipv4_normalize(struct dynbuf *host)
/* most importantly this doesn't allow a leading plus or minus */
return HOST_NAME;
l = strtoul(c, &endp, 0);
+ if(errno)
+ return HOST_NAME;
+#if SIZEOF_LONG > 4
+ /* a value larger than 32 bits */
+ if(l > UINT_MAX)
+ return HOST_NAME;
+#endif
parts[n] = l;
c = endp;
@@ -706,16 +715,6 @@ static int ipv4_normalize(struct dynbuf *host)
default:
return HOST_NAME;
}
-
- /* overflow */
- if((l == ULONG_MAX) && (errno == ERANGE))
- return HOST_NAME;
-
-#if SIZEOF_LONG > 4
- /* a value larger than 32 bits */
- if(l > UINT_MAX)
- return HOST_NAME;
-#endif
}
switch(n) {
@@ -846,8 +845,8 @@ out:
return uc;
}
-CURLUcode Curl_url_set_authority(CURLU *u, const char *authority,
- unsigned int flags)
+/* used for HTTP/2 server push */
+CURLUcode Curl_url_set_authority(CURLU *u, const char *authority)
{
CURLUcode result;
struct dynbuf host;
@@ -855,8 +854,8 @@ CURLUcode Curl_url_set_authority(CURLU *u, const char *authority,
DEBUGASSERT(authority);
Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH);
- result = parse_authority(u, authority, strlen(authority), flags,
- &host, !!u->scheme);
+ result = parse_authority(u, authority, strlen(authority),
+ CURLU_DISALLOW_USER, &host, !!u->scheme);
if(result)
Curl_dyn_free(&host);
else {
@@ -1242,6 +1241,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
fragment = strchr(path, '#');
if(fragment) {
fraglen = pathlen - (fragment - path);
+ u->fragment_present = TRUE;
if(fraglen > 1) {
/* skip the leading '#' in the copy but include the terminating null */
if(flags & CURLU_URLENCODE) {
@@ -1269,6 +1269,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
size_t qlen = fragment ? (size_t)(fragment - query) :
pathlen - (query - path);
pathlen -= qlen;
+ u->query_present = TRUE;
if(qlen > 1) {
if(flags & CURLU_URLENCODE) {
struct dynbuf enc;
@@ -1404,6 +1405,8 @@ CURLU *curl_url_dup(const CURLU *in)
DUP(u, in, fragment);
DUP(u, in, zoneid);
u->portnum = in->portnum;
+ u->fragment_present = in->fragment_present;
+ u->query_present = in->query_present;
}
return u;
fail:
@@ -1488,10 +1491,16 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
ptr = u->query;
ifmissing = CURLUE_NO_QUERY;
plusdecode = urldecode;
+ if(ptr && !ptr[0] && !(flags & CURLU_GET_EMPTY))
+ /* there was a blank query and the user do not ask for it */
+ ptr = NULL;
break;
case CURLUPART_FRAGMENT:
ptr = u->fragment;
ifmissing = CURLUE_NO_FRAGMENT;
+ if(!ptr && u->fragment_present && flags & CURLU_GET_EMPTY)
+ /* there was a blank fragment and the user asks for it */
+ ptr = "";
break;
case CURLUPART_URL: {
char *url;
@@ -1499,13 +1508,18 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
char *options = u->options;
char *port = u->port;
char *allochost = NULL;
+ bool show_fragment =
+ u->fragment || (u->fragment_present && flags & CURLU_GET_EMPTY);
+ bool show_query =
+ (u->query && u->query[0]) ||
+ (u->query_present && flags & CURLU_GET_EMPTY);
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",
u->path,
- u->fragment? "#": "",
- u->fragment? u->fragment : "");
+ show_fragment ? "#": "",
+ u->fragment ? u->fragment : "");
}
else if(!u->host)
return CURLUE_NO_HOST;
@@ -1593,9 +1607,9 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
port ? ":": "",
port ? port : "",
u->path ? u->path : "/",
- (u->query && u->query[0]) ? "?": "",
- (u->query && u->query[0]) ? u->query : "",
- u->fragment? "#": "",
+ show_query ? "?": "",
+ u->query ? u->query : "",
+ show_fragment ? "#": "",
u->fragment? u->fragment : "");
free(allochost);
}
@@ -1687,7 +1701,6 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
const char *part, unsigned int flags)
{
char **storep = NULL;
- long port = 0;
bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
bool plusencode = FALSE;
bool urlskipslash = FALSE;
@@ -1730,9 +1743,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
break;
case CURLUPART_QUERY:
storep = &u->query;
+ u->query_present = FALSE;
break;
case CURLUPART_FRAGMENT:
storep = &u->fragment;
+ u->fragment_present = FALSE;
break;
default:
return CURLUE_UNKNOWN_PART;
@@ -1794,18 +1809,26 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
storep = &u->zoneid;
break;
case CURLUPART_PORT:
- {
- char *endp;
- urlencode = FALSE; /* never */
- port = strtol(part, &endp, 10); /* Port number must be decimal */
- if((port <= 0) || (port > 0xffff))
- return CURLUE_BAD_PORT_NUMBER;
- if(*endp)
- /* weirdly provided number, not good! */
+ if(!ISDIGIT(part[0]))
+ /* not a number */
return CURLUE_BAD_PORT_NUMBER;
- storep = &u->port;
- }
- break;
+ else {
+ char *tmp;
+ char *endp;
+ unsigned long port;
+ errno = 0;
+ port = strtoul(part, &endp, 10); /* must be decimal */
+ if(errno || (port > 0xffff) || *endp)
+ /* weirdly provided number, not good! */
+ return CURLUE_BAD_PORT_NUMBER;
+ tmp = strdup(part);
+ if(!tmp)
+ return CURLUE_OUT_OF_MEMORY;
+ free(u->port);
+ u->port = tmp;
+ u->portnum = (unsigned short)port;
+ return CURLUE_OK;
+ }
case CURLUPART_PATH:
urlskipslash = TRUE;
leadingslash = TRUE; /* enforce */
@@ -1816,9 +1839,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
appendquery = (flags & CURLU_APPENDQUERY)?1:0;
equalsencode = appendquery;
storep = &u->query;
+ u->query_present = TRUE;
break;
case CURLUPART_FRAGMENT:
storep = &u->fragment;
+ u->fragment_present = TRUE;
break;
case CURLUPART_URL: {
/*
@@ -1966,9 +1991,5 @@ nomem:
free(*storep);
*storep = (char *)newp;
}
- /* set after the string, to make it not assigned if the allocation above
- fails */
- if(port)
- u->portnum = port;
return CURLUE_OK;
}
diff --git a/libs/libcurl/src/urldata.h b/libs/libcurl/src/urldata.h
index d8c8d07d48..1e606dde5b 100644
--- a/libs/libcurl/src/urldata.h
+++ b/libs/libcurl/src/urldata.h
@@ -55,6 +55,15 @@
struct curl_trc_featt;
+#ifdef USE_ECH
+/* CURLECH_ bits for the tls_ech option */
+# define CURLECH_DISABLE (1<<0)
+# define CURLECH_GREASE (1<<1)
+# define CURLECH_ENABLE (1<<2)
+# define CURLECH_HARD (1<<3)
+# define CURLECH_CLA_CFG (1<<4)
+#endif
+
#ifdef USE_WEBSOCKETS
/* CURLPROTO_GOPHERS (29) is the highest publicly used protocol bit number,
* the rest are internal information. If we use higher bits we only do this on
@@ -104,7 +113,7 @@ typedef unsigned int curl_prot_t;
#define PROTO_FAMILY_SSH (CURLPROTO_SCP|CURLPROTO_SFTP)
#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) || \
- !defined(CURL_DISABLE_POP3)
+ !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_FILE)
/* these protocols support CURLOPT_DIRLISTONLY */
#define CURL_LIST_ONLY_PROTOCOL 1
#endif
@@ -232,8 +241,7 @@ typedef CURLcode (*Curl_datastream)(struct Curl_easy *data,
#ifdef HAVE_GSSAPI
/* Types needed for krb5-ftp connections */
struct krb5buffer {
- void *data;
- size_t size;
+ struct dynbuf buf;
size_t index;
BIT(eof_flag);
};
@@ -279,6 +287,8 @@ struct ssl_peer {
char *dispname; /* display version of hostname */
char *sni; /* SNI version of hostname or NULL if not usable */
ssl_peer_type type; /* type of the peer information */
+ int port; /* port we are talking to */
+ int transport; /* TCP or QUIC */
};
struct ssl_primary_config {
@@ -334,6 +344,8 @@ struct ssl_general_config {
int ca_cache_timeout; /* Certificate store cache timeout (seconds) */
};
+typedef void Curl_ssl_sessionid_dtor(void *sessionid, size_t idsize);
+
/* information stored about one single SSL session */
struct Curl_ssl_session {
char *name; /* host name for which this ID was used */
@@ -341,9 +353,11 @@ struct Curl_ssl_session {
const char *scheme; /* protocol scheme used */
void *sessionid; /* as returned from the SSL layer */
size_t idsize; /* if known, otherwise 0 */
+ Curl_ssl_sessionid_dtor *sessionid_free; /* free `sessionid` callback */
long age; /* just a number, the higher the more recent */
int remote_port; /* remote port */
int conn_to_port; /* remote port for the connection (may be -1) */
+ int transport; /* TCP or QUIC */
struct ssl_primary_config ssl_config; /* setup for this session */
};
@@ -444,14 +458,6 @@ struct ntlmdata {
unsigned char nonce[8];
unsigned int target_info_len;
void *target_info; /* TargetInfo received in the ntlm type-2 message */
-
-#if defined(NTLM_WB_ENABLED)
- /* used for communication with Samba's winbind daemon helper ntlm_auth */
- curl_socket_t ntlm_auth_hlpr_socket;
- pid_t ntlm_auth_hlpr_pid;
- char *challenge; /* The received base64 encoded ntlm type-2 message */
- char *response; /* The generated base64 ntlm type-1/type-3 message */
-#endif
#endif
};
#endif
@@ -632,6 +638,9 @@ enum doh_slots {
DOH_PROBE_SLOT_IPADDR_V6 = 1, /* 'V6' likewise */
/* Space here for (possibly build-specific) additional slot definitions */
+#ifdef USE_HTTPSRR
+ DOH_PROBE_SLOT_HTTPS = 2, /* for HTTPS RR */
+#endif
/* for example */
/* #ifdef WANT_DOH_FOOBAR_TXT */
@@ -647,7 +656,7 @@ enum doh_slots {
*/
struct Curl_handler {
- const char *scheme; /* URL scheme name. */
+ const char *scheme; /* URL scheme name in lowercase */
/* Complement to setup_connection_internals(). This is done before the
transfer "owns" the connection. */
@@ -706,12 +715,18 @@ struct Curl_handler {
CURLcode (*disconnect)(struct Curl_easy *, struct connectdata *,
bool dead_connection);
- /* If used, this function gets called from transfer.c:readwrite_data() to
+ /* If used, this function gets called from transfer.c to
allow the protocol to do extra handling in writing response to
the client. */
CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t blen,
bool is_eos);
+ /* If used, this function gets called from transfer.c to
+ allow the protocol to do extra handling in writing a single response
+ header line to the client. */
+ CURLcode (*write_resp_hd)(struct Curl_easy *data,
+ const char *hd, size_t hdlen, bool is_eos);
+
/* This function can perform various checks on the connection. See
CONNCHECK_* for more information about the checks that can be performed,
and CONNRESULT_* for the results that can be returned. */
@@ -983,7 +998,7 @@ struct connectdata {
int remote_port; /* the remote port, not the proxy port! */
int conn_to_port; /* the remote port to connect to. valid only if
bits.conn_to_port is set */
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
unsigned int scope_id; /* Scope id for IPv6 */
#endif
unsigned short localport;
@@ -1327,22 +1342,28 @@ struct UrlState {
/* Dynamically allocated strings, MUST be freed before this struct is
killed. */
struct dynamically_allocated_data {
- char *proxyuserpwd;
char *uagent;
char *accept_encoding;
char *userpwd;
char *rangeline;
char *ref;
char *host;
+#ifndef CURL_DISABLE_COOKIES
char *cookiehost;
+#endif
+#ifndef CURL_DISABLE_RTSP
char *rtsp_transport;
+#endif
char *te; /* TE: request header */
/* transfer credentials */
char *user;
char *passwd;
+#ifndef CURL_DISABLE_PROXY
+ char *proxyuserpwd;
char *proxyuser;
char *proxypasswd;
+#endif
} aptr;
unsigned char httpwant; /* when non-zero, a specific HTTP version requested
@@ -1379,7 +1400,6 @@ struct UrlState {
BIT(done); /* set to FALSE when Curl_init_do() is called and set to TRUE
when multi_done() is called, to prevent multi_done() to get
invoked twice when the multi interface is used. */
- BIT(previouslypending); /* this transfer WAS in the multi->pending queue */
#ifndef CURL_DISABLE_COOKIES
BIT(cookie_engine);
#endif
@@ -1407,95 +1427,127 @@ struct UrlState {
struct Curl_multi; /* declared in multihandle.c */
-/*
- * This enumeration MUST not use conditional directives (#ifdefs), new
- * null terminated strings MUST be added to the enumeration immediately
- * before STRING_LASTZEROTERMINATED, binary fields immediately before
- * STRING_LAST. When doing so, ensure that the packages/OS400/chkstring.c
- * test is updated and applicable changes for EBCDIC to ASCII conversion
- * are catered for in curl_easy_setopt_ccsid()
- */
enum dupstring {
STRING_CERT, /* client certificate file name */
- STRING_CERT_PROXY, /* client certificate file name */
STRING_CERT_TYPE, /* format for certificate (default: PEM)*/
+ STRING_KEY, /* private key file name */
+ STRING_KEY_PASSWD, /* plain text private key password */
+ STRING_KEY_TYPE, /* format for private key (default: PEM) */
+ STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */
+ STRING_SSL_CAFILE, /* certificate file to verify peer against */
+ STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */
+ STRING_SSL_CIPHER_LIST, /* list of ciphers to use */
+ STRING_SSL_CIPHER13_LIST, /* list of TLS 1.3 ciphers to use */
+ STRING_SSL_CRLFILE, /* crl file to check certificate */
+ STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
+ STRING_SERVICE_NAME, /* Service name */
+#ifndef CURL_DISABLE_PROXY
+ STRING_CERT_PROXY, /* client certificate file name */
STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/
+ STRING_KEY_PROXY, /* private key file name */
+ STRING_KEY_PASSWD_PROXY, /* plain text private key password */
+ STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */
+ STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */
+ STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
+ STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
+ STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */
+ STRING_SSL_CIPHER13_LIST_PROXY, /* list of TLS 1.3 ciphers to use */
+ STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */
+ STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */
+ STRING_PROXY_SERVICE_NAME, /* Proxy service name */
+#endif
+#ifndef CURL_DISABLE_COOKIES
STRING_COOKIE, /* HTTP cookie string to send */
STRING_COOKIEJAR, /* dump all cookies to this file */
+#endif
STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */
STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */
STRING_DEVICE, /* local network interface/address to use */
STRING_ENCODING, /* Accept-Encoding string */
+#ifndef CURL_DISABLE_FTP
STRING_FTP_ACCOUNT, /* ftp account data */
STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */
STRING_FTPPORT, /* port to send with the FTP PORT command */
- STRING_KEY, /* private key file name */
- STRING_KEY_PROXY, /* private key file name */
- STRING_KEY_PASSWD, /* plain text private key password */
- STRING_KEY_PASSWD_PROXY, /* plain text private key password */
- STRING_KEY_TYPE, /* format for private key (default: PEM) */
- STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */
+#endif
+#if defined(HAVE_GSSAPI)
STRING_KRB_LEVEL, /* krb security level */
+#endif
+#ifndef CURL_DISABLE_NETRC
STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find
$HOME/.netrc */
+#endif
+#ifndef CURL_DISABLE_PROXY
STRING_PROXY, /* proxy to use */
STRING_PRE_PROXY, /* pre socks proxy to use */
+#endif
STRING_SET_RANGE, /* range, if used */
STRING_SET_REFERER, /* custom string for the HTTP referer field */
STRING_SET_URL, /* what original URL to work on */
- STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */
- STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */
- STRING_SSL_CAFILE, /* certificate file to verify peer against */
- STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
- STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */
- STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
- STRING_SSL_CIPHER_LIST, /* list of ciphers to use */
- STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */
- STRING_SSL_CIPHER13_LIST, /* list of TLS 1.3 ciphers to use */
- STRING_SSL_CIPHER13_LIST_PROXY, /* list of TLS 1.3 ciphers to use */
STRING_USERAGENT, /* User-Agent string */
- STRING_SSL_CRLFILE, /* crl file to check certificate */
- STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */
- STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
- STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */
STRING_SSL_ENGINE, /* name of ssl engine */
STRING_USERNAME, /* <username>, if used */
STRING_PASSWORD, /* <password>, if used */
STRING_OPTIONS, /* <options>, if used */
+#ifndef CURL_DISABLE_PROXY
STRING_PROXYUSERNAME, /* Proxy <username>, if used */
STRING_PROXYPASSWORD, /* Proxy <password>, if used */
STRING_NOPROXY, /* List of hosts which should not use the proxy, if
used */
+#endif
+#ifndef CURL_DISABLE_RTSP
STRING_RTSP_SESSION_ID, /* Session ID to use */
STRING_RTSP_STREAM_URI, /* Stream URI for this request */
STRING_RTSP_TRANSPORT, /* Transport for this session */
+#endif
+#ifdef USE_SSH
STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */
STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
STRING_SSH_HOST_PUBLIC_KEY_SHA256, /* sha256 of host public key in base64 */
STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */
- STRING_PROXY_SERVICE_NAME, /* Proxy service name */
- STRING_SERVICE_NAME, /* Service name */
+#endif
+#ifndef CURL_DISABLE_SMTP
STRING_MAIL_FROM,
STRING_MAIL_AUTH,
+#endif
+#ifdef USE_TLS_SRP
STRING_TLSAUTH_USERNAME, /* TLS auth <username> */
- STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth <username> */
STRING_TLSAUTH_PASSWORD, /* TLS auth <password> */
+#ifndef CURL_DISABLE_PROXY
+ STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth <username> */
STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth <password> */
+#endif
+#endif
STRING_BEARER, /* <bearer>, if used */
+#ifdef USE_UNIX_SOCKETS
STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */
+#endif
STRING_TARGET, /* CURLOPT_REQUEST_TARGET */
+#ifndef CURL_DISABLE_DOH
STRING_DOH, /* CURLOPT_DOH_URL */
+#endif
+#ifndef CURL_DISABLE_ALTSVC
STRING_ALTSVC, /* CURLOPT_ALTSVC */
+#endif
+#ifndef CURL_DISABLE_HSTS
STRING_HSTS, /* CURLOPT_HSTS */
+#endif
STRING_SASL_AUTHZID, /* CURLOPT_SASL_AUTHZID */
+#ifdef USE_ARES
STRING_DNS_SERVERS,
STRING_DNS_INTERFACE,
STRING_DNS_LOCAL_IP4,
STRING_DNS_LOCAL_IP6,
+#endif
STRING_SSL_EC_CURVES,
+#ifndef CURL_DISABLE_AWS
STRING_AWS_SIGV4, /* Parameters for V4 signature */
+#endif
+#ifndef CURL_DISABLE_PROXY
STRING_HAPROXY_CLIENT_IP, /* CURLOPT_HAPROXY_CLIENT_IP */
+#endif
+ STRING_ECH_CONFIG, /* CURLOPT_ECH_CONFIG */
+ STRING_ECH_PUBLIC, /* CURLOPT_ECH_PUBLIC */
/* -- end of null-terminated strings -- */
@@ -1510,13 +1562,15 @@ enum dupstring {
enum dupblob {
BLOB_CERT,
- BLOB_CERT_PROXY,
BLOB_KEY,
- BLOB_KEY_PROXY,
BLOB_SSL_ISSUERCERT,
- BLOB_SSL_ISSUERCERT_PROXY,
BLOB_CAINFO,
+#ifndef CURL_DISABLE_PROXY
+ BLOB_CERT_PROXY,
+ BLOB_KEY_PROXY,
+ BLOB_SSL_ISSUERCERT_PROXY,
BLOB_CAINFO_PROXY,
+#endif
BLOB_LAST
};
@@ -1667,7 +1721,7 @@ struct UserDefined {
unsigned int new_file_perms; /* when creating remote files */
char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
struct curl_blob *blobs[BLOB_LAST];
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
unsigned int scope_id; /* Scope id for IPv6 */
#endif
curl_prot_t allowed_protocols;
@@ -1735,7 +1789,9 @@ struct UserDefined {
BIT(cookiesession); /* new cookie session? */
#endif
BIT(crlf); /* convert crlf on ftp upload(?) */
+#ifdef USE_SSH
BIT(ssh_compression); /* enable SSH compression */
+#endif
/* Here follows boolean settings that define how to behave during
this session. They are STATIC, set by libcurl users or at least initially
@@ -1745,7 +1801,9 @@ struct UserDefined {
don't want lengthy cleanups to delay termination,
e.g. after a DNS timeout */
BIT(get_filetime); /* get the time and get of the remote file */
+#ifndef CURL_DISABLE_PROXY
BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */
+#endif
BIT(prefer_ascii); /* ASCII rather than binary */
BIT(remote_append); /* append, not overwrite, on upload */
#ifdef CURL_LIST_ONLY_PROTOCOL
@@ -1772,7 +1830,9 @@ struct UserDefined {
location: */
BIT(opt_no_body); /* as set with CURLOPT_NOBODY */
BIT(verbose); /* output verbosity */
+#if defined(HAVE_GSSAPI)
BIT(krb); /* Kerberos connection requested */
+#endif
BIT(reuse_forbid); /* forbidden to be reused, close after use */
BIT(reuse_fresh); /* do not reuse an existing connection */
BIT(no_signal); /* do not use any signal/alarm handler */
@@ -1797,9 +1857,13 @@ struct UserDefined {
BIT(suppress_connect_headers); /* suppress proxy CONNECT response headers
from user callbacks */
BIT(dns_shuffle_addresses); /* whether to shuffle addresses before use */
+#ifndef CURL_DISABLE_PROXY
BIT(haproxyprotocol); /* whether to send HAProxy PROXY protocol v1
header */
+#endif
+#ifdef USE_UNIX_SOCKETS
BIT(abstract_unix_socket);
+#endif
BIT(disallow_username_in_url); /* disallow username in url */
#ifndef CURL_DISABLE_DOH
BIT(doh); /* DNS-over-HTTPS enabled */
@@ -1811,6 +1875,9 @@ struct UserDefined {
#ifdef USE_WEBSOCKETS
BIT(ws_raw_mode);
#endif
+#ifdef USE_ECH
+ int tls_ech; /* TLS ECH configuration */
+#endif
};
#ifndef CURL_DISABLE_MIME
diff --git a/libs/libcurl/src/vauth/cleartext.c b/libs/libcurl/src/vauth/cleartext.c
index 8234dced08..015df2c33b 100644
--- a/libs/libcurl/src/vauth/cleartext.c
+++ b/libs/libcurl/src/vauth/cleartext.c
@@ -107,12 +107,11 @@ CURLcode Curl_auth_create_plain_message(const char *authzid,
* valuep [in] - The user name or user's password.
* out [out] - The result storage.
*
- * Returns CURLE_OK on success.
+ * Returns void.
*/
-CURLcode Curl_auth_create_login_message(const char *valuep, struct bufref *out)
+void Curl_auth_create_login_message(const char *valuep, struct bufref *out)
{
Curl_bufref_set(out, valuep, strlen(valuep), NULL);
- return CURLE_OK;
}
/*
@@ -126,13 +125,13 @@ CURLcode Curl_auth_create_login_message(const char *valuep, struct bufref *out)
* user [in] - The user name.
* out [out] - The result storage.
*
- * Returns CURLE_OK on success.
+ * Returns void.
*/
-CURLcode Curl_auth_create_external_message(const char *user,
+void Curl_auth_create_external_message(const char *user,
struct bufref *out)
{
/* This is the same formatting as the login message */
- return Curl_auth_create_login_message(user, out);
+ Curl_auth_create_login_message(user, out);
}
#endif /* if no users */
diff --git a/libs/libcurl/src/vauth/digest.c b/libs/libcurl/src/vauth/digest.c
index 8a0e7335bf..59ab4e842e 100644
--- a/libs/libcurl/src/vauth/digest.c
+++ b/libs/libcurl/src/vauth/digest.c
@@ -288,7 +288,7 @@ static CURLcode auth_decode_digest_md5_message(const struct bufref *chlgref,
/* Retrieve realm string from the challenge */
if(!auth_digest_get_key_value(chlg, "realm=\"", realm, rlen, '\"')) {
/* Challenge does not have a realm, set empty string [RFC2831] page 6 */
- strcpy(realm, "");
+ *realm = '\0';
}
/* Retrieve algorithm string from the challenge */
diff --git a/libs/libcurl/src/vauth/vauth.h b/libs/libcurl/src/vauth/vauth.h
index 5d5c2f4c9c..fb43bc5e02 100644
--- a/libs/libcurl/src/vauth/vauth.h
+++ b/libs/libcurl/src/vauth/vauth.h
@@ -79,12 +79,10 @@ CURLcode Curl_auth_create_plain_message(const char *authzid,
struct bufref *out);
/* This is used to generate a LOGIN cleartext message */
-CURLcode Curl_auth_create_login_message(const char *value,
- struct bufref *out);
+void Curl_auth_create_login_message(const char *value, struct bufref *out);
/* This is used to generate an EXTERNAL cleartext message */
-CURLcode Curl_auth_create_external_message(const char *user,
- struct bufref *out);
+void Curl_auth_create_external_message(const char *user, struct bufref *out);
#ifndef CURL_DISABLE_DIGEST_AUTH
/* This is used to generate a CRAM-MD5 response message */
diff --git a/libs/libcurl/src/version.c b/libs/libcurl/src/version.c
index d21e4a194b..bb63f2583f 100644
--- a/libs/libcurl/src/version.c
+++ b/libs/libcurl/src/version.c
@@ -55,6 +55,7 @@
#ifdef USE_LIBRTMP
#include <librtmp/rtmp.h>
+#include "curl_rtmp.h"
#endif
#ifdef HAVE_LIBZ
@@ -152,7 +153,7 @@ char *curl_version(void)
#ifdef USE_NGHTTP2
char h2_version[40];
#endif
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
char h3_version[40];
#endif
#ifdef USE_LIBRTMP
@@ -174,8 +175,7 @@ char *curl_version(void)
/* Override version string when environment variable CURL_VERSION is set */
const char *debugversion = getenv("CURL_VERSION");
if(debugversion) {
- strncpy(out, debugversion, sizeof(out)-1);
- out[sizeof(out)-1] = '\0';
+ msnprintf(out, sizeof(out), "%s", debugversion);
return out;
}
#endif
@@ -208,6 +208,8 @@ char *curl_version(void)
src[i++] = idn_version;
#elif defined(USE_WIN32_IDN)
src[i++] = (char *)"WinIDN";
+#elif defined(USE_APPLE_IDN)
+ src[i++] = (char *)"AppleIDN";
#endif
#ifdef USE_LIBPSL
@@ -233,25 +235,13 @@ char *curl_version(void)
Curl_http2_ver(h2_version, sizeof(h2_version));
src[i++] = h2_version;
#endif
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
Curl_quic_ver(h3_version, sizeof(h3_version));
src[i++] = h3_version;
#endif
#ifdef USE_LIBRTMP
- {
- char suff[2];
- if(RTMP_LIB_VERSION & 0xff) {
- suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1;
- suff[1] = '\0';
- }
- else
- suff[0] = '\0';
-
- msnprintf(rtmp_version, sizeof(rtmp_version), "librtmp/%d.%d%s",
- RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
- suff);
- src[i++] = rtmp_version;
- }
+ Curl_rtmp_version(rtmp_version, sizeof(rtmp_version));
+ src[i++] = rtmp_version;
#endif
#ifdef USE_HYPER
msnprintf(hyper_buf, sizeof(hyper_buf), "Hyper/%s", hyper_version());
@@ -428,6 +418,14 @@ static int https_proxy_present(curl_version_info_data *info)
}
#endif
+#if defined(USE_SSL) && defined(USE_ECH)
+static int ech_present(curl_version_info_data *info)
+{
+ (void) info;
+ return Curl_ssl_supports(NULL, SSLSUPP_ECH);
+}
+#endif
+
/*
* Features table.
*
@@ -456,6 +454,9 @@ static const struct feat features_table[] = {
#ifdef DEBUGBUILD
FEATURE("Debug", NULL, CURL_VERSION_DEBUG),
#endif
+#if defined(USE_SSL) && defined(USE_ECH)
+ FEATURE("ECH", ech_present, 0),
+#endif
#ifdef USE_GSASL
FEATURE("gsasl", NULL, CURL_VERSION_GSASL),
#endif
@@ -468,17 +469,17 @@ static const struct feat features_table[] = {
#if defined(USE_NGHTTP2)
FEATURE("HTTP2", NULL, CURL_VERSION_HTTP2),
#endif
-#if defined(ENABLE_QUIC)
+#if defined(USE_HTTP3)
FEATURE("HTTP3", NULL, CURL_VERSION_HTTP3),
#endif
#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \
!defined(CURL_DISABLE_HTTP)
FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY),
#endif
-#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
FEATURE("IDN", idn_present, CURL_VERSION_IDN),
#endif
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
FEATURE("IPv6", NULL, CURL_VERSION_IPV6),
#endif
#ifdef USE_KERBEROS5
@@ -497,10 +498,6 @@ static const struct feat features_table[] = {
#ifdef USE_NTLM
FEATURE("NTLM", NULL, CURL_VERSION_NTLM),
#endif
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
- defined(NTLM_WB_ENABLED)
- FEATURE("NTLM_WB", NULL, CURL_VERSION_NTLM_WB),
-#endif
#if defined(USE_LIBPSL)
FEATURE("PSL", NULL, CURL_VERSION_PSL),
#endif
@@ -572,7 +569,8 @@ static curl_version_info_data version_info = {
NULL, /* zstd version */
NULL, /* Hyper version */
NULL, /* gsasl version */
- feature_names
+ feature_names,
+ NULL /* rtmp version */
};
curl_version_info_data *curl_version_info(CURLversion stamp)
@@ -647,7 +645,7 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
}
#endif
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
{
static char quicbuffer[80];
Curl_quic_ver(quicbuffer, sizeof(quicbuffer));
@@ -680,5 +678,13 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
feature_names[n] = NULL; /* Terminate array. */
version_info.features = features;
+#ifdef USE_LIBRTMP
+ {
+ static char rtmp_version[30];
+ Curl_rtmp_version(rtmp_version, sizeof(rtmp_version));
+ version_info.rtmp_version = rtmp_version;
+ }
+#endif
+
return &version_info;
}
diff --git a/libs/libcurl/src/vquic/curl_msh3.c b/libs/libcurl/src/vquic/curl_msh3.c
index a5b3e54c3b..5827d99c24 100644
--- a/libs/libcurl/src/vquic/curl_msh3.c
+++ b/libs/libcurl/src/vquic/curl_msh3.c
@@ -27,6 +27,7 @@
#ifdef USE_MSH3
#include "urldata.h"
+#include "hash.h"
#include "timeval.h"
#include "multiif.h"
#include "sendf.h"
@@ -118,6 +119,7 @@ struct cf_msh3_ctx {
struct cf_call_data call_data;
struct curltime connect_started; /* time the current attempt started */
struct curltime handshake_at; /* time connect handshake finished */
+ struct Curl_hash streams; /* hash `data->id` to `stream_ctx` */
/* Flags written by msh3/msquic thread */
bool handshake_complete;
bool handshake_succeeded;
@@ -127,6 +129,8 @@ struct cf_msh3_ctx {
BIT(active);
};
+static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data);
+
/* How to access `call_data` from a cf_msh3 filter */
#undef CF_CTX_CALL_DATA
#define CF_CTX_CALL_DATA(cf) \
@@ -153,18 +157,26 @@ struct stream_ctx {
bool recv_header_complete;
};
-#define H3_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \
- ((struct HTTP *)(d)->req.p.http)->h3_ctx \
- : NULL))
-#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
-#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
- H3_STREAM_CTX(d)->id : -2)
+#define H3_STREAM_CTX(ctx,data) ((struct stream_ctx *)((data && ctx)? \
+ Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
+
+static void h3_stream_ctx_free(struct stream_ctx *stream)
+{
+ Curl_bufq_free(&stream->recvbuf);
+ free(stream);
+}
+static void h3_stream_hash_free(void *stream)
+{
+ DEBUGASSERT(stream);
+ h3_stream_ctx_free((struct stream_ctx *)stream);
+}
static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(stream)
return CURLE_OK;
@@ -173,25 +185,29 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
if(!stream)
return CURLE_OUT_OF_MEMORY;
- H3_STREAM_LCTX(data) = stream;
stream->req = ZERO_NULL;
msh3_lock_initialize(&stream->recv_lock);
Curl_bufq_init2(&stream->recvbuf, H3_STREAM_CHUNK_SIZE,
H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
CURL_TRC_CF(data, cf, "data setup");
+
+ if(!Curl_hash_offt_set(&ctx->streams, data->id, stream)) {
+ h3_stream_ctx_free(stream);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
return CURLE_OK;
}
static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)cf;
if(stream) {
CURL_TRC_CF(data, cf, "easy handle is done");
- Curl_bufq_free(&stream->recvbuf);
- free(stream);
- H3_STREAM_LCTX(data) = NULL;
+ Curl_hash_offt_remove(&ctx->streams, data->id);
}
}
@@ -213,7 +229,8 @@ static void drain_stream_from_other_thread(struct Curl_easy *data,
static void drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
unsigned char bits;
(void)cf;
@@ -311,7 +328,8 @@ static int decode_status_code(const char *value, size_t len)
static CURLcode write_resp_raw(struct Curl_easy *data,
const void *mem, size_t memlen)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result = CURLE_OK;
ssize_t nwritten;
@@ -337,10 +355,12 @@ static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
const MSH3_HEADER *hd)
{
struct Curl_easy *data = userp;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result;
(void)Request;
+ DEBUGF(infof(data, "[MSH3] header received, stream=%d", !!stream));
if(!stream || stream->recv_header_complete) {
return;
}
@@ -386,7 +406,8 @@ static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
const uint8_t *buf)
{
struct Curl_easy *data = IfContext;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result;
bool rv = FALSE;
@@ -425,7 +446,8 @@ static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
bool aborted, uint64_t error)
{
struct Curl_easy *data = IfContext;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)Request;
if(!stream)
@@ -444,7 +466,8 @@ static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request,
void *IfContext)
{
struct Curl_easy *data = IfContext;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(!stream)
return;
@@ -456,7 +479,8 @@ static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request,
void *IfContext, void *SendContext)
{
struct Curl_easy *data = IfContext;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(!stream)
return;
(void)Request;
@@ -468,7 +492,8 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
struct Curl_easy *data,
CURLcode *err)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nread = -1;
if(!stream) {
@@ -501,7 +526,8 @@ out:
static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
/* we have no indication from msh3 when it would be a good time
* to juggle the connection again. So, we compromise by calling
@@ -518,17 +544,17 @@ static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data)
static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nread = -1;
struct cf_call_data save;
- (void)cf;
+ CURL_TRC_CF(data, cf, "cf_recv(len=%zu), stream=%d", len, !!stream);
if(!stream) {
*err = CURLE_RECV_ERROR;
return -1;
}
CF_DATA_SAVE(save, cf, data);
- CURL_TRC_CF(data, cf, "req: recv with %zu byte buffer", len);
msh3_lock_acquire(&stream->recv_lock);
@@ -570,7 +596,7 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct h1_req_parser h1;
struct dynhds h2_headers;
MSH3_HEADER *nva = NULL;
@@ -682,7 +708,7 @@ static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf,
struct easy_pollset *ps)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
@@ -701,7 +727,8 @@ static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf,
static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct cf_call_data save;
bool pending = FALSE;
@@ -737,7 +764,8 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
struct Curl_easy *data,
int event, int arg1, void *arg2)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_msh3_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct cf_call_data save;
CURLcode result = CURLE_OK;
@@ -785,6 +813,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
CURLcode result;
bool verify;
+ Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
conn_config = Curl_ssl_cf_get_primary_config(cf);
if(!conn_config)
return CURLE_FAILED_INIT;
@@ -911,6 +940,7 @@ static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data)
MsH3ApiClose(ctx->api);
ctx->api = NULL;
}
+ Curl_hash_destroy(&ctx->streams);
if(ctx->active) {
/* We share our socket at cf->conn->sock[cf->sockindex] when active.
@@ -1019,6 +1049,20 @@ struct Curl_cftype Curl_cft_http3 = {
cf_msh3_query,
};
+static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data)
+{
+ if(data && data->conn) {
+ struct Curl_cfilter *cf = data->conn->cfilter[FIRSTSOCKET];
+ while(cf) {
+ if(cf->cft == &Curl_cft_http3)
+ return cf->ctx;
+ cf = cf->next;
+ }
+ }
+ DEBUGF(infof(data, "no filter context found"));
+ return NULL;
+}
+
CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct connectdata *conn,
diff --git a/libs/libcurl/src/vquic/curl_ngtcp2.c b/libs/libcurl/src/vquic/curl_ngtcp2.c
index f4c66c71ac..9bc4b3a5a5 100644
--- a/libs/libcurl/src/vquic/curl_ngtcp2.c
+++ b/libs/libcurl/src/vquic/curl_ngtcp2.c
@@ -44,6 +44,7 @@
#endif
#include "urldata.h"
+#include "hash.h"
#include "sendf.h"
#include "strdup.h"
#include "rand.h"
@@ -113,7 +114,7 @@ void Curl_ngtcp2_ver(char *p, size_t len)
struct cf_ngtcp2_ctx {
struct cf_quic_ctx q;
struct ssl_peer peer;
- struct quic_tls_ctx tls;
+ struct curl_tls_ctx tls;
ngtcp2_path connected_path;
ngtcp2_conn *qconn;
ngtcp2_cid dcid;
@@ -130,9 +131,14 @@ struct cf_ngtcp2_ctx {
struct curltime handshake_at; /* time connect handshake finished */
struct curltime reconnect_at; /* time the next attempt should start */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
+ struct dynbuf scratch; /* temp buffer for header construction */
+ struct Curl_hash streams; /* hash `data->id` to `h3_stream_ctx` */
size_t max_stream_window; /* max flow window for one stream */
uint64_t max_idle_ms; /* max idle time for QUIC connection */
+ uint64_t used_bidi_streams; /* bidi streams we have opened */
+ uint64_t max_bidi_streams; /* max bidi streams we can open */
int qlogfd;
+ BIT(conn_closed); /* connection is closed */
};
/* How to access `call_data` from a cf_ngtcp2 filter */
@@ -140,18 +146,27 @@ struct cf_ngtcp2_ctx {
#define CF_CTX_CALL_DATA(cf) \
((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
+struct pkt_io_ctx;
+static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct pkt_io_ctx *pktx);
+static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct pkt_io_ctx *pktx);
+
/**
* All about the H3 internals of a stream
*/
struct h3_stream_ctx {
- int64_t id; /* HTTP/3 protocol identifier */
+ curl_int64_t id; /* HTTP/3 protocol identifier */
struct bufq sendbuf; /* h3 request body */
struct h1_req_parser h1; /* h1 request parsing */
size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
size_t upload_blocked_len; /* the amount written last and EGAINed */
- uint64_t error3; /* HTTP/3 stream error code */
+ curl_uint64_t error3; /* HTTP/3 stream error code */
curl_off_t upload_left; /* number of request bytes left to upload */
int status_code; /* HTTP status code */
+ CURLcode xfer_result; /* result from xfer_resp_write(_hd) */
bool resp_hds_complete; /* we have a complete, final response */
bool closed; /* TRUE on stream close */
bool reset; /* TRUE on stream reset */
@@ -159,18 +174,29 @@ struct h3_stream_ctx {
BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
};
-#define H3_STREAM_CTX(d) ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \
- ((struct HTTP *)(d)->req.p.http)->h3_ctx \
- : NULL))
-#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
-#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
- H3_STREAM_CTX(d)->id : -2)
+#define H3_STREAM_CTX(ctx,data) ((struct h3_stream_ctx *)(\
+ data? Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
+#define H3_STREAM_CTX_ID(ctx,id) ((struct h3_stream_ctx *)(\
+ Curl_hash_offt_get(&(ctx)->streams, (id))))
+
+static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
+{
+ Curl_bufq_free(&stream->sendbuf);
+ Curl_h1_req_parse_free(&stream->h1);
+ free(stream);
+}
+
+static void h3_stream_hash_free(void *stream)
+{
+ DEBUGASSERT(stream);
+ h3_stream_ctx_free((struct h3_stream_ctx *)stream);
+}
static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(!data || !data->req.p.http) {
failf(data, "initialization failure, transfer not http initialized");
@@ -191,59 +217,85 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
stream->sendbuf_len_in_flight = 0;
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
- H3_STREAM_LCTX(data) = stream;
+ if(!Curl_hash_offt_set(&ctx->streams, data->id, stream)) {
+ h3_stream_ctx_free(stream);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
return CURLE_OK;
}
-static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
+static void cf_ngtcp2_stream_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct h3_stream_ctx *stream)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ DEBUGASSERT(data);
+ DEBUGASSERT(stream);
+ if(!stream->closed && ctx->qconn && ctx->h3conn) {
+ CURLcode result;
+
+ nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL);
+ ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL);
+ stream->closed = TRUE;
+ (void)ngtcp2_conn_shutdown_stream(ctx->qconn, 0, stream->id,
+ NGHTTP3_H3_REQUEST_CANCELLED);
+ result = cf_progress_egress(cf, data, NULL);
+ if(result)
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cancel stream -> %d",
+ stream->id, result);
+ }
+}
+static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)cf;
if(stream) {
- CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id);
- if(ctx->h3conn && !stream->closed) {
- nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream->id);
- nghttp3_conn_close_stream(ctx->h3conn, stream->id,
- NGHTTP3_H3_REQUEST_CANCELLED);
- nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL);
- ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL);
- stream->closed = TRUE;
- }
-
- Curl_bufq_free(&stream->sendbuf);
- Curl_h1_req_parse_free(&stream->h1);
- free(stream);
- H3_STREAM_LCTX(data) = NULL;
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] easy handle is done",
+ stream->id);
+ cf_ngtcp2_stream_close(cf, data, stream);
+ Curl_hash_offt_remove(&ctx->streams, data->id);
}
}
static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
struct Curl_easy *data,
- int64_t stream_id)
+ int64_t stream_id,
+ struct h3_stream_ctx **pstream)
{
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *sdata;
+ struct h3_stream_ctx *stream;
(void)cf;
- if(H3_STREAM_ID(data) == stream_id) {
+ stream = H3_STREAM_CTX(ctx, data);
+ if(stream && stream->id == stream_id) {
+ *pstream = stream;
return data;
}
else {
DEBUGASSERT(data->multi);
for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
- if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream_id) {
+ if(sdata->conn != data->conn)
+ continue;
+ stream = H3_STREAM_CTX(ctx, sdata);
+ if(stream && stream->id == stream_id) {
+ *pstream = stream;
return sdata;
}
}
}
+ *pstream = NULL;
return NULL;
}
static void h3_drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
unsigned char bits;
(void)cf;
@@ -289,12 +341,6 @@ static void pktx_init(struct pkt_io_ctx *pktx,
pktx_update_time(pktx, cf);
}
-static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct pkt_io_ctx *pktx);
-static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct pkt_io_ctx *pktx);
static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
uint64_t datalen, void *user_data,
void *stream_user_data);
@@ -380,13 +426,60 @@ static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
return 0;
}
+static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
+static bool cf_ngtcp2_err_is_fatal(int code)
+{
+ return (NGTCP2_ERR_FATAL >= code) ||
+ (NGTCP2_ERR_DROP_CONN == code) ||
+ (NGTCP2_ERR_IDLE_CLOSE == code);
+}
+
+static void cf_ngtcp2_err_set(struct Curl_cfilter *cf,
+ struct Curl_easy *data, int code)
+{
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ if(!ctx->last_error.error_code) {
+ if(NGTCP2_ERR_CRYPTO == code) {
+ ngtcp2_ccerr_set_tls_alert(&ctx->last_error,
+ ngtcp2_conn_get_tls_alert(ctx->qconn),
+ NULL, 0);
+ }
+ else {
+ ngtcp2_ccerr_set_liberr(&ctx->last_error, code, NULL, 0);
+ }
+ }
+ if(cf_ngtcp2_err_is_fatal(code))
+ cf_ngtcp2_conn_close(cf, data);
+}
+
+static bool cf_ngtcp2_h3_err_is_fatal(int code)
+{
+ return (NGHTTP3_ERR_FATAL >= code) ||
+ (NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM == code);
+}
+
+static void cf_ngtcp2_h3_err_set(struct Curl_cfilter *cf,
+ struct Curl_easy *data, int code)
+{
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ if(!ctx->last_error.error_code) {
+ ngtcp2_ccerr_set_application_error(&ctx->last_error,
+ nghttp3_err_infer_quic_app_error_code(code), NULL, 0);
+ }
+ if(cf_ngtcp2_h3_err_is_fatal(code))
+ cf_ngtcp2_conn_close(cf, data);
+}
+
static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
- int64_t stream_id, uint64_t offset,
+ int64_t sid, uint64_t offset,
const uint8_t *buf, size_t buflen,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ curl_int64_t stream_id = (curl_int64_t)sid;
nghttp3_ssize nconsumed;
int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0;
struct Curl_easy *data = stream_user_data;
@@ -395,18 +488,18 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
nconsumed =
nghttp3_conn_read_stream(ctx->h3conn, stream_id, buf, buflen, fin);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read_stream(len=%zu) -> %zd",
- stream_id, buflen, nconsumed);
+ if(!data)
+ data = CF_DATA_CURRENT(cf);
+ if(data)
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read_stream(len=%zu) -> %zd",
+ stream_id, buflen, nconsumed);
if(nconsumed < 0) {
- if(!data) {
- struct Curl_easy *cdata = CF_DATA_CURRENT(cf);
- CURL_TRC_CF(cdata, cf, "[%" PRId64 "] nghttp3 error on stream not "
- "used by us, ignored", stream_id);
- return 0;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX_ID(ctx, stream_id);
+ if(data && stream) {
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] error on known stream, "
+ "reset=%d, closed=%d",
+ stream_id, stream->reset, stream->closed);
}
- ngtcp2_ccerr_set_application_error(
- &ctx->last_error,
- nghttp3_err_infer_quic_app_error_code((int)nconsumed), NULL, 0);
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -442,41 +535,45 @@ cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
}
static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
- int64_t stream3_id, uint64_t app_error_code,
+ int64_t sid, uint64_t app_error_code,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
- struct Curl_easy *data = stream_user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct Curl_easy *data = stream_user_data;
+ curl_int64_t stream_id = (curl_int64_t)sid;
int rv;
(void)tconn;
- (void)data;
/* stream is closed... */
+ if(!data)
+ data = CF_DATA_CURRENT(cf);
+ if(!data)
+ return NGTCP2_ERR_CALLBACK_FAILURE;
if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
app_error_code = NGHTTP3_H3_NO_ERROR;
}
- rv = nghttp3_conn_close_stream(ctx->h3conn, stream3_id,
- app_error_code);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] quic close(err=%"
- PRIu64 ") -> %d", stream3_id, app_error_code, rv);
+ rv = nghttp3_conn_close_stream(ctx->h3conn, stream_id, app_error_code);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] quic close(app_error=%"
+ CURL_PRIu64 ") -> %d", stream_id, (curl_uint64_t)app_error_code,
+ rv);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
- ngtcp2_ccerr_set_application_error(
- &ctx->last_error, nghttp3_err_infer_quic_app_error_code(rv), NULL, 0);
+ cf_ngtcp2_h3_err_set(cf, data, rv);
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
-static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
+static int cb_stream_reset(ngtcp2_conn *tconn, int64_t sid,
uint64_t final_size, uint64_t app_error_code,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ curl_int64_t stream_id = (curl_int64_t)sid;
struct Curl_easy *data = stream_user_data;
int rv;
(void)tconn;
@@ -485,7 +582,7 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
(void)data;
rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reset -> %d", stream_id, rv);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -516,19 +613,26 @@ static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
uint64_t max_streams,
void *user_data)
{
- (void)tconn;
- (void)max_streams;
- (void)user_data;
+ struct Curl_cfilter *cf = user_data;
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct Curl_easy *data = CF_DATA_CURRENT(cf);
+ (void)tconn;
+ ctx->max_bidi_streams = max_streams;
+ if(data)
+ CURL_TRC_CF(data, cf, "max bidi streams now %" CURL_PRIu64
+ ", used %" CURL_PRIu64, (curl_uint64_t)ctx->max_bidi_streams,
+ (curl_uint64_t)ctx->used_bidi_streams);
return 0;
}
-static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
+static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t sid,
uint64_t max_data, void *user_data,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ curl_int64_t stream_id = (curl_int64_t)sid;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
struct Curl_easy *s_data;
struct h3_stream_ctx *stream;
@@ -541,12 +645,12 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
- s_data = get_stream_easy(cf, data, stream_id);
- stream = H3_STREAM_CTX(s_data);
- if(stream && stream->quic_flow_blocked) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] unblock quic flow", stream_id);
+ s_data = get_stream_easy(cf, data, stream_id, &stream);
+ if(s_data && stream && stream->quic_flow_blocked) {
+ CURL_TRC_CF(s_data, cf, "[%" CURL_PRId64 "] unblock quic flow",
+ stream_id);
stream->quic_flow_blocked = FALSE;
- h3_drain_stream(cf, data);
+ h3_drain_stream(cf, s_data);
}
return 0;
}
@@ -676,7 +780,7 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
if(rv) {
failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
ngtcp2_strerror(rv));
- ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0);
+ cf_ngtcp2_err_set(cf, data, rv);
return CURLE_SEND_ERROR;
}
result = cf_progress_ingress(cf, data, pktx);
@@ -712,7 +816,7 @@ static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
if(want_recv || want_send) {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct cf_call_data save;
bool c_exhaust, s_exhaust;
@@ -730,13 +834,15 @@ static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
}
}
-static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
+static int cb_h3_stream_close(nghttp3_conn *conn, int64_t sid,
uint64_t app_error_code, void *user_data,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ curl_int64_t stream_id = (curl_int64_t)sid;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)conn;
(void)stream_id;
@@ -745,24 +851,50 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
return 0;
stream->closed = TRUE;
- stream->error3 = app_error_code;
+ stream->error3 = (curl_uint64_t)app_error_code;
if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
stream->reset = TRUE;
stream->send_closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" PRId64 "] RESET: error %" PRId64,
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] RESET: error %" CURL_PRIu64,
stream->id, stream->error3);
}
else {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] CLOSED", stream->id);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] CLOSED", stream->id);
}
h3_drain_stream(cf, data);
return 0;
}
-static CURLcode write_resp_hds(struct Curl_easy *data,
- const char *buf, size_t blen)
+static void h3_xfer_write_resp_hd(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct h3_stream_ctx *stream,
+ const char *buf, size_t blen, bool eos)
{
- return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
+
+ /* If we already encountered an error, skip further writes */
+ if(!stream->xfer_result) {
+ stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos);
+ if(stream->xfer_result)
+ CURL_TRC_CF(data, cf, "[%"CURL_PRId64"] error %d writing %zu "
+ "bytes of headers", stream->id, stream->xfer_result, blen);
+ }
+}
+
+static void h3_xfer_write_resp(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct h3_stream_ctx *stream,
+ const char *buf, size_t blen, bool eos)
+{
+
+ /* If we already encountered an error, skip further writes */
+ if(!stream->xfer_result) {
+ stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos);
+ /* If the transfer write is errored, we do not want any more data */
+ if(stream->xfer_result) {
+ CURL_TRC_CF(data, cf, "[%"CURL_PRId64"] error %d writing %zu bytes "
+ "of data", stream->id, stream->xfer_result, blen);
+ }
+ }
}
static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
@@ -772,8 +904,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
- CURLcode result;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)conn;
(void)stream3_id;
@@ -781,19 +912,14 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
if(!stream)
return NGHTTP3_ERR_CALLBACK_FAILURE;
- result = Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
- if(result) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d",
- stream->id, blen, result);
- return NGHTTP3_ERR_CALLBACK_FAILURE;
- }
+ h3_xfer_write_resp(cf, data, stream, (char *)buf, blen, FALSE);
if(blen) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] ACK %zu bytes of DATA",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] ACK %zu bytes of DATA",
stream->id, blen);
ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id, blen);
ngtcp2_conn_extend_max_offset(ctx->qconn, blen);
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu", stream->id, blen);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] DATA len=%zu", stream->id, blen);
return 0;
}
@@ -813,13 +939,14 @@ static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream3_id,
return 0;
}
-static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
+static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
int fin, void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
- CURLcode result = CURLE_OK;
+ curl_int64_t stream_id = (curl_int64_t)sid;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)conn;
(void)stream_id;
(void)fin;
@@ -828,12 +955,9 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
if(!stream)
return 0;
/* add a CRLF only if we've received some headers */
- result = write_resp_hds(data, "\r\n", 2);
- if(result) {
- return -1;
- }
+ h3_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] end_headers, status=%d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] end_headers, status=%d",
stream_id, stream->status_code);
if(stream->status_code / 100 != 1) {
stream->resp_hds_complete = TRUE;
@@ -842,16 +966,18 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
return 0;
}
-static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
+static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
int32_t token, nghttp3_rcbuf *name,
nghttp3_rcbuf *value, uint8_t flags,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ curl_int64_t stream_id = (curl_int64_t)sid;
nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result = CURLE_OK;
(void)conn;
(void)stream_id;
@@ -864,42 +990,45 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
return 0;
if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
- char line[14]; /* status line is always 13 characters long */
- size_t ncopy;
result = Curl_http_decode_status(&stream->status_code,
(const char *)h3val.base, h3val.len);
if(result)
return -1;
- ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
- stream->status_code);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] status: %s", stream_id, line);
- result = write_resp_hds(data, line, ncopy);
+ Curl_dyn_reset(&ctx->scratch);
+ result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/3 "));
+ if(!result)
+ result = Curl_dyn_addn(&ctx->scratch,
+ (const char *)h3val.base, h3val.len);
+ if(!result)
+ result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
+ if(!result)
+ h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch),
+ Curl_dyn_len(&ctx->scratch), FALSE);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] status: %s",
+ stream_id, Curl_dyn_ptr(&ctx->scratch));
if(result) {
return -1;
}
}
else {
/* store as an HTTP1-style header */
- CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] header: %.*s: %.*s",
stream_id, (int)h3name.len, h3name.base,
(int)h3val.len, h3val.base);
- result = write_resp_hds(data, (const char *)h3name.base, h3name.len);
- if(result) {
- return -1;
- }
- result = write_resp_hds(data, ": ", 2);
- if(result) {
- return -1;
- }
- result = write_resp_hds(data, (const char *)h3val.base, h3val.len);
- if(result) {
- return -1;
- }
- result = write_resp_hds(data, "\r\n", 2);
- if(result) {
- return -1;
- }
+ Curl_dyn_reset(&ctx->scratch);
+ result = Curl_dyn_addn(&ctx->scratch,
+ (const char *)h3name.base, h3name.len);
+ if(!result)
+ result = Curl_dyn_addn(&ctx->scratch, STRCONST(": "));
+ if(!result)
+ result = Curl_dyn_addn(&ctx->scratch,
+ (const char *)h3val.base, h3val.len);
+ if(!result)
+ result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
+ if(!result)
+ h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch),
+ Curl_dyn_len(&ctx->scratch), FALSE);
}
return 0;
}
@@ -923,11 +1052,12 @@ static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
return 0;
}
-static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
+static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t sid,
uint64_t app_error_code, void *user_data,
void *stream_user_data) {
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ curl_int64_t stream_id = (curl_int64_t)sid;
struct Curl_easy *data = stream_user_data;
int rv;
(void)conn;
@@ -935,7 +1065,7 @@ static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id,
app_error_code);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reset -> %d", stream_id, rv);
if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -1031,14 +1161,14 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
(void)cf;
if(stream->reset) {
failf(data,
- "HTTP/3 stream %" PRId64 " reset by server", stream->id);
+ "HTTP/3 stream %" CURL_PRId64 " reset by server", stream->id);
*err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
goto out;
}
else if(!stream->resp_hds_complete) {
failf(data,
- "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
- " all response header fields, treated as error",
+ "HTTP/3 stream %" CURL_PRId64 " was closed cleanly, but before "
+ "getting all response header fields, treated as error",
stream->id);
*err = CURLE_HTTP3;
goto out;
@@ -1055,7 +1185,7 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t blen, CURLcode *err)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nread = -1;
struct cf_call_data save;
struct pkt_io_ctx pktx;
@@ -1072,7 +1202,7 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
pktx_init(&pktx, cf, data);
- if(!stream) {
+ if(!stream || ctx->conn_closed) {
*err = CURLE_RECV_ERROR;
goto out;
}
@@ -1083,7 +1213,14 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out;
}
- if(stream->closed) {
+ if(stream->xfer_result) {
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] xfer write failed", stream->id);
+ cf_ngtcp2_stream_close(cf, data, stream);
+ *err = stream->xfer_result;
+ nread = -1;
+ goto out;
+ }
+ else if(stream->closed) {
nread = recv_closed_stream(cf, data, stream, err);
goto out;
}
@@ -1102,7 +1239,7 @@ out:
nread = -1;
}
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
stream? stream->id : -1, blen, nread, *err);
CF_DATA_RESTORE(cf, save);
return nread;
@@ -1113,8 +1250,9 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
size_t skiplen;
(void)cf;
@@ -1147,8 +1285,9 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nwritten = 0;
size_t nvecs = 0;
(void)cf;
@@ -1191,12 +1330,12 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
}
else if(!nwritten) {
/* Not EOF, and nothing to give, we signal WOULDBLOCK. */
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> AGAIN",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read req body -> AGAIN",
stream->id);
return NGHTTP3_ERR_WOULDBLOCK;
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read req body -> "
"%d vecs%s with %zu (buffered=%zu, left=%"
CURL_FORMAT_CURL_OFF_T ")",
stream->id, (int)nvecs,
@@ -1217,6 +1356,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = NULL;
+ int64_t sid;
struct dynhds h2_headers;
size_t nheader;
nghttp3_nv *nva = NULL;
@@ -1231,7 +1371,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
*err = h3_data_setup(cf, data);
if(*err)
goto out;
- stream = H3_STREAM_CTX(data);
+ stream = H3_STREAM_CTX(ctx, data);
DEBUGASSERT(stream);
if(!stream) {
*err = CURLE_FAILED_INIT;
@@ -1272,12 +1412,15 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
nva[i].flags = NGHTTP3_NV_FLAG_NONE;
}
- rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &stream->id, data);
+ rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &sid, data);
if(rc) {
failf(data, "can get bidi streams");
*err = CURLE_SEND_ERROR;
+ nwritten = -1;
goto out;
}
+ stream->id = (curl_int64_t)sid;
+ ++ctx->used_bidi_streams;
switch(data->state.httpreq) {
case HTTPREQ_POST:
@@ -1308,12 +1451,12 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
if(rc) {
switch(rc) {
case NGHTTP3_ERR_CONN_CLOSING:
- CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send, "
+ CURL_TRC_CF(data, cf, "h3sid[%" CURL_PRId64 "] failed to send, "
"connection is closing", stream->id);
break;
default:
- CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send -> %d (%s)",
- stream->id, rc, ngtcp2_strerror(rc));
+ CURL_TRC_CF(data, cf, "h3sid[%" CURL_PRId64 "] failed to send -> "
+ "%d (%s)", stream->id, rc, ngtcp2_strerror(rc));
break;
}
*err = CURLE_SEND_ERROR;
@@ -1322,10 +1465,10 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
}
if(Curl_trc_is_verbose(data)) {
- infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s",
+ infof(data, "[HTTP/3] [%" CURL_PRId64 "] OPENED stream for %s",
stream->id, data->state.url);
for(i = 0; i < nheader; ++i) {
- infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->id,
+ infof(data, "[HTTP/3] [%" CURL_PRId64 "] [%.*s: %.*s]", stream->id,
(int)nva[i].namelen, nva[i].name,
(int)nva[i].valuelen, nva[i].value);
}
@@ -1341,7 +1484,7 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t sent = 0;
struct cf_call_data save;
struct pkt_io_ctx pktx;
@@ -1361,12 +1504,25 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
if(!stream || stream->id < 0) {
+ if(ctx->conn_closed) {
+ CURL_TRC_CF(data, cf, "cannot open stream on closed connection");
+ *err = CURLE_SEND_ERROR;
+ sent = -1;
+ goto out;
+ }
sent = h3_stream_open(cf, data, buf, len, err);
if(sent < 0) {
CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
goto out;
}
- stream = H3_STREAM_CTX(data);
+ stream = H3_STREAM_CTX(ctx, data);
+ }
+ else if(stream->xfer_result) {
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] xfer write failed", stream->id);
+ cf_ngtcp2_stream_close(cf, data, stream);
+ *err = stream->xfer_result;
+ sent = -1;
+ goto out;
}
else if(stream->upload_blocked_len) {
/* the data in `buf` has already been submitted or added to the
@@ -1390,21 +1546,27 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* body. This happens on 30x or 40x responses.
* We silently discard the data sent, since this is not a transport
* error situation. */
- CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] discarding data"
"on closed stream with response", stream->id);
*err = CURLE_OK;
sent = (ssize_t)len;
goto out;
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] send_body(len=%zu) "
"-> stream closed", stream->id, len);
*err = CURLE_HTTP3;
sent = -1;
goto out;
}
+ else if(ctx->conn_closed) {
+ CURL_TRC_CF(data, cf, "cannot send on closed connection");
+ *err = CURLE_SEND_ERROR;
+ sent = -1;
+ goto out;
+ }
else {
sent = Curl_bufq_write(&stream->sendbuf, buf, len, err);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send, add to "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send, add to "
"sendbuf(len=%zu) -> %zd, %d",
stream->id, len, sent, *err);
if(sent < 0) {
@@ -1425,7 +1587,7 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* caller. Instead we EAGAIN and remember how much we have already
* "written" into our various internal connection buffers. */
stream->upload_blocked_len = sent;
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu), "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu), "
"%zu bytes in flight -> EGAIN", stream->id, len,
stream->sendbuf_len_in_flight);
*err = CURLE_AGAIN;
@@ -1438,7 +1600,7 @@ out:
*err = result;
sent = -1;
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu) -> %zd, %d",
stream? stream->id : -1, len, sent, *err);
CF_DATA_RESTORE(cf, save);
return sent;
@@ -1478,16 +1640,7 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
if(rv) {
CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)",
ngtcp2_strerror(rv), rv);
- if(!ctx->last_error.error_code) {
- if(rv == NGTCP2_ERR_CRYPTO) {
- ngtcp2_ccerr_set_tls_alert(&ctx->last_error,
- ngtcp2_conn_get_tls_alert(ctx->qconn),
- NULL, 0);
- }
- else {
- ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0);
- }
- }
+ cf_ngtcp2_err_set(pktx->cf, pktx->data, rv);
if(rv == NGTCP2_ERR_CRYPTO)
/* this is a "TLS problem", but a failed certificate verification
@@ -1570,9 +1723,7 @@ static ssize_t read_pkt_to_send(void *userp,
if(veccnt < 0) {
failf(x->data, "nghttp3_conn_writev_stream returned error: %s",
nghttp3_strerror((int)veccnt));
- ngtcp2_ccerr_set_application_error(
- &ctx->last_error,
- nghttp3_err_infer_quic_app_error_code((int)veccnt), NULL, 0);
+ cf_ngtcp2_h3_err_set(x->cf, x->data, (int)veccnt);
*err = CURLE_SEND_ERROR;
return -1;
}
@@ -1593,11 +1744,11 @@ static ssize_t read_pkt_to_send(void *userp,
else if(n < 0) {
switch(n) {
case NGTCP2_ERR_STREAM_DATA_BLOCKED: {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(x->data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
DEBUGASSERT(ndatalen == -1);
nghttp3_conn_block_stream(ctx->h3conn, stream_id);
- CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] block quic flow",
- stream_id);
+ CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRId64 "] block quic flow",
+ (curl_int64_t)stream_id);
DEBUGASSERT(stream);
if(stream)
stream->quic_flow_blocked = TRUE;
@@ -1619,7 +1770,7 @@ static ssize_t read_pkt_to_send(void *userp,
DEBUGASSERT(ndatalen == -1);
failf(x->data, "ngtcp2_conn_writev_stream returned error: %s",
ngtcp2_strerror((int)n));
- ngtcp2_ccerr_set_liberr(&ctx->last_error, (int)n, NULL, 0);
+ cf_ngtcp2_err_set(x->cf, x->data, (int)n);
*err = CURLE_SEND_ERROR;
nwritten = -1;
goto out;
@@ -1807,7 +1958,7 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
h3_data_done(cf, data);
break;
case CF_CTRL_DATA_DONE_SEND: {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(stream && !stream->send_closed) {
stream->send_closed = TRUE;
stream->upload_left = Curl_bufq_len(&stream->sendbuf);
@@ -1816,7 +1967,7 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
break;
}
case CF_CTRL_DATA_IDLE: {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURL_TRC_CF(data, cf, "data idle");
if(stream && !stream->closed) {
result = check_and_set_expiry(cf, data, NULL);
@@ -1846,6 +1997,9 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
if(ctx->qconn)
ngtcp2_conn_del(ctx->qconn);
Curl_bufcp_free(&ctx->stream_bufcp);
+ Curl_dyn_free(&ctx->scratch);
+ Curl_hash_clean(&ctx->streams);
+ Curl_hash_destroy(&ctx->streams);
Curl_ssl_peer_cleanup(&ctx->peer);
memset(ctx, 0, sizeof(*ctx));
@@ -1853,31 +2007,42 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
ctx->call_data = save;
}
-static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- if(ctx && ctx->qconn) {
+ if(ctx && ctx->qconn && !ctx->conn_closed) {
char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
struct pkt_io_ctx pktx;
ngtcp2_ssize rc;
- CURL_TRC_CF(data, cf, "close");
+ ctx->conn_closed = TRUE;
pktx_init(&pktx, cf, data);
rc = ngtcp2_conn_write_connection_close(ctx->qconn, NULL, /* path */
NULL, /* pkt_info */
(uint8_t *)buffer, sizeof(buffer),
&ctx->last_error, pktx.ts);
+ CURL_TRC_CF(data, cf, "closing connection(err_type=%d, err_code=%"
+ CURL_PRIu64 ") -> %d", ctx->last_error.type,
+ (curl_uint64_t)ctx->last_error.error_code, (int)rc);
if(rc > 0) {
while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) &&
SOCKERRNO == EINTR);
}
+ }
+}
+static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct cf_call_data save;
+
+ CF_DATA_SAVE(save, cf, data);
+ if(ctx && ctx->qconn) {
+ cf_ngtcp2_conn_close(cf, data);
cf_ngtcp2_ctx_clear(ctx);
+ CURL_TRC_CF(data, cf, "close");
}
-
cf->connected = FALSE;
CF_DATA_RESTORE(cf, save);
}
@@ -1898,25 +2063,59 @@ static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
(void)save;
}
-static CURLcode tls_ctx_setup(struct quic_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data)
+#ifdef USE_OPENSSL
+/* The "new session" callback must return zero if the session can be removed
+ * or non-zero if the session has been put into the session cache.
+ */
+static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
{
+ struct Curl_cfilter *cf;
+ struct cf_ngtcp2_ctx *ctx;
+ struct Curl_easy *data;
+ ngtcp2_crypto_conn_ref *cref;
+
+ cref = (ngtcp2_crypto_conn_ref *)SSL_get_app_data(ssl);
+ cf = cref? cref->user_data : NULL;
+ ctx = cf? cf->ctx : NULL;
+ data = cf? CF_DATA_CURRENT(cf) : NULL;
+ if(cf && data && ctx) {
+ Curl_ossl_add_session(cf, data, &ctx->peer, ssl_sessionid);
+ return 1;
+ }
+ return 0;
+}
+#endif /* USE_OPENSSL */
+
+static CURLcode tls_ctx_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *user_data)
+{
+ struct curl_tls_ctx *ctx = user_data;
(void)cf;
#ifdef USE_OPENSSL
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
- if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ssl_ctx) != 0) {
+ if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ossl.ssl_ctx)
+ != 0) {
failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
return CURLE_FAILED_INIT;
}
#else
- if(ngtcp2_crypto_quictls_configure_client_context(ctx->ssl_ctx) != 0) {
+ if(ngtcp2_crypto_quictls_configure_client_context(ctx->ossl.ssl_ctx) != 0) {
failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
return CURLE_FAILED_INIT;
}
#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
+ /* Enable the session cache because it's a prerequisite for the
+ * "new session" callback. Use the "external storage" mode to prevent
+ * OpenSSL from creating an internal session cache.
+ */
+ SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
+ SSL_SESS_CACHE_CLIENT |
+ SSL_SESS_CACHE_NO_INTERNAL);
+ SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb);
+
#elif defined(USE_GNUTLS)
- if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls->session) != 0) {
+ if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) {
failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
return CURLE_FAILED_INIT;
}
@@ -1948,18 +2147,24 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
H3_STREAM_POOL_SPARES);
+ Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
+ Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
- result = Curl_ssl_peer_init(&ctx->peer, cf);
+ result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
if(result)
return result;
#define H3_ALPN "\x2h3\x5h3-29"
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
H3_ALPN, sizeof(H3_ALPN) - 1,
- tls_ctx_setup, &ctx->conn_ref);
+ tls_ctx_setup, &ctx->tls, &ctx->conn_ref);
if(result)
return result;
+#ifdef USE_OPENSSL
+ SSL_set_quic_use_legacy_codepoint(ctx->tls.ossl.ssl, 0);
+#endif
+
ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
result = Curl_rand(data, ctx->dcid.data, NGTCP2_MAX_CIDLEN);
if(result)
@@ -2001,8 +2206,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
-#ifdef USE_GNUTLS
- ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls->session);
+#ifdef USE_OPENSSL
+ ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl);
+#elif defined(USE_GNUTLS)
+ ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
#else
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ssl);
#endif
@@ -2118,17 +2325,28 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
switch(query) {
case CF_QUERY_MAX_CONCURRENT: {
- const ngtcp2_transport_params *rp;
DEBUGASSERT(pres1);
-
CF_DATA_SAVE(save, cf, data);
- rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
- if(rp)
- *pres1 = (rp->initial_max_streams_bidi > INT_MAX)?
- INT_MAX : (int)rp->initial_max_streams_bidi;
- else /* not arrived yet? */
+ /* Set after transport params arrived and continually updated
+ * by callback. QUIC counts the number over the lifetime of the
+ * connection, ever increasing.
+ * We count the *open* transfers plus the budget for new ones. */
+ if(!ctx->qconn || ctx->conn_closed) {
+ *pres1 = 0;
+ }
+ else if(ctx->max_bidi_streams) {
+ uint64_t avail_bidi_streams = 0;
+ uint64_t max_streams = CONN_INUSE(cf->conn);
+ if(ctx->max_bidi_streams > ctx->used_bidi_streams)
+ avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams;
+ max_streams += avail_bidi_streams;
+ *pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
+ }
+ else /* transport params not arrived yet? take our default. */
*pres1 = Curl_multi_max_concurrent_streams(data->multi);
- CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1);
+ CURL_TRC_CF(data, cf, "query conn[%" CURL_FORMAT_CURL_OFF_T "]: "
+ "MAX_CONCURRENT -> %d (%zu in use)",
+ cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
CF_DATA_RESTORE(cf, save);
return CURLE_OK;
}
@@ -2169,9 +2387,9 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
const ngtcp2_transport_params *rp;
struct cf_call_data save;
- CF_DATA_SAVE(save, cf, data);
+ CF_DATA_SAVE(save, cf, data);
*input_pending = FALSE;
- if(!ctx->qconn)
+ if(!ctx->qconn || ctx->conn_closed)
goto out;
/* Both sides of the QUIC connection announce they max idle times in
diff --git a/libs/libcurl/src/vquic/curl_osslq.c b/libs/libcurl/src/vquic/curl_osslq.c
index caa78935f1..3ffdfecf82 100644
--- a/libs/libcurl/src/vquic/curl_osslq.c
+++ b/libs/libcurl/src/vquic/curl_osslq.c
@@ -32,6 +32,7 @@
#include <nghttp3/nghttp3.h>
#include "urldata.h"
+#include "hash.h"
#include "sendf.h"
#include "strdup.h"
#include "rand.h"
@@ -182,7 +183,7 @@ static CURLcode make_bio_addr(BIO_ADDR **pbio_addr,
result = CURLE_OK;
break;
}
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case AF_INET6: {
struct sockaddr_in6 * const sin =
(struct sockaddr_in6 * const)(void *)&addr->sa_addr;
@@ -192,7 +193,7 @@ static CURLcode make_bio_addr(BIO_ADDR **pbio_addr,
result = CURLE_OK;
break;
}
-#endif /* ENABLE_IPV6 */
+#endif /* USE_IPV6 */
default:
/* sunsupported */
DEBUGASSERT(0);
@@ -210,7 +211,7 @@ out:
/* QUIC stream (not necessarily H3) */
struct cf_osslq_stream {
- int64_t id;
+ curl_int64_t id;
SSL *ssl;
struct bufq recvbuf; /* QUIC war data recv buffer */
BIT(recvd_eos);
@@ -281,7 +282,7 @@ static void cf_osslq_h3conn_cleanup(struct cf_osslq_h3conn *h3)
struct cf_osslq_ctx {
struct cf_quic_ctx q;
struct ssl_peer peer;
- struct quic_tls_ctx tls;
+ struct curl_tls_ctx tls;
struct cf_call_data call_data;
struct cf_osslq_h3conn h3;
struct curltime started_at; /* time the current attempt started */
@@ -289,6 +290,7 @@ struct cf_osslq_ctx {
struct curltime first_byte_at; /* when first byte was recvd */
struct curltime reconnect_at; /* time the next attempt should start */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
+ struct Curl_hash streams; /* hash `data->id` to `h3_stream_ctx` */
size_t max_stream_window; /* max flow window for one stream */
uint64_t max_idle_ms; /* max idle time for QUIC connection */
BIT(got_first_byte); /* if first byte was received */
@@ -306,6 +308,8 @@ static void cf_osslq_ctx_clear(struct cf_osslq_ctx *ctx)
Curl_vquic_tls_cleanup(&ctx->tls);
vquic_ctx_free(&ctx->q);
Curl_bufcp_free(&ctx->stream_bufcp);
+ Curl_hash_clean(&ctx->streams);
+ Curl_hash_destroy(&ctx->streams);
Curl_ssl_peer_cleanup(&ctx->peer);
memset(ctx, 0, sizeof(*ctx));
@@ -318,7 +322,7 @@ static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data)
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
- if(ctx && ctx->tls.ssl) {
+ if(ctx && ctx->tls.ossl.ssl) {
/* TODO: send connection close */
CURL_TRC_CF(data, cf, "cf_osslq_close()");
cf_osslq_ctx_clear(ctx);
@@ -355,8 +359,8 @@ static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3,
if(h3->remote_ctrl_n >= ARRAYSIZE(h3->remote_ctrl)) {
/* rejected, we are full */
- CURL_TRC_CF(data, cf, "[%" PRId64 "] rejecting additional remote stream",
- stream_id);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] rejecting remote stream",
+ (curl_int64_t)stream_id);
SSL_free(stream_ssl);
return CURLE_FAILED_INIT;
}
@@ -366,13 +370,13 @@ static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3,
nstream->id = stream_id;
nstream->ssl = stream_ssl;
Curl_bufq_initp(&nstream->recvbuf, &ctx->stream_bufcp, 1, BUFQ_OPT_NONE);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] accepted new remote uni stream",
- stream_id);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] accepted remote uni stream",
+ (curl_int64_t)stream_id);
break;
}
default:
- CURL_TRC_CF(data, cf, "[%" PRId64 "] rejecting remote non-uni-read"
- " stream", stream_id);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reject remote non-uni-read"
+ " stream", (curl_int64_t)stream_id);
SSL_free(stream_ssl);
return CURLE_FAILED_INIT;
}
@@ -403,7 +407,7 @@ static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf,
(reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) {
result = CURLE_PEER_FAILED_VERIFICATION;
- lerr = SSL_get_verify_result(ctx->tls.ssl);
+ lerr = SSL_get_verify_result(ctx->tls.ossl.ssl);
if(lerr != X509_V_OK) {
ssl_config->certverifyresult = lerr;
msnprintf(ebuf, sizeof(ebuf),
@@ -482,7 +486,7 @@ struct h3_stream_ctx {
size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
size_t upload_blocked_len; /* the amount written last and EGAINed */
size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */
- uint64_t error3; /* HTTP/3 stream error code */
+ curl_uint64_t error3; /* HTTP/3 stream error code */
curl_off_t upload_left; /* number of request bytes left to upload */
curl_off_t download_recvd; /* number of response DATA bytes received */
int status_code; /* HTTP status code */
@@ -493,18 +497,29 @@ struct h3_stream_ctx {
BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
};
-#define H3_STREAM_CTX(d) ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \
- ((struct HTTP *)(d)->req.p.http)->h3_ctx \
- : NULL))
-#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
-#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
- H3_STREAM_CTX(d)->s.id : -2)
+#define H3_STREAM_CTX(ctx,data) ((struct h3_stream_ctx *)(\
+ data? Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
+
+static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
+{
+ cf_osslq_stream_cleanup(&stream->s);
+ Curl_bufq_free(&stream->sendbuf);
+ Curl_bufq_free(&stream->recvbuf);
+ Curl_h1_req_parse_free(&stream->h1);
+ free(stream);
+}
+
+static void h3_stream_hash_free(void *stream)
+{
+ DEBUGASSERT(stream);
+ h3_stream_ctx_free((struct h3_stream_ctx *)stream);
+}
static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(!data || !data->req.p.http) {
failf(data, "initialization failure, transfer not http initialized");
@@ -530,18 +545,23 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
stream->recv_buf_nonflow = 0;
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
- H3_STREAM_LCTX(data) = stream;
+ if(!Curl_hash_offt_set(&ctx->streams, data->id, stream)) {
+ h3_stream_ctx_free(stream);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
return CURLE_OK;
}
static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)cf;
if(stream) {
- CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->s.id);
+ CURL_TRC_CF(data, cf, "[%"CURL_PRId64"] easy handle is done",
+ stream->s.id);
if(ctx->h3.conn && !stream->closed) {
nghttp3_conn_shutdown_stream_read(ctx->h3.conn, stream->s.id);
nghttp3_conn_close_stream(ctx->h3.conn, stream->s.id,
@@ -550,12 +570,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
stream->closed = TRUE;
}
- cf_osslq_stream_cleanup(&stream->s);
- Curl_bufq_free(&stream->sendbuf);
- Curl_bufq_free(&stream->recvbuf);
- Curl_h1_req_parse_free(&stream->h1);
- free(stream);
- H3_STREAM_LCTX(data) = NULL;
+ Curl_hash_offt_remove(&ctx->streams, data->id);
}
}
@@ -564,7 +579,7 @@ static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
int64_t stream_id)
{
struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct Curl_easy *sdata;
if(stream && stream->s.id == stream_id) {
@@ -582,9 +597,11 @@ static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
else {
DEBUGASSERT(data->multi);
for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
- if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream_id) {
- stream = H3_STREAM_CTX(sdata);
- return stream? &stream->s : NULL;
+ if(sdata->conn != data->conn)
+ continue;
+ stream = H3_STREAM_CTX(ctx, sdata);
+ if(stream && stream->s.id == stream_id) {
+ return &stream->s;
}
}
}
@@ -594,7 +611,8 @@ static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
static void h3_drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_osslq_ctx *ctx = cf->ctx;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
unsigned char bits;
(void)cf;
@@ -624,8 +642,9 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_osslq_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)conn;
(void)stream_id;
@@ -638,11 +657,11 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
stream->reset = TRUE;
stream->send_closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" PRId64 "] RESET: error %" PRId64,
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] RESET: error %" CURL_PRIu64,
stream->s.id, stream->error3);
}
else {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] CLOSED", stream->s.id);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] CLOSED", stream->s.id);
}
h3_drain_stream(cf, data);
return 0;
@@ -658,7 +677,8 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf,
const void *mem, size_t memlen,
bool flow)
{
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_osslq_ctx *ctx = cf->ctx;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result = CURLE_OK;
ssize_t nwritten;
@@ -688,8 +708,9 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_osslq_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result;
(void)conn;
@@ -700,12 +721,12 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
result = write_resp_raw(cf, data, buf, buflen, TRUE);
if(result) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] DATA len=%zu, ERROR %d",
stream->s.id, buflen, result);
return NGHTTP3_ERR_CALLBACK_FAILURE;
}
stream->download_recvd += (curl_off_t)buflen;
- CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, total=%zd",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] DATA len=%zu, total=%zd",
stream->s.id, buflen, stream->download_recvd);
h3_drain_stream(cf, data);
return 0;
@@ -716,27 +737,30 @@ static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_osslq_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)conn;
(void)stream_id;
if(stream)
- CURL_TRC_CF(data, cf, "[%" PRId64 "] deferred consume %zu bytes",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] deferred consume %zu bytes",
stream->s.id, consumed);
return 0;
}
-static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
+static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
int32_t token, nghttp3_rcbuf *name,
nghttp3_rcbuf *value, uint8_t flags,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ curl_int64_t stream_id = sid;
+ struct cf_osslq_ctx *ctx = cf->ctx;
nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result = CURLE_OK;
(void)conn;
(void)stream_id;
@@ -758,7 +782,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
return -1;
ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
stream->status_code);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] status: %s", stream_id, line);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] status: %s", stream_id, line);
result = write_resp_raw(cf, data, line, ncopy, FALSE);
if(result) {
return -1;
@@ -766,7 +790,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
}
else {
/* store as an HTTP1-style header */
- CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] header: %.*s: %.*s",
stream_id, (int)h3name.len, h3name.base,
(int)h3val.len, h3val.base);
result = write_resp_raw(cf, data, h3name.base, h3name.len, FALSE);
@@ -789,12 +813,14 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
return 0;
}
-static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
+static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
int fin, void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_osslq_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ curl_int64_t stream_id = sid;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result = CURLE_OK;
(void)conn;
(void)stream_id;
@@ -809,7 +835,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
return -1;
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] end_headers, status=%d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] end_headers, status=%d",
stream_id, stream->status_code);
if(stream->status_code / 100 != 1) {
stream->resp_hds_complete = TRUE;
@@ -818,30 +844,34 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
return 0;
}
-static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
+static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t sid,
uint64_t app_error_code, void *user_data,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_osslq_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ curl_int64_t stream_id = sid;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)conn;
(void)app_error_code;
if(!stream || !stream->s.ssl)
return 0;
- CURL_TRC_CF(data, cf, "[%" PRId64 "] stop_sending", stream_id);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] stop_sending", stream_id);
cf_osslq_stream_close(&stream->s);
return 0;
}
-static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
+static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t sid,
uint64_t app_error_code, void *user_data,
void *stream_user_data) {
struct Curl_cfilter *cf = user_data;
+ struct cf_osslq_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ curl_int64_t stream_id = sid;
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
int rv;
(void)conn;
@@ -849,7 +879,7 @@ static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
SSL_STREAM_RESET_ARGS args = {0};
args.quic_error_code = app_error_code;
rv = !SSL_stream_reset(stream->s.ssl, &args, sizeof(args));
- CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reset -> %d", stream_id, rv);
if(!rv) {
return NGHTTP3_ERR_CALLBACK_FAILURE;
}
@@ -864,8 +894,9 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_osslq_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nwritten = 0;
size_t nvecs = 0;
(void)cf;
@@ -908,12 +939,12 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
}
else if(!nwritten) {
/* Not EOF, and nothing to give, we signal WOULDBLOCK. */
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> AGAIN",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read req body -> AGAIN",
stream->s.id);
return NGHTTP3_ERR_WOULDBLOCK;
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read req body -> "
"%d vecs%s with %zu (buffered=%zu, left=%"
CURL_FORMAT_CURL_OFF_T ")",
stream->s.id, (int)nvecs,
@@ -928,8 +959,9 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
+ struct cf_osslq_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
size_t skiplen;
(void)cf;
@@ -1042,14 +1074,15 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
H3_STREAM_POOL_SPARES);
- result = Curl_ssl_peer_init(&ctx->peer, cf);
+ Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
+ result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
if(result)
goto out;
#define H3_ALPN "\x2h3"
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
H3_ALPN, sizeof(H3_ALPN) - 1,
- NULL, NULL);
+ NULL, NULL, NULL);
if(result)
goto out;
@@ -1093,12 +1126,12 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
goto out;
}
- if(!SSL_set1_initial_peer_addr(ctx->tls.ssl, baddr)) {
+ if(!SSL_set1_initial_peer_addr(ctx->tls.ossl.ssl, baddr)) {
failf(data, "failed to set the initial peer address");
result = CURLE_FAILED_INIT;
goto out;
}
- if(!SSL_set_blocking_mode(ctx->tls.ssl, 0)) {
+ if(!SSL_set_blocking_mode(ctx->tls.ossl.ssl, 0)) {
failf(data, "failed to turn off blocking mode");
result = CURLE_FAILED_INIT;
goto out;
@@ -1106,7 +1139,8 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
#ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
/* Added in OpenSSL v3.3.x */
- if(!SSL_set_feature_request_uint(ctx->tls.ssl, SSL_VALUE_QUIC_IDLE_TIMEOUT,
+ if(!SSL_set_feature_request_uint(ctx->tls.ossl.ssl,
+ SSL_VALUE_QUIC_IDLE_TIMEOUT,
CURL_QUIC_MAX_IDLE_MS)) {
CURL_TRC_CF(data, cf, "error setting idle timeout, ");
result = CURLE_FAILED_INIT;
@@ -1114,13 +1148,13 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
}
#endif
- SSL_set_bio(ctx->tls.ssl, bio, bio);
+ SSL_set_bio(ctx->tls.ossl.ssl, bio, bio);
bio = NULL;
- SSL_set_connect_state(ctx->tls.ssl);
- SSL_set_incoming_stream_policy(ctx->tls.ssl,
+ SSL_set_connect_state(ctx->tls.ossl.ssl);
+ SSL_set_incoming_stream_policy(ctx->tls.ossl.ssl,
SSL_INCOMING_STREAM_POLICY_ACCEPT, 0);
/* setup the H3 things on top of the QUIC connection */
- result = cf_osslq_h3conn_init(ctx, ctx->tls.ssl, cf);
+ result = cf_osslq_h3conn_init(ctx, ctx->tls.ossl.ssl, cf);
out:
if(bio)
@@ -1154,7 +1188,7 @@ static ssize_t h3_quic_recv(void *reader_ctx,
return -1;
}
else if(detail == SSL_ERROR_ZERO_RETURN) {
- CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> EOS",
+ CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRId64 "] h3_quic_recv -> EOS",
x->s->id);
x->s->recvd_eos = TRUE;
return 0;
@@ -1163,9 +1197,9 @@ static ssize_t h3_quic_recv(void *reader_ctx,
SSL_STREAM_STATE_RESET_REMOTE) {
uint64_t app_error_code = NGHTTP3_H3_NO_ERROR;
SSL_get_stream_read_error_code(x->s->ssl, &app_error_code);
- CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> RESET, "
- "rv=%d, app_err=%" PRIu64,
- x->s->id, rv, app_error_code);
+ CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRId64 "] h3_quic_recv -> RESET, "
+ "rv=%d, app_err=%" CURL_PRIu64,
+ x->s->id, rv, (curl_uint64_t)app_error_code);
if(app_error_code != NGHTTP3_H3_NO_ERROR) {
x->s->reset = TRUE;
}
@@ -1177,10 +1211,6 @@ static ssize_t h3_quic_recv(void *reader_ctx,
return -1;
}
}
- else {
- /* CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> %zu bytes",
- x->s->id, nread); */
- }
return (ssize_t)nread;
}
@@ -1224,7 +1254,7 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
while(Curl_bufq_peek(&s->recvbuf, &buf, &blen)) {
nread = nghttp3_conn_read_stream(ctx->h3.conn, s->id,
buf, blen, 0);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] forward %zu bytes "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] forward %zu bytes "
"to nghttp3 -> %zd", s->id, blen, nread);
if(nread < 0) {
failf(data, "nghttp3_conn_read_stream(len=%zu) error: %s",
@@ -1263,7 +1293,7 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id,
NGHTTP3_H3_NO_ERROR);
s->closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" PRId64 "] close nghttp3 stream -> %d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] close nghttp3 stream -> %d",
s->id, rv);
if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
failf(data, "nghttp3_conn_close_stream returned error: %s",
@@ -1276,7 +1306,7 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
}
out:
if(result)
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_osslq_stream_recv -> %d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_osslq_stream_recv -> %d",
s->id, result);
return result;
}
@@ -1287,22 +1317,23 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
struct cf_osslq_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
- if(!ctx->tls.ssl)
+ if(!ctx->tls.ossl.ssl)
goto out;
ERR_clear_error();
/* 1. Check for new incoming streams */
while(1) {
- SSL *snew = SSL_accept_stream(ctx->tls.ssl, SSL_ACCEPT_STREAM_NO_BLOCK);
+ SSL *snew = SSL_accept_stream(ctx->tls.ossl.ssl,
+ SSL_ACCEPT_STREAM_NO_BLOCK);
if(!snew)
break;
(void)cf_osslq_h3conn_add_stream(&ctx->h3, snew, cf, data);
}
- if(!SSL_handle_events(ctx->tls.ssl)) {
- int detail = SSL_get_error(ctx->tls.ssl, 0);
+ if(!SSL_handle_events(ctx->tls.ossl.ssl)) {
+ int detail = SSL_get_error(ctx->tls.ossl.ssl, 0);
result = cf_osslq_ssl_err(cf, data, detail, CURLE_RECV_ERROR);
}
@@ -1322,7 +1353,7 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
DEBUGASSERT(data->multi);
for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
if(sdata->conn == data->conn && CURL_WANT_RECV(sdata)) {
- stream = H3_STREAM_CTX(sdata);
+ stream = H3_STREAM_CTX(ctx, sdata);
if(stream && !stream->closed &&
!Curl_bufq_is_full(&stream->recvbuf)) {
result = cf_osslq_stream_recv(&stream->s, cf, sdata);
@@ -1349,7 +1380,7 @@ static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
if(ctx->h3.conn) {
for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
if(sdata->conn == data->conn) {
- stream = H3_STREAM_CTX(sdata);
+ stream = H3_STREAM_CTX(ctx, sdata);
if(stream && stream->s.ssl && stream->s.send_blocked &&
!SSL_want_write(stream->s.ssl)) {
nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id);
@@ -1369,7 +1400,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
struct cf_osslq_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
- if(!ctx->tls.ssl || !ctx->h3.conn)
+ if(!ctx->tls.ossl.ssl || !ctx->h3.conn)
goto out;
for(;;) {
@@ -1398,8 +1429,8 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
/* Get the stream for this data */
s = cf_osslq_get_qstream(cf, data, stream_id);
if(!s) {
- failf(data, "nghttp3_conn_writev_stream gave unknown stream %" PRId64,
- stream_id);
+ failf(data, "nghttp3_conn_writev_stream gave unknown stream %"
+ CURL_PRId64, (curl_int64_t)stream_id);
result = CURLE_SEND_ERROR;
goto out;
}
@@ -1427,8 +1458,8 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
if(ok) {
/* As OpenSSL buffers the data, we count this as acknowledged
* from nghttp3's point of view */
- CURL_TRC_CF(data, cf, "[%"PRId64"] send %zu bytes to QUIC ok",
- s->id, vec[i].len);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] send %zu bytes to QUIC ok",
+ s->id, vec[i].len);
acked_len += vec[i].len;
}
else {
@@ -1437,16 +1468,16 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
/* QUIC blocked us from writing more */
- CURL_TRC_CF(data, cf, "[%"PRId64"] send %zu bytes to QUIC blocked",
- s->id, vec[i].len);
+ CURL_TRC_CF(data, cf, "[%"CURL_PRId64 "] send %zu bytes to "
+ "QUIC blocked", s->id, vec[i].len);
written = 0;
nghttp3_conn_block_stream(ctx->h3.conn, s->id);
s->send_blocked = blocked = TRUE;
break;
default:
- failf(data, "[%"PRId64"] send %zu bytes to QUIC, SSL error %d",
+ failf(data, "[%"CURL_PRId64 "] send %zu bytes to QUIC, SSL error %d",
s->id, vec[i].len, detail);
- result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR);
+ result = cf_osslq_ssl_err(cf, data, detail, CURLE_HTTP3);
goto out;
}
}
@@ -1470,13 +1501,13 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
result = CURLE_SEND_ERROR;
goto out;
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] forwarded %zu/%zu h3 bytes "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] forwarded %zu/%zu h3 bytes "
"to QUIC, eos=%d", s->id, acked_len, total_len, eos);
}
if(eos && !s->send_blocked && !eos_written) {
/* wrote everything and H3 indicates end of stream */
- CURL_TRC_CF(data, cf, "[%" PRId64 "] closing QUIC stream", s->id);
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] closing QUIC stream", s->id);
SSL_stream_conclude(s->ssl, 0);
}
}
@@ -1492,7 +1523,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
struct cf_osslq_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
- if(!ctx->tls.ssl)
+ if(!ctx->tls.ossl.ssl)
goto out;
ERR_clear_error();
@@ -1500,8 +1531,8 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
if(result)
goto out;
- if(!SSL_handle_events(ctx->tls.ssl)) {
- int detail = SSL_get_error(ctx->tls.ssl, 0);
+ if(!SSL_handle_events(ctx->tls.ossl.ssl)) {
+ int detail = SSL_get_error(ctx->tls.ossl.ssl, 0);
result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR);
}
@@ -1521,8 +1552,8 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
timediff_t timeoutms;
int is_infinite = TRUE;
- if(ctx->tls.ssl &&
- SSL_get_event_timeout(ctx->tls.ssl, &tv, &is_infinite) &&
+ if(ctx->tls.ossl.ssl &&
+ SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite) &&
!is_infinite) {
timeoutms = curlx_tvtoms(&tv);
/* QUIC want to be called again latest at the returned timeout */
@@ -1533,7 +1564,7 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
result = cf_progress_egress(cf, data);
if(result)
goto out;
- if(SSL_get_event_timeout(ctx->tls.ssl, &tv, &is_infinite)) {
+ if(SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite)) {
timeoutms = curlx_tvtoms(&tv);
}
}
@@ -1578,7 +1609,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
goto out;
}
- if(!ctx->tls.ssl) {
+ if(!ctx->tls.ossl.ssl) {
ctx->started_at = now;
result = cf_osslq_ctx_start(cf, data);
if(result)
@@ -1594,7 +1625,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
}
ERR_clear_error();
- err = SSL_do_handshake(ctx->tls.ssl);
+ err = SSL_do_handshake(ctx->tls.ossl.ssl);
if(err == 1) {
/* connected */
@@ -1612,7 +1643,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
}
}
else {
- int detail = SSL_get_error(ctx->tls.ssl, err);
+ int detail = SSL_get_error(ctx->tls.ossl.ssl, err);
switch(detail) {
case SSL_ERROR_WANT_READ:
ctx->q.last_io = now;
@@ -1643,7 +1674,8 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
}
out:
- if(result == CURLE_RECV_ERROR && ctx->tls.ssl && ctx->protocol_shutdown) {
+ if(result == CURLE_RECV_ERROR && ctx->tls.ossl.ssl &&
+ ctx->protocol_shutdown) {
/* When a QUIC server instance is shutting down, it may send us a
* CONNECTION_CLOSE right away. Our connection then enters the DRAINING
* state. The CONNECT may work in the near future again. Indicate
@@ -1689,7 +1721,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
*err = h3_data_setup(cf, data);
if(*err)
goto out;
- stream = H3_STREAM_CTX(data);
+ stream = H3_STREAM_CTX(ctx, data);
DEBUGASSERT(stream);
if(!stream) {
*err = CURLE_FAILED_INIT;
@@ -1731,7 +1763,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
}
DEBUGASSERT(stream->s.id == -1);
- *err = cf_osslq_stream_open(&stream->s, ctx->tls.ssl, 0,
+ *err = cf_osslq_stream_open(&stream->s, ctx->tls.ossl.ssl, 0,
&ctx->stream_bufcp, data);
if(*err) {
failf(data, "can't get bidi streams");
@@ -1768,11 +1800,11 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
if(rc) {
switch(rc) {
case NGHTTP3_ERR_CONN_CLOSING:
- CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send, "
+ CURL_TRC_CF(data, cf, "h3sid[%"CURL_PRId64"] failed to send, "
"connection is closing", stream->s.id);
break;
default:
- CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send -> %d (%s)",
+ CURL_TRC_CF(data, cf, "h3sid[%"CURL_PRId64 "] failed to send -> %d (%s)",
stream->s.id, rc, nghttp3_strerror(rc));
break;
}
@@ -1782,10 +1814,11 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
}
if(Curl_trc_is_verbose(data)) {
- infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s",
+ infof(data, "[HTTP/3] [%" CURL_PRId64 "] OPENED stream for %s",
stream->s.id, data->state.url);
for(i = 0; i < nheader; ++i) {
- infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->s.id,
+ infof(data, "[HTTP/3] [%" CURL_PRId64 "] [%.*s: %.*s]",
+ stream->s.id,
(int)nva[i].namelen, nva[i].name,
(int)nva[i].valuelen, nva[i].value);
}
@@ -1801,14 +1834,14 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct cf_call_data save;
ssize_t nwritten;
CURLcode result;
CF_DATA_SAVE(save, cf, data);
DEBUGASSERT(cf->connected);
- DEBUGASSERT(ctx->tls.ssl);
+ DEBUGASSERT(ctx->tls.ossl.ssl);
DEBUGASSERT(ctx->h3.conn);
*err = CURLE_OK;
@@ -1832,7 +1865,7 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
goto out;
}
- stream = H3_STREAM_CTX(data);
+ stream = H3_STREAM_CTX(ctx, data);
}
else if(stream->upload_blocked_len) {
/* the data in `buf` has already been submitted or added to the
@@ -1856,13 +1889,13 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* body. This happens on 30x or 40x responses.
* We silently discard the data sent, since this is not a transport
* error situation. */
- CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] discarding data"
"on closed stream with response", stream->s.id);
*err = CURLE_OK;
nwritten = (ssize_t)len;
goto out;
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] send_body(len=%zu) "
"-> stream closed", stream->s.id, len);
*err = CURLE_HTTP3;
nwritten = -1;
@@ -1870,7 +1903,7 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
else {
nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send, add to "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send, add to "
"sendbuf(len=%zu) -> %zd, %d",
stream->s.id, len, nwritten, *err);
if(nwritten < 0) {
@@ -1891,7 +1924,7 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* caller. Instead we EAGAIN and remember how much we have already
* "written" into our various internal connection buffers. */
stream->upload_blocked_len = nwritten;
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu), "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu), "
"%zu bytes in flight -> EGAIN", stream->s.id, len,
stream->sendbuf_len_in_flight);
*err = CURLE_AGAIN;
@@ -1900,7 +1933,7 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
out:
result = check_and_set_expiry(cf, data);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu) -> %zd, %d",
stream? stream->s.id : -1, len, nwritten, *err);
CF_DATA_RESTORE(cf, save);
return nwritten;
@@ -1916,13 +1949,15 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
(void)cf;
if(stream->reset) {
failf(data,
- "HTTP/3 stream %" PRId64 " reset by server", stream->s.id);
+ "HTTP/3 stream %" CURL_PRId64 " reset by server",
+ stream->s.id);
*err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
goto out;
}
else if(!stream->resp_hds_complete) {
failf(data,
- "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
+ "HTTP/3 stream %" CURL_PRId64
+ " was closed cleanly, but before getting"
" all response header fields, treated as error",
stream->s.id);
*err = CURLE_HTTP3;
@@ -1939,7 +1974,7 @@ static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nread = -1;
struct cf_call_data save;
CURLcode result;
@@ -1948,7 +1983,7 @@ static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
CF_DATA_SAVE(save, cf, data);
DEBUGASSERT(cf->connected);
DEBUGASSERT(ctx);
- DEBUGASSERT(ctx->tls.ssl);
+ DEBUGASSERT(ctx->tls.ossl.ssl);
DEBUGASSERT(ctx->h3.conn);
*err = CURLE_OK;
@@ -1961,7 +1996,7 @@ static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
if(nread < 0) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read recvbuf(len=%zu) "
"-> %zd, %d", stream->s.id, len, nread, *err);
goto out;
}
@@ -1979,7 +2014,7 @@ static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
if(nread < 0) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read recvbuf(len=%zu) "
"-> %zd, %d", stream->s.id, len, nread, *err);
goto out;
}
@@ -2009,7 +2044,7 @@ out:
nread = -1;
}
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(len=%zu) -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_recv(len=%zu) -> %zd, %d",
stream? stream->s.id : -1, len, nread, *err);
CF_DATA_RESTORE(cf, save);
return nread;
@@ -2022,7 +2057,8 @@ out:
static bool cf_osslq_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
- const struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_osslq_ctx *ctx = cf->ctx;
+ const struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)cf;
return stream && !Curl_bufq_is_empty(&stream->recvbuf);
}
@@ -2051,7 +2087,7 @@ static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf,
h3_data_done(cf, data);
break;
case CF_CTRL_DATA_DONE_SEND: {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(stream && !stream->send_closed) {
stream->send_closed = TRUE;
stream->upload_left = Curl_bufq_len(&stream->sendbuf);
@@ -2060,7 +2096,7 @@ static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf,
break;
}
case CF_CTRL_DATA_IDLE: {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURL_TRC_CF(data, cf, "data idle");
if(stream && !stream->closed) {
result = check_and_set_expiry(cf, data);
@@ -2084,7 +2120,7 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf,
CF_DATA_SAVE(save, cf, data);
*input_pending = FALSE;
- if(!ctx->tls.ssl)
+ if(!ctx->tls.ossl.ssl)
goto out;
#ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
@@ -2092,7 +2128,8 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf,
{
timediff_t idletime;
uint64_t idle_ms = ctx->max_idle_ms;
- if(!SSL_get_value_uint(ctx->tls.ssl, SSL_VALUE_CLASS_FEATURE_NEGOTIATED,
+ if(!SSL_get_value_uint(ctx->tls.ossl.ssl,
+ SSL_VALUE_CLASS_FEATURE_NEGOTIATED,
SSL_VALUE_QUIC_IDLE_TIMEOUT, &idle_ms)) {
CURL_TRC_CF(data, cf, "error getting negotiated idle timeout, "
"assume connection is dead.");
@@ -2132,15 +2169,15 @@ static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
{
struct cf_osslq_ctx *ctx = cf->ctx;
- if(!ctx->tls.ssl) {
+ if(!ctx->tls.ossl.ssl) {
/* NOP */
}
else if(!cf->connected) {
/* during handshake, transfer has not started yet. we always
* add our socket for polling if SSL wants to send/recv */
Curl_pollset_set(data, ps, ctx->q.sockfd,
- SSL_net_read_desired(ctx->tls.ssl),
- SSL_net_write_desired(ctx->tls.ssl));
+ SSL_net_read_desired(ctx->tls.ossl.ssl),
+ SSL_net_write_desired(ctx->tls.ossl.ssl));
}
else {
/* once connected, we only modify the socket if it is present.
@@ -2149,8 +2186,8 @@ static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
if(want_recv || want_send) {
Curl_pollset_set(data, ps, ctx->q.sockfd,
- SSL_net_read_desired(ctx->tls.ssl),
- SSL_net_write_desired(ctx->tls.ssl));
+ SSL_net_read_desired(ctx->tls.ossl.ssl),
+ SSL_net_write_desired(ctx->tls.ossl.ssl));
}
}
}
@@ -2166,7 +2203,7 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
#ifdef SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL
/* Added in OpenSSL v3.3.x */
uint64_t v;
- if(!SSL_get_value_uint(ctx->tls.ssl, SSL_VALUE_CLASS_GENERIC,
+ if(!SSL_get_value_uint(ctx->tls.ossl.ssl, SSL_VALUE_CLASS_GENERIC,
SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL, &v)) {
CURL_TRC_CF(data, cf, "error getting available local bidi streams");
return CURLE_HTTP3;
diff --git a/libs/libcurl/src/vquic/curl_quiche.c b/libs/libcurl/src/vquic/curl_quiche.c
index e79137ebbd..0a2fab2213 100644
--- a/libs/libcurl/src/vquic/curl_quiche.c
+++ b/libs/libcurl/src/vquic/curl_quiche.c
@@ -29,6 +29,7 @@
#include <openssl/err.h>
#include <openssl/ssl.h>
#include "bufq.h"
+#include "hash.h"
#include "urldata.h"
#include "cfilters.h"
#include "cf-socket.h"
@@ -88,7 +89,7 @@ void Curl_quiche_ver(char *p, size_t len)
struct cf_quiche_ctx {
struct cf_quic_ctx q;
struct ssl_peer peer;
- struct quic_tls_ctx tls;
+ struct curl_tls_ctx tls;
quiche_conn *qconn;
quiche_config *cfg;
quiche_h3_conn *h3c;
@@ -98,8 +99,8 @@ struct cf_quiche_ctx {
struct curltime handshake_at; /* time connect handshake finished */
struct curltime reconnect_at; /* time the next attempt should start */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
+ struct Curl_hash streams; /* hash `data->id` to `stream_ctx` */
curl_off_t data_recvd;
- uint64_t max_idle_ms; /* max idle time for QUIC conn */
BIT(goaway); /* got GOAWAY from server */
BIT(x509_store_setup); /* if x509 store has been set up */
};
@@ -123,55 +124,71 @@ static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx)
quiche_conn_free(ctx->qconn);
if(ctx->cfg)
quiche_config_free(ctx->cfg);
- /* quiche just freed ctx->tls.ssl */
- ctx->tls.ssl = NULL;
+ /* quiche just freed it */
+ ctx->tls.ossl.ssl = NULL;
Curl_vquic_tls_cleanup(&ctx->tls);
Curl_ssl_peer_cleanup(&ctx->peer);
vquic_ctx_free(&ctx->q);
Curl_bufcp_free(&ctx->stream_bufcp);
+ Curl_hash_clean(&ctx->streams);
+ Curl_hash_destroy(&ctx->streams);
memset(ctx, 0, sizeof(*ctx));
}
}
+static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
/**
* All about the H3 internals of a stream
*/
struct stream_ctx {
- int64_t id; /* HTTP/3 protocol stream identifier */
+ curl_uint64_t id; /* HTTP/3 protocol stream identifier */
struct bufq recvbuf; /* h3 response */
struct h1_req_parser h1; /* h1 request parsing */
- uint64_t error3; /* HTTP/3 stream error code */
+ curl_uint64_t error3; /* HTTP/3 stream error code */
curl_off_t upload_left; /* number of request bytes left to upload */
- bool closed; /* TRUE on stream close */
- bool reset; /* TRUE on stream reset */
- bool send_closed; /* stream is locally closed */
- bool resp_hds_complete; /* complete, final response has been received */
- bool resp_got_header; /* TRUE when h3 stream has recvd some HEADER */
+ BIT(opened); /* TRUE after stream has been opened */
+ BIT(closed); /* TRUE on stream close */
+ BIT(reset); /* TRUE on stream reset */
+ BIT(send_closed); /* stream is locally closed */
+ BIT(resp_hds_complete); /* final response has been received */
+ BIT(resp_got_header); /* TRUE when h3 stream has recvd some HEADER */
BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
};
-#define H3_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \
- ((struct HTTP *)(d)->req.p.http)->h3_ctx \
- : NULL))
-#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
-#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
- H3_STREAM_CTX(d)->id : -2)
+#define H3_STREAM_CTX(ctx,data) ((struct stream_ctx *)(\
+ data? Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
+
+static void h3_stream_ctx_free(struct stream_ctx *stream)
+{
+ Curl_bufq_free(&stream->recvbuf);
+ Curl_h1_req_parse_free(&stream->h1);
+ free(stream);
+}
+
+static void h3_stream_hash_free(void *stream)
+{
+ DEBUGASSERT(stream);
+ h3_stream_ctx_free((struct stream_ctx *)stream);
+}
static void check_resumes(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
+ struct cf_quiche_ctx *ctx = cf->ctx;
struct Curl_easy *sdata;
struct stream_ctx *stream;
DEBUGASSERT(data->multi);
for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
if(sdata->conn == data->conn) {
- stream = H3_STREAM_CTX(sdata);
+ stream = H3_STREAM_CTX(ctx, sdata);
if(stream && stream->quic_flow_blocked) {
stream->quic_flow_blocked = FALSE;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
- CURL_TRC_CF(data, cf, "[%"PRId64"] unblock", stream->id);
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] unblock", stream->id);
}
}
}
@@ -181,7 +198,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(stream)
return CURLE_OK;
@@ -190,22 +207,28 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
if(!stream)
return CURLE_OUT_OF_MEMORY;
- H3_STREAM_LCTX(data) = stream;
stream->id = -1;
Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
+
+ if(!Curl_hash_offt_set(&ctx->streams, data->id, stream)) {
+ h3_stream_ctx_free(stream);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
return CURLE_OK;
}
static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ CURLcode result;
(void)cf;
if(stream) {
- CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id);
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] easy handle is done", stream->id);
if(ctx->qconn && !stream->closed) {
quiche_conn_stream_shutdown(ctx->qconn, stream->id,
QUICHE_SHUTDOWN_READ, CURL_H3_NO_ERROR);
@@ -215,18 +238,19 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
stream->send_closed = TRUE;
}
stream->closed = TRUE;
+ result = cf_flush_egress(cf, data);
+ if(result)
+ CURL_TRC_CF(data, cf, "data_done, flush egress -> %d", result);
}
- Curl_bufq_free(&stream->recvbuf);
- Curl_h1_req_parse_free(&stream->h1);
- free(stream);
- H3_STREAM_LCTX(data) = NULL;
+ Curl_hash_offt_remove(&ctx->streams, data->id);
}
}
static void drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_quiche_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
unsigned char bits;
(void)cf;
@@ -241,25 +265,50 @@ static void drain_stream(struct Curl_cfilter *cf,
static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
struct Curl_easy *data,
- int64_t stream3_id)
+ curl_uint64_t stream_id,
+ struct stream_ctx **pstream)
{
+ struct cf_quiche_ctx *ctx = cf->ctx;
struct Curl_easy *sdata;
+ struct stream_ctx *stream;
(void)cf;
- if(H3_STREAM_ID(data) == stream3_id) {
+ stream = H3_STREAM_CTX(ctx, data);
+ if(stream && stream->id == stream_id) {
+ *pstream = stream;
return data;
}
else {
DEBUGASSERT(data->multi);
for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
- if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream3_id) {
+ if(sdata->conn != data->conn)
+ continue;
+ stream = H3_STREAM_CTX(ctx, sdata);
+ if(stream && stream->id == stream_id) {
+ *pstream = stream;
return sdata;
}
}
}
+ *pstream = NULL;
return NULL;
}
+static void cf_quiche_expire_conn_closed(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct Curl_easy *sdata;
+
+ DEBUGASSERT(data->multi);
+ CURL_TRC_CF(data, cf, "conn closed, expire all transfers");
+ for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ if(sdata == data || sdata->conn != data->conn)
+ continue;
+ CURL_TRC_CF(sdata, cf, "conn closed, expire transfer");
+ Curl_expire(sdata, 0, EXPIRE_RUN_NOW);
+ }
+}
+
/*
* write_resp_raw() copies response data in raw format to the `data`'s
* receive buffer. If not enough space is available, it appends to the
@@ -269,7 +318,8 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf,
struct Curl_easy *data,
const void *mem, size_t memlen)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_quiche_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result = CURLE_OK;
ssize_t nwritten;
@@ -299,14 +349,15 @@ static int cb_each_header(uint8_t *name, size_t name_len,
void *argp)
{
struct cb_ctx *x = argp;
- struct stream_ctx *stream = H3_STREAM_CTX(x->data);
+ struct cf_quiche_ctx *ctx = x->cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
CURLcode result;
if(!stream)
return CURLE_OK;
if((name_len == 7) && !strncmp(HTTP_PSEUDO_STATUS, (char *)name, 7)) {
- CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] status: %.*s",
+ CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRIu64 "] status: %.*s",
stream->id, (int)value_len, value);
result = write_resp_raw(x->cf, x->data, "HTTP/3 ", sizeof("HTTP/3 ") - 1);
if(!result)
@@ -315,7 +366,7 @@ static int cb_each_header(uint8_t *name, size_t name_len,
result = write_resp_raw(x->cf, x->data, " \r\n", 3);
}
else {
- CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] header: %.*s: %.*s",
+ CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRIu64 "] header: %.*s: %.*s",
stream->id, (int)name_len, name,
(int)value_len, value);
result = write_resp_raw(x->cf, x->data, name, name_len);
@@ -327,7 +378,7 @@ static int cb_each_header(uint8_t *name, size_t name_len,
result = write_resp_raw(x->cf, x->data, "\r\n", 2);
}
if(result) {
- CURL_TRC_CF(x->data, x->cf, "[%"PRId64"] on header error %d",
+ CURL_TRC_CF(x->data, x->cf, "[%"CURL_PRIu64"] on header error %d",
stream->id, result);
}
return result;
@@ -339,7 +390,7 @@ static ssize_t stream_resp_read(void *reader_ctx,
{
struct cb_ctx *x = reader_ctx;
struct cf_quiche_ctx *ctx = x->cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(x->data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
ssize_t nread;
if(!stream) {
@@ -362,7 +413,8 @@ static ssize_t stream_resp_read(void *reader_ctx,
static CURLcode cf_recv_body(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_quiche_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nwritten;
struct cb_ctx cb_ctx;
CURLcode result = CURLE_OK;
@@ -383,9 +435,9 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf,
stream_resp_read, &cb_ctx, &result);
if(nwritten < 0 && result != CURLE_AGAIN) {
- CURL_TRC_CF(data, cf, "[%"PRId64"] recv_body error %zd",
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] recv_body error %zd",
stream->id, nwritten);
- failf(data, "Error %d in HTTP/3 response body for stream[%"PRId64"]",
+ failf(data, "Error %d in HTTP/3 response body for stream[%"CURL_PRIu64"]",
result, stream->id);
stream->closed = TRUE;
stream->reset = TRUE;
@@ -420,17 +472,15 @@ static const char *cf_ev_name(quiche_h3_event *ev)
static CURLcode h3_process_event(struct Curl_cfilter *cf,
struct Curl_easy *data,
- int64_t stream3_id,
+ struct stream_ctx *stream,
quiche_h3_event *ev)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
struct cb_ctx cb_ctx;
CURLcode result = CURLE_OK;
int rc;
if(!stream)
return CURLE_OK;
- DEBUGASSERT(stream3_id == stream->id);
switch(quiche_h3_event_type(ev)) {
case QUICHE_H3_EVENT_HEADERS:
stream->resp_got_header = TRUE;
@@ -438,11 +488,11 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
cb_ctx.data = data;
rc = quiche_h3_event_for_each_header(ev, cb_each_header, &cb_ctx);
if(rc) {
- failf(data, "Error %d in HTTP/3 response header for stream[%"PRId64"]",
- rc, stream3_id);
+ failf(data, "Error %d in HTTP/3 response header for stream[%"
+ CURL_PRIu64"]", rc, stream->id);
return CURLE_RECV_ERROR;
}
- CURL_TRC_CF(data, cf, "[%"PRId64"] <- [HEADERS]", stream3_id);
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] <- [HEADERS]", stream->id);
break;
case QUICHE_H3_EVENT_DATA:
@@ -452,7 +502,7 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
break;
case QUICHE_H3_EVENT_RESET:
- CURL_TRC_CF(data, cf, "[%"PRId64"] RESET", stream3_id);
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] RESET", stream->id);
stream->closed = TRUE;
stream->reset = TRUE;
stream->send_closed = TRUE;
@@ -460,7 +510,7 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
break;
case QUICHE_H3_EVENT_FINISHED:
- CURL_TRC_CF(data, cf, "[%"PRId64"] CLOSED", stream3_id);
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] CLOSED", stream->id);
if(!stream->resp_hds_complete) {
result = write_resp_raw(cf, data, "\r\n", 2);
if(result)
@@ -472,12 +522,12 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
break;
case QUICHE_H3_EVENT_GOAWAY:
- CURL_TRC_CF(data, cf, "[%"PRId64"] <- [GOAWAY]", stream3_id);
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] <- [GOAWAY]", stream->id);
break;
default:
- CURL_TRC_CF(data, cf, "[%"PRId64"] recv, unhandled event %d",
- stream3_id, quiche_h3_event_type(ev));
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] recv, unhandled event %d",
+ stream->id, quiche_h3_event_type(ev));
break;
}
return result;
@@ -487,36 +537,33 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = NULL;
struct Curl_easy *sdata;
quiche_h3_event *ev;
CURLcode result;
/* Take in the events and distribute them to the transfers. */
while(ctx->h3c) {
- int64_t stream3_id = quiche_h3_conn_poll(ctx->h3c, ctx->qconn, &ev);
+ curl_int64_t stream3_id = quiche_h3_conn_poll(ctx->h3c, ctx->qconn, &ev);
if(stream3_id == QUICHE_H3_ERR_DONE) {
break;
}
else if(stream3_id < 0) {
- CURL_TRC_CF(data, cf, "[%"PRId64"] error poll: %"PRId64,
- stream? stream->id : -1, stream3_id);
+ CURL_TRC_CF(data, cf, "error poll: %"CURL_PRId64, stream3_id);
return CURLE_HTTP3;
}
- sdata = get_stream_easy(cf, data, stream3_id);
- if(!sdata) {
- CURL_TRC_CF(data, cf, "[%"PRId64"] discard event %s for "
- "unknown [%"PRId64"]",
- stream? stream->id : -1, cf_ev_name(ev), stream3_id);
+ sdata = get_stream_easy(cf, data, stream3_id, &stream);
+ if(!sdata || !stream) {
+ CURL_TRC_CF(data, cf, "discard event %s for unknown [%"CURL_PRId64"]",
+ cf_ev_name(ev), stream3_id);
}
else {
- result = h3_process_event(cf, sdata, stream3_id, ev);
+ result = h3_process_event(cf, sdata, stream, ev);
drain_stream(cf, sdata);
if(result) {
- CURL_TRC_CF(data, cf, "[%"PRId64"] error processing event %s "
- "for [%"PRId64"] -> %d",
- stream? stream->id : -1, cf_ev_name(ev),
+ CURL_TRC_CF(data, cf, "error processing event %s "
+ "for [%"CURL_PRIu64"] -> %d", cf_ev_name(ev),
stream3_id, result);
if(data == sdata) {
/* Only report this error to the caller if it is about the
@@ -560,11 +607,19 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
&recv_info);
if(nread < 0) {
if(QUICHE_ERR_DONE == nread) {
+ if(quiche_conn_is_draining(ctx->qconn)) {
+ CURL_TRC_CF(r->data, r->cf, "ingress, connection is draining");
+ return CURLE_RECV_ERROR;
+ }
+ if(quiche_conn_is_closed(ctx->qconn)) {
+ CURL_TRC_CF(r->data, r->cf, "ingress, connection is closed");
+ return CURLE_RECV_ERROR;
+ }
CURL_TRC_CF(r->data, r->cf, "ingress, quiche is DONE");
return CURLE_OK;
}
else if(QUICHE_ERR_TLS_FAIL == nread) {
- long verify_ok = SSL_get_verify_result(ctx->tls.ssl);
+ long verify_ok = SSL_get_verify_result(ctx->tls.ossl.ssl);
if(verify_ok != X509_V_OK) {
failf(r->data, "SSL certificate problem: %s",
X509_verify_cert_error_string(verify_ok));
@@ -651,8 +706,8 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
struct cf_quiche_ctx *ctx = cf->ctx;
ssize_t nread;
CURLcode result;
- int64_t expiry_ns;
- int64_t timeout_ns;
+ curl_int64_t expiry_ns;
+ curl_int64_t timeout_ns;
struct read_ctx readx;
size_t pkt_count, gsolen;
@@ -660,7 +715,13 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
if(!expiry_ns) {
quiche_conn_on_timeout(ctx->qconn);
if(quiche_conn_is_closed(ctx->qconn)) {
- failf(data, "quiche_conn_on_timeout closed the connection");
+ if(quiche_conn_is_timed_out(ctx->qconn))
+ failf(data, "connection closed by idle timeout");
+ else
+ failf(data, "connection closed by server");
+ /* Connection timed out, expire all transfers belonging to it
+ * as will not get any more POLL events here. */
+ cf_quiche_expire_conn_closed(cf, data);
return CURLE_SEND_ERROR;
}
}
@@ -725,25 +786,26 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
struct Curl_easy *data,
CURLcode *err)
{
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_quiche_ctx *ctx = cf->ctx;
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nread = -1;
DEBUGASSERT(stream);
if(stream->reset) {
failf(data,
- "HTTP/3 stream %" PRId64 " reset by server", stream->id);
+ "HTTP/3 stream %" CURL_PRIu64 " reset by server", stream->id);
*err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, was reset -> %d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] cf_recv, was reset -> %d",
stream->id, *err);
}
else if(!stream->resp_got_header) {
failf(data,
- "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
- " all response header fields, treated as error",
+ "HTTP/3 stream %" CURL_PRIu64 " was closed cleanly, but before "
+ "getting all response header fields, treated as error",
stream->id);
/* *err = CURLE_PARTIAL_FILE; */
*err = CURLE_HTTP3;
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, closed incomplete"
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] cf_recv, closed incomplete"
" -> %d", stream->id, *err);
}
else {
@@ -757,7 +819,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nread = -1;
CURLcode result;
@@ -771,7 +833,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(!Curl_bufq_is_empty(&stream->recvbuf)) {
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] read recvbuf(len=%zu) "
"-> %zd, %d", stream->id, len, nread, *err);
if(nread < 0)
goto out;
@@ -788,7 +850,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
- CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] read recvbuf(len=%zu) "
"-> %zd, %d", stream->id, len, nread, *err);
if(nread < 0)
goto out;
@@ -822,7 +884,7 @@ out:
}
if(nread > 0)
ctx->data_recvd += nread;
- CURL_TRC_CF(data, cf, "[%"PRId64"] cf_recv(total=%"
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] cf_recv(total=%"
CURL_FORMAT_CURL_OFF_T ") -> %zd, %d",
stream->id, ctx->data_recvd, nread, *err);
return nread;
@@ -838,9 +900,9 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
size_t nheader, i;
- int64_t stream3_id;
+ curl_int64_t stream3_id;
struct dynhds h2_headers;
quiche_h3_header *nva = NULL;
ssize_t nwritten;
@@ -850,7 +912,7 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
if(*err) {
return -1;
}
- stream = H3_STREAM_CTX(data);
+ stream = H3_STREAM_CTX(ctx, data);
DEBUGASSERT(stream);
}
@@ -915,14 +977,14 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
if(QUICHE_H3_ERR_STREAM_BLOCKED == stream3_id) {
/* quiche seems to report this error if the connection window is
* exhausted. Which happens frequently and intermittent. */
- CURL_TRC_CF(data, cf, "[%"PRId64"] blocked", stream->id);
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] blocked", stream->id);
stream->quic_flow_blocked = TRUE;
*err = CURLE_AGAIN;
nwritten = -1;
goto out;
}
else {
- CURL_TRC_CF(data, cf, "send_request(%s) -> %" PRId64,
+ CURL_TRC_CF(data, cf, "send_request(%s) -> %" CURL_PRIu64,
data->state.url, stream3_id);
}
*err = CURLE_SEND_ERROR;
@@ -930,17 +992,18 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
goto out;
}
- DEBUGASSERT(stream->id == -1);
+ DEBUGASSERT(!stream->opened);
*err = CURLE_OK;
stream->id = stream3_id;
+ stream->opened = TRUE;
stream->closed = FALSE;
stream->reset = FALSE;
if(Curl_trc_is_verbose(data)) {
- infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s",
+ infof(data, "[HTTP/3] [%" CURL_PRIu64 "] OPENED stream for %s",
stream->id, data->state.url);
for(i = 0; i < nheader; ++i) {
- infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->id,
+ infof(data, "[HTTP/3] [%" CURL_PRIu64 "] [%.*s: %.*s]", stream->id,
(int)nva[i].name_len, nva[i].name,
(int)nva[i].value_len, nva[i].value);
}
@@ -956,7 +1019,7 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result;
ssize_t nwritten;
@@ -968,11 +1031,11 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out;
}
- if(!stream || stream->id < 0) {
+ if(!stream || !stream->opened) {
nwritten = h3_open_stream(cf, data, buf, len, err);
if(nwritten < 0)
goto out;
- stream = H3_STREAM_CTX(data);
+ stream = H3_STREAM_CTX(ctx, data);
}
else if(stream->closed) {
if(stream->resp_hds_complete) {
@@ -984,13 +1047,13 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* sending the 30x response.
* This is sort of a race: had the transfer loop called recv first,
* it would see the response and stop/discard sending on its own- */
- CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] discarding data"
"on closed stream with response", stream->id);
*err = CURLE_OK;
nwritten = (ssize_t)len;
goto out;
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
"-> stream closed", stream->id, len);
*err = CURLE_HTTP3;
nwritten = -1;
@@ -1005,7 +1068,7 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
/* TODO: we seem to be blocked on flow control and should HOLD
* sending. But when do we open again? */
if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
"-> window exhausted", stream->id, len);
stream->quic_flow_blocked = TRUE;
}
@@ -1014,21 +1077,21 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out;
}
else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
"-> invalid stream state", stream->id, len);
*err = CURLE_HTTP3;
nwritten = -1;
goto out;
}
else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
"-> exceeds size", stream->id, len);
*err = CURLE_SEND_ERROR;
nwritten = -1;
goto out;
}
else if(nwritten < 0) {
- CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
"-> quiche err %zd", stream->id, len, nwritten);
*err = CURLE_SEND_ERROR;
nwritten = -1;
@@ -1043,7 +1106,7 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
if(stream->upload_left == 0)
stream->send_closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" PRId64 "] send body(len=%zu, "
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send body(len=%zu, "
"left=%" CURL_FORMAT_CURL_OFF_T ") -> %zd",
stream->id, len, stream->upload_left, nwritten);
*err = CURLE_OK;
@@ -1056,7 +1119,7 @@ out:
*err = result;
nwritten = -1;
}
- CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
stream? stream->id : -1, len, nwritten, *err);
return nwritten;
}
@@ -1065,10 +1128,10 @@ static bool stream_is_writeable(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- return stream && (quiche_conn_stream_writable(ctx->qconn,
- (uint64_t)stream->id, 1) > 0);
+ return stream && (quiche_conn_stream_writable(
+ ctx->qconn, (curl_uint64_t)stream->id, 1) > 0);
}
static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
@@ -1083,12 +1146,12 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
if(want_recv || want_send) {
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
bool c_exhaust, s_exhaust;
c_exhaust = FALSE; /* Have not found any call in quiche that tells
us if the connection itself is blocked */
- s_exhaust = want_send && stream && stream->id >= 0 &&
+ s_exhaust = want_send && stream && stream->opened &&
(stream->quic_flow_blocked || !stream_is_writeable(cf, data));
want_recv = (want_recv || c_exhaust || s_exhaust);
want_send = (!s_exhaust && want_send) ||
@@ -1105,7 +1168,8 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
static bool cf_quiche_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
- const struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct cf_quiche_ctx *ctx = cf->ctx;
+ const struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)cf;
return stream && !Curl_bufq_is_empty(&stream->recvbuf);
}
@@ -1127,6 +1191,7 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
struct Curl_easy *data,
int event, int arg1, void *arg2)
{
+ struct cf_quiche_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
(void)arg1;
@@ -1144,7 +1209,7 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
h3_data_done(cf, data);
break;
case CF_CTRL_DATA_DONE_SEND: {
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(stream && !stream->send_closed) {
unsigned char body[1];
ssize_t sent;
@@ -1153,13 +1218,13 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
stream->upload_left = 0;
body[0] = 'X';
sent = cf_quiche_send(cf, data, body, 0, &result);
- CURL_TRC_CF(data, cf, "[%"PRId64"] DONE_SEND -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] DONE_SEND -> %zd, %d",
stream->id, sent, result);
}
break;
}
case CF_CTRL_DATA_IDLE: {
- struct stream_ctx *stream = H3_STREAM_CTX(data);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(stream && !stream->closed) {
result = cf_flush_egress(cf, data);
if(result)
@@ -1191,16 +1256,16 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
debug_log_init = 1;
}
#endif
- ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
H3_STREAM_POOL_SPARES);
+ Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
ctx->data_recvd = 0;
result = vquic_ctx_init(&ctx->q);
if(result)
return result;
- result = Curl_ssl_peer_init(&ctx->peer, cf);
+ result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
if(result)
return result;
@@ -1210,7 +1275,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
return CURLE_FAILED_INIT;
}
quiche_config_enable_pacing(ctx->cfg, false);
- quiche_config_set_max_idle_timeout(ctx->cfg, ctx->max_idle_ms * 1000);
+ quiche_config_set_max_idle_timeout(ctx->cfg, CURL_QUIC_MAX_IDLE_MS);
quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024)
/* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */);
quiche_config_set_initial_max_streams_bidi(ctx->cfg, QUIC_MAX_STREAMS);
@@ -1235,7 +1300,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
QUICHE_H3_APPLICATION_PROTOCOL,
sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1,
- NULL, cf);
+ NULL, NULL, cf);
if(result)
return result;
@@ -1255,7 +1320,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
(struct sockaddr *)&ctx->q.local_addr,
ctx->q.local_addrlen,
&sockaddr->sa_addr, sockaddr->addrlen,
- ctx->cfg, ctx->tls.ssl, false);
+ ctx->cfg, ctx->tls.ossl.ssl, false);
if(!ctx->qconn) {
failf(data, "can't create quiche connection");
return CURLE_OUT_OF_MEMORY;
@@ -1433,12 +1498,14 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
switch(query) {
case CF_QUERY_MAX_CONCURRENT: {
- uint64_t max_streams = CONN_INUSE(cf->conn);
+ curl_uint64_t max_streams = CONN_INUSE(cf->conn);
if(!ctx->goaway) {
max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn);
}
*pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
- CURL_TRC_CF(data, cf, "query: MAX_CONCURRENT -> %d", *pres1);
+ CURL_TRC_CF(data, cf, "query conn[%" CURL_FORMAT_CURL_OFF_T "]: "
+ "MAX_CONCURRENT -> %d (%zu in use)",
+ cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
return CURLE_OK;
}
case CF_QUERY_CONNECT_REPLY_MS:
@@ -1480,23 +1547,12 @@ static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf,
if(!ctx->qconn)
return FALSE;
- /* Both sides of the QUIC connection announce they max idle times in
- * the transport parameters. Look at the minimum of both and if
- * we exceed this, regard the connection as dead. The other side
- * may have completely purged it and will no longer respond
- * to any packets from us. */
- {
- quiche_transport_params qpeerparams;
- timediff_t idletime;
- uint64_t idle_ms = ctx->max_idle_ms;
-
- if(quiche_conn_peer_transport_params(ctx->qconn, &qpeerparams) &&
- qpeerparams.peer_max_idle_timeout &&
- qpeerparams.peer_max_idle_timeout < idle_ms)
- idle_ms = qpeerparams.peer_max_idle_timeout;
- idletime = Curl_timediff(Curl_now(), cf->conn->lastused);
- if(idletime > 0 && (uint64_t)idletime > idle_ms)
- return FALSE;
+ if(quiche_conn_is_closed(ctx->qconn)) {
+ if(quiche_conn_is_timed_out(ctx->qconn))
+ CURL_TRC_CF(data, cf, "connection was closed due to idle timeout");
+ else
+ CURL_TRC_CF(data, cf, "connection is closed");
+ return FALSE;
}
if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
diff --git a/libs/libcurl/src/vquic/vquic-tls.c b/libs/libcurl/src/vquic/vquic-tls.c
index 2a5f243e5d..df8a4f5c19 100644
--- a/libs/libcurl/src/vquic/vquic-tls.c
+++ b/libs/libcurl/src/vquic/vquic-tls.c
@@ -24,7 +24,7 @@
#include "curl_setup.h"
-#if defined(ENABLE_QUIC) && \
+#if defined(USE_HTTP3) && \
(defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL))
#ifdef USE_OPENSSL
@@ -61,277 +61,12 @@
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
-#ifdef USE_OPENSSL
-#define QUIC_CIPHERS \
- "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
- "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
-#define QUIC_GROUPS "P-256:X25519:P-384:P-521"
-#elif defined(USE_GNUTLS)
-#define QUIC_PRIORITY \
- "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
- "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
- "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
- "%DISABLE_TLS13_COMPAT_MODE"
-#elif defined(USE_WOLFSSL)
+#if defined(USE_WOLFSSL)
+
#define QUIC_CIPHERS \
"TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
"POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
#define QUIC_GROUPS "P-256:P-384:P-521"
-#endif
-
-
-#ifdef USE_OPENSSL
-
-static void keylog_callback(const SSL *ssl, const char *line)
-{
- (void)ssl;
- Curl_tls_keylog_write_line(line);
-}
-
-static CURLcode curl_ossl_init_ctx(struct quic_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- Curl_vquic_tls_ctx_setup *ctx_setup)
-{
- struct ssl_primary_config *conn_config;
- CURLcode result = CURLE_FAILED_INIT;
-
- DEBUGASSERT(!ctx->ssl_ctx);
-#ifdef USE_OPENSSL_QUIC
- ctx->ssl_ctx = SSL_CTX_new(OSSL_QUIC_client_method());
-#else
- ctx->ssl_ctx = SSL_CTX_new(TLS_method());
-#endif
- if(!ctx->ssl_ctx) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
- conn_config = Curl_ssl_cf_get_primary_config(cf);
- if(!conn_config) {
- result = CURLE_FAILED_INIT;
- goto out;
- }
-
- if(ctx_setup) {
- result = ctx_setup(ctx, cf, data);
- if(result)
- goto out;
- }
-
- SSL_CTX_set_default_verify_paths(ctx->ssl_ctx);
-
- {
- const char *curves = conn_config->curves ?
- conn_config->curves : QUIC_GROUPS;
- if(!SSL_CTX_set1_curves_list(ctx->ssl_ctx, curves)) {
- failf(data, "failed setting curves list for QUIC: '%s'", curves);
- return CURLE_SSL_CIPHER;
- }
- }
-
-#ifndef OPENSSL_IS_BORINGSSL
- {
- const char *ciphers13 = conn_config->cipher_list13 ?
- conn_config->cipher_list13 : QUIC_CIPHERS;
- if(SSL_CTX_set_ciphersuites(ctx->ssl_ctx, ciphers13) != 1) {
- failf(data, "failed setting QUIC cipher suite: %s", ciphers13);
- return CURLE_SSL_CIPHER;
- }
- infof(data, "QUIC cipher selection: %s", ciphers13);
- }
-#endif
-
- /* Open the file if a TLS or QUIC backend has not done this before. */
- Curl_tls_keylog_open();
- if(Curl_tls_keylog_enabled()) {
- SSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback);
- }
-
- /* OpenSSL always tries to verify the peer, this only says whether it should
- * fail to connect if the verification fails, or if it should continue
- * anyway. In the latter case the result of the verification is checked with
- * SSL_get_verify_result() below. */
- SSL_CTX_set_verify(ctx->ssl_ctx, conn_config->verifypeer ?
- SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
-
- /* give application a chance to interfere with SSL set up. */
- if(data->set.ssl.fsslctx) {
- /* When a user callback is installed to modify the SSL_CTX,
- * we need to do the full initialization before calling it.
- * See: #11800 */
- if(!ctx->x509_store_setup) {
- result = Curl_ssl_setup_x509_store(cf, data, ctx->ssl_ctx);
- if(result)
- goto out;
- ctx->x509_store_setup = TRUE;
- }
- Curl_set_in_callback(data, true);
- result = (*data->set.ssl.fsslctx)(data, ctx->ssl_ctx,
- data->set.ssl.fsslctxp);
- Curl_set_in_callback(data, false);
- if(result) {
- failf(data, "error signaled by ssl ctx callback");
- goto out;
- }
- }
- result = CURLE_OK;
-
-out:
- if(result && ctx->ssl_ctx) {
- SSL_CTX_free(ctx->ssl_ctx);
- ctx->ssl_ctx = NULL;
- }
- return result;
-}
-
-static CURLcode curl_ossl_set_client_cert(struct quic_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- SSL_CTX *ssl_ctx = ctx->ssl_ctx;
- const struct ssl_config_data *ssl_config;
-
- ssl_config = Curl_ssl_cf_get_config(cf, data);
- DEBUGASSERT(ssl_config);
-
- if(ssl_config->primary.clientcert ||
- ssl_config->primary.cert_blob ||
- ssl_config->cert_type) {
- return Curl_ossl_set_client_cert(
- data, ssl_ctx, ssl_config->primary.clientcert,
- ssl_config->primary.cert_blob, ssl_config->cert_type,
- ssl_config->key, ssl_config->key_blob,
- ssl_config->key_type, ssl_config->key_passwd);
- }
-
- return CURLE_OK;
-}
-
-/** SSL callbacks ***/
-
-static CURLcode curl_ossl_init_ssl(struct quic_tls_ctx *ctx,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- const char *alpn, size_t alpn_len,
- void *user_data)
-{
- DEBUGASSERT(!ctx->ssl);
- ctx->ssl = SSL_new(ctx->ssl_ctx);
-
- SSL_set_app_data(ctx->ssl, user_data);
- SSL_set_connect_state(ctx->ssl);
-#ifndef USE_OPENSSL_QUIC
- SSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);
-#endif
-
- if(alpn)
- SSL_set_alpn_protos(ctx->ssl, (const uint8_t *)alpn, (int)alpn_len);
-
- if(peer->sni) {
- if(!SSL_set_tlsext_host_name(ctx->ssl, peer->sni)) {
- failf(data, "Failed set SNI");
- SSL_free(ctx->ssl);
- ctx->ssl = NULL;
- return CURLE_QUIC_CONNECT_ERROR;
- }
- }
- return CURLE_OK;
-}
-
-#elif defined(USE_GNUTLS)
-static int keylog_callback(gnutls_session_t session, const char *label,
- const gnutls_datum_t *secret)
-{
- gnutls_datum_t crandom;
- gnutls_datum_t srandom;
-
- gnutls_session_get_random(session, &crandom, &srandom);
- if(crandom.size != 32) {
- return -1;
- }
-
- Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
- return 0;
-}
-
-static CURLcode curl_gtls_init_ctx(struct quic_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- const char *alpn, size_t alpn_len,
- Curl_vquic_tls_ctx_setup *ctx_setup,
- void *user_data)
-{
- struct ssl_primary_config *conn_config;
- CURLcode result;
- gnutls_datum_t alpns[5];
- /* this will need some attention when HTTPS proxy over QUIC get fixed */
- long * const pverifyresult = &data->set.ssl.certverifyresult;
- int rc;
-
- conn_config = Curl_ssl_cf_get_primary_config(cf);
- if(!conn_config)
- return CURLE_FAILED_INIT;
-
- DEBUGASSERT(ctx->gtls == NULL);
- ctx->gtls = calloc(1, sizeof(*(ctx->gtls)));
- if(!ctx->gtls)
- return CURLE_OUT_OF_MEMORY;
-
- result = gtls_client_init(data, conn_config, &data->set.ssl,
- peer, ctx->gtls, pverifyresult);
- if(result)
- return result;
-
- gnutls_session_set_ptr(ctx->gtls->session, user_data);
-
- if(ctx_setup) {
- result = ctx_setup(ctx, cf, data);
- if(result)
- return result;
- }
-
- rc = gnutls_priority_set_direct(ctx->gtls->session, QUIC_PRIORITY, NULL);
- if(rc < 0) {
- CURL_TRC_CF(data, cf, "gnutls_priority_set_direct failed: %s\n",
- gnutls_strerror(rc));
- return CURLE_QUIC_CONNECT_ERROR;
- }
-
- /* Open the file if a TLS or QUIC backend has not done this before. */
- Curl_tls_keylog_open();
- if(Curl_tls_keylog_enabled()) {
- gnutls_session_set_keylog_function(ctx->gtls->session, keylog_callback);
- }
-
- /* convert the ALPN string from our arguments to a list of strings
- * that gnutls wants and will convert internally back to this very
- * string for sending to the server. nice. */
- if(alpn) {
- size_t i, alen = alpn_len;
- unsigned char *s = (unsigned char *)alpn;
- unsigned char slen;
- for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) {
- slen = s[0];
- if(slen >= alen)
- return CURLE_FAILED_INIT;
- alpns[i].data = s + 1;
- alpns[i].size = slen;
- s += slen + 1;
- alen -= (size_t)slen + 1;
- }
- if(alen) /* not all alpn chars used, wrong format or too many */
- return CURLE_FAILED_INIT;
- if(i) {
- gnutls_alpn_set_protocols(ctx->gtls->session,
- alpns, (unsigned int)i,
- GNUTLS_ALPN_MANDATORY);
- }
- }
-
- return CURLE_OK;
-}
-#elif defined(USE_WOLFSSL)
#if defined(HAVE_SECRET_CALLBACK)
static void keylog_callback(const WOLFSSL *ssl, const char *line)
@@ -341,10 +76,11 @@ static void keylog_callback(const WOLFSSL *ssl, const char *line)
}
#endif
-static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx,
+static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
- Curl_vquic_tls_ctx_setup *ctx_setup)
+ Curl_vquic_tls_ctx_setup *cb_setup,
+ void *cb_user_data)
{
struct ssl_primary_config *conn_config;
CURLcode result = CURLE_FAILED_INIT;
@@ -361,8 +97,8 @@ static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx,
goto out;
}
- if(ctx_setup) {
- result = ctx_setup(ctx, cf, data);
+ if(cb_setup) {
+ result = cb_setup(cf, data, cb_user_data);
if(result)
goto out;
}
@@ -458,7 +194,7 @@ out:
/** SSL callbacks ***/
-static CURLcode curl_wssl_init_ssl(struct quic_tls_ctx *ctx,
+static CURLcode curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
@@ -486,57 +222,50 @@ static CURLcode curl_wssl_init_ssl(struct quic_tls_ctx *ctx,
}
#endif /* defined(USE_WOLFSSL) */
-CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx,
+CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
- Curl_vquic_tls_ctx_setup *ctx_setup,
- void *user_data)
+ Curl_vquic_tls_ctx_setup *cb_setup,
+ void *cb_user_data, void *ssl_user_data)
{
CURLcode result;
#ifdef USE_OPENSSL
- result = curl_ossl_init_ctx(ctx, cf, data, ctx_setup);
- if(result)
- return result;
-
- result = curl_ossl_set_client_cert(ctx, cf, data);
- if(result)
- return result;
-
- return curl_ossl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data);
+ (void)result;
+ return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer, TRNSPRT_QUIC,
+ (const unsigned char *)alpn, alpn_len,
+ cb_setup, cb_user_data, NULL, ssl_user_data);
#elif defined(USE_GNUTLS)
(void)result;
- return curl_gtls_init_ctx(ctx, cf, data, peer, alpn, alpn_len,
- ctx_setup, user_data);
+ return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer,
+ (const unsigned char *)alpn, alpn_len,
+ cb_setup, cb_user_data, ssl_user_data);
#elif defined(USE_WOLFSSL)
- result = curl_wssl_init_ctx(ctx, cf, data, ctx_setup);
+ result = curl_wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
if(result)
return result;
- return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data);
+ return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, ssl_user_data);
#else
#error "no TLS lib in used, should not happen"
return CURLE_FAILED_INIT;
#endif
}
-void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx)
+void Curl_vquic_tls_cleanup(struct curl_tls_ctx *ctx)
{
#ifdef USE_OPENSSL
- if(ctx->ssl)
- SSL_free(ctx->ssl);
- if(ctx->ssl_ctx)
- SSL_CTX_free(ctx->ssl_ctx);
+ if(ctx->ossl.ssl)
+ SSL_free(ctx->ossl.ssl);
+ if(ctx->ossl.ssl_ctx)
+ SSL_CTX_free(ctx->ossl.ssl_ctx);
#elif defined(USE_GNUTLS)
- if(ctx->gtls) {
- if(ctx->gtls->cred)
- gnutls_certificate_free_credentials(ctx->gtls->cred);
- if(ctx->gtls->session)
- gnutls_deinit(ctx->gtls->session);
- free(ctx->gtls);
- }
+ if(ctx->gtls.cred)
+ gnutls_certificate_free_credentials(ctx->gtls.cred);
+ if(ctx->gtls.session)
+ gnutls_deinit(ctx->gtls.session);
#elif defined(USE_WOLFSSL)
if(ctx->ssl)
wolfSSL_free(ctx->ssl);
@@ -546,16 +275,22 @@ void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx)
memset(ctx, 0, sizeof(*ctx));
}
-CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx,
+CURLcode Curl_vquic_tls_before_recv(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data)
{
#ifdef USE_OPENSSL
- if(!ctx->x509_store_setup) {
- CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ssl_ctx);
+ if(!ctx->ossl.x509_store_setup) {
+ CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ossl.ssl_ctx);
+ if(result)
+ return result;
+ ctx->ossl.x509_store_setup = TRUE;
+ }
+#elif defined(USE_GNUTLS)
+ if(!ctx->gtls.trust_setup) {
+ CURLcode result = Curl_gtls_client_trust_setup(cf, data, &ctx->gtls);
if(result)
return result;
- ctx->x509_store_setup = TRUE;
}
#else
(void)ctx; (void)cf; (void)data;
@@ -563,7 +298,7 @@ CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx,
return CURLE_OK;
}
-CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx,
+CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer)
@@ -575,39 +310,33 @@ CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx,
if(!conn_config)
return CURLE_FAILED_INIT;
- if(conn_config->verifyhost) {
#ifdef USE_OPENSSL
- X509 *server_cert;
- server_cert = SSL_get1_peer_certificate(ctx->ssl);
- if(!server_cert) {
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- result = Curl_ossl_verifyhost(data, cf->conn, peer, server_cert);
- X509_free(server_cert);
- if(result)
- return result;
+ (void)conn_config;
+ result = Curl_oss_check_peer_cert(cf, data, &ctx->ossl, peer);
#elif defined(USE_GNUTLS)
- result = Curl_gtls_verifyserver(data, ctx->gtls->session,
+ if(conn_config->verifyhost) {
+ result = Curl_gtls_verifyserver(data, ctx->gtls.session,
conn_config, &data->set.ssl, peer,
data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
if(result)
return result;
+ }
#elif defined(USE_WOLFSSL)
- if(!peer->sni ||
- wolfSSL_check_domain_name(ctx->ssl, peer->sni) == SSL_FAILURE)
- return CURLE_PEER_FAILED_VERIFICATION;
-#endif
- infof(data, "Verified certificate just fine");
+ (void)data;
+ if(conn_config->verifyhost) {
+ if(peer->sni) {
+ WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->ssl);
+ if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
+ == WOLFSSL_FAILURE) {
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ wolfSSL_X509_free(cert);
+ }
+
}
- else
- infof(data, "Skipped certificate verification");
-#ifdef USE_OPENSSL
- if(data->set.ssl.certinfo)
- /* asked to gather certificate info */
- (void)Curl_ossl_certchain(data, ctx->ssl);
#endif
return result;
}
-#endif /* !ENABLE_QUIC && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
+#endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
diff --git a/libs/libcurl/src/vquic/vquic-tls.h b/libs/libcurl/src/vquic/vquic-tls.h
index 60dc7b18b6..e7d33d4b46 100644
--- a/libs/libcurl/src/vquic/vquic-tls.h
+++ b/libs/libcurl/src/vquic/vquic-tls.h
@@ -26,21 +26,20 @@
#include "curl_setup.h"
#include "bufq.h"
+#include "vtls/openssl.h"
-#if defined(ENABLE_QUIC) && \
+#if defined(USE_HTTP3) && \
(defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL))
-struct quic_tls_ctx {
+struct curl_tls_ctx {
#ifdef USE_OPENSSL
- SSL_CTX *ssl_ctx;
- SSL *ssl;
+ struct ossl_ctx ossl;
#elif defined(USE_GNUTLS)
- struct gtls_instance *gtls;
+ struct gtls_ctx gtls;
#elif defined(USE_WOLFSSL)
WOLFSSL_CTX *ssl_ctx;
WOLFSSL *ssl;
#endif
- BIT(x509_store_setup); /* if x509 store has been set up */
};
/**
@@ -50,9 +49,9 @@ struct quic_tls_ctx {
* - openssl/wolfssl: SSL_CTX* has just been created
* - gnutls: gtls_client_init() has run
*/
-typedef CURLcode Curl_vquic_tls_ctx_setup(struct quic_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data);
+typedef CURLcode Curl_vquic_tls_ctx_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *cb_user_data);
/**
* Initialize the QUIC TLS instances based of the SSL configurations
@@ -64,23 +63,25 @@ typedef CURLcode Curl_vquic_tls_ctx_setup(struct quic_tls_ctx *ctx,
* @param alpn the ALPN string in protocol format ((len+bytes+)+),
* may be NULL
* @param alpn_len the overall number of bytes in `alpn`
- * @param ctx_setup optional callback for very early TLS config
- * @param user_data optional pointer to set in TLS application context
+ * @param cb_setup optional callback for very early TLS config
+ ± @param cb_user_data user_data param for callback
+ * @param ssl_user_data optional pointer to set in TLS application context
*/
-CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx,
+CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
- Curl_vquic_tls_ctx_setup *ctx_setup,
- void *user_data);
+ Curl_vquic_tls_ctx_setup *cb_setup,
+ void *cb_user_data,
+ void *ssl_user_data);
/**
* Cleanup all data that has been initialized.
*/
-void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx);
+void Curl_vquic_tls_cleanup(struct curl_tls_ctx *ctx);
-CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx,
+CURLcode Curl_vquic_tls_before_recv(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data);
@@ -88,11 +89,11 @@ CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx,
* After the QUIC basic handshake has been, verify that the peer
* (and its certificate) fulfill our requirements.
*/
-CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx,
+CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer);
-#endif /* !ENABLE_QUIC && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
+#endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
#endif /* HEADER_CURL_VQUIC_TLS_H */
diff --git a/libs/libcurl/src/vquic/vquic.c b/libs/libcurl/src/vquic/vquic.c
index 422f7d18c0..feff3395cc 100644
--- a/libs/libcurl/src/vquic/vquic.c
+++ b/libs/libcurl/src/vquic/vquic.c
@@ -59,7 +59,7 @@
#include "memdebug.h"
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
#ifdef O_BINARY
#define QLOGMODE O_WRONLY|O_CREAT|O_BINARY
@@ -663,7 +663,7 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data,
return CURLE_OK;
}
-#else /* ENABLE_QUIC */
+#else /* USE_HTTP3 */
CURLcode Curl_conn_may_http3(struct Curl_easy *data,
const struct connectdata *conn)
@@ -674,4 +674,4 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data,
return CURLE_NOT_BUILT_IN;
}
-#endif /* !ENABLE_QUIC */
+#endif /* !USE_HTTP3 */
diff --git a/libs/libcurl/src/vquic/vquic.h b/libs/libcurl/src/vquic/vquic.h
index 618f62ab5a..dde9003fa3 100644
--- a/libs/libcurl/src/vquic/vquic.h
+++ b/libs/libcurl/src/vquic/vquic.h
@@ -26,7 +26,7 @@
#include "curl_setup.h"
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
struct Curl_cfilter;
struct Curl_easy;
struct connectdata;
@@ -52,11 +52,11 @@ bool Curl_conn_is_http3(const struct Curl_easy *data,
extern struct Curl_cftype Curl_cft_http3;
-#else /* ENABLE_QUIC */
+#else /* USE_HTTP3 */
#define Curl_conn_is_http3(a,b,c) FALSE
-#endif /* !ENABLE_QUIC */
+#endif /* !USE_HTTP3 */
CURLcode Curl_conn_may_http3(struct Curl_easy *data,
const struct connectdata *conn);
diff --git a/libs/libcurl/src/vquic/vquic_int.h b/libs/libcurl/src/vquic/vquic_int.h
index ce7983029a..52203735bf 100644
--- a/libs/libcurl/src/vquic/vquic_int.h
+++ b/libs/libcurl/src/vquic/vquic_int.h
@@ -27,7 +27,7 @@
#include "curl_setup.h"
#include "bufq.h"
-#ifdef ENABLE_QUIC
+#ifdef USE_HTTP3
#define MAX_PKT_BURST 10
#define MAX_UDP_PAYLOAD_SIZE 1452
@@ -88,6 +88,6 @@ CURLcode vquic_recv_packets(struct Curl_cfilter *cf,
size_t max_pkts,
vquic_recv_pkt_cb *recv_cb, void *userp);
-#endif /* !ENABLE_QUIC */
+#endif /* !USE_HTTP3 */
#endif /* HEADER_CURL_VQUIC_QUIC_INT_H */
diff --git a/libs/libcurl/src/vssh/libssh.c b/libs/libcurl/src/vssh/libssh.c
index 8d5cdcfbb9..9ba38ac257 100644
--- a/libs/libcurl/src/vssh/libssh.c
+++ b/libs/libcurl/src/vssh/libssh.c
@@ -162,6 +162,7 @@ const struct Curl_handler Curl_handler_scp = {
myssh_getsock, /* perform_getsock */
scp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
@@ -189,6 +190,7 @@ const struct Curl_handler Curl_handler_sftp = {
myssh_getsock, /* perform_getsock */
sftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
diff --git a/libs/libcurl/src/vssh/libssh2.c b/libs/libcurl/src/vssh/libssh2.c
index f1e1dfd0fc..eff5bd8fe1 100644
--- a/libs/libcurl/src/vssh/libssh2.c
+++ b/libs/libcurl/src/vssh/libssh2.c
@@ -139,6 +139,7 @@ const struct Curl_handler Curl_handler_scp = {
ssh_getsock, /* perform_getsock */
scp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ssh_attach, /* attach */
PORT_SSH, /* defport */
@@ -168,6 +169,7 @@ const struct Curl_handler Curl_handler_sftp = {
ssh_getsock, /* perform_getsock */
sftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ssh_attach, /* attach */
PORT_SSH, /* defport */
@@ -201,7 +203,8 @@ kbd_callback(const char *name, int name_len, const char *instruction,
if(num_prompts == 1) {
struct connectdata *conn = data->conn;
responses[0].text = strdup(conn->passwd);
- responses[0].length = curlx_uztoui(strlen(conn->passwd));
+ responses[0].length =
+ responses[0].text == NULL ? 0 : curlx_uztoui(strlen(conn->passwd));
}
(void)prompts;
} /* kbd_callback */
@@ -1083,6 +1086,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* To ponder about: should really the lib be messing about with the
HOME environment variable etc? */
char *home = curl_getenv("HOME");
+ struct_stat sbuf;
/* If no private key file is specified, try some common paths. */
if(home) {
@@ -1090,12 +1094,12 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->rsa = aprintf("%s/.ssh/id_rsa", home);
if(!sshc->rsa)
out_of_memory = TRUE;
- else if(access(sshc->rsa, R_OK) != 0) {
+ else if(stat(sshc->rsa, &sbuf)) {
Curl_safefree(sshc->rsa);
sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
if(!sshc->rsa)
out_of_memory = TRUE;
- else if(access(sshc->rsa, R_OK) != 0) {
+ else if(stat(sshc->rsa, &sbuf)) {
Curl_safefree(sshc->rsa);
}
}
@@ -1104,10 +1108,10 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(!out_of_memory && !sshc->rsa) {
/* Nothing found; try the current dir. */
sshc->rsa = strdup("id_rsa");
- if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
+ if(sshc->rsa && stat(sshc->rsa, &sbuf)) {
Curl_safefree(sshc->rsa);
sshc->rsa = strdup("id_dsa");
- if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
+ if(sshc->rsa && stat(sshc->rsa, &sbuf)) {
Curl_safefree(sshc->rsa);
/* Out of guesses. Set to the empty string to avoid
* surprising info messages. */
@@ -3282,7 +3286,6 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
return CURLE_FAILED_INIT;
}
-#ifdef HAVE_LIBSSH2_VERSION
/* Set the packet read timeout if the libssh2 version supports it */
#if LIBSSH2_VERSION_NUM >= 0x010B00
if(data->set.server_response_timeout > 0) {
@@ -3290,7 +3293,6 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
data->set.server_response_timeout / 1000);
}
#endif
-#endif
#ifndef CURL_DISABLE_PROXY
if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
diff --git a/libs/libcurl/src/vssh/wolfssh.c b/libs/libcurl/src/vssh/wolfssh.c
index fcba60e8ee..58009faef0 100644
--- a/libs/libcurl/src/vssh/wolfssh.c
+++ b/libs/libcurl/src/vssh/wolfssh.c
@@ -94,6 +94,7 @@ const struct Curl_handler Curl_handler_scp = {
wssh_getsock, /* perform_getsock */
wscp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
@@ -123,6 +124,7 @@ const struct Curl_handler Curl_handler_sftp = {
wssh_getsock, /* perform_getsock */
wsftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
+ ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
diff --git a/libs/libcurl/src/vtls/bearssl.c b/libs/libcurl/src/vtls/bearssl.c
index 9ccfd8f473..f5f6ad3756 100644
--- a/libs/libcurl/src/vtls/bearssl.c
+++ b/libs/libcurl/src/vtls/bearssl.c
@@ -28,6 +28,7 @@
#include <bearssl.h>
#include "bearssl.h"
+#include "cipher_suite.h"
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
@@ -37,7 +38,6 @@
#include "select.h"
#include "multiif.h"
#include "curl_printf.h"
-#include "strcase.h"
/* The last #include files should be: */
#include "curl_memory.h"
@@ -120,9 +120,9 @@ static CURLcode load_cafile(struct cafile_source *source,
br_x509_pkey *pkey;
FILE *fp = 0;
unsigned char buf[BUFSIZ];
- const unsigned char *p;
+ const unsigned char *p = NULL;
const char *name;
- size_t n, i, pushed;
+ size_t n = 0, i, pushed;
DEBUGASSERT(source->type == CAFILE_SOURCE_PATH
|| source->type == CAFILE_SOURCE_BLOB);
@@ -360,219 +360,121 @@ static const br_x509_class x509_vtable = {
x509_get_pkey
};
-struct st_cipher {
- const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */
- const char *alias_name; /* Alias name is the same as OpenSSL cipher name */
- uint16_t num; /* BearSSL cipher suite */
-};
-
-/* Macro to initialize st_cipher data structure */
-#define CIPHER_DEF(num, alias) { #num, alias, BR_##num }
-
-static const struct st_cipher ciphertable[] = {
+static const uint16_t ciphertable[] = {
/* RFC 2246 TLS 1.0 */
- CIPHER_DEF(TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
- "DES-CBC3-SHA"),
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
/* RFC 3268 TLS 1.0 AES */
- CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
- "AES128-SHA"),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
- "AES256-SHA"),
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
/* RFC 5246 TLS 1.2 */
- CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
- "AES128-SHA256"),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
- "AES256-SHA256"),
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
/* RFC 5288 TLS 1.2 AES GCM */
- CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
- "AES128-GCM-SHA256"),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
- "AES256-GCM-SHA384"),
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
/* RFC 4492 TLS 1.0 ECC */
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */
- "ECDH-ECDSA-DES-CBC3-SHA"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */
- "ECDH-ECDSA-AES128-SHA"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */
- "ECDH-ECDSA-AES256-SHA"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */
- "ECDHE-ECDSA-DES-CBC3-SHA"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
- "ECDHE-ECDSA-AES128-SHA"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
- "ECDHE-ECDSA-AES256-SHA"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */
- "ECDH-RSA-DES-CBC3-SHA"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */
- "ECDH-RSA-AES128-SHA"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */
- "ECDH-RSA-AES256-SHA"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */
- "ECDHE-RSA-DES-CBC3-SHA"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
- "ECDHE-RSA-AES128-SHA"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
- "ECDHE-RSA-AES256-SHA"),
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
/* RFC 5289 TLS 1.2 ECC HMAC SHA256/384 */
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
- "ECDHE-ECDSA-AES128-SHA256"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
- "ECDHE-ECDSA-AES256-SHA384"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */
- "ECDH-ECDSA-AES128-SHA256"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */
- "ECDH-ECDSA-AES256-SHA384"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
- "ECDHE-RSA-AES128-SHA256"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
- "ECDHE-RSA-AES256-SHA384"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */
- "ECDH-RSA-AES128-SHA256"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */
- "ECDH-RSA-AES256-SHA384"),
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */
/* RFC 5289 TLS 1.2 GCM */
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
- "ECDHE-ECDSA-AES128-GCM-SHA256"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
- "ECDHE-ECDSA-AES256-GCM-SHA384"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */
- "ECDH-ECDSA-AES128-GCM-SHA256"),
- CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */
- "ECDH-ECDSA-AES256-GCM-SHA384"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
- "ECDHE-RSA-AES128-GCM-SHA256"),
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
- "ECDHE-RSA-AES256-GCM-SHA384"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */
- "ECDH-RSA-AES128-GCM-SHA256"),
- CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */
- "ECDH-RSA-AES256-GCM-SHA384"),
-#ifdef BR_TLS_RSA_WITH_AES_128_CCM
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */
+#ifdef BR_TLS_RSA_WITH_AES_128_CCM
/* RFC 6655 TLS 1.2 CCM
Supported since BearSSL 0.6 */
- CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM, /* 0xC09C */
- "AES128-CCM"),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM, /* 0xC09D */
- "AES256-CCM"),
- CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM_8, /* 0xC0A0 */
- "AES128-CCM8"),
- CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM_8, /* 0xC0A1 */
- "AES256-CCM8"),
+ BR_TLS_RSA_WITH_AES_128_CCM, /* 0xC09C */
+ BR_TLS_RSA_WITH_AES_256_CCM, /* 0xC09D */
+ BR_TLS_RSA_WITH_AES_128_CCM_8, /* 0xC0A0 */
+ BR_TLS_RSA_WITH_AES_256_CCM_8, /* 0xC0A1 */
/* RFC 7251 TLS 1.2 ECC CCM
Supported since BearSSL 0.6 */
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM, /* 0xC0AC */
- "ECDHE-ECDSA-AES128-CCM"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM, /* 0xC0AD */
- "ECDHE-ECDSA-AES256-CCM"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, /* 0xC0AE */
- "ECDHE-ECDSA-AES128-CCM8"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, /* 0xC0AF */
- "ECDHE-ECDSA-AES256-CCM8"),
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, /* 0xC0AC */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, /* 0xC0AD */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, /* 0xC0AE */
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, /* 0xC0AF */
#endif
/* RFC 7905 TLS 1.2 ChaCha20-Poly1305
Supported since BearSSL 0.2 */
- CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
- "ECDHE-RSA-CHACHA20-POLY1305"),
- CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
- "ECDHE-ECDSA-CHACHA20-POLY1305"),
+ BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
+ BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
};
#define NUM_OF_CIPHERS (sizeof(ciphertable) / sizeof(ciphertable[0]))
-#define CIPHER_NAME_BUF_LEN 64
-
-static bool is_separator(char c)
-{
- /* Return whether character is a cipher list separator. */
- switch(c) {
- case ' ':
- case '\t':
- case ':':
- case ',':
- case ';':
- return true;
- }
- return false;
-}
static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data,
br_ssl_engine_context *ssl_eng,
const char *ciphers)
{
- uint16_t selected_ciphers[NUM_OF_CIPHERS];
- size_t selected_count = 0;
- const char *cipher_start = ciphers;
- const char *cipher_end;
- size_t i, j;
-
- if(!cipher_start)
- return CURLE_SSL_CIPHER;
-
- while(true) {
- const char *cipher;
- size_t clen;
-
- /* Extract the next cipher name from the ciphers string */
- while(is_separator(*cipher_start))
- ++cipher_start;
- if(!*cipher_start)
- break;
- cipher_end = cipher_start;
- while(*cipher_end && !is_separator(*cipher_end))
- ++cipher_end;
-
- clen = cipher_end - cipher_start;
- cipher = cipher_start;
-
- cipher_start = cipher_end;
-
- /* Lookup the cipher name in the table of available ciphers. If the cipher
- name starts with "TLS_" we do the lookup by IANA name. Otherwise, we try
- to match cipher name by an (OpenSSL) alias. */
- if(strncasecompare(cipher, "TLS_", 4)) {
- for(i = 0; i < NUM_OF_CIPHERS &&
- (strlen(ciphertable[i].name) == clen) &&
- !strncasecompare(cipher, ciphertable[i].name, clen); ++i);
+ uint16_t selected[NUM_OF_CIPHERS];
+ size_t count = 0, i;
+ const char *ptr, *end;
+
+ for(ptr = ciphers; ptr[0] != '\0' && count < NUM_OF_CIPHERS; ptr = end) {
+ uint16_t id = Curl_cipher_suite_walk_str(&ptr, &end);
+
+ /* Check if cipher is supported */
+ if(id) {
+ for(i = 0; i < NUM_OF_CIPHERS && ciphertable[i] != id; i++);
+ if(i == NUM_OF_CIPHERS)
+ id = 0;
}
- else {
- for(i = 0; i < NUM_OF_CIPHERS &&
- (strlen(ciphertable[i].alias_name) == clen) &&
- !strncasecompare(cipher, ciphertable[i].alias_name, clen); ++i);
- }
- if(i == NUM_OF_CIPHERS) {
- infof(data, "BearSSL: unknown cipher in list: %.*s",
- (int)clen, cipher);
+ if(!id) {
+ if(ptr[0] != '\0')
+ infof(data, "BearSSL: unknown cipher in list: \"%.*s\"",
+ (int) (end - ptr), ptr);
continue;
}
/* No duplicates allowed */
- for(j = 0; j < selected_count &&
- selected_ciphers[j] != ciphertable[i].num; j++);
- if(j < selected_count) {
- infof(data, "BearSSL: duplicate cipher in list: %.*s",
- (int)clen, cipher);
+ for(i = 0; i < count && selected[i] != id; i++);
+ if(i < count) {
+ infof(data, "BearSSL: duplicate cipher in list: \"%.*s\"",
+ (int) (end - ptr), ptr);
continue;
}
- DEBUGASSERT(selected_count < NUM_OF_CIPHERS);
- selected_ciphers[selected_count] = ciphertable[i].num;
- ++selected_count;
+ selected[count++] = id;
}
- if(selected_count == 0) {
+ if(count == 0) {
failf(data, "BearSSL: no supported cipher in list");
return CURLE_SSL_CIPHER;
}
- br_ssl_engine_set_suites(ssl_eng, selected_ciphers, selected_count);
+ br_ssl_engine_set_suites(ssl_eng, selected, count);
return CURLE_OK;
}
@@ -686,7 +588,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "connect_step1, check session cache");
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &session, NULL)) {
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
session_set = 1;
infof(data, "BearSSL: reusing session ID");
@@ -830,7 +732,7 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
if(ret == 0) {
failf(data, "SSL: EOF without close notify");
- return CURLE_READ_ERROR;
+ return CURLE_RECV_ERROR;
}
if(ret <= 0) {
return result;
@@ -846,6 +748,9 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
struct bearssl_ssl_backend_data *backend =
(struct bearssl_ssl_backend_data *)connssl->backend;
+ br_ssl_session_parameters session;
+ char cipher_str[64];
+ char ver_str[16];
CURLcode ret;
DEBUGASSERT(backend);
@@ -856,6 +761,7 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
return CURLE_OK;
if(ret == CURLE_OK) {
unsigned int tver;
+
if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
failf(data, "SSL: connection closed during handshake");
return CURLE_SSL_CONNECT_ERROR;
@@ -863,16 +769,29 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
connssl->connecting_state = ssl_connect_3;
/* Informational message */
tver = br_ssl_engine_get_version(&backend->ctx.eng);
- if(tver == 0x0303)
- infof(data, "SSL connection using TLSv1.2");
- else if(tver == 0x0304)
- infof(data, "SSL connection using TLSv1.3");
- else
- infof(data, "SSL connection using TLS 0x%x", tver);
+ if(tver == BR_TLS12)
+ strcpy(ver_str, "TLSv1.2");
+ else if(tver == BR_TLS11)
+ strcpy(ver_str, "TLSv1.1");
+ else if(tver == BR_TLS10)
+ strcpy(ver_str, "TLSv1.0");
+ else {
+ msnprintf(ver_str, sizeof(ver_str), "TLS 0x%04x", tver);
+ }
+ br_ssl_engine_get_session_parameters(&backend->ctx.eng, &session);
+ Curl_cipher_suite_get_str(session.cipher_suite, cipher_str,
+ sizeof(cipher_str), true);
+ infof(data, "BearSSL: %s connection using %s", ver_str, cipher_str);
}
return ret;
}
+static void bearssl_session_free(void *sessionid, size_t idsize)
+{
+ (void)idsize;
+ free(sessionid);
+}
+
static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -896,7 +815,6 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
if(ssl_config->primary.sessionid) {
bool incache;
- bool added = FALSE;
void *oldsession;
br_ssl_session_parameters *session;
@@ -905,16 +823,16 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
return CURLE_OUT_OF_MEMORY;
br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &oldsession, NULL));
+ incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ &oldsession, NULL));
if(incache)
Curl_ssl_delsessionid(data, oldsession);
- ret = Curl_ssl_addsessionid(cf, data, session, 0, &added);
+
+ ret = Curl_ssl_addsessionid(cf, data, &connssl->peer, session, 0,
+ bearssl_session_free);
Curl_ssl_sessionid_unlock(data);
- if(!added)
- free(session);
- if(ret) {
- return CURLE_OUT_OF_MEMORY;
- }
+ if(ret)
+ return ret;
}
connssl->connecting_state = ssl_connect_done;
@@ -1173,11 +1091,6 @@ static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
-static void bearssl_session_free(void *ptr)
-{
- free(ptr);
-}
-
static CURLcode bearssl_sha256sum(const unsigned char *input,
size_t inputlen,
unsigned char *sha256sum,
@@ -1210,7 +1123,6 @@ const struct Curl_ssl Curl_ssl_bearssl = {
bearssl_get_internals, /* get_internals */
bearssl_close, /* close_one */
Curl_none_close_all, /* close_all */
- bearssl_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/cipher_suite.c b/libs/libcurl/src/vtls/cipher_suite.c
new file mode 100644
index 0000000000..723b94d13f
--- /dev/null
+++ b/libs/libcurl/src/vtls/cipher_suite.c
@@ -0,0 +1,716 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Jan Venekamp, <jan@venekamp.net>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
+#include "cipher_suite.h"
+#include "curl_printf.h"
+#include "strcase.h"
+#include <string.h>
+
+/*
+ * To support the CURLOPT_SSL_CIPHER_LIST option on SSL backends
+ * that do not support it natively, but do support setting a list of
+ * IANA ids, we need a list of all supported cipher suite names
+ * (openssl and IANA) to be able to look up the IANA ids.
+ *
+ * To keep the binary size of this list down we compress each entry
+ * down to 2 + 6 bytes using the C preprocessor.
+ */
+
+/*
+ * mbedTLS NOTE: mbedTLS has mbedtls_ssl_get_ciphersuite_id() to
+ * convert a string representation to an IANA id, we do not use that
+ * because it does not support "standard" openssl cipher suite
+ * names, nor IANA names.
+ */
+
+/* NOTE: also see tests/unit/unit3205.c */
+
+/* Text for cipher suite parts (max 64 entries),
+ keep indexes below in sync with this! */
+static const char *cs_txt =
+ "\0"
+ "TLS" "\0"
+ "WITH" "\0"
+ "128" "\0"
+ "256" "\0"
+ "3DES" "\0"
+ "8" "\0"
+ "AES" "\0"
+ "AES128" "\0"
+ "AES256" "\0"
+ "CBC" "\0"
+ "CBC3" "\0"
+ "CCM" "\0"
+ "CCM8" "\0"
+ "CHACHA20" "\0"
+ "DES" "\0"
+ "DHE" "\0"
+ "ECDH" "\0"
+ "ECDHE" "\0"
+ "ECDSA" "\0"
+ "EDE" "\0"
+ "GCM" "\0"
+ "MD5" "\0"
+ "NULL" "\0"
+ "POLY1305" "\0"
+ "PSK" "\0"
+ "RSA" "\0"
+ "SHA" "\0"
+ "SHA256" "\0"
+ "SHA384" "\0"
+#if defined(USE_MBEDTLS)
+ "ARIA" "\0"
+ "ARIA128" "\0"
+ "ARIA256" "\0"
+ "CAMELLIA" "\0"
+ "CAMELLIA128" "\0"
+ "CAMELLIA256" "\0"
+#endif
+;
+/* Indexes of above cs_txt */
+enum {
+ CS_TXT_IDX_,
+ CS_TXT_IDX_TLS,
+ CS_TXT_IDX_WITH,
+ CS_TXT_IDX_128,
+ CS_TXT_IDX_256,
+ CS_TXT_IDX_3DES,
+ CS_TXT_IDX_8,
+ CS_TXT_IDX_AES,
+ CS_TXT_IDX_AES128,
+ CS_TXT_IDX_AES256,
+ CS_TXT_IDX_CBC,
+ CS_TXT_IDX_CBC3,
+ CS_TXT_IDX_CCM,
+ CS_TXT_IDX_CCM8,
+ CS_TXT_IDX_CHACHA20,
+ CS_TXT_IDX_DES,
+ CS_TXT_IDX_DHE,
+ CS_TXT_IDX_ECDH,
+ CS_TXT_IDX_ECDHE,
+ CS_TXT_IDX_ECDSA,
+ CS_TXT_IDX_EDE,
+ CS_TXT_IDX_GCM,
+ CS_TXT_IDX_MD5,
+ CS_TXT_IDX_NULL,
+ CS_TXT_IDX_POLY1305,
+ CS_TXT_IDX_PSK,
+ CS_TXT_IDX_RSA,
+ CS_TXT_IDX_SHA,
+ CS_TXT_IDX_SHA256,
+ CS_TXT_IDX_SHA384,
+#if defined(USE_MBEDTLS)
+ CS_TXT_IDX_ARIA,
+ CS_TXT_IDX_ARIA128,
+ CS_TXT_IDX_ARIA256,
+ CS_TXT_IDX_CAMELLIA,
+ CS_TXT_IDX_CAMELLIA128,
+ CS_TXT_IDX_CAMELLIA256,
+#endif
+ CS_TXT_LEN,
+};
+
+#define CS_ZIP_IDX(a, b, c, d, e, f, g, h) \
+{ \
+ (uint8_t) ((a) << 2 | ((b) & 0x3F) >> 4), \
+ (uint8_t) ((b) << 4 | ((c) & 0x3F) >> 2), \
+ (uint8_t) ((c) << 6 | ((d) & 0x3F)), \
+ (uint8_t) ((e) << 2 | ((f) & 0x3F) >> 4), \
+ (uint8_t) ((f) << 4 | ((g) & 0x3F) >> 2), \
+ (uint8_t) ((g) << 6 | ((h) & 0x3F)) \
+}
+#define CS_ENTRY(id, a, b, c, d, e, f, g, h) \
+{ \
+ id, \
+ CS_ZIP_IDX( \
+ CS_TXT_IDX_ ## a, CS_TXT_IDX_ ## b, \
+ CS_TXT_IDX_ ## c, CS_TXT_IDX_ ## d, \
+ CS_TXT_IDX_ ## e, CS_TXT_IDX_ ## f, \
+ CS_TXT_IDX_ ## g, CS_TXT_IDX_ ## h \
+ ) \
+}
+
+struct cs_entry {
+ uint16_t id;
+ uint8_t zip[6];
+};
+
+/* !checksrc! disable COMMANOSPACE all */
+static const struct cs_entry cs_list [] = {
+ CS_ENTRY(0x002F, TLS,RSA,WITH,AES,128,CBC,SHA,),
+ CS_ENTRY(0x002F, AES128,SHA,,,,,,),
+ CS_ENTRY(0x0035, TLS,RSA,WITH,AES,256,CBC,SHA,),
+ CS_ENTRY(0x0035, AES256,SHA,,,,,,),
+ CS_ENTRY(0x003C, TLS,RSA,WITH,AES,128,CBC,SHA256,),
+ CS_ENTRY(0x003C, AES128,SHA256,,,,,,),
+ CS_ENTRY(0x003D, TLS,RSA,WITH,AES,256,CBC,SHA256,),
+ CS_ENTRY(0x003D, AES256,SHA256,,,,,,),
+ CS_ENTRY(0x009C, TLS,RSA,WITH,AES,128,GCM,SHA256,),
+ CS_ENTRY(0x009C, AES128,GCM,SHA256,,,,,),
+ CS_ENTRY(0x009D, TLS,RSA,WITH,AES,256,GCM,SHA384,),
+ CS_ENTRY(0x009D, AES256,GCM,SHA384,,,,,),
+ CS_ENTRY(0xC004, TLS,ECDH,ECDSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC004, ECDH,ECDSA,AES128,SHA,,,,),
+ CS_ENTRY(0xC005, TLS,ECDH,ECDSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC005, ECDH,ECDSA,AES256,SHA,,,,),
+ CS_ENTRY(0xC009, TLS,ECDHE,ECDSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC009, ECDHE,ECDSA,AES128,SHA,,,,),
+ CS_ENTRY(0xC00A, TLS,ECDHE,ECDSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC00A, ECDHE,ECDSA,AES256,SHA,,,,),
+ CS_ENTRY(0xC00E, TLS,ECDH,RSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC00E, ECDH,RSA,AES128,SHA,,,,),
+ CS_ENTRY(0xC00F, TLS,ECDH,RSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC00F, ECDH,RSA,AES256,SHA,,,,),
+ CS_ENTRY(0xC013, TLS,ECDHE,RSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC013, ECDHE,RSA,AES128,SHA,,,,),
+ CS_ENTRY(0xC014, TLS,ECDHE,RSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC014, ECDHE,RSA,AES256,SHA,,,,),
+ CS_ENTRY(0xC023, TLS,ECDHE,ECDSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0xC023, ECDHE,ECDSA,AES128,SHA256,,,,),
+ CS_ENTRY(0xC024, TLS,ECDHE,ECDSA,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0xC024, ECDHE,ECDSA,AES256,SHA384,,,,),
+ CS_ENTRY(0xC025, TLS,ECDH,ECDSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0xC025, ECDH,ECDSA,AES128,SHA256,,,,),
+ CS_ENTRY(0xC026, TLS,ECDH,ECDSA,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0xC026, ECDH,ECDSA,AES256,SHA384,,,,),
+ CS_ENTRY(0xC027, TLS,ECDHE,RSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0xC027, ECDHE,RSA,AES128,SHA256,,,,),
+ CS_ENTRY(0xC028, TLS,ECDHE,RSA,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0xC028, ECDHE,RSA,AES256,SHA384,,,,),
+ CS_ENTRY(0xC029, TLS,ECDH,RSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0xC029, ECDH,RSA,AES128,SHA256,,,,),
+ CS_ENTRY(0xC02A, TLS,ECDH,RSA,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0xC02A, ECDH,RSA,AES256,SHA384,,,,),
+ CS_ENTRY(0xC02B, TLS,ECDHE,ECDSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0xC02B, ECDHE,ECDSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0xC02C, TLS,ECDHE,ECDSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0xC02C, ECDHE,ECDSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0xC02D, TLS,ECDH,ECDSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0xC02D, ECDH,ECDSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0xC02E, TLS,ECDH,ECDSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0xC02E, ECDH,ECDSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0xC02F, TLS,ECDHE,RSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0xC02F, ECDHE,RSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0xC030, TLS,ECDHE,RSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0xC030, ECDHE,RSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0xC031, TLS,ECDH,RSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0xC031, ECDH,RSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0xC032, TLS,ECDH,RSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0xC032, ECDH,RSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0xCCA8, TLS,ECDHE,RSA,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCA8, ECDHE,RSA,CHACHA20,POLY1305,,,,),
+ CS_ENTRY(0xCCA9, TLS,ECDHE,ECDSA,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCA9, ECDHE,ECDSA,CHACHA20,POLY1305,,,,),
+#if defined(USE_MBEDTLS)
+ CS_ENTRY(0x0001, TLS,RSA,WITH,NULL,MD5,,,),
+ CS_ENTRY(0x0001, NULL,MD5,,,,,,),
+ CS_ENTRY(0x0002, TLS,RSA,WITH,NULL,SHA,,,),
+ CS_ENTRY(0x0002, NULL,SHA,,,,,,),
+ CS_ENTRY(0x002C, TLS,PSK,WITH,NULL,SHA,,,),
+ CS_ENTRY(0x002C, PSK,NULL,SHA,,,,,),
+ CS_ENTRY(0x002D, TLS,DHE,PSK,WITH,NULL,SHA,,),
+ CS_ENTRY(0x002D, DHE,PSK,NULL,SHA,,,,),
+ CS_ENTRY(0x002E, TLS,RSA,PSK,WITH,NULL,SHA,,),
+ CS_ENTRY(0x002E, RSA,PSK,NULL,SHA,,,,),
+ CS_ENTRY(0x0033, TLS,DHE,RSA,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0x0033, DHE,RSA,AES128,SHA,,,,),
+ CS_ENTRY(0x0039, TLS,DHE,RSA,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0x0039, DHE,RSA,AES256,SHA,,,,),
+ CS_ENTRY(0x003B, TLS,RSA,WITH,NULL,SHA256,,,),
+ CS_ENTRY(0x003B, NULL,SHA256,,,,,,),
+ CS_ENTRY(0x0067, TLS,DHE,RSA,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0x0067, DHE,RSA,AES128,SHA256,,,,),
+ CS_ENTRY(0x006B, TLS,DHE,RSA,WITH,AES,256,CBC,SHA256),
+ CS_ENTRY(0x006B, DHE,RSA,AES256,SHA256,,,,),
+ CS_ENTRY(0x008C, TLS,PSK,WITH,AES,128,CBC,SHA,),
+ CS_ENTRY(0x008C, PSK,AES128,CBC,SHA,,,,),
+ CS_ENTRY(0x008D, TLS,PSK,WITH,AES,256,CBC,SHA,),
+ CS_ENTRY(0x008D, PSK,AES256,CBC,SHA,,,,),
+ CS_ENTRY(0x0090, TLS,DHE,PSK,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0x0090, DHE,PSK,AES128,CBC,SHA,,,),
+ CS_ENTRY(0x0091, TLS,DHE,PSK,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0x0091, DHE,PSK,AES256,CBC,SHA,,,),
+ CS_ENTRY(0x0094, TLS,RSA,PSK,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0x0094, RSA,PSK,AES128,CBC,SHA,,,),
+ CS_ENTRY(0x0095, TLS,RSA,PSK,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0x0095, RSA,PSK,AES256,CBC,SHA,,,),
+ CS_ENTRY(0x009E, TLS,DHE,RSA,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0x009E, DHE,RSA,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0x009F, TLS,DHE,RSA,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0x009F, DHE,RSA,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0x00A8, TLS,PSK,WITH,AES,128,GCM,SHA256,),
+ CS_ENTRY(0x00A8, PSK,AES128,GCM,SHA256,,,,),
+ CS_ENTRY(0x00A9, TLS,PSK,WITH,AES,256,GCM,SHA384,),
+ CS_ENTRY(0x00A9, PSK,AES256,GCM,SHA384,,,,),
+ CS_ENTRY(0x00AA, TLS,DHE,PSK,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0x00AA, DHE,PSK,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0x00AB, TLS,DHE,PSK,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0x00AB, DHE,PSK,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0x00AC, TLS,RSA,PSK,WITH,AES,128,GCM,SHA256),
+ CS_ENTRY(0x00AC, RSA,PSK,AES128,GCM,SHA256,,,),
+ CS_ENTRY(0x00AD, TLS,RSA,PSK,WITH,AES,256,GCM,SHA384),
+ CS_ENTRY(0x00AD, RSA,PSK,AES256,GCM,SHA384,,,),
+ CS_ENTRY(0x00AE, TLS,PSK,WITH,AES,128,CBC,SHA256,),
+ CS_ENTRY(0x00AE, PSK,AES128,CBC,SHA256,,,,),
+ CS_ENTRY(0x00AF, TLS,PSK,WITH,AES,256,CBC,SHA384,),
+ CS_ENTRY(0x00AF, PSK,AES256,CBC,SHA384,,,,),
+ CS_ENTRY(0x00B0, TLS,PSK,WITH,NULL,SHA256,,,),
+ CS_ENTRY(0x00B0, PSK,NULL,SHA256,,,,,),
+ CS_ENTRY(0x00B1, TLS,PSK,WITH,NULL,SHA384,,,),
+ CS_ENTRY(0x00B1, PSK,NULL,SHA384,,,,,),
+ CS_ENTRY(0x00B2, TLS,DHE,PSK,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0x00B2, DHE,PSK,AES128,CBC,SHA256,,,),
+ CS_ENTRY(0x00B3, TLS,DHE,PSK,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0x00B3, DHE,PSK,AES256,CBC,SHA384,,,),
+ CS_ENTRY(0x00B4, TLS,DHE,PSK,WITH,NULL,SHA256,,),
+ CS_ENTRY(0x00B4, DHE,PSK,NULL,SHA256,,,,),
+ CS_ENTRY(0x00B5, TLS,DHE,PSK,WITH,NULL,SHA384,,),
+ CS_ENTRY(0x00B5, DHE,PSK,NULL,SHA384,,,,),
+ CS_ENTRY(0x00B6, TLS,RSA,PSK,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0x00B6, RSA,PSK,AES128,CBC,SHA256,,,),
+ CS_ENTRY(0x00B7, TLS,RSA,PSK,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0x00B7, RSA,PSK,AES256,CBC,SHA384,,,),
+ CS_ENTRY(0x00B8, TLS,RSA,PSK,WITH,NULL,SHA256,,),
+ CS_ENTRY(0x00B8, RSA,PSK,NULL,SHA256,,,,),
+ CS_ENTRY(0x00B9, TLS,RSA,PSK,WITH,NULL,SHA384,,),
+ CS_ENTRY(0x00B9, RSA,PSK,NULL,SHA384,,,,),
+ CS_ENTRY(0x1301, TLS,AES,128,GCM,SHA256,,,),
+ CS_ENTRY(0x1302, TLS,AES,256,GCM,SHA384,,,),
+ CS_ENTRY(0x1303, TLS,CHACHA20,POLY1305,SHA256,,,,),
+ CS_ENTRY(0x1304, TLS,AES,128,CCM,SHA256,,,),
+ CS_ENTRY(0x1305, TLS,AES,128,CCM,8,SHA256,,),
+ CS_ENTRY(0xC001, TLS,ECDH,ECDSA,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC001, ECDH,ECDSA,NULL,SHA,,,,),
+ CS_ENTRY(0xC006, TLS,ECDHE,ECDSA,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC006, ECDHE,ECDSA,NULL,SHA,,,,),
+ CS_ENTRY(0xC00B, TLS,ECDH,RSA,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC00B, ECDH,RSA,NULL,SHA,,,,),
+ CS_ENTRY(0xC010, TLS,ECDHE,RSA,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC010, ECDHE,RSA,NULL,SHA,,,,),
+ CS_ENTRY(0xC035, TLS,ECDHE,PSK,WITH,AES,128,CBC,SHA),
+ CS_ENTRY(0xC035, ECDHE,PSK,AES128,CBC,SHA,,,),
+ CS_ENTRY(0xC036, TLS,ECDHE,PSK,WITH,AES,256,CBC,SHA),
+ CS_ENTRY(0xC036, ECDHE,PSK,AES256,CBC,SHA,,,),
+ CS_ENTRY(0xCCAB, TLS,PSK,WITH,CHACHA20,POLY1305,SHA256,,),
+ CS_ENTRY(0xCCAB, PSK,CHACHA20,POLY1305,,,,,),
+#endif
+#if defined(USE_BEARSSL)
+ CS_ENTRY(0x000A, TLS,RSA,WITH,3DES,EDE,CBC,SHA,),
+ CS_ENTRY(0x000A, DES,CBC3,SHA,,,,,),
+ CS_ENTRY(0xC003, TLS,ECDH,ECDSA,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0xC003, ECDH,ECDSA,DES,CBC3,SHA,,,),
+ CS_ENTRY(0xC008, TLS,ECDHE,ECDSA,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0xC008, ECDHE,ECDSA,DES,CBC3,SHA,,,),
+ CS_ENTRY(0xC00D, TLS,ECDH,RSA,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0xC00D, ECDH,RSA,DES,CBC3,SHA,,,),
+ CS_ENTRY(0xC012, TLS,ECDHE,RSA,WITH,3DES,EDE,CBC,SHA),
+ CS_ENTRY(0xC012, ECDHE,RSA,DES,CBC3,SHA,,,),
+#endif
+ CS_ENTRY(0xC09C, TLS,RSA,WITH,AES,128,CCM,,),
+ CS_ENTRY(0xC09C, AES128,CCM,,,,,,),
+ CS_ENTRY(0xC09D, TLS,RSA,WITH,AES,256,CCM,,),
+ CS_ENTRY(0xC09D, AES256,CCM,,,,,,),
+ CS_ENTRY(0xC0A0, TLS,RSA,WITH,AES,128,CCM,8,),
+ CS_ENTRY(0xC0A0, AES128,CCM8,,,,,,),
+ CS_ENTRY(0xC0A1, TLS,RSA,WITH,AES,256,CCM,8,),
+ CS_ENTRY(0xC0A1, AES256,CCM8,,,,,,),
+ CS_ENTRY(0xC0AC, TLS,ECDHE,ECDSA,WITH,AES,128,CCM,),
+ CS_ENTRY(0xC0AC, ECDHE,ECDSA,AES128,CCM,,,,),
+ CS_ENTRY(0xC0AD, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,),
+ CS_ENTRY(0xC0AD, ECDHE,ECDSA,AES256,CCM,,,,),
+ CS_ENTRY(0xC0AE, TLS,ECDHE,ECDSA,WITH,AES,128,CCM,8),
+ CS_ENTRY(0xC0AE, ECDHE,ECDSA,AES128,CCM8,,,,),
+ CS_ENTRY(0xC0AF, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,8),
+ CS_ENTRY(0xC0AF, ECDHE,ECDSA,AES256,CCM8,,,,),
+#if defined(USE_MBEDTLS)
+ /* entries marked ns are "non-standard", they are not in openssl */
+ CS_ENTRY(0x0041, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA,),
+ CS_ENTRY(0x0041, CAMELLIA128,SHA,,,,,,),
+ CS_ENTRY(0x0045, TLS,DHE,RSA,WITH,CAMELLIA,128,CBC,SHA),
+ CS_ENTRY(0x0045, DHE,RSA,CAMELLIA128,SHA,,,,),
+ CS_ENTRY(0x0084, TLS,RSA,WITH,CAMELLIA,256,CBC,SHA,),
+ CS_ENTRY(0x0084, CAMELLIA256,SHA,,,,,,),
+ CS_ENTRY(0x0088, TLS,DHE,RSA,WITH,CAMELLIA,256,CBC,SHA),
+ CS_ENTRY(0x0088, DHE,RSA,CAMELLIA256,SHA,,,,),
+ CS_ENTRY(0x00BA, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA256,),
+ CS_ENTRY(0x00BA, CAMELLIA128,SHA256,,,,,,),
+ CS_ENTRY(0x00BE, TLS,DHE,RSA,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0x00BE, DHE,RSA,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0x00C0, TLS,RSA,WITH,CAMELLIA,256,CBC,SHA256,),
+ CS_ENTRY(0x00C0, CAMELLIA256,SHA256,,,,,,),
+ CS_ENTRY(0x00C4, TLS,DHE,RSA,WITH,CAMELLIA,256,CBC,SHA256),
+ CS_ENTRY(0x00C4, DHE,RSA,CAMELLIA256,SHA256,,,,),
+ CS_ENTRY(0xC037, TLS,ECDHE,PSK,WITH,AES,128,CBC,SHA256),
+ CS_ENTRY(0xC037, ECDHE,PSK,AES128,CBC,SHA256,,,),
+ CS_ENTRY(0xC038, TLS,ECDHE,PSK,WITH,AES,256,CBC,SHA384),
+ CS_ENTRY(0xC038, ECDHE,PSK,AES256,CBC,SHA384,,,),
+ CS_ENTRY(0xC039, TLS,ECDHE,PSK,WITH,NULL,SHA,,),
+ CS_ENTRY(0xC039, ECDHE,PSK,NULL,SHA,,,,),
+ CS_ENTRY(0xC03A, TLS,ECDHE,PSK,WITH,NULL,SHA256,,),
+ CS_ENTRY(0xC03A, ECDHE,PSK,NULL,SHA256,,,,),
+ CS_ENTRY(0xC03B, TLS,ECDHE,PSK,WITH,NULL,SHA384,,),
+ CS_ENTRY(0xC03B, ECDHE,PSK,NULL,SHA384,,,,),
+ CS_ENTRY(0xC03C, TLS,RSA,WITH,ARIA,128,CBC,SHA256,),
+ CS_ENTRY(0xC03C, ARIA128,SHA256,,,,,,), /* ns */
+ CS_ENTRY(0xC03D, TLS,RSA,WITH,ARIA,256,CBC,SHA384,),
+ CS_ENTRY(0xC03D, ARIA256,SHA384,,,,,,), /* ns */
+ CS_ENTRY(0xC044, TLS,DHE,RSA,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC044, DHE,RSA,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC045, TLS,DHE,RSA,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC045, DHE,RSA,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC048, TLS,ECDHE,ECDSA,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC048, ECDHE,ECDSA,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC049, TLS,ECDHE,ECDSA,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC049, ECDHE,ECDSA,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC04A, TLS,ECDH,ECDSA,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC04A, ECDH,ECDSA,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC04B, TLS,ECDH,ECDSA,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC04B, ECDH,ECDSA,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC04C, TLS,ECDHE,RSA,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC04C, ECDHE,ARIA128,SHA256,,,,,), /* ns */
+ CS_ENTRY(0xC04D, TLS,ECDHE,RSA,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC04D, ECDHE,ARIA256,SHA384,,,,,), /* ns */
+ CS_ENTRY(0xC04E, TLS,ECDH,RSA,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC04E, ECDH,ARIA128,SHA256,,,,,), /* ns */
+ CS_ENTRY(0xC04F, TLS,ECDH,RSA,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC04F, ECDH,ARIA256,SHA384,,,,,), /* ns */
+ CS_ENTRY(0xC050, TLS,RSA,WITH,ARIA,128,GCM,SHA256,),
+ CS_ENTRY(0xC050, ARIA128,GCM,SHA256,,,,,),
+ CS_ENTRY(0xC051, TLS,RSA,WITH,ARIA,256,GCM,SHA384,),
+ CS_ENTRY(0xC051, ARIA256,GCM,SHA384,,,,,),
+ CS_ENTRY(0xC052, TLS,DHE,RSA,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC052, DHE,RSA,ARIA128,GCM,SHA256,,,),
+ CS_ENTRY(0xC053, TLS,DHE,RSA,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC053, DHE,RSA,ARIA256,GCM,SHA384,,,),
+ CS_ENTRY(0xC05C, TLS,ECDHE,ECDSA,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC05C, ECDHE,ECDSA,ARIA128,GCM,SHA256,,,),
+ CS_ENTRY(0xC05D, TLS,ECDHE,ECDSA,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC05D, ECDHE,ECDSA,ARIA256,GCM,SHA384,,,),
+ CS_ENTRY(0xC05E, TLS,ECDH,ECDSA,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC05E, ECDH,ECDSA,ARIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC05F, TLS,ECDH,ECDSA,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC05F, ECDH,ECDSA,ARIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC060, TLS,ECDHE,RSA,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC060, ECDHE,ARIA128,GCM,SHA256,,,,),
+ CS_ENTRY(0xC061, TLS,ECDHE,RSA,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC061, ECDHE,ARIA256,GCM,SHA384,,,,),
+ CS_ENTRY(0xC062, TLS,ECDH,RSA,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC062, ECDH,ARIA128,GCM,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC063, TLS,ECDH,RSA,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC063, ECDH,ARIA256,GCM,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC064, TLS,PSK,WITH,ARIA,128,CBC,SHA256,),
+ CS_ENTRY(0xC064, PSK,ARIA128,SHA256,,,,,), /* ns */
+ CS_ENTRY(0xC065, TLS,PSK,WITH,ARIA,256,CBC,SHA384,),
+ CS_ENTRY(0xC065, PSK,ARIA256,SHA384,,,,,), /* ns */
+ CS_ENTRY(0xC066, TLS,DHE,PSK,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC066, DHE,PSK,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC067, TLS,DHE,PSK,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC067, DHE,PSK,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC068, TLS,RSA,PSK,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC068, RSA,PSK,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC069, TLS,RSA,PSK,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC069, RSA,PSK,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC06A, TLS,PSK,WITH,ARIA,128,GCM,SHA256,),
+ CS_ENTRY(0xC06A, PSK,ARIA128,GCM,SHA256,,,,),
+ CS_ENTRY(0xC06B, TLS,PSK,WITH,ARIA,256,GCM,SHA384,),
+ CS_ENTRY(0xC06B, PSK,ARIA256,GCM,SHA384,,,,),
+ CS_ENTRY(0xC06C, TLS,DHE,PSK,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC06C, DHE,PSK,ARIA128,GCM,SHA256,,,),
+ CS_ENTRY(0xC06D, TLS,DHE,PSK,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC06D, DHE,PSK,ARIA256,GCM,SHA384,,,),
+ CS_ENTRY(0xC06E, TLS,RSA,PSK,WITH,ARIA,128,GCM,SHA256),
+ CS_ENTRY(0xC06E, RSA,PSK,ARIA128,GCM,SHA256,,,),
+ CS_ENTRY(0xC06F, TLS,RSA,PSK,WITH,ARIA,256,GCM,SHA384),
+ CS_ENTRY(0xC06F, RSA,PSK,ARIA256,GCM,SHA384,,,),
+ CS_ENTRY(0xC070, TLS,ECDHE,PSK,WITH,ARIA,128,CBC,SHA256),
+ CS_ENTRY(0xC070, ECDHE,PSK,ARIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC071, TLS,ECDHE,PSK,WITH,ARIA,256,CBC,SHA384),
+ CS_ENTRY(0xC071, ECDHE,PSK,ARIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC072, TLS,ECDHE,ECDSA,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC072, ECDHE,ECDSA,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0xC073, TLS,ECDHE,ECDSA,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC073, ECDHE,ECDSA,CAMELLIA256,SHA384,,,,),
+ CS_ENTRY(0xC074, TLS,ECDH,ECDSA,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC074, ECDH,ECDSA,CAMELLIA128,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC075, TLS,ECDH,ECDSA,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC075, ECDH,ECDSA,CAMELLIA256,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC076, TLS,ECDHE,RSA,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC076, ECDHE,RSA,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0xC077, TLS,ECDHE,RSA,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC077, ECDHE,RSA,CAMELLIA256,SHA384,,,,),
+ CS_ENTRY(0xC078, TLS,ECDH,RSA,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC078, ECDH,CAMELLIA128,SHA256,,,,,), /* ns */
+ CS_ENTRY(0xC079, TLS,ECDH,RSA,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC079, ECDH,CAMELLIA256,SHA384,,,,,), /* ns */
+ CS_ENTRY(0xC07A, TLS,RSA,WITH,CAMELLIA,128,GCM,SHA256,),
+ CS_ENTRY(0xC07A, CAMELLIA128,GCM,SHA256,,,,,), /* ns */
+ CS_ENTRY(0xC07B, TLS,RSA,WITH,CAMELLIA,256,GCM,SHA384,),
+ CS_ENTRY(0xC07B, CAMELLIA256,GCM,SHA384,,,,,), /* ns */
+ CS_ENTRY(0xC07C, TLS,DHE,RSA,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC07C, DHE,RSA,CAMELLIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC07D, TLS,DHE,RSA,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC07D, DHE,RSA,CAMELLIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC086, TLS,ECDHE,ECDSA,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC086, ECDHE,ECDSA,CAMELLIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC087, TLS,ECDHE,ECDSA,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC087, ECDHE,ECDSA,CAMELLIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC088, TLS,ECDH,ECDSA,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC088, ECDH,ECDSA,CAMELLIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC089, TLS,ECDH,ECDSA,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC089, ECDH,ECDSA,CAMELLIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC08A, TLS,ECDHE,RSA,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC08A, ECDHE,CAMELLIA128,GCM,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC08B, TLS,ECDHE,RSA,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC08B, ECDHE,CAMELLIA256,GCM,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC08C, TLS,ECDH,RSA,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC08C, ECDH,CAMELLIA128,GCM,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC08D, TLS,ECDH,RSA,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC08D, ECDH,CAMELLIA256,GCM,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC08E, TLS,PSK,WITH,CAMELLIA,128,GCM,SHA256,),
+ CS_ENTRY(0xC08E, PSK,CAMELLIA128,GCM,SHA256,,,,), /* ns */
+ CS_ENTRY(0xC08F, TLS,PSK,WITH,CAMELLIA,256,GCM,SHA384,),
+ CS_ENTRY(0xC08F, PSK,CAMELLIA256,GCM,SHA384,,,,), /* ns */
+ CS_ENTRY(0xC090, TLS,DHE,PSK,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC090, DHE,PSK,CAMELLIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC091, TLS,DHE,PSK,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC091, DHE,PSK,CAMELLIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC092, TLS,RSA,PSK,WITH,CAMELLIA,128,GCM,SHA256),
+ CS_ENTRY(0xC092, RSA,PSK,CAMELLIA128,GCM,SHA256,,,), /* ns */
+ CS_ENTRY(0xC093, TLS,RSA,PSK,WITH,CAMELLIA,256,GCM,SHA384),
+ CS_ENTRY(0xC093, RSA,PSK,CAMELLIA256,GCM,SHA384,,,), /* ns */
+ CS_ENTRY(0xC094, TLS,PSK,WITH,CAMELLIA,128,CBC,SHA256,),
+ CS_ENTRY(0xC094, PSK,CAMELLIA128,SHA256,,,,,),
+ CS_ENTRY(0xC095, TLS,PSK,WITH,CAMELLIA,256,CBC,SHA384,),
+ CS_ENTRY(0xC095, PSK,CAMELLIA256,SHA384,,,,,),
+ CS_ENTRY(0xC096, TLS,DHE,PSK,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC096, DHE,PSK,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0xC097, TLS,DHE,PSK,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC097, DHE,PSK,CAMELLIA256,SHA384,,,,),
+ CS_ENTRY(0xC098, TLS,RSA,PSK,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC098, RSA,PSK,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0xC099, TLS,RSA,PSK,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC099, RSA,PSK,CAMELLIA256,SHA384,,,,),
+ CS_ENTRY(0xC09A, TLS,ECDHE,PSK,WITH,CAMELLIA,128,CBC,SHA256),
+ CS_ENTRY(0xC09A, ECDHE,PSK,CAMELLIA128,SHA256,,,,),
+ CS_ENTRY(0xC09B, TLS,ECDHE,PSK,WITH,CAMELLIA,256,CBC,SHA384),
+ CS_ENTRY(0xC09B, ECDHE,PSK,CAMELLIA256,SHA384,,,,),
+ CS_ENTRY(0xC09E, TLS,DHE,RSA,WITH,AES,128,CCM,),
+ CS_ENTRY(0xC09E, DHE,RSA,AES128,CCM,,,,),
+ CS_ENTRY(0xC09F, TLS,DHE,RSA,WITH,AES,256,CCM,),
+ CS_ENTRY(0xC09F, DHE,RSA,AES256,CCM,,,,),
+ CS_ENTRY(0xC0A2, TLS,DHE,RSA,WITH,AES,128,CCM,8),
+ CS_ENTRY(0xC0A2, DHE,RSA,AES128,CCM8,,,,),
+ CS_ENTRY(0xC0A3, TLS,DHE,RSA,WITH,AES,256,CCM,8),
+ CS_ENTRY(0xC0A3, DHE,RSA,AES256,CCM8,,,,),
+ CS_ENTRY(0xC0A4, TLS,PSK,WITH,AES,128,CCM,,),
+ CS_ENTRY(0xC0A4, PSK,AES128,CCM,,,,,),
+ CS_ENTRY(0xC0A5, TLS,PSK,WITH,AES,256,CCM,,),
+ CS_ENTRY(0xC0A5, PSK,AES256,CCM,,,,,),
+ CS_ENTRY(0xC0A6, TLS,DHE,PSK,WITH,AES,128,CCM,),
+ CS_ENTRY(0xC0A6, DHE,PSK,AES128,CCM,,,,),
+ CS_ENTRY(0xC0A7, TLS,DHE,PSK,WITH,AES,256,CCM,),
+ CS_ENTRY(0xC0A7, DHE,PSK,AES256,CCM,,,,),
+ CS_ENTRY(0xC0A8, TLS,PSK,WITH,AES,128,CCM,8,),
+ CS_ENTRY(0xC0A8, PSK,AES128,CCM8,,,,,),
+ CS_ENTRY(0xC0A9, TLS,PSK,WITH,AES,256,CCM,8,),
+ CS_ENTRY(0xC0A9, PSK,AES256,CCM8,,,,,),
+ CS_ENTRY(0xC0AA, TLS,PSK,DHE,WITH,AES,128,CCM,8),
+ CS_ENTRY(0xC0AA, DHE,PSK,AES128,CCM8,,,,),
+ CS_ENTRY(0xC0AB, TLS,PSK,DHE,WITH,AES,256,CCM,8),
+ CS_ENTRY(0xC0AB, DHE,PSK,AES256,CCM8,,,,),
+ CS_ENTRY(0xCCAA, TLS,DHE,RSA,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCAA, DHE,RSA,CHACHA20,POLY1305,,,,),
+ CS_ENTRY(0xCCAC, TLS,ECDHE,PSK,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCAC, ECDHE,PSK,CHACHA20,POLY1305,,,,),
+ CS_ENTRY(0xCCAD, TLS,DHE,PSK,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCAD, DHE,PSK,CHACHA20,POLY1305,,,,),
+ CS_ENTRY(0xCCAE, TLS,RSA,PSK,WITH,CHACHA20,POLY1305,SHA256,),
+ CS_ENTRY(0xCCAE, RSA,PSK,CHACHA20,POLY1305,,,,),
+#endif
+};
+#define CS_LIST_LEN (sizeof(cs_list) / sizeof(cs_list[0]))
+
+static int cs_str_to_zip(const char *cs_str, size_t cs_len,
+ uint8_t zip[6])
+{
+ uint8_t indexes[8] = {0};
+ const char *entry, *cur;
+ const char *nxt = cs_str;
+ const char *end = cs_str + cs_len;
+ char separator = '-';
+ int idx, i = 0;
+ size_t len;
+
+ /* split the cipher string by '-' or '_' */
+ if(strncasecompare(cs_str, "TLS", 3))
+ separator = '_';
+
+ do {
+ if(i == 8)
+ return -1;
+
+ /* determine the length of the part */
+ cur = nxt;
+ for(; nxt < end && *nxt != '\0' && *nxt != separator; nxt++);
+ len = nxt - cur;
+
+ /* lookup index for the part (skip empty string at 0) */
+ for(idx = 1, entry = cs_txt + 1; idx < CS_TXT_LEN; idx++) {
+ size_t elen = strlen(entry);
+ if(elen == len && strncasecompare(entry, cur, len))
+ break;
+ entry += elen + 1;
+ }
+ if(idx == CS_TXT_LEN)
+ return -1;
+
+ indexes[i++] = (uint8_t) idx;
+ } while(nxt < end && *(nxt++) != '\0');
+
+ /* zip the 8 indexes into 48 bits */
+ zip[0] = (uint8_t) (indexes[0] << 2 | (indexes[1] & 0x3F) >> 4);
+ zip[1] = (uint8_t) (indexes[1] << 4 | (indexes[2] & 0x3F) >> 2);
+ zip[2] = (uint8_t) (indexes[2] << 6 | (indexes[3] & 0x3F));
+ zip[3] = (uint8_t) (indexes[4] << 2 | (indexes[5] & 0x3F) >> 4);
+ zip[4] = (uint8_t) (indexes[5] << 4 | (indexes[6] & 0x3F) >> 2);
+ zip[5] = (uint8_t) (indexes[6] << 6 | (indexes[7] & 0x3F));
+
+ return 0;
+}
+
+static int cs_zip_to_str(const uint8_t zip[6],
+ char *buf, size_t buf_size)
+{
+ uint8_t indexes[8] = {0};
+ const char *entry;
+ char separator = '-';
+ int idx, i, r;
+ size_t len = 0;
+
+ /* unzip the 8 indexes */
+ indexes[0] = zip[0] >> 2;
+ indexes[1] = ((zip[0] << 4) & 0x3F) | zip[1] >> 4;
+ indexes[2] = ((zip[1] << 2) & 0x3F) | zip[2] >> 6;
+ indexes[3] = ((zip[2] << 0) & 0x3F);
+ indexes[4] = zip[3] >> 2;
+ indexes[5] = ((zip[3] << 4) & 0x3F) | zip[4] >> 4;
+ indexes[6] = ((zip[4] << 2) & 0x3F) | zip[5] >> 6;
+ indexes[7] = ((zip[5] << 0) & 0x3F);
+
+ if(indexes[0] == CS_TXT_IDX_TLS)
+ separator = '_';
+
+ for(i = 0; i < 8 && indexes[i] != 0 && len < buf_size; i++) {
+ if(indexes[i] >= CS_TXT_LEN)
+ return -1;
+
+ /* lookup the part string for the index (skip empty string at 0) */
+ for(idx = 1, entry = cs_txt + 1; idx < indexes[i]; idx++) {
+ size_t elen = strlen(entry);
+ entry += elen + 1;
+ }
+
+ /* append the part string to the buffer */
+ if(i > 0)
+ r = msnprintf(&buf[len], buf_size - len, "%c%s", separator, entry);
+ else
+ r = msnprintf(&buf[len], buf_size - len, "%s", entry);
+
+ if(r < 0)
+ return -1;
+ len += r;
+ }
+
+ return 0;
+}
+
+uint16_t Curl_cipher_suite_lookup_id(const char *cs_str, size_t cs_len)
+{
+ size_t i;
+ uint8_t zip[6];
+
+ if(cs_len > 0 && cs_str_to_zip(cs_str, cs_len, zip) == 0) {
+ for(i = 0; i < CS_LIST_LEN; i++) {
+ if(memcmp(cs_list[i].zip, zip, sizeof(zip)) == 0)
+ return cs_list[i].id;
+ }
+ }
+
+ return 0;
+}
+
+static bool cs_is_separator(char c)
+{
+ switch(c) {
+ case ' ':
+ case '\t':
+ case ':':
+ case ',':
+ case ';':
+ return true;
+ default:;
+ }
+ return false;
+}
+
+uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end)
+{
+ /* move string pointer to first non-separator or end of string */
+ for(; cs_is_separator(*str[0]); (*str)++);
+
+ /* move end pointer to next separator or end of string */
+ for(*end = *str; *end[0] != '\0' && !cs_is_separator(*end[0]); (*end)++);
+
+ return Curl_cipher_suite_lookup_id(*str, *end - *str);
+}
+
+int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
+ bool prefer_rfc)
+{
+ size_t i, j = CS_LIST_LEN;
+ int r = -1;
+
+ for(i = 0; i < CS_LIST_LEN; i++) {
+ if(cs_list[i].id != id)
+ continue;
+ if((cs_list[i].zip[0] >> 2 != CS_TXT_IDX_TLS) == !prefer_rfc) {
+ j = i;
+ break;
+ }
+ if(j == CS_LIST_LEN)
+ j = i;
+ }
+
+ if(j < CS_LIST_LEN)
+ r = cs_zip_to_str(cs_list[j].zip, buf, buf_size);
+
+ if(r < 0)
+ msnprintf(buf, buf_size, "TLS_UNKNOWN_0x%04x", id);
+
+ return r;
+}
+
+#endif /* defined(USE_MBEDTLS) || defined(USE_BEARSSL) */
diff --git a/libs/libcurl/src/curl_ntlm_wb.h b/libs/libcurl/src/vtls/cipher_suite.h
index 08be13e8d8..712325e9f3 100644
--- a/libs/libcurl/src/curl_ntlm_wb.h
+++ b/libs/libcurl/src/vtls/cipher_suite.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_NTLM_WB_H
-#define HEADER_CURL_NTLM_WB_H
+#ifndef HEADER_CURL_CIPHER_SUITE_H
+#define HEADER_CURL_CIPHER_SUITE_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Jan Venekamp, <jan@venekamp.net>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,20 +26,21 @@
#include "curl_setup.h"
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
- defined(NTLM_WB_ENABLED)
+#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
+#include <stdint.h>
-/* this is for ntlm header input */
-CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
- struct connectdata *conn, bool proxy,
- const char *header);
+/* Lookup IANA id for cipher suite string, returns 0 if not recognized */
+uint16_t Curl_cipher_suite_lookup_id(const char *cs_str, size_t cs_len);
-/* this is for creating ntlm header output */
-CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
- bool proxy);
+/* Walk over cipher suite string, update str and end pointers to next
+ cipher suite in string, returns IANA id of that suite if recognized */
+uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end);
-void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn);
+/* Copy openssl or RFC name for cipher suite in supplied buffer.
+ Caller is responsible to supply sufficiently large buffer (size
+ of 64 should suffice), excess bytes are silently truncated. */
+int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
+ bool prefer_rfc);
-#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */
-
-#endif /* HEADER_CURL_NTLM_WB_H */
+#endif /* defined(USE_MBEDTLS) || defined(USE_BEARSSL) */
+#endif /* HEADER_CURL_CIPHER_SUITE_H */
diff --git a/libs/libcurl/src/vtls/gtls.c b/libs/libcurl/src/vtls/gtls.c
index 1184ceb5c6..ef7f6059a3 100644
--- a/libs/libcurl/src/vtls/gtls.c
+++ b/libs/libcurl/src/vtls/gtls.c
@@ -43,6 +43,7 @@
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
+#include "keylog.h"
#include "gtls.h"
#include "vtls.h"
#include "vtls_int.h"
@@ -59,6 +60,16 @@
/* The last #include file should be: */
#include "memdebug.h"
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+#define QUIC_PRIORITY \
+ "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
+ "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
+ "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
+ "%DISABLE_TLS13_COMPAT_MODE"
+
/* Enable GnuTLS debugging by defining GTLSDEBUG */
/*#define GTLSDEBUG */
@@ -77,22 +88,25 @@ static bool gtls_inited = FALSE;
# include <gnutls/ocsp.h>
struct gtls_ssl_backend_data {
- struct gtls_instance gtls;
+ struct gtls_ctx gtls;
};
static ssize_t gtls_push(void *s, const void *buf, size_t blen)
{
struct Curl_cfilter *cf = s;
struct ssl_connect_data *connssl = cf->ctx;
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
CURLcode result;
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %zd, err=%d",
+ blen, nwritten, result);
+ backend->gtls.io_result = result;
if(nwritten < 0) {
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
gnutls_transport_set_errno(backend->gtls.session,
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nwritten = -1;
@@ -104,15 +118,27 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen)
{
struct Curl_cfilter *cf = s;
struct ssl_connect_data *connssl = cf->ctx;
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result;
DEBUGASSERT(data);
+ if(!backend->gtls.trust_setup) {
+ result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
+ if(result) {
+ gnutls_transport_set_errno(backend->gtls.session, EINVAL);
+ backend->gtls.io_result = result;
+ return -1;
+ }
+ }
+
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ CURL_TRC_CF(data, cf, "glts_pull(len=%zu) -> %zd, err=%d",
+ blen, nread, result);
+ backend->gtls.io_result = result;
if(nread < 0) {
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
gnutls_transport_set_errno(backend->gtls.session,
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nread = -1;
@@ -268,8 +294,17 @@ static CURLcode handshake(struct Curl_cfilter *cf,
/* socket is readable or writable */
}
+ backend->gtls.io_result = CURLE_OK;
rc = gnutls_handshake(session);
+ if(!backend->gtls.trust_setup) {
+ /* After having send off the ClientHello, we prepare the trust
+ * store to verify the coming certificate from the server */
+ CURLcode result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
+ if(result)
+ return result;
+ }
+
if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
connssl->connecting_state =
gnutls_record_get_direction(session)?
@@ -290,6 +325,9 @@ static CURLcode handshake(struct Curl_cfilter *cf,
infof(data, "gnutls_handshake() warning: %s", strerr);
continue;
}
+ else if((rc < 0) && backend->gtls.io_result) {
+ return backend->gtls.io_result;
+ }
else if(rc < 0) {
const char *strerr = NULL;
@@ -330,6 +368,7 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
static CURLcode
set_ssl_version_min_max(struct Curl_easy *data,
+ struct ssl_peer *peer,
struct ssl_primary_config *conn_config,
const char **prioritylist,
const char *tls13support)
@@ -337,6 +376,16 @@ set_ssl_version_min_max(struct Curl_easy *data,
long ssl_version = conn_config->version;
long ssl_version_max = conn_config->version_max;
+ if(peer->transport == TRNSPRT_QUIC) {
+ if((ssl_version != CURL_SSLVERSION_DEFAULT) &&
+ (ssl_version < CURL_SSLVERSION_TLSv1_3)) {
+ failf(data, "QUIC needs at least TLS version 1.3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ *prioritylist = QUIC_PRIORITY;
+ return CURLE_OK;
+ }
+
if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
(ssl_version == CURL_SSLVERSION_TLSv1))
ssl_version = CURL_SSLVERSION_TLSv1_0;
@@ -401,62 +450,15 @@ set_ssl_version_min_max(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
-CURLcode gtls_client_init(struct Curl_easy *data,
- struct ssl_primary_config *config,
- struct ssl_config_data *ssl_config,
- struct ssl_peer *peer,
- struct gtls_instance *gtls,
- long *pverifyresult)
+CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct gtls_ctx *gtls)
{
- unsigned int init_flags;
+ struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
int rc;
- bool sni = TRUE; /* default is SNI enabled */
- const char *prioritylist;
- const char *err = NULL;
- const char *tls13support;
- CURLcode result;
-
- if(!gtls_inited)
- gtls_init();
-
- *pverifyresult = 0;
-
- if(config->version == CURL_SSLVERSION_SSLv2) {
- failf(data, "GnuTLS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(config->version == CURL_SSLVERSION_SSLv3)
- sni = FALSE; /* SSLv3 has no SNI */
-
- /* allocate a cred struct */
- rc = gnutls_certificate_allocate_credentials(&gtls->cred);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
- return CURLE_SSL_CONNECT_ERROR;
- }
-
-#ifdef USE_GNUTLS_SRP
- if(config->username && Curl_auth_allowed_to_host(data)) {
- infof(data, "Using TLS-SRP username: %s", config->username);
-
- rc = gnutls_srp_allocate_client_credentials(&gtls->srp_client_cred);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
- gnutls_strerror(rc));
- return CURLE_OUT_OF_MEMORY;
- }
-
- rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
- config->username,
- config->password);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_srp_set_client_cred() failed: %s",
- gnutls_strerror(rc));
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
- }
-#endif
+ CURL_TRC_CF(data, cf, "setup trust anchors and CRLs");
if(config->verifypeer) {
bool imported_native_ca = false;
@@ -485,7 +487,7 @@ CURLcode gtls_client_init(struct Curl_easy *data,
config->CAfile, gnutls_strerror(rc),
(imported_native_ca ? ", continuing anyway" : ""));
if(!imported_native_ca) {
- *pverifyresult = rc;
+ ssl_config->certverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
}
}
@@ -503,7 +505,7 @@ CURLcode gtls_client_init(struct Curl_easy *data,
config->CApath, gnutls_strerror(rc),
(imported_native_ca ? ", continuing anyway" : ""));
if(!imported_native_ca) {
- *pverifyresult = rc;
+ ssl_config->certverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
}
}
@@ -526,6 +528,148 @@ CURLcode gtls_client_init(struct Curl_easy *data,
infof(data, "found %d CRL in %s", rc, config->CRLfile);
}
+ gtls->trust_setup = TRUE;
+ return CURLE_OK;
+}
+
+static void gtls_sessionid_free(void *sessionid, size_t idsize)
+{
+ (void)idsize;
+ free(sessionid);
+}
+
+static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ gnutls_session_t session)
+{
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result = CURLE_OK;
+
+ if(ssl_config->primary.sessionid) {
+ /* we always unconditionally get the session id here, as even if we
+ already got it from the cache and asked to use it in the connection, it
+ might've been rejected and then a new one is in use now and we need to
+ detect that. */
+ void *connect_sessionid;
+ size_t connect_idsize = 0;
+
+ /* get the session ID data size */
+ gnutls_session_get_data(session, NULL, &connect_idsize);
+ connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
+ if(!connect_sessionid) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ bool incache;
+ void *ssl_sessionid;
+
+ /* extract session ID to the allocated buffer */
+ gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+ DEBUGF(infof(data, "get session id (len=%zu) and store in cache",
+ connect_idsize));
+ Curl_ssl_sessionid_lock(data);
+ incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ &ssl_sessionid, NULL));
+ if(incache) {
+ /* there was one before in the cache, so instead of risking that the
+ previous one was rejected, we just kill that and store the new */
+ Curl_ssl_delsessionid(data, ssl_sessionid);
+ }
+
+ /* store this session id, takes ownership */
+ result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
+ connect_sessionid, connect_idsize,
+ gtls_sessionid_free);
+ Curl_ssl_sessionid_unlock(data);
+ }
+ }
+ return result;
+}
+
+static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
+ unsigned when, unsigned int incoming,
+ const gnutls_datum_t *msg)
+{
+ struct Curl_cfilter *cf = gnutls_session_get_ptr(session);
+
+ (void)msg;
+ (void)incoming;
+ if(when) { /* after message has been processed */
+ struct Curl_easy *data = CF_DATA_CURRENT(cf);
+ if(data) {
+ DEBUGF(infof(data, "handshake: %s message type %d",
+ incoming? "incoming" : "outgoing", htype));
+ switch(htype) {
+ case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
+ gtls_update_session_id(cf, data, session);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static CURLcode gtls_client_init(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ struct gtls_ctx *gtls)
+{
+ struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ unsigned int init_flags;
+ int rc;
+ bool sni = TRUE; /* default is SNI enabled */
+ const char *prioritylist;
+ const char *err = NULL;
+ const char *tls13support;
+ CURLcode result;
+
+ if(!gtls_inited)
+ gtls_init();
+
+ if(config->version == CURL_SSLVERSION_SSLv2) {
+ failf(data, "GnuTLS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(config->version == CURL_SSLVERSION_SSLv3)
+ sni = FALSE; /* SSLv3 has no SNI */
+
+ /* allocate a cred struct */
+ rc = gnutls_certificate_allocate_credentials(&gtls->cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef USE_GNUTLS_SRP
+ if(config->username && Curl_auth_allowed_to_host(data)) {
+ infof(data, "Using TLS-SRP username: %s", config->username);
+
+ rc = gnutls_srp_allocate_client_credentials(&gtls->srp_client_cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
+ config->username,
+ config->password);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_set_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ }
+#endif
+
+ ssl_config->certverifyresult = 0;
+
/* Initialize TLS session as a client */
init_flags = GNUTLS_CLIENT;
@@ -578,7 +722,8 @@ CURLcode gtls_client_init(struct Curl_easy *data,
}
/* At this point we know we have a supported TLS version, so set it */
- result = set_ssl_version_min_max(data, config, &prioritylist, tls13support);
+ result = set_ssl_version_min_max(data, peer,
+ config, &prioritylist, tls13support);
if(result)
return result;
@@ -611,6 +756,11 @@ CURLcode gtls_client_init(struct Curl_easy *data,
}
if(config->clientcert) {
+ if(!gtls->trust_setup) {
+ result = Curl_gtls_client_trust_setup(cf, data, gtls);
+ if(result)
+ return result;
+ }
if(ssl_config->key_passwd) {
const unsigned int supported_key_encryption_algorithms =
GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
@@ -677,46 +827,78 @@ CURLcode gtls_client_init(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode
-gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+static int keylog_callback(gnutls_session_t session, const char *label,
+ const gnutls_datum_t *secret)
+{
+ gnutls_datum_t crandom;
+ gnutls_datum_t srandom;
+
+ gnutls_session_get_random(session, &crandom, &srandom);
+ if(crandom.size != 32) {
+ return -1;
+ }
+
+ Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
+ return 0;
+}
+
+CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const unsigned char *alpn, size_t alpn_len,
+ Curl_gtls_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ void *ssl_user_data)
{
- struct ssl_connect_data *connssl = cf->ctx;
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- long * const pverifyresult = &ssl_config->certverifyresult;
CURLcode result;
- DEBUGASSERT(backend);
-
- if(connssl->state == ssl_connection_complete)
- /* to make us tolerant against being called more than once for the
- same connection */
- return CURLE_OK;
+ DEBUGASSERT(gctx);
- result = gtls_client_init(data, conn_config, ssl_config,
- &connssl->peer,
- &backend->gtls, pverifyresult);
+ result = gtls_client_init(cf, data, peer, gctx);
if(result)
return result;
- if(connssl->alpn) {
- struct alpn_proto_buf proto;
- gnutls_datum_t alpn[ALPN_ENTRIES_MAX];
- size_t i;
+ gnutls_session_set_ptr(gctx->session, ssl_user_data);
+
+ if(cb_setup) {
+ result = cb_setup(cf, data, cb_user_data);
+ if(result)
+ return result;
+ }
+
+ /* Open the file if a TLS or QUIC backend has not done this before. */
+ Curl_tls_keylog_open();
+ if(Curl_tls_keylog_enabled()) {
+ gnutls_session_set_keylog_function(gctx->session, keylog_callback);
+ }
- for(i = 0; i < connssl->alpn->count; ++i) {
- alpn[i].data = (unsigned char *)connssl->alpn->entries[i];
- alpn[i].size = (unsigned)strlen(connssl->alpn->entries[i]);
+ /* convert the ALPN string from our arguments to a list of strings
+ * that gnutls wants and will convert internally back to this very
+ * string for sending to the server. nice. */
+ if(alpn && alpn_len) {
+ gnutls_datum_t alpns[5];
+ size_t i, alen = alpn_len;
+ unsigned char *s = (unsigned char *)alpn;
+ unsigned char slen;
+ for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) {
+ slen = s[0];
+ if(slen >= alen)
+ return CURLE_FAILED_INIT;
+ alpns[i].data = s + 1;
+ alpns[i].size = slen;
+ s += slen + 1;
+ alen -= (size_t)slen + 1;
}
- if(gnutls_alpn_set_protocols(backend->gtls.session, alpn,
- (unsigned)connssl->alpn->count, 0)) {
+ if(alen) /* not all alpn chars used, wrong format or too many */
+ return CURLE_FAILED_INIT;
+ if(i && gnutls_alpn_set_protocols(gctx->session,
+ alpns, (unsigned int)i,
+ GNUTLS_ALPN_MANDATORY)) {
failf(data, "failed setting ALPN");
return CURLE_SSL_CONNECT_ERROR;
}
- Curl_alpn_to_proto_str(&proto, connssl->alpn);
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
/* This might be a reconnect, so we check for a session ID in the cache
@@ -726,16 +908,55 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
size_t ssl_idsize;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, &ssl_idsize)) {
+ if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, &ssl_idsize)) {
/* we got a session id, use it! */
- gnutls_session_set_data(backend->gtls.session,
- ssl_sessionid, ssl_idsize);
+ int rc;
- /* Informational message */
- infof(data, "SSL reusing session ID");
+ rc = gnutls_session_set_data(gctx->session, ssl_sessionid, ssl_idsize);
+ if(rc < 0)
+ infof(data, "SSL failed to set session ID");
+ else
+ infof(data, "SSL reusing session ID (size=%zu)", ssl_idsize);
}
Curl_ssl_sessionid_unlock(data);
}
+ return CURLE_OK;
+}
+
+static CURLcode
+gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
+ struct alpn_proto_buf proto;
+ CURLcode result;
+
+ DEBUGASSERT(backend);
+ DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
+
+ if(connssl->state == ssl_connection_complete)
+ /* to make us tolerant against being called more than once for the
+ same connection */
+ return CURLE_OK;
+
+ memset(&proto, 0, sizeof(proto));
+ if(connssl->alpn) {
+ result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
+ if(result) {
+ failf(data, "Error determining ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer,
+ proto.data, proto.len, NULL, NULL, cf);
+ if(result)
+ return result;
+
+ gnutls_handshake_set_hook_function(backend->gtls.session,
+ GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
+ gtls_handshake_cb);
/* register callback functions and handle to send and receive data. */
gnutls_transport_set_ptr(backend->gtls.session, cf);
@@ -1071,7 +1292,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
/* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
addresses. */
if(!rc) {
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
#define use_addr in6_addr
#else
#define use_addr in_addr
@@ -1081,7 +1302,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
if(Curl_inet_pton(AF_INET, peer->hostname, addrbuf) > 0)
addrlen = 4;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else if(Curl_inet_pton(AF_INET6, peer->hostname, addrbuf) > 0)
addrlen = 16;
#endif
@@ -1245,9 +1466,13 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+#ifndef CURL_DISABLE_PROXY
const char *pinned_key = Curl_ssl_cf_is_proxy(cf)?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#else
+ const char *pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#endif
CURLcode result;
result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config,
@@ -1266,47 +1491,10 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
Curl_alpn_set_negotiated(cf, data, NULL, 0);
}
- if(ssl_config->primary.sessionid) {
- /* we always unconditionally get the session id here, as even if we
- already got it from the cache and asked to use it in the connection, it
- might've been rejected and then a new one is in use now and we need to
- detect that. */
- void *connect_sessionid;
- size_t connect_idsize = 0;
-
- /* get the session ID data size */
- gnutls_session_get_data(session, NULL, &connect_idsize);
- connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
-
- if(connect_sessionid) {
- bool incache;
- bool added = FALSE;
- void *ssl_sessionid;
-
- /* extract session ID to the allocated buffer */
- gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
-
- Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL));
- if(incache) {
- /* there was one before in the cache, so instead of risking that the
- previous one was rejected, we just kill that and store the new */
- Curl_ssl_delsessionid(data, ssl_sessionid);
- }
-
- /* store this session id */
- result = Curl_ssl_addsessionid(cf, data, connect_sessionid,
- connect_idsize, &added);
- Curl_ssl_sessionid_unlock(data);
- if(!added)
- free(connect_sessionid);
- if(result) {
- result = CURLE_OUT_OF_MEMORY;
- }
- }
- else
- result = CURLE_OUT_OF_MEMORY;
- }
+ /* Only on TLSv1.2 or lower do we have the session id now. For
+ * TLSv1.3 we get it via a SESSION_TICKET message that arrives later. */
+ if(gnutls_protocol_get_version(session) < GNUTLS_TLS1_3)
+ result = gtls_update_session_id(cf, data, session);
out:
return result;
@@ -1418,12 +1606,13 @@ static ssize_t gtls_send(struct Curl_cfilter *cf,
(void)data;
DEBUGASSERT(backend);
+ backend->gtls.io_result = CURLE_OK;
rc = gnutls_record_send(backend->gtls.session, mem, len);
if(rc < 0) {
- *curlcode = (rc == GNUTLS_E_AGAIN)
- ? CURLE_AGAIN
- : CURLE_SEND_ERROR;
+ *curlcode = (rc == GNUTLS_E_AGAIN)?
+ CURLE_AGAIN :
+ (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);
rc = -1;
}
@@ -1559,6 +1748,7 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
(void)data;
DEBUGASSERT(backend);
+ backend->gtls.io_result = CURLE_OK;
ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
*curlcode = CURLE_AGAIN;
@@ -1583,7 +1773,8 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
failf(data, "GnuTLS recv error (%d): %s",
(int)ret, gnutls_strerror((int)ret));
- *curlcode = CURLE_RECV_ERROR;
+ *curlcode = backend->gtls.io_result?
+ backend->gtls.io_result : CURLE_RECV_ERROR;
ret = -1;
goto out;
}
@@ -1592,11 +1783,6 @@ out:
return ret;
}
-static void gtls_session_free(void *ptr)
-{
- free(ptr);
-}
-
static size_t gtls_version(char *buffer, size_t size)
{
return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
@@ -1663,7 +1849,6 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_get_internals, /* get_internals */
gtls_close, /* close_one */
Curl_none_close_all, /* close_all */
- gtls_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/gtls.h b/libs/libcurl/src/vtls/gtls.h
index 998957e689..534b320287 100644
--- a/libs/libcurl/src/vtls/gtls.h
+++ b/libs/libcurl/src/vtls/gtls.h
@@ -45,29 +45,39 @@ struct ssl_primary_config;
struct ssl_config_data;
struct ssl_peer;
-struct gtls_instance {
+struct gtls_ctx {
gnutls_session_t session;
gnutls_certificate_credentials_t cred;
#ifdef USE_GNUTLS_SRP
gnutls_srp_client_credentials_t srp_client_cred;
#endif
+ CURLcode io_result; /* result of last IO cfilter operation */
+ BIT(trust_setup); /* x509 anchors + CRLs have been set up */
};
-CURLcode
-gtls_client_init(struct Curl_easy *data,
- struct ssl_primary_config *config,
- struct ssl_config_data *ssl_config,
- struct ssl_peer *peer,
- struct gtls_instance *gtls,
- long *pverifyresult);
+typedef CURLcode Curl_gtls_ctx_setup_cb(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *user_data);
-CURLcode
-Curl_gtls_verifyserver(struct Curl_easy *data,
- gnutls_session_t session,
- struct ssl_primary_config *config,
- struct ssl_config_data *ssl_config,
- struct ssl_peer *peer,
- const char *pinned_key);
+CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const unsigned char *alpn, size_t alpn_len,
+ Curl_gtls_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ void *ssl_user_data);
+
+CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct gtls_ctx *gtls);
+
+CURLcode Curl_gtls_verifyserver(struct Curl_easy *data,
+ gnutls_session_t session,
+ struct ssl_primary_config *config,
+ struct ssl_config_data *ssl_config,
+ struct ssl_peer *peer,
+ const char *pinned_key);
extern const struct Curl_ssl Curl_ssl_gnutls;
diff --git a/libs/libcurl/src/vtls/keylog.c b/libs/libcurl/src/vtls/keylog.c
index 4a1f8ce74b..9cdfc02213 100644
--- a/libs/libcurl/src/vtls/keylog.c
+++ b/libs/libcurl/src/vtls/keylog.c
@@ -24,6 +24,7 @@
#include "curl_setup.h"
#if defined(USE_OPENSSL) || \
+ defined(USE_GNUTLS) || \
defined(USE_WOLFSSL) || \
(defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \
defined(USE_QUICHE)
diff --git a/libs/libcurl/src/vtls/mbedtls.c b/libs/libcurl/src/vtls/mbedtls.c
index 22a6a8cba2..d4820c4c50 100644
--- a/libs/libcurl/src/vtls/mbedtls.c
+++ b/libs/libcurl/src/vtls/mbedtls.c
@@ -67,6 +67,8 @@
#pragma GCC diagnostic pop
#endif
+#include "cipher_suite.h"
+#include "strcase.h"
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
@@ -107,6 +109,7 @@ struct mbed_ssl_backend_data {
#ifdef HAS_ALPN
const char *protocols[3];
#endif
+ int *ciphersuites;
};
/* apply threading? */
@@ -119,6 +122,10 @@ struct mbed_ssl_backend_data {
#define mbedtls_strerror(a,b,c) b[0] = 0
#endif
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && MBEDTLS_VERSION_NUMBER >= 0x03060000
+#define TLS13_SUPPORT
+#endif
+
#if defined(THREADING_SUPPORT)
static mbedtls_entropy_context ts_entropy;
@@ -163,15 +170,18 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
static void mbed_debug(void *context, int level, const char *f_name,
int line_nb, const char *line)
{
- struct Curl_easy *data = NULL;
-
- if(!context)
- return;
-
- data = (struct Curl_easy *)context;
-
- infof(data, "%s", line);
+ struct Curl_easy *data = (struct Curl_easy *)context;
(void) level;
+ (void) line_nb;
+ (void) f_name;
+
+ if(data) {
+ size_t len = strlen(line);
+ if(len && (line[len - 1] == '\n'))
+ /* discount any trailing newline */
+ len--;
+ infof(data, "%.*s", (int)len, line);
+ }
}
#endif
@@ -256,7 +266,12 @@ static CURLcode mbedtls_version_from_curl(
*mbedver = MBEDTLS_SSL_VERSION_TLS1_2;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_3:
+#ifdef TLS13_SUPPORT
+ *mbedver = MBEDTLS_SSL_VERSION_TLS1_3;
+ return CURLE_OK;
+#else
break;
+#endif
}
return CURLE_SSL_CONNECT_ERROR;
@@ -303,7 +318,11 @@ set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
#if MBEDTLS_VERSION_NUMBER >= 0x03020000
mbedtls_ssl_protocol_version mbedtls_ver_min = MBEDTLS_SSL_VERSION_TLS1_2;
+#ifdef TLS13_SUPPORT
+ mbedtls_ssl_protocol_version mbedtls_ver_max = MBEDTLS_SSL_VERSION_TLS1_3;
+#else
mbedtls_ssl_protocol_version mbedtls_ver_max = MBEDTLS_SSL_VERSION_TLS1_2;
+#endif
#elif MBEDTLS_VERSION_NUMBER >= 0x03000000
int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3;
@@ -327,7 +346,11 @@ set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
case CURL_SSLVERSION_MAX_DEFAULT:
+#ifdef TLS13_SUPPORT
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
+#else
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+#endif
break;
}
@@ -352,9 +375,113 @@ set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
mbedtls_ver_max);
#endif
+#ifdef TLS13_SUPPORT
+ if(mbedtls_ver_min == MBEDTLS_SSL_VERSION_TLS1_3) {
+ mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_REQUIRED);
+ }
+ else {
+ mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+ }
+#else
+ mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+#endif
+
return result;
}
+/* TLS_ECJPAKE_WITH_AES_128_CCM_8 (0xC0FF) is marked experimental
+ in mbedTLS. The number is not reserved by IANA nor is the
+ cipher suite present in other SSL implementations. Provide
+ provisional support for specifying the cipher suite here. */
+#ifdef MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
+static int
+mbed_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
+ bool prefer_rfc)
+{
+ if(id == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
+ msnprintf(buf, buf_size, "%s", "TLS_ECJPAKE_WITH_AES_128_CCM_8");
+ else
+ return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
+ return 0;
+}
+
+static uint16_t
+mbed_cipher_suite_walk_str(const char **str, const char **end)
+{
+ uint16_t id = Curl_cipher_suite_walk_str(str, end);
+ size_t len = *end - *str;
+
+ if(!id) {
+ if(strncasecompare("TLS_ECJPAKE_WITH_AES_128_CCM_8", *str, len))
+ id = MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8;
+ }
+ return id;
+}
+#else
+#define mbed_cipher_suite_get_str Curl_cipher_suite_get_str
+#define mbed_cipher_suite_walk_str Curl_cipher_suite_walk_str
+#endif
+
+static CURLcode
+mbed_set_selected_ciphers(struct Curl_easy *data,
+ struct mbed_ssl_backend_data *backend,
+ const char *ciphers)
+{
+ const int *supported;
+ int *selected;
+ size_t supported_len, count = 0, i;
+ const char *ptr, *end;
+
+ supported = mbedtls_ssl_list_ciphersuites();
+ for(i = 0; supported[i] != 0; i++);
+ supported_len = i;
+
+ selected = malloc(sizeof(int) * (supported_len + 1));
+ if(!selected)
+ return CURLE_OUT_OF_MEMORY;
+
+ for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
+ uint16_t id = mbed_cipher_suite_walk_str(&ptr, &end);
+
+ /* Check if cipher is supported */
+ if(id) {
+ for(i = 0; i < supported_len && supported[i] != id; i++);
+ if(i == supported_len)
+ id = 0;
+ }
+ if(!id) {
+ if(ptr[0] != '\0')
+ infof(data, "mbedTLS: unknown cipher in list: \"%.*s\"",
+ (int) (end - ptr), ptr);
+ continue;
+ }
+
+ /* No duplicates allowed (so selected cannot overflow) */
+ for(i = 0; i < count && selected[i] != id; i++);
+ if(i < count) {
+ infof(data, "mbedTLS: duplicate cipher in list: \"%.*s\"",
+ (int) (end - ptr), ptr);
+ continue;
+ }
+
+ selected[count++] = id;
+ }
+
+ selected[count] = 0;
+
+ if(count == 0) {
+ free(selected);
+ failf(data, "mbedTLS: no supported cipher in list");
+ return CURLE_SSL_CIPHER;
+ }
+
+ /* mbedtls_ssl_conf_ciphersuites(): The ciphersuites array is not copied.
+ It must remain valid for the lifetime of the SSL configuration */
+ backend->ciphersuites = selected;
+ mbedtls_ssl_conf_ciphersuites(&backend->config, backend->ciphersuites);
+ return CURLE_OK;
+}
+
static CURLcode
mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -384,6 +511,16 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_NOT_BUILT_IN;
}
+#ifdef TLS13_SUPPORT
+ ret = psa_crypto_init();
+ if(ret != PSA_SUCCESS) {
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "mbedTLS psa_crypto_init returned (-0x%04X) %s",
+ -ret, errorbuf);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif /* TLS13_SUPPORT */
+
#ifdef THREADING_SUPPORT
mbedtls_ctr_drbg_init(&backend->ctr_drbg);
@@ -589,7 +726,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#endif
- infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->port);
+ infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->peer.port);
mbedtls_ssl_config_init(&backend->config);
ret = mbedtls_ssl_config_defaults(&backend->config,
@@ -602,10 +739,6 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
mbedtls_ssl_init(&backend->ssl);
- if(mbedtls_ssl_setup(&backend->ssl, &backend->config)) {
- failf(data, "mbedTLS: ssl_init failed");
- return CURLE_SSL_CONNECT_ERROR;
- }
/* new profile with RSA min key len = 1024 ... */
mbedtls_ssl_conf_cert_profile(&backend->config,
@@ -635,17 +768,34 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
- mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
-
mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random,
&backend->ctr_drbg);
+
+ ret = mbedtls_ssl_setup(&backend->ssl, &backend->config);
+ if(ret) {
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "ssl_setup failed - mbedTLS: (-0x%04X) %s",
+ -ret, errorbuf);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
mbedtls_ssl_set_bio(&backend->ssl, cf,
mbedtls_bio_cf_write,
mbedtls_bio_cf_read,
NULL /* rev_timeout() */);
- mbedtls_ssl_conf_ciphersuites(&backend->config,
- mbedtls_ssl_list_ciphersuites());
+ if(conn_config->cipher_list) {
+ ret = mbed_set_selected_ciphers(data, backend, conn_config->cipher_list);
+ if(ret) {
+ failf(data, "mbedTLS: failed to set cipher suites");
+ return ret;
+ }
+ }
+ else {
+ mbedtls_ssl_conf_ciphersuites(&backend->config,
+ mbedtls_ssl_list_ciphersuites());
+ }
+
#if defined(MBEDTLS_SSL_RENEGOTIATION)
mbedtls_ssl_conf_renegotiation(&backend->config,
@@ -662,7 +812,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
void *old_session = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &old_session, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &old_session, NULL)) {
ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(data);
@@ -752,9 +902,15 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
(struct mbed_ssl_backend_data *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
const mbedtls_x509_crt *peercert;
+ char cipher_str[64];
+ uint16_t cipher_id;
+#ifndef CURL_DISABLE_PROXY
const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#else
+ const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#endif
DEBUGASSERT(backend);
@@ -776,8 +932,10 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
- infof(data, "mbedTLS: Handshake complete, cipher is %s",
- mbedtls_ssl_get_ciphersuite(&backend->ssl));
+ cipher_id = (uint16_t)
+ mbedtls_ssl_get_ciphersuite_id_from_ssl(&backend->ssl);
+ mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), true);
+ infof(data, "mbedTLS: Handshake complete, cipher is %s", cipher_str);
ret = mbedtls_ssl_get_verify_result(&backend->ssl);
@@ -911,6 +1069,13 @@ pinnedpubkey_error:
return CURLE_OK;
}
+static void mbedtls_session_free(void *sessionid, size_t idsize)
+{
+ (void)idsize;
+ mbedtls_ssl_session_free(sessionid);
+ free(sessionid);
+}
+
static CURLcode
mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -927,7 +1092,6 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
int ret;
mbedtls_ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
- bool added = FALSE;
our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
if(!our_ssl_sessionid)
@@ -946,20 +1110,16 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
/* If there's already a matching session in the cache, delete it */
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL))
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ &old_ssl_sessionid, NULL))
Curl_ssl_delsessionid(data, old_ssl_sessionid);
- retcode = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid,
- 0, &added);
+ retcode = Curl_ssl_addsessionid(cf, data, &connssl->peer,
+ our_ssl_sessionid, 0,
+ mbedtls_session_free);
Curl_ssl_sessionid_unlock(data);
- if(!added) {
- mbedtls_ssl_session_free(our_ssl_sessionid);
- free(our_ssl_sessionid);
- }
- if(retcode) {
- failf(data, "failed to store ssl session");
+ if(retcode)
return retcode;
- }
}
connssl->connecting_state = ssl_connect_done;
@@ -1014,6 +1174,7 @@ static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef MBEDTLS_X509_CRL_PARSE_C
mbedtls_x509_crl_free(&backend->crl);
#endif
+ Curl_safefree(backend->ciphersuites);
mbedtls_ssl_config_free(&backend->config);
mbedtls_ssl_free(&backend->ssl);
mbedtls_ctr_drbg_free(&backend->ctr_drbg);
@@ -1042,8 +1203,11 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
return 0;
- *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ?
- CURLE_AGAIN : CURLE_RECV_ERROR;
+ *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
+#ifdef TLS13_SUPPORT
+ || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
+#endif
+ ) ? CURLE_AGAIN : CURLE_RECV_ERROR;
return -1;
}
@@ -1052,12 +1216,6 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
return len;
}
-static void mbedtls_session_free(void *ptr)
-{
- mbedtls_ssl_session_free(ptr);
- free(ptr);
-}
-
static size_t mbedtls_version(char *buffer, size_t size)
{
#ifdef MBEDTLS_VERSION_C
@@ -1336,7 +1494,6 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
mbedtls_get_internals, /* get_internals */
mbedtls_close, /* close_one */
mbedtls_close_all, /* close_all */
- mbedtls_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c
index b22ec269ac..f53cb69471 100644
--- a/libs/libcurl/src/vtls/openssl.c
+++ b/libs/libcurl/src/vtls/openssl.c
@@ -82,6 +82,17 @@
#include <openssl/tls1.h>
#include <openssl/evp.h>
+#ifdef USE_ECH
+# ifndef OPENSSL_IS_BORINGSSL
+# include <openssl/ech.h>
+# endif
+# include "curl_base64.h"
+# define ECH_ENABLED(__data__) \
+ (__data__->set.tls_ech && \
+ !(__data__->set.tls_ech & CURLECH_DISABLE)\
+ )
+#endif /* USE_ECH */
+
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
#include <openssl/ocsp.h>
#endif
@@ -193,12 +204,10 @@
* Whether SSL_CTX_set_keylog_callback is available.
* OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
* BoringSSL: supported since d28f59c27bac (committed 2015-11-19)
- * LibreSSL: supported since 3.5.0 (released 2022-02-24)
+ * LibreSSL: not supported. 3.5.0+ has a stub function that does nothing.
*/
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
!defined(LIBRESSL_VERSION_NUMBER)) || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER >= 0x3050000fL) || \
defined(OPENSSL_IS_BORINGSSL)
#define HAVE_KEYLOG_CALLBACK
#endif
@@ -298,20 +307,6 @@ typedef unsigned long sslerr_t;
#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
#endif /* !LIBRESSL_VERSION_NUMBER */
-struct ossl_ssl_backend_data {
- /* these ones requires specific SSL-types */
- SSL_CTX* ctx;
- SSL* handle;
- X509* server_cert;
- BIO_METHOD *bio_method;
- CURLcode io_result; /* result of last BIO cfilter operation */
-#ifndef HAVE_KEYLOG_CALLBACK
- /* Set to true once a valid keylog entry has been created to avoid dupes. */
- bool keylog_done;
-#endif
- bool x509_store_setup; /* x509 store has been set up */
-};
-
#if defined(HAVE_SSL_X509_STORE_SHARE)
struct multi_ssl_backend_data {
char *CAfile; /* CAfile path used to generate X509 store */
@@ -726,8 +721,7 @@ static int ossl_bio_cf_out_write(BIO *bio, const char *buf, int blen)
{
struct Curl_cfilter *cf = BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
CURLcode result = CURLE_SEND_ERROR;
@@ -737,7 +731,7 @@ static int ossl_bio_cf_out_write(BIO *bio, const char *buf, int blen)
CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d",
blen, (int)nwritten, result);
BIO_clear_retry_flags(bio);
- backend->io_result = result;
+ octx->io_result = result;
if(nwritten < 0) {
if(CURLE_AGAIN == result)
BIO_set_retry_write(bio);
@@ -749,8 +743,7 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
{
struct Curl_cfilter *cf = BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result = CURLE_RECV_ERROR;
@@ -764,7 +757,7 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d",
blen, (int)nread, result);
BIO_clear_retry_flags(bio);
- backend->io_result = result;
+ octx->io_result = result;
if(nread < 0) {
if(CURLE_AGAIN == result)
BIO_set_retry_read(bio);
@@ -775,13 +768,13 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
/* Before returning server replies to the SSL instance, we need
* to have setup the x509 store or verification will fail. */
- if(!backend->x509_store_setup) {
- result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
+ if(!octx->x509_store_setup) {
+ result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
if(result) {
- backend->io_result = result;
+ octx->io_result = result;
return -1;
}
- backend->x509_store_setup = TRUE;
+ octx->x509_store_setup = TRUE;
}
return (int)nread;
@@ -1883,13 +1876,12 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data)
static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
(void)data;
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
- if(backend->handle) {
+ if(octx->ssl) {
/* Send the TLS shutdown if we are still connected *and* if
* the peer did not already close the connection. */
if(cf->next && cf->next->connected && !connssl->peer_closed) {
@@ -1900,8 +1892,8 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
ERR_clear_error();
- nread = SSL_read(backend->handle, buf, (int)sizeof(buf));
- err = SSL_get_error(backend->handle, nread);
+ nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
+ err = SSL_get_error(octx->ssl, nread);
if(!nread && err == SSL_ERROR_ZERO_RETURN) {
CURLcode result;
ssize_t n;
@@ -1924,12 +1916,12 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
CURL_TRC_CF(data, cf, "not from sending TLS shutdown on "
"connection closed by peer");
}
- else if(SSL_shutdown(backend->handle) == 1) {
+ else if(SSL_shutdown(octx->ssl) == 1) {
CURL_TRC_CF(data, cf, "SSL shutdown finished");
}
else {
- nread = SSL_read(backend->handle, buf, (int)sizeof(buf));
- err = SSL_get_error(backend->handle, nread);
+ nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
+ err = SSL_get_error(octx->ssl, nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
case SSL_ERROR_ZERO_RETURN: /* no more data */
@@ -1955,20 +1947,20 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
}
ERR_clear_error();
- SSL_set_connect_state(backend->handle);
+ SSL_set_connect_state(octx->ssl);
}
- SSL_free(backend->handle);
- backend->handle = NULL;
+ SSL_free(octx->ssl);
+ octx->ssl = NULL;
}
- if(backend->ctx) {
- SSL_CTX_free(backend->ctx);
- backend->ctx = NULL;
- backend->x509_store_setup = FALSE;
+ if(octx->ssl_ctx) {
+ SSL_CTX_free(octx->ssl_ctx);
+ octx->ssl_ctx = NULL;
+ octx->x509_store_setup = FALSE;
}
- if(backend->bio_method) {
- ossl_bio_cf_method_free(backend->bio_method);
- backend->bio_method = NULL;
+ if(octx->bio_method) {
+ ossl_bio_cf_method_free(octx->bio_method);
+ octx->bio_method = NULL;
}
}
@@ -1988,11 +1980,10 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
int buffsize;
int err;
bool done = FALSE;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
int loop = 10;
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
#ifndef CURL_DISABLE_FTP
/* This has only been tested on the proftpd server, and the mod_tls code
@@ -2001,10 +1992,10 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
we do not send one. Let's hope other servers do the same... */
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- (void)SSL_shutdown(backend->handle);
+ (void)SSL_shutdown(octx->ssl);
#endif
- if(backend->handle) {
+ if(octx->ssl) {
buffsize = (int)sizeof(buf);
while(!done && loop--) {
int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
@@ -2014,8 +2005,8 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
/* Something to read, let's do it and hope that it is the close
notify alert from the server */
- nread = SSL_read(backend->handle, buf, buffsize);
- err = SSL_get_error(backend->handle, nread);
+ nread = SSL_read(octx->ssl, buf, buffsize);
+ err = SSL_get_error(octx->ssl, nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
@@ -2060,7 +2051,7 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
if(data->set.verbose) {
#ifdef HAVE_SSL_GET_SHUTDOWN
- switch(SSL_get_shutdown(backend->handle)) {
+ switch(SSL_get_shutdown(octx->ssl)) {
case SSL_SENT_SHUTDOWN:
infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN");
break;
@@ -2075,16 +2066,17 @@ static int ossl_shutdown(struct Curl_cfilter *cf,
#endif
}
- SSL_free(backend->handle);
- backend->handle = NULL;
+ SSL_free(octx->ssl);
+ octx->ssl = NULL;
}
return retval;
}
-static void ossl_session_free(void *ptr)
+static void ossl_session_free(void *sessionid, size_t idsize)
{
/* free the ID */
- SSL_SESSION_free(ptr);
+ (void)idsize;
+ SSL_SESSION_free(sessionid);
}
/*
@@ -2165,14 +2157,14 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
int target; /* target type, GEN_DNS or GEN_IPADD */
size_t addrlen = 0;
STACK_OF(GENERAL_NAME) *altnames;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct in6_addr addr;
#else
struct in_addr addr;
#endif
CURLcode result = CURLE_OK;
bool dNSName = FALSE; /* if a dNSName field exists in the cert */
- bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */
+ bool iPAddress = FALSE; /* if an iPAddress field exists in the cert */
size_t hostlen;
(void)conn;
@@ -2184,7 +2176,7 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
target = GEN_IPADD;
addrlen = sizeof(struct in_addr);
break;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
case CURL_SSL_PEER_IPV6:
if(!Curl_inet_pton(AF_INET6, peer->hostname, &addr))
return CURLE_PEER_FAILED_VERIFICATION;
@@ -2381,8 +2373,7 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
OCSP_BASICRESP *br = NULL;
X509_STORE *st = NULL;
STACK_OF(X509) *ch = NULL;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
X509 *cert;
OCSP_CERTID *id = NULL;
int cert_status, crl_reason;
@@ -2390,9 +2381,9 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
int ret;
long len;
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
- len = SSL_get_tlsext_status_ocsp_resp(backend->handle, &status);
+ len = SSL_get_tlsext_status_ocsp_resp(octx->ssl, &status);
if(!status) {
failf(data, "No OCSP response received");
@@ -2422,13 +2413,13 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
goto end;
}
- ch = SSL_get_peer_cert_chain(backend->handle);
+ ch = SSL_get_peer_cert_chain(octx->ssl);
if(!ch) {
failf(data, "Could not get peer certificate chain");
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
- st = SSL_CTX_get_cert_store(backend->ctx);
+ st = SSL_CTX_get_cert_store(octx->ssl_ctx);
#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
(defined(LIBRESSL_VERSION_NUMBER) && \
@@ -2465,7 +2456,7 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
}
/* Compute the certificate's ID */
- cert = SSL_get1_peer_certificate(backend->handle);
+ cert = SSL_get1_peer_certificate(octx->ssl);
if(!cert) {
failf(data, "Error getting peer certificate");
result = CURLE_SSL_INVALIDCERTSTATUS;
@@ -2880,10 +2871,9 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
#ifdef TLS1_3_VERSION
{
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
- DEBUGASSERT(backend);
- SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION);
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ DEBUGASSERT(octx);
+ SSL_CTX_set_max_proto_version(octx->ssl_ctx, TLS1_3_VERSION);
*ctx_options |= SSL_OP_NO_TLSv1_2;
}
#else
@@ -2941,61 +2931,64 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
}
#endif
-/* The "new session" callback must return zero if the session can be removed
- * or non-zero if the session has been put into the session cache.
- */
-static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
+CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct ssl_peer *peer,
+ SSL_SESSION *session)
{
- int res = 0;
- struct Curl_easy *data;
- struct Curl_cfilter *cf;
const struct ssl_config_data *config;
- struct ssl_connect_data *connssl;
bool isproxy;
+ bool added = FALSE;
- cf = (struct Curl_cfilter*) SSL_get_app_data(ssl);
- connssl = cf? cf->ctx : NULL;
- data = connssl? CF_DATA_CURRENT(cf) : NULL;
- /* The sockindex has been stored as a pointer to an array element */
if(!cf || !data)
- return 0;
+ goto out;
isproxy = Curl_ssl_cf_is_proxy(cf);
config = Curl_ssl_cf_get_config(cf, data);
if(config->primary.sessionid) {
bool incache;
- bool added = FALSE;
- void *old_ssl_sessionid = NULL;
+ void *old_session = NULL;
Curl_ssl_sessionid_lock(data);
if(isproxy)
incache = FALSE;
else
- incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
- if(incache) {
- if(old_ssl_sessionid != ssl_sessionid) {
- infof(data, "old SSL session ID is stale, removing");
- Curl_ssl_delsessionid(data, old_ssl_sessionid);
- incache = FALSE;
- }
+ incache = !(Curl_ssl_getsessionid(cf, data, peer,
+ &old_session, NULL));
+ if(incache && (old_session != session)) {
+ infof(data, "old SSL session ID is stale, removing");
+ Curl_ssl_delsessionid(data, old_session);
+ incache = FALSE;
}
if(!incache) {
- if(!Curl_ssl_addsessionid(cf, data, ssl_sessionid,
- 0 /* unknown size */, &added)) {
- if(added) {
- /* the session has been put into the session cache */
- res = 1;
- }
- }
- else
- failf(data, "failed to store ssl session");
+ added = TRUE;
+ Curl_ssl_addsessionid(cf, data, peer, session, 0, ossl_session_free);
}
Curl_ssl_sessionid_unlock(data);
}
- return res;
+out:
+ if(!added)
+ ossl_session_free(session, 0);
+ return CURLE_OK;
+}
+
+/* The "new session" callback must return zero if the session can be removed
+ * or non-zero if the session has been put into the session cache.
+ */
+static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
+{
+ struct Curl_cfilter *cf;
+ struct Curl_easy *data;
+ struct ssl_connect_data *connssl;
+
+ cf = (struct Curl_cfilter*) SSL_get_app_data(ssl);
+ connssl = cf? cf->ctx : NULL;
+ data = connssl? CF_DATA_CURRENT(cf) : NULL;
+ Curl_ossl_add_session(cf, data, &connssl->peer, ssl_sessionid);
+ return 1;
}
static CURLcode load_cacert_from_memory(X509_STORE *store,
@@ -3390,7 +3383,7 @@ static bool cached_x509_store_different(
static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
- struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct Curl_multi *multi = data->multi;
X509_STORE *store = NULL;
DEBUGASSERT(multi);
@@ -3410,7 +3403,7 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
X509_STORE *store)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct Curl_multi *multi = data->multi;
struct multi_ssl_backend_data *mbackend;
DEBUGASSERT(multi);
@@ -3493,29 +3486,33 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
}
#endif /* HAVE_SSL_X509_STORE_SHARE */
-static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ int transport, /* TCP or QUIC */
+ const unsigned char *alpn, size_t alpn_len,
+ Curl_ossl_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ Curl_ossl_new_session_cb *cb_new_session,
+ void *ssl_user_data)
{
CURLcode result = CURLE_OK;
- char *ciphers;
+ const char *ciphers;
SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
- struct ssl_connect_data *connssl = cf->ctx;
ctx_option_t ctx_options = 0;
void *ssl_sessionid = NULL;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- BIO *bio;
const long int ssl_version = conn_config->version;
char * const ssl_cert = ssl_config->primary.clientcert;
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
const char * const ssl_cert_type = ssl_config->cert_type;
const bool verifypeer = conn_config->verifypeer;
char error_buffer[256];
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
-
- DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
- DEBUGASSERT(backend);
+#ifdef USE_ECH
+ struct ssl_connect_data *connssl = cf->ctx;
+#endif
/* Make funny stuff to get random input */
result = ossl_seed(data);
@@ -3524,56 +3521,74 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
ssl_config->certverifyresult = !X509_V_OK;
- /* check to see if we've been told to use an explicit SSL/TLS version */
-
- switch(ssl_version) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2:
- case CURL_SSLVERSION_TLSv1_3:
- /* it will be handled later with the context options */
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- req_method = TLS_client_method();
+ switch(transport) {
+ case TRNSPRT_TCP:
+ /* check to see if we've been told to use an explicit SSL/TLS version */
+ switch(ssl_version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ /* it will be handled later with the context options */
+ #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+ req_method = TLS_client_method();
+ #else
+ req_method = SSLv23_client_method();
+ #endif
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "No SSLv2 support");
+ return CURLE_NOT_BUILT_IN;
+ case CURL_SSLVERSION_SSLv3:
+ failf(data, "No SSLv3 support");
+ return CURLE_NOT_BUILT_IN;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ break;
+ case TRNSPRT_QUIC:
+ if((ssl_version != CURL_SSLVERSION_DEFAULT) &&
+ (ssl_version < CURL_SSLVERSION_TLSv1_3)) {
+ failf(data, "QUIC needs at least TLS version 1.3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#ifdef USE_OPENSSL_QUIC
+ req_method = OSSL_QUIC_client_method();
+#elif (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+ req_method = TLS_method();
#else
req_method = SSLv23_client_method();
#endif
break;
- case CURL_SSLVERSION_SSLv2:
- failf(data, "No SSLv2 support");
- return CURLE_NOT_BUILT_IN;
- case CURL_SSLVERSION_SSLv3:
- failf(data, "No SSLv3 support");
- return CURLE_NOT_BUILT_IN;
default:
- failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ failf(data, "unsupported transport %d in SSL init", transport);
return CURLE_SSL_CONNECT_ERROR;
}
- if(backend->ctx) {
- /* This happens when an error was encountered before in this
- * step and we are called to do it again. Get rid of any leftover
- * from the previous call. */
- ossl_close(cf, data);
- }
- backend->ctx = SSL_CTX_new(req_method);
- if(!backend->ctx) {
+ DEBUGASSERT(!octx->ssl_ctx);
+ octx->ssl_ctx = SSL_CTX_new(req_method);
+
+ if(!octx->ssl_ctx) {
failf(data, "SSL: couldn't create a context: %s",
ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer)));
return CURLE_OUT_OF_MEMORY;
}
-#ifdef SSL_MODE_RELEASE_BUFFERS
- SSL_CTX_set_mode(backend->ctx, SSL_MODE_RELEASE_BUFFERS);
-#endif
+ if(cb_setup) {
+ result = cb_setup(cf, data, cb_user_data);
+ if(result)
+ return result;
+ }
#ifdef SSL_CTRL_SET_MSG_CALLBACK
if(data->set.fdebug && data->set.verbose) {
/* the SSL trace callback is only used for verbose logging */
- SSL_CTX_set_msg_callback(backend->ctx, ossl_trace);
- SSL_CTX_set_msg_callback_arg(backend->ctx, cf);
+ SSL_CTX_set_msg_callback(octx->ssl_ctx, ossl_trace);
+ SSL_CTX_set_msg_callback_arg(octx->ssl_ctx, cf);
}
#endif
@@ -3653,7 +3668,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
ctx_options |= SSL_OP_NO_SSLv3;
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */
- result = ossl_set_ssl_version_min_max(cf, backend->ctx);
+ result = ossl_set_ssl_version_min_max(cf, octx->ssl_ctx);
#else
result = ossl_set_ssl_version_min_max_legacy(&ctx_options, cf, data);
#endif
@@ -3666,26 +3681,20 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
- SSL_CTX_set_options(backend->ctx, ctx_options);
+ SSL_CTX_set_options(octx->ssl_ctx, ctx_options);
#ifdef HAS_ALPN
- if(connssl->alpn) {
- struct alpn_proto_buf proto;
-
- result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
- if(result ||
- SSL_CTX_set_alpn_protos(backend->ctx, proto.data, proto.len)) {
+ if(alpn && alpn_len) {
+ if(SSL_CTX_set_alpn_protos(octx->ssl_ctx, alpn, (int)alpn_len)) {
failf(data, "Error setting ALPN");
return CURLE_SSL_CONNECT_ERROR;
}
- Curl_alpn_to_proto_str(&proto, connssl->alpn);
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
#endif
if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
if(!result &&
- !cert_stuff(data, backend->ctx,
+ !cert_stuff(data, octx->ssl_ctx,
ssl_cert, ssl_cert_blob, ssl_cert_type,
ssl_config->key, ssl_config->key_blob,
ssl_config->key_type, ssl_config->key_passwd))
@@ -3696,10 +3705,10 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
}
ciphers = conn_config->cipher_list;
- if(!ciphers)
- ciphers = (char *)DEFAULT_CIPHER_SELECTION;
+ if(!ciphers && (peer->transport != TRNSPRT_QUIC))
+ ciphers = DEFAULT_CIPHER_SELECTION;
if(ciphers) {
- if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
+ if(!SSL_CTX_set_cipher_list(octx->ssl_ctx, ciphers)) {
failf(data, "failed setting cipher list: %s", ciphers);
return CURLE_SSL_CIPHER;
}
@@ -3708,9 +3717,9 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
{
- char *ciphers13 = conn_config->cipher_list13;
+ const char *ciphers13 = conn_config->cipher_list13;
if(ciphers13) {
- if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) {
+ if(!SSL_CTX_set_ciphersuites(octx->ssl_ctx, ciphers13)) {
failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13);
return CURLE_SSL_CIPHER;
}
@@ -3721,14 +3730,14 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
/* OpenSSL 1.1.1 requires clients to opt-in for PHA */
- SSL_CTX_set_post_handshake_auth(backend->ctx, 1);
+ SSL_CTX_set_post_handshake_auth(octx->ssl_ctx, 1);
#endif
#ifdef HAVE_SSL_CTX_SET_EC_CURVES
{
- char *curves = conn_config->curves;
+ const char *curves = conn_config->curves;
if(curves) {
- if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
+ if(!SSL_CTX_set1_curves_list(octx->ssl_ctx, curves)) {
failf(data, "failed setting curves list: '%s'", curves);
return CURLE_SSL_CIPHER;
}
@@ -3742,18 +3751,18 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
char * const ssl_password = ssl_config->primary.password;
infof(data, "Using TLS-SRP username: %s", ssl_username);
- if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) {
+ if(!SSL_CTX_set_srp_username(octx->ssl_ctx, ssl_username)) {
failf(data, "Unable to set SRP user name");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- if(!SSL_CTX_set_srp_password(backend->ctx, ssl_password)) {
+ if(!SSL_CTX_set_srp_password(octx->ssl_ctx, ssl_password)) {
failf(data, "failed setting SRP password");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(!conn_config->cipher_list) {
infof(data, "Setting cipher list SRP");
- if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) {
+ if(!SSL_CTX_set_cipher_list(octx->ssl_ctx, "SRP")) {
failf(data, "failed setting SRP cipher list");
return CURLE_SSL_CIPHER;
}
@@ -3765,38 +3774,40 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
* fail to connect if the verification fails, or if it should continue
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
- SSL_CTX_set_verify(backend->ctx,
+ SSL_CTX_set_verify(octx->ssl_ctx,
verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
/* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */
#ifdef HAVE_KEYLOG_CALLBACK
if(Curl_tls_keylog_enabled()) {
- SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback);
+ SSL_CTX_set_keylog_callback(octx->ssl_ctx, ossl_keylog_callback);
}
#endif
- /* Enable the session cache because it's a prerequisite for the "new session"
- * callback. Use the "external storage" mode to prevent OpenSSL from creating
- * an internal session cache.
- */
- SSL_CTX_set_session_cache_mode(backend->ctx,
- SSL_SESS_CACHE_CLIENT |
- SSL_SESS_CACHE_NO_INTERNAL);
- SSL_CTX_sess_set_new_cb(backend->ctx, ossl_new_session_cb);
+ if(cb_new_session) {
+ /* Enable the session cache because it's a prerequisite for the
+ * "new session" callback. Use the "external storage" mode to prevent
+ * OpenSSL from creating an internal session cache.
+ */
+ SSL_CTX_set_session_cache_mode(octx->ssl_ctx,
+ SSL_SESS_CACHE_CLIENT |
+ SSL_SESS_CACHE_NO_INTERNAL);
+ SSL_CTX_sess_set_new_cb(octx->ssl_ctx, cb_new_session);
+ }
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
/* When a user callback is installed to modify the SSL_CTX,
* we need to do the full initialization before calling it.
* See: #11800 */
- if(!backend->x509_store_setup) {
- result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
+ if(!octx->x509_store_setup) {
+ result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
if(result)
return result;
- backend->x509_store_setup = TRUE;
+ octx->x509_store_setup = TRUE;
}
Curl_set_in_callback(data, true);
- result = (*data->set.ssl.fsslctx)(data, backend->ctx,
+ result = (*data->set.ssl.fsslctx)(data, octx->ssl_ctx,
data->set.ssl.fsslctxp);
Curl_set_in_callback(data, false);
if(result) {
@@ -3806,47 +3817,174 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
}
/* Let's make an SSL structure */
- if(backend->handle)
- SSL_free(backend->handle);
- backend->handle = SSL_new(backend->ctx);
- if(!backend->handle) {
+ if(octx->ssl)
+ SSL_free(octx->ssl);
+ octx->ssl = SSL_new(octx->ssl_ctx);
+ if(!octx->ssl) {
failf(data, "SSL: couldn't create a context (handle)");
return CURLE_OUT_OF_MEMORY;
}
- SSL_set_app_data(backend->handle, cf);
+ SSL_set_app_data(octx->ssl, ssl_user_data);
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
if(conn_config->verifystatus)
- SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp);
+ SSL_set_tlsext_status_type(octx->ssl, TLSEXT_STATUSTYPE_ocsp);
#endif
#if (defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) && \
defined(ALLOW_RENEG)
- SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely);
+ SSL_set_renegotiate_mode(octx->ssl, ssl_renegotiate_freely);
#endif
- SSL_set_connect_state(backend->handle);
+ SSL_set_connect_state(octx->ssl);
- backend->server_cert = 0x0;
+ octx->server_cert = 0x0;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- if(connssl->peer.sni) {
- if(!SSL_set_tlsext_host_name(backend->handle, connssl->peer.sni)) {
+ if(peer->sni) {
+ if(!SSL_set_tlsext_host_name(octx->ssl, peer->sni)) {
failf(data, "Failed set SNI");
return CURLE_SSL_CONNECT_ERROR;
}
}
-#endif
- SSL_set_app_data(backend->handle, cf);
+#ifdef USE_ECH
+ if(ECH_ENABLED(data)) {
+ unsigned char *ech_config = NULL;
+ size_t ech_config_len = 0;
+ char *outername = data->set.str[STRING_ECH_PUBLIC];
+ int trying_ech_now = 0;
+
+ if(data->set.tls_ech & CURLECH_GREASE) {
+ infof(data, "ECH: will GREASE ClientHello");
+# ifdef OPENSSL_IS_BORINGSSL
+ SSL_set_enable_ech_grease(octx->ssl, 1);
+# else
+ SSL_set_options(octx->ssl, SSL_OP_ECH_GREASE);
+# endif
+ }
+ else if(data->set.tls_ech & CURLECH_CLA_CFG) {
+# ifdef OPENSSL_IS_BORINGSSL
+ /* have to do base64 decode here for boring */
+ const char *b64 = data->set.str[STRING_ECH_CONFIG];
+
+ if(!b64) {
+ infof(data, "ECH: ECHConfig from command line empty");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ ech_config_len = 2 * strlen(b64);
+ result = Curl_base64_decode(b64, &ech_config, &ech_config_len);
+ if(result || !ech_config) {
+ infof(data, "ECH: can't base64 decode ECHConfig from command line");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return result;
+ }
+ if(SSL_set1_ech_config_list(octx->ssl, ech_config,
+ ech_config_len) != 1) {
+ infof(data, "ECH: SSL_ECH_set1_echconfig failed");
+ if(data->set.tls_ech & CURLECH_HARD) {
+ free(ech_config);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ free(ech_config);
+ trying_ech_now = 1;
+# else
+ ech_config = (unsigned char *) data->set.str[STRING_ECH_CONFIG];
+ if(!ech_config) {
+ infof(data, "ECH: ECHConfig from command line empty");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ ech_config_len = strlen(data->set.str[STRING_ECH_CONFIG]);
+ if(SSL_ech_set1_echconfig(octx->ssl, ech_config, ech_config_len) != 1) {
+ infof(data, "ECH: SSL_ECH_set1_echconfig failed");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else
+ trying_ech_now = 1;
+# endif
+ infof(data, "ECH: ECHConfig from command line");
+ }
+ else {
+ struct Curl_dns_entry *dns = NULL;
+
+ dns = Curl_fetch_addr(data, connssl->peer.hostname, connssl->peer.port);
+ if(!dns) {
+ infof(data, "ECH: requested but no DNS info available");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ struct Curl_https_rrinfo *rinfo = NULL;
+
+ rinfo = dns->hinfo;
+ if(rinfo && rinfo->echconfiglist) {
+ unsigned char *ecl = rinfo->echconfiglist;
+ size_t elen = rinfo->echconfiglist_len;
+
+ infof(data, "ECH: ECHConfig from DoH HTTPS RR");
+# ifndef OPENSSL_IS_BORINGSSL
+ if(SSL_ech_set1_echconfig(octx->ssl, ecl, elen) != 1) {
+ infof(data, "ECH: SSL_ECH_set1_echconfig failed");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+# else
+ if(SSL_set1_ech_config_list(octx->ssl, ecl, elen) != 1) {
+ infof(data, "ECH: SSL_set1_ech_config_list failed (boring)");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+# endif
+ else {
+ trying_ech_now = 1;
+ infof(data, "ECH: imported ECHConfigList of length %ld", elen);
+ }
+ }
+ else {
+ infof(data, "ECH: requested but no ECHConfig available");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ Curl_resolv_unlock(data, dns);
+ }
+ }
+# ifdef OPENSSL_IS_BORINGSSL
+ if(trying_ech_now && outername) {
+ infof(data, "ECH: setting public_name not supported with boringssl");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+# else
+ if(trying_ech_now && outername) {
+ infof(data, "ECH: inner: '%s', outer: '%s'",
+ connssl->peer.hostname, outername);
+ result = SSL_ech_set_server_names(octx->ssl,
+ connssl->peer.hostname, outername,
+ 0 /* do send outer */);
+ if(result != 1) {
+ infof(data, "ECH: rv failed to set server name(s) %d [ERROR]", result);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+# endif /* not BORING */
+ if(trying_ech_now
+ && SSL_set_min_proto_version(octx->ssl, TLS1_3_VERSION) != 1) {
+ infof(data, "ECH: Can't force TLSv1.3 [ERROR]");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif /* USE_ECH */
- connssl->reused_session = FALSE;
- if(ssl_config->primary.sessionid) {
+#endif
+
+ octx->reused_session = FALSE;
+ if(ssl_config->primary.sessionid && transport == TRNSPRT_TCP) {
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
- if(!SSL_set_session(backend->handle, ssl_sessionid)) {
+ if(!SSL_set_session(octx->ssl, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(data);
failf(data, "SSL: SSL_set_session failed: %s",
ossl_strerror(ERR_get_error(), error_buffer,
@@ -3855,15 +3993,46 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
}
/* Informational message */
infof(data, "SSL reusing session ID");
- connssl->reused_session = TRUE;
+ octx->reused_session = TRUE;
}
Curl_ssl_sessionid_unlock(data);
}
- backend->bio_method = ossl_bio_cf_method_create();
- if(!backend->bio_method)
+ return CURLE_OK;
+}
+
+static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ struct alpn_proto_buf proto;
+ BIO *bio;
+ CURLcode result;
+
+ DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
+ DEBUGASSERT(octx);
+ memset(&proto, 0, sizeof(proto));
+#ifdef HAS_ALPN
+ if(connssl->alpn) {
+ result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
+ if(result) {
+ failf(data, "Error determining ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif
+
+ result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer, TRNSPRT_TCP,
+ proto.data, proto.len, NULL, NULL,
+ ossl_new_session_cb, cf);
+ if(result)
+ return result;
+
+ octx->bio_method = ossl_bio_cf_method_create();
+ if(!octx->bio_method)
return CURLE_OUT_OF_MEMORY;
- bio = BIO_new(backend->bio_method);
+ bio = BIO_new(octx->bio_method);
if(!bio)
return CURLE_OUT_OF_MEMORY;
@@ -3875,40 +4044,109 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
* We check on the function in configure, since libressl and friends
* each have their own versions to add support for this. */
BIO_up_ref(bio);
- SSL_set0_rbio(backend->handle, bio);
- SSL_set0_wbio(backend->handle, bio);
+ SSL_set0_rbio(octx->ssl, bio);
+ SSL_set0_wbio(octx->ssl, bio);
#else
- SSL_set_bio(backend->handle, bio, bio);
+ SSL_set_bio(octx->ssl, bio, bio);
#endif
- connssl->connecting_state = ssl_connect_2;
+#ifdef HAS_ALPN
+ if(connssl->alpn) {
+ Curl_alpn_to_proto_str(&proto, connssl->alpn);
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+ }
+#endif
+ connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
}
+#ifdef USE_ECH
+/* If we have retry configs, then trace those out */
+static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl,
+ int reason)
+{
+ CURLcode result = CURLE_OK;
+ size_t rcl = 0;
+ int rv = 1;
+# ifndef OPENSSL_IS_BORINGSSL
+ char *inner = NULL;
+ unsigned char *rcs = NULL;
+ char *outer = NULL;
+# else
+ const char *inner = NULL;
+ const uint8_t *rcs = NULL;
+ const char *outer = NULL;
+ size_t out_name_len = 0;
+ int servername_type = 0;
+# endif
+
+ /* nothing to trace if not doing ECH */
+ if(!ECH_ENABLED(data))
+ return;
+# ifndef OPENSSL_IS_BORINGSSL
+ rv = SSL_ech_get_retry_config(ssl, &rcs, &rcl);
+# else
+ SSL_get0_ech_retry_configs(ssl, &rcs, &rcl);
+ rv = (int)rcl;
+# endif
+
+ if(rv && rcs) {
+# define HEXSTR_MAX 800
+ char *b64str = NULL;
+ size_t blen = 0;
+
+ result = Curl_base64_encode((const char *)rcs, rcl,
+ &b64str, &blen);
+ if(!result && b64str)
+ infof(data, "ECH: retry_configs %s", b64str);
+ free(b64str);
+# ifndef OPENSSL_IS_BORINGSSL
+ rv = SSL_ech_get_status(ssl, &inner, &outer);
+ infof(data, "ECH: retry_configs for %s from %s, %d %d",
+ inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
+#else
+ rv = SSL_ech_accepted(ssl);
+ servername_type = SSL_get_servername_type(ssl);
+ inner = SSL_get_servername(ssl, servername_type);
+ SSL_get0_ech_name_override(ssl, &outer, &out_name_len);
+ /* TODO: get the inner from boring */
+ infof(data, "ECH: retry_configs for %s from %s, %d %d",
+ inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
+#endif
+ }
+ else
+ infof(data, "ECH: no retry_configs (rv = %d)", rv);
+# ifndef OPENSSL_IS_BORINGSSL
+ OPENSSL_free((void *)rcs);
+# endif
+ return;
+}
+
+#endif
+
static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
int err;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|| ssl_connect_2_reading == connssl->connecting_state
|| ssl_connect_2_writing == connssl->connecting_state);
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
ERR_clear_error();
- err = SSL_connect(backend->handle);
+ err = SSL_connect(octx->ssl);
- if(!backend->x509_store_setup) {
+ if(!octx->x509_store_setup) {
/* After having send off the ClientHello, we prepare the x509
* store to verify the coming certificate from the server */
- CURLcode result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
+ CURLcode result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
if(result)
return result;
- backend->x509_store_setup = TRUE;
+ octx->x509_store_setup = TRUE;
}
#ifndef HAVE_KEYLOG_CALLBACK
@@ -3916,7 +4154,9 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
/* If key logging is enabled, wait for the handshake to complete and then
* proceed with logging secrets (for TLS 1.2 or older).
*/
- ossl_log_tls12_secret(backend->handle, &backend->keylog_done);
+ bool done = FALSE;
+ ossl_log_tls12_secret(octx->ssl, &done);
+ octx->keylog_done = done;
}
#endif
@@ -3924,7 +4164,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
0 is "not successful but was shut down controlled"
<0 is "handshake was not successful, because a fatal error occurred" */
if(1 != err) {
- int detail = SSL_get_error(backend->handle, err);
+ int detail = SSL_get_error(octx->ssl, err);
if(SSL_ERROR_WANT_READ == detail) {
connssl->connecting_state = ssl_connect_2_reading;
@@ -3946,7 +4186,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
return CURLE_OK;
}
#endif
- if(backend->io_result == CURLE_AGAIN) {
+ if(octx->io_result == CURLE_AGAIN) {
return CURLE_OK;
}
else {
@@ -3974,7 +4214,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
(reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) {
result = CURLE_PEER_FAILED_VERIFICATION;
- lerr = SSL_get_verify_result(backend->handle);
+ lerr = SSL_get_verify_result(octx->ssl);
if(lerr != X509_V_OK) {
ssl_config->certverifyresult = lerr;
msnprintf(error_buffer, sizeof(error_buffer),
@@ -3997,6 +4237,21 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
}
#endif
+#ifdef USE_ECH
+ else if((lib == ERR_LIB_SSL) &&
+# ifndef OPENSSL_IS_BORINGSSL
+ (reason == SSL_R_ECH_REQUIRED)) {
+# else
+ (reason == SSL_R_ECH_REJECTED)) {
+# endif
+
+ /* trace retry_configs if we got some */
+ ossl_trace_ech_retry_configs(data, octx->ssl, reason);
+
+ result = CURLE_ECH_REQUIRED;
+ ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+ }
+#endif
else {
result = CURLE_SSL_CONNECT_ERROR;
ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
@@ -4016,7 +4271,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
Curl_strerror(sockerr, extramsg, sizeof(extramsg));
failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
- connssl->peer.hostname, connssl->port);
+ connssl->peer.hostname, connssl->peer.port);
return result;
}
@@ -4034,22 +4289,84 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
connssl->connecting_state = ssl_connect_3;
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
- SSL_get_peer_signature_type_nid(backend->handle, &psigtype_nid);
+ SSL_get_peer_signature_type_nid(octx->ssl, &psigtype_nid);
#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
- negotiated_group_name = SSL_get0_group_name(backend->handle);
+ negotiated_group_name = SSL_get0_group_name(octx->ssl);
#else
negotiated_group_name =
- OBJ_nid2sn(SSL_get_negotiated_group(backend->handle) & 0x0000FFFF);
+ OBJ_nid2sn(SSL_get_negotiated_group(octx->ssl) & 0x0000FFFF);
#endif
#endif
/* Informational message */
infof(data, "SSL connection using %s / %s / %s / %s",
- SSL_get_version(backend->handle),
- SSL_get_cipher(backend->handle),
+ SSL_get_version(octx->ssl),
+ SSL_get_cipher(octx->ssl),
negotiated_group_name? negotiated_group_name : "[blank]",
OBJ_nid2sn(psigtype_nid));
+#ifdef USE_ECH
+# ifndef OPENSSL_IS_BORINGSSL
+ if(ECH_ENABLED(data)) {
+ char *inner = NULL, *outer = NULL;
+ const char *status = NULL;
+ int rv;
+
+ rv = SSL_ech_get_status(octx->ssl, &inner, &outer);
+ switch(rv) {
+ case SSL_ECH_STATUS_SUCCESS:
+ status = "succeeded";
+ break;
+ case SSL_ECH_STATUS_GREASE_ECH:
+ status = "sent GREASE, got retry-configs";
+ break;
+ case SSL_ECH_STATUS_GREASE:
+ status = "sent GREASE";
+ break;
+ case SSL_ECH_STATUS_NOT_TRIED:
+ status = "not attempted";
+ break;
+ case SSL_ECH_STATUS_NOT_CONFIGURED:
+ status = "not configured";
+ break;
+ case SSL_ECH_STATUS_BACKEND:
+ status = "backend (unexpected)";
+ break;
+ case SSL_ECH_STATUS_FAILED:
+ status = "failed";
+ break;
+ case SSL_ECH_STATUS_BAD_CALL:
+ status = "bad call (unexpected)";
+ break;
+ case SSL_ECH_STATUS_BAD_NAME:
+ status = "bad name (unexpected)";
+ break;
+ default:
+ status = "unexpected status";
+ infof(data, "ECH: unexpected status %d",rv);
+ }
+ infof(data, "ECH: result: status is %s, inner is %s, outer is %s",
+ (status?status:"NULL"),
+ (inner?inner:"NULL"),
+ (outer?outer:"NULL"));
+ OPENSSL_free(inner);
+ OPENSSL_free(outer);
+ if(rv == SSL_ECH_STATUS_GREASE_ECH) {
+ /* trace retry_configs if we got some */
+ ossl_trace_ech_retry_configs(data, octx->ssl, 0);
+ }
+ if(rv != SSL_ECH_STATUS_SUCCESS
+ && data->set.tls_ech & CURLECH_HARD) {
+ infof(data, "ECH: ech-hard failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+ infof(data, "ECH: result: status is not attempted");
+ }
+# endif /* BORING */
+#endif /* USE_ECH */
+
#ifdef HAS_ALPN
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
* negotiated
@@ -4057,7 +4374,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
if(connssl->alpn) {
const unsigned char *neg_protocol;
unsigned int len;
- SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len);
+ SSL_get0_alpn_selected(octx->ssl, &neg_protocol, &len);
return Curl_alpn_set_negotiated(cf, data, neg_protocol, len);
}
@@ -4194,20 +4511,12 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl)
#define infof_certstack(data, ssl)
#endif
-/*
- * Get the server cert, verify it and show it, etc., only call failf() if the
- * 'strict' argument is TRUE as otherwise all this is for informational
- * purposes only!
- *
- * We check certificates to authenticate the server; otherwise we risk
- * man-in-the-middle attack.
- */
-static CURLcode servercert(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool strict)
+CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ossl_ctx *octx,
+ struct ssl_peer *peer)
{
struct connectdata *conn = cf->conn;
- struct ssl_connect_data *connssl = cf->ctx;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
CURLcode result = CURLE_OK;
@@ -4219,10 +4528,9 @@ static CURLcode servercert(struct Curl_cfilter *cf,
char buffer[2048];
const char *ptr;
BIO *mem = BIO_new(BIO_s_mem());
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ bool strict = (conn_config->verifypeer || conn_config->verifyhost);
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
if(!mem) {
failf(data,
@@ -4235,10 +4543,10 @@ static CURLcode servercert(struct Curl_cfilter *cf,
if(data->set.ssl.certinfo)
/* asked to gather certificate info */
- (void)Curl_ossl_certchain(data, backend->handle);
+ (void)Curl_ossl_certchain(data, octx->ssl);
- backend->server_cert = SSL_get1_peer_certificate(backend->handle);
- if(!backend->server_cert) {
+ octx->server_cert = SSL_get1_peer_certificate(octx->ssl);
+ if(!octx->server_cert) {
BIO_free(mem);
if(!strict)
return CURLE_OK;
@@ -4250,19 +4558,19 @@ static CURLcode servercert(struct Curl_cfilter *cf,
infof(data, "%s certificate:",
Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server");
- rc = x509_name_oneline(X509_get_subject_name(backend->server_cert),
+ rc = x509_name_oneline(X509_get_subject_name(octx->server_cert),
buffer, sizeof(buffer));
infof(data, " subject: %s", rc?"[NONE]":buffer);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
{
long len;
- ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert));
+ ASN1_TIME_print(mem, X509_get0_notBefore(octx->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
infof(data, " start date: %.*s", (int)len, ptr);
(void)BIO_reset(mem);
- ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert));
+ ASN1_TIME_print(mem, X509_get0_notAfter(octx->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
infof(data, " expire date: %.*s", (int)len, ptr);
(void)BIO_reset(mem);
@@ -4272,16 +4580,15 @@ static CURLcode servercert(struct Curl_cfilter *cf,
BIO_free(mem);
if(conn_config->verifyhost) {
- result = Curl_ossl_verifyhost(data, conn, &connssl->peer,
- backend->server_cert);
+ result = Curl_ossl_verifyhost(data, conn, peer, octx->server_cert);
if(result) {
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return result;
}
}
- rc = x509_name_oneline(X509_get_issuer_name(backend->server_cert),
+ rc = x509_name_oneline(X509_get_issuer_name(octx->server_cert),
buffer, sizeof(buffer));
if(rc) {
if(strict)
@@ -4305,8 +4612,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
" error %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)) );
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return CURLE_OUT_OF_MEMORY;
}
}
@@ -4318,8 +4625,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
" error %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)) );
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return CURLE_OUT_OF_MEMORY;
}
@@ -4328,8 +4635,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
failf(data, "SSL: Unable to open issuer cert (%s)",
conn_config->issuercert);
BIO_free(fp);
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
}
@@ -4341,19 +4648,19 @@ static CURLcode servercert(struct Curl_cfilter *cf,
conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
- if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) {
+ if(X509_check_issued(issuer, octx->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
@@ -4363,7 +4670,7 @@ static CURLcode servercert(struct Curl_cfilter *cf,
X509_free(issuer);
}
- lerr = SSL_get_verify_result(backend->handle);
+ lerr = SSL_get_verify_result(octx->ssl);
ssl_config->certverifyresult = lerr;
if(lerr != X509_V_OK) {
if(conn_config->verifypeer) {
@@ -4383,11 +4690,11 @@ static CURLcode servercert(struct Curl_cfilter *cf,
infof(data, " SSL certificate verify ok.");
}
- infof_certstack(data, backend->handle);
+ infof_certstack(data, octx->ssl);
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
- if(conn_config->verifystatus && !connssl->reused_session) {
+ if(conn_config->verifystatus && !octx->reused_session) {
/* don't do this after Session ID reuse */
result = verifystatus(cf, data);
if(result) {
@@ -4397,7 +4704,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
void *old_ssl_sessionid = NULL;
bool incache;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
+ incache = !(Curl_ssl_getsessionid(cf, data, peer,
+ &old_ssl_sessionid, NULL));
if(incache) {
infof(data, "Remove session ID again from cache");
Curl_ssl_delsessionid(data, old_ssl_sessionid);
@@ -4405,8 +4713,8 @@ static CURLcode servercert(struct Curl_cfilter *cf,
Curl_ssl_sessionid_unlock(data);
}
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return result;
}
}
@@ -4416,18 +4724,21 @@ static CURLcode servercert(struct Curl_cfilter *cf,
/* when not strict, we don't bother about the verify cert problems */
result = CURLE_OK;
+#ifndef CURL_DISABLE_PROXY
ptr = Curl_ssl_cf_is_proxy(cf)?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#else
+ ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#endif
if(!result && ptr) {
- result = ossl_pkp_pin_peer_pubkey(data, backend->server_cert, ptr);
+ result = ossl_pkp_pin_peer_pubkey(data, octx->server_cert, ptr);
if(result)
failf(data, "SSL: public key does not match pinned public key");
}
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
- connssl->connecting_state = ssl_connect_done;
+ X509_free(octx->server_cert);
+ octx->server_cert = NULL;
return result;
}
@@ -4437,7 +4748,7 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
{
CURLcode result = CURLE_OK;
struct ssl_connect_data *connssl = cf->ctx;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
@@ -4448,9 +4759,7 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
* operations.
*/
- result = servercert(cf, data, conn_config->verifypeer ||
- conn_config->verifyhost);
-
+ result = Curl_oss_check_peer_cert(cf, data, octx, &connssl->peer);
if(!result)
connssl->connecting_state = ssl_connect_done;
@@ -4590,12 +4899,11 @@ static bool ossl_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
(void)data;
- DEBUGASSERT(connssl && backend);
- if(backend->handle && SSL_pending(backend->handle))
+ DEBUGASSERT(connssl && octx);
+ if(octx->ssl && SSL_pending(octx->ssl))
return TRUE;
return FALSE;
}
@@ -4614,19 +4922,18 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
int memlen;
int rc;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
(void)data;
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
ERR_clear_error();
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- rc = SSL_write(backend->handle, mem, memlen);
+ rc = SSL_write(octx->ssl, mem, memlen);
if(rc <= 0) {
- err = SSL_get_error(backend->handle, rc);
+ err = SSL_get_error(octx->ssl, rc);
switch(err) {
case SSL_ERROR_WANT_READ:
@@ -4641,7 +4948,7 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
{
int sockerr = SOCKERRNO;
- if(backend->io_result == CURLE_AGAIN) {
+ if(octx->io_result == CURLE_AGAIN) {
*curlcode = CURLE_AGAIN;
rc = -1;
goto out;
@@ -4698,20 +5005,19 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
int buffsize;
struct connectdata *conn = cf->conn;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
(void)data;
- DEBUGASSERT(backend);
+ DEBUGASSERT(octx);
ERR_clear_error();
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- nread = (ssize_t)SSL_read(backend->handle, buf, buffsize);
+ nread = (ssize_t)SSL_read(octx->ssl, buf, buffsize);
if(nread <= 0) {
/* failed SSL_read */
- int err = SSL_get_error(backend->handle, (int)nread);
+ int err = SSL_get_error(octx->ssl, (int)nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
@@ -4733,7 +5039,7 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
/* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
value/errno" */
/* https://www.openssl.org/docs/crypto/ERR_get_error.html */
- if(backend->io_result == CURLE_AGAIN) {
+ if(octx->io_result == CURLE_AGAIN) {
*curlcode = CURLE_AGAIN;
nread = -1;
goto out;
@@ -4924,11 +5230,10 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl,
CURLINFO info)
{
/* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
- struct ossl_ssl_backend_data *backend =
- (struct ossl_ssl_backend_data *)connssl->backend;
- DEBUGASSERT(backend);
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ DEBUGASSERT(octx);
return info == CURLINFO_TLS_SESSION ?
- (void *)backend->ctx : (void *)backend->handle;
+ (void *)octx->ssl_ctx : (void *)octx->ssl;
}
static void ossl_free_multi_ssl_backend_data(
@@ -4956,9 +5261,12 @@ const struct Curl_ssl Curl_ssl_openssl = {
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
SSLSUPP_TLS13_CIPHERSUITES |
#endif
+#ifdef USE_ECH
+ SSLSUPP_ECH |
+#endif
SSLSUPP_HTTPS_PROXY,
- sizeof(struct ossl_ssl_backend_data),
+ sizeof(struct ossl_ctx),
ossl_init, /* init */
ossl_cleanup, /* cleanup */
@@ -4974,7 +5282,6 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_get_internals, /* get_internals */
ossl_close, /* close_one */
ossl_close_all, /* close_all */
- ossl_session_free, /* session_free */
ossl_set_engine, /* set_engine */
ossl_set_engine_default, /* set_engine_default */
ossl_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/openssl.h b/libs/libcurl/src/vtls/openssl.h
index df36a831b1..f46fbf3722 100644
--- a/libs/libcurl/src/vtls/openssl.h
+++ b/libs/libcurl/src/vtls/openssl.h
@@ -36,6 +36,39 @@
#include "urldata.h"
+/* Struct to hold a Curl OpenSSL instance */
+struct ossl_ctx {
+ /* these ones requires specific SSL-types */
+ SSL_CTX* ssl_ctx;
+ SSL* ssl;
+ X509* server_cert;
+ BIO_METHOD *bio_method;
+ CURLcode io_result; /* result of last BIO cfilter operation */
+#ifndef HAVE_KEYLOG_CALLBACK
+ /* Set to true once a valid keylog entry has been created to avoid dupes. */
+ BIT(keylog_done);
+#endif
+ BIT(x509_store_setup); /* x509 store has been set up */
+ BIT(reused_session); /* session-ID was reused for this */
+};
+
+typedef CURLcode Curl_ossl_ctx_setup_cb(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *user_data);
+
+typedef int Curl_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid);
+
+CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ int transport, /* TCP or QUIC */
+ const unsigned char *alpn, size_t alpn_len,
+ Curl_ossl_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ Curl_ossl_new_session_cb *cb_new_session,
+ void *ssl_user_data);
+
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
#define SSL_get1_peer_certificate SSL_get_peer_certificate
#endif
@@ -66,5 +99,23 @@ CURLcode Curl_ossl_ctx_configure(struct Curl_cfilter *cf,
struct Curl_easy *data,
SSL_CTX *ssl_ctx);
+/*
+ * Add a new session to the cache. Takes ownership of the session.
+ */
+CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct ssl_peer *peer,
+ SSL_SESSION *ssl_sessionid);
+
+/*
+ * Get the server cert, verify it and show it, etc., only call failf() if
+ * ssl config verifypeer or -host is set. Otherwise all this is for
+ * informational purposes only!
+ */
+CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ossl_ctx *octx,
+ struct ssl_peer *peer);
+
#endif /* USE_OPENSSL */
#endif /* HEADER_CURL_SSLUSE_H */
diff --git a/libs/libcurl/src/vtls/rustls.c b/libs/libcurl/src/vtls/rustls.c
index 0688df13ef..0e65c37f37 100644
--- a/libs/libcurl/src/vtls/rustls.c
+++ b/libs/libcurl/src/vtls/rustls.c
@@ -46,7 +46,8 @@ struct rustls_ssl_backend_data
{
const struct rustls_client_config *config;
struct rustls_connection *conn;
- bool data_pending;
+ size_t plain_out_buffered;
+ BIT(data_in_pending);
};
/* For a given rustls_result error code, return the best-matching CURLcode. */
@@ -61,7 +62,7 @@ static CURLcode map_error(rustls_result r)
case RUSTLS_RESULT_NULL_PARAMETER:
return CURLE_BAD_FUNCTION_ARGUMENT;
default:
- return CURLE_READ_ERROR;
+ return CURLE_RECV_ERROR;
}
}
@@ -74,7 +75,7 @@ cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
(void)data;
DEBUGASSERT(ctx && ctx->backend);
backend = (struct rustls_ssl_backend_data *)ctx->backend;
- return backend->data_pending;
+ return backend->data_in_pending;
}
struct io_ctx {
@@ -101,6 +102,8 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
else if(nread == 0)
connssl->peer_closed = TRUE;
*out_n = (int)nread;
+ CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d",
+ len, nread, result);
return ret;
}
@@ -120,10 +123,8 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
ret = EINVAL;
}
*out_n = (int)nwritten;
- /*
- CURL_TRC_CFX(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
- len, nwritten, result));
- */
+ CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
+ len, nwritten, result);
return ret;
}
@@ -150,7 +151,7 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
char buffer[STRERROR_LEN];
failf(data, "reading from socket: %s",
Curl_strerror(io_error, buffer, sizeof(buffer)));
- *err = CURLE_READ_ERROR;
+ *err = CURLE_RECV_ERROR;
return -1;
}
@@ -165,7 +166,7 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
return -1;
}
- backend->data_pending = TRUE;
+ backend->data_in_pending = TRUE;
*err = CURLE_OK;
return (ssize_t)tls_bytes_read;
}
@@ -200,7 +201,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
rconn = backend->conn;
while(plain_bytes_copied < plainlen) {
- if(!backend->data_pending) {
+ if(!backend->data_in_pending) {
if(tls_recv_more(cf, data, err) < 0) {
if(*err != CURLE_AGAIN) {
nread = -1;
@@ -215,12 +216,12 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
plainlen - plain_bytes_copied,
&n);
if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
- backend->data_pending = FALSE;
+ backend->data_in_pending = FALSE;
}
else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) {
failf(data, "rustls: peer closed TCP connection "
"without first closing TLS connection");
- *err = CURLE_READ_ERROR;
+ *err = CURLE_RECV_ERROR;
nread = -1;
goto out;
}
@@ -230,7 +231,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
size_t errorlen;
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf);
- *err = CURLE_READ_ERROR;
+ *err = CURLE_RECV_ERROR;
nread = -1;
goto out;
}
@@ -265,6 +266,42 @@ out:
return nread;
}
+static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
+ struct rustls_connection *rconn)
+{
+ struct io_ctx io_ctx;
+ rustls_io_result io_error;
+ size_t tlswritten = 0;
+ size_t tlswritten_total = 0;
+ CURLcode result = CURLE_OK;
+
+ io_ctx.cf = cf;
+ io_ctx.data = data;
+
+ while(rustls_connection_wants_write(rconn)) {
+ io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
+ &tlswritten);
+ if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
+ CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
+ tlswritten_total);
+ return CURLE_AGAIN;
+ }
+ else if(io_error) {
+ char buffer[STRERROR_LEN];
+ failf(data, "writing to socket: %s",
+ Curl_strerror(io_error, buffer, sizeof(buffer)));
+ return CURLE_SEND_ERROR;
+ }
+ if(tlswritten == 0) {
+ failf(data, "EOF in swrite");
+ return CURLE_SEND_ERROR;
+ }
+ CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
+ tlswritten_total += tlswritten;
+ }
+ return result;
+}
+
/*
* On each call:
* - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0).
@@ -283,26 +320,43 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
struct rustls_ssl_backend_data *const backend =
(struct rustls_ssl_backend_data *)connssl->backend;
struct rustls_connection *rconn = NULL;
- struct io_ctx io_ctx;
size_t plainwritten = 0;
- size_t tlswritten = 0;
- size_t tlswritten_total = 0;
rustls_result rresult;
- rustls_io_result io_error;
char errorbuf[256];
size_t errorlen;
+ const unsigned char *buf = plainbuf;
+ size_t blen = plainlen;
+ ssize_t nwritten = 0;
DEBUGASSERT(backend);
rconn = backend->conn;
+ DEBUGASSERT(rconn);
+
+ CURL_TRC_CF(data, cf, "cf_send(len=%zu)", plainlen);
+
+ /* If a previous send blocked, we already added its plain bytes
+ * to rustsls and must not do that again. Flush the TLS bytes and,
+ * if successful, deduct the previous plain bytes from the current
+ * send. */
+ if(backend->plain_out_buffered) {
+ *err = cr_flush_out(cf, data, rconn);
+ CURL_TRC_CF(data, cf, "cf_send: flushing %zu previously added bytes -> %d",
+ backend->plain_out_buffered, *err);
+ if(*err)
+ return -1;
+ if(blen > backend->plain_out_buffered) {
+ blen -= backend->plain_out_buffered;
+ buf += backend->plain_out_buffered;
+ }
+ else
+ blen = 0;
+ nwritten += (ssize_t)backend->plain_out_buffered;
+ backend->plain_out_buffered = 0;
+ }
- CURL_TRC_CF(data, cf, "cf_send: %zu plain bytes", plainlen);
-
- io_ctx.cf = cf;
- io_ctx.data = data;
-
- if(plainlen > 0) {
- rresult = rustls_connection_write(rconn, plainbuf, plainlen,
- &plainwritten);
+ if(blen > 0) {
+ CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to rustls", blen);
+ rresult = rustls_connection_write(rconn, buf, blen, &plainwritten);
if(rresult != RUSTLS_RESULT_OK) {
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
failf(data, "rustls_connection_write: %.*s", (int)errorlen, errorbuf);
@@ -316,32 +370,27 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
}
- while(rustls_connection_wants_write(rconn)) {
- io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
- &tlswritten);
- if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
- CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
- tlswritten_total);
- *err = CURLE_AGAIN;
- return -1;
- }
- else if(io_error) {
- char buffer[STRERROR_LEN];
- failf(data, "writing to socket: %s",
- Curl_strerror(io_error, buffer, sizeof(buffer)));
- *err = CURLE_WRITE_ERROR;
- return -1;
- }
- if(tlswritten == 0) {
- failf(data, "EOF in swrite");
- *err = CURLE_WRITE_ERROR;
- return -1;
+ *err = cr_flush_out(cf, data, rconn);
+ if(*err) {
+ if(CURLE_AGAIN == *err) {
+ /* The TLS bytes may have been partially written, but we fail the
+ * complete send() and remember how much we already added to rustls. */
+ CURL_TRC_CF(data, cf, "cf_send: EAGAIN, remember we added %zu plain"
+ " bytes already to rustls", blen);
+ backend->plain_out_buffered = plainwritten;
+ if(nwritten) {
+ *err = CURLE_OK;
+ return (ssize_t)nwritten;
+ }
}
- CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
- tlswritten_total += tlswritten;
+ return -1;
}
+ else
+ nwritten += (ssize_t)plainwritten;
- return plainwritten;
+ CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zd",
+ plainlen, *err, nwritten);
+ return nwritten;
}
/* A server certificate verify callback for rustls that always returns
@@ -357,12 +406,12 @@ static bool
cr_hostname_is_ip(const char *hostname)
{
struct in_addr in;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct in6_addr in6;
if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
return true;
}
-#endif /* ENABLE_IPV6 */
+#endif /* USE_IPV6 */
if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
return true;
}
@@ -479,18 +528,14 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
backend->config = rustls_client_config_builder_build(config_builder);
DEBUGASSERT(rconn == NULL);
- {
- /* rustls claims to manage ip address hostnames as well here. So,
- * if we have an SNI, we use it, otherwise we pass the hostname */
- char *server = connssl->peer.sni?
- connssl->peer.sni : connssl->peer.hostname;
- result = rustls_client_connection_new(backend->config, server, &rconn);
- }
+ result = rustls_client_connection_new(backend->config,
+ connssl->peer.hostname, &rconn);
if(result != RUSTLS_RESULT_OK) {
rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
failf(data, "rustls_client_connection_new: %.*s", (int)errorlen, errorbuf);
return CURLE_COULDNT_CONNECT;
}
+ DEBUGASSERT(rconn);
rustls_connection_set_userdata(rconn, backend);
backend->conn = rconn;
return CURLE_OK;
@@ -539,9 +584,12 @@ cr_connect_common(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
- if(ssl_connection_none == connssl->state) {
+ CURL_TRC_CF(data, cf, "cr_connect_common, state=%d", connssl->state);
+ *done = FALSE;
+ if(!backend->conn) {
result = cr_init_backend(cf, data,
(struct rustls_ssl_backend_data *)connssl->backend);
+ CURL_TRC_CF(data, cf, "cr_connect_common, init backend -> %d", result);
if(result != CURLE_OK) {
return result;
}
@@ -558,21 +606,34 @@ cr_connect_common(struct Curl_cfilter *cf,
*/
if(!rustls_connection_is_handshaking(rconn)) {
infof(data, "Done handshaking");
- /* Done with the handshake. Set up callbacks to send/receive data. */
- connssl->state = ssl_connection_complete;
-
+ /* rustls claims it is no longer handshaking *before* it has
+ * send its FINISHED message off. We attempt to let it write
+ * one more time. Oh my.
+ */
cr_set_negotiated_alpn(cf, data, rconn);
-
+ cr_send(cf, data, NULL, 0, &tmperr);
+ if(tmperr == CURLE_AGAIN) {
+ connssl->connecting_state = ssl_connect_2_writing;
+ return CURLE_OK;
+ }
+ else if(tmperr != CURLE_OK) {
+ return tmperr;
+ }
+ /* REALLY Done with the handshake. */
+ connssl->state = ssl_connection_complete;
*done = TRUE;
return CURLE_OK;
}
wants_read = rustls_connection_wants_read(rconn);
- wants_write = rustls_connection_wants_write(rconn);
+ wants_write = rustls_connection_wants_write(rconn) ||
+ backend->plain_out_buffered;
DEBUGASSERT(wants_read || wants_write);
writefd = wants_write?sockfd:CURL_SOCKET_BAD;
readfd = wants_read?sockfd:CURL_SOCKET_BAD;
+ connssl->connecting_state = wants_write?
+ ssl_connect_2_writing : ssl_connect_2_reading;
/* check allowed time left */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -584,8 +645,8 @@ cr_connect_common(struct Curl_cfilter *cf,
socket_check_timeout = blocking?timeout_ms:0;
- what = Curl_socket_check(
- readfd, CURL_SOCKET_BAD, writefd, socket_check_timeout);
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ socket_check_timeout);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -597,19 +658,18 @@ cr_connect_common(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
if(0 == what) {
- infof(data, "Curl_socket_check: %s would block",
+ CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block",
wants_read&&wants_write ? "writing and reading" :
wants_write ? "writing" : "reading");
- *done = FALSE;
return CURLE_OK;
}
/* socket is readable or writable */
if(wants_write) {
- infof(data, "rustls_connection wants us to write_tls.");
+ CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls.");
cr_send(cf, data, NULL, 0, &tmperr);
if(tmperr == CURLE_AGAIN) {
- infof(data, "writing would block");
+ CURL_TRC_CF(data, cf, "writing would block");
/* fall through */
}
else if(tmperr != CURLE_OK) {
@@ -618,14 +678,13 @@ cr_connect_common(struct Curl_cfilter *cf,
}
if(wants_read) {
- infof(data, "rustls_connection wants us to read_tls.");
-
+ CURL_TRC_CF(data, cf, "rustls_connection wants us to read_tls.");
if(tls_recv_more(cf, data, &tmperr) < 0) {
if(tmperr == CURLE_AGAIN) {
- infof(data, "reading would block");
+ CURL_TRC_CF(data, cf, "reading would block");
/* fall through */
}
- else if(tmperr == CURLE_READ_ERROR) {
+ else if(tmperr == CURLE_RECV_ERROR) {
return CURLE_SSL_CONNECT_ERROR;
}
else {
@@ -648,37 +707,12 @@ cr_connect_nonblocking(struct Curl_cfilter *cf,
}
static CURLcode
-cr_connect_blocking(struct Curl_cfilter *cf UNUSED_PARAM,
- struct Curl_easy *data UNUSED_PARAM)
+cr_connect_blocking(struct Curl_cfilter *cf, struct Curl_easy *data)
{
bool done; /* unused */
return cr_connect_common(cf, data, true, &done);
}
-static void cr_adjust_pollset(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct easy_pollset *ps)
-{
- if(!cf->connected) {
- curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
- struct ssl_connect_data *const connssl = cf->ctx;
- struct rustls_ssl_backend_data *const backend =
- (struct rustls_ssl_backend_data *)connssl->backend;
- struct rustls_connection *rconn = NULL;
-
- (void)data;
- DEBUGASSERT(backend);
- rconn = backend->conn;
-
- if(rustls_connection_wants_write(rconn)) {
- Curl_pollset_add_out(data, ps, sock);
- }
- if(rustls_connection_wants_read(rconn)) {
- Curl_pollset_add_in(data, ps, sock);
- }
- }
-}
-
static void *
cr_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
@@ -699,8 +733,8 @@ cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
ssize_t n = 0;
DEBUGASSERT(backend);
-
if(backend->conn && !connssl->peer_closed) {
+ CURL_TRC_CF(data, cf, "closing connection, send notify");
rustls_connection_send_close_notify(backend->conn);
n = cr_send(cf, data, NULL, 0, &tmperr);
if(n < 0) {
@@ -725,7 +759,6 @@ static size_t cr_version(char *buffer, size_t size)
const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_CAINFO_BLOB | /* supports */
- SSLSUPP_TLS13_CIPHERSUITES |
SSLSUPP_HTTPS_PROXY,
sizeof(struct rustls_ssl_backend_data),
@@ -739,11 +772,10 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_cert_status_request, /* cert_status_request */
cr_connect_blocking, /* connect */
cr_connect_nonblocking, /* connect_nonblocking */
- cr_adjust_pollset, /* adjust_pollset */
+ Curl_ssl_adjust_pollset, /* adjust_pollset */
cr_get_internals, /* get_internals */
cr_close, /* close_one */
Curl_none_close_all, /* close_all */
- Curl_none_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c
index d63d321bf3..d172b567c4 100644
--- a/libs/libcurl/src/vtls/schannel.c
+++ b/libs/libcurl/src/vtls/schannel.c
@@ -1071,7 +1071,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 1/3)",
- connssl->peer.hostname, connssl->port));
+ connssl->peer.hostname, connssl->peer.port));
if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
@@ -1129,7 +1129,8 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* check for an existing reusable credential handle */
if(ssl_config->primary.sessionid) {
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ (void **)&old_cred, NULL)) {
backend->cred = old_cred;
DEBUGF(infof(data, "schannel: reusing existing credential handle"));
@@ -1335,7 +1336,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 2/3)",
- connssl->peer.hostname, connssl->port));
+ connssl->peer.hostname, connssl->peer.port));
if(!backend->cred || !backend->ctxt)
return CURLE_SSL_CONNECT_ERROR;
@@ -1569,9 +1570,13 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
}
+#ifndef CURL_DISABLE_PROXY
pubkey_ptr = Curl_ssl_cf_is_proxy(cf)?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#else
+ pubkey_ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#endif
if(pubkey_ptr) {
result = schannel_pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
if(result) {
@@ -1670,6 +1675,28 @@ add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, bool reverse_order,
return args->result == CURLE_OK;
}
+static void schannel_session_free(void *sessionid, size_t idsize)
+{
+ /* this is expected to be called under sessionid lock */
+ struct Curl_schannel_cred *cred = sessionid;
+
+ (void)idsize;
+ if(cred) {
+ cred->refcount--;
+ if(cred->refcount == 0) {
+ s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+ curlx_unicodefree(cred->sni_hostname);
+#ifdef HAS_CLIENT_CERT_PATH
+ if(cred->client_cert_store) {
+ CertCloseStore(cred->client_cert_store, 0);
+ cred->client_cert_store = NULL;
+ }
+#endif
+ Curl_safefree(cred);
+ }
+ }
+}
+
static CURLcode
schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -1689,7 +1716,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 3/3)",
- connssl->peer.hostname, connssl->port));
+ connssl->peer.hostname, connssl->peer.port));
if(!backend->cred)
return CURLE_SSL_CONNECT_ERROR;
@@ -1747,11 +1774,11 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
/* save the current session data for possible reuse */
if(ssl_config->primary.sessionid) {
bool incache;
- bool added = FALSE;
struct Curl_schannel_cred *old_cred = NULL;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL));
+ incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ (void **)&old_cred, NULL));
if(incache) {
if(old_cred != backend->cred) {
DEBUGF(infof(data,
@@ -1762,20 +1789,15 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
if(!incache) {
- result = Curl_ssl_addsessionid(cf, data, backend->cred,
+ /* Up ref count since call takes ownership */
+ backend->cred->refcount++;
+ result = Curl_ssl_addsessionid(cf, data, &connssl->peer, backend->cred,
sizeof(struct Curl_schannel_cred),
- &added);
+ schannel_session_free);
if(result) {
Curl_ssl_sessionid_unlock(data);
- failf(data, "schannel: failed to store credential handle");
return result;
}
- else if(added) {
- /* this cred session is now also referenced by sessionid cache */
- backend->cred->refcount++;
- DEBUGF(infof(data,
- "schannel: stored credential handle in session cache"));
- }
}
Curl_ssl_sessionid_unlock(data);
}
@@ -2450,27 +2472,6 @@ static bool schannel_data_pending(struct Curl_cfilter *cf,
return FALSE;
}
-static void schannel_session_free(void *ptr)
-{
- /* this is expected to be called under sessionid lock */
- struct Curl_schannel_cred *cred = ptr;
-
- if(cred) {
- cred->refcount--;
- if(cred->refcount == 0) {
- s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
- curlx_unicodefree(cred->sni_hostname);
-#ifdef HAS_CLIENT_CERT_PATH
- if(cred->client_cert_store) {
- CertCloseStore(cred->client_cert_store, 0);
- cred->client_cert_store = NULL;
- }
-#endif
- Curl_safefree(cred);
- }
- }
-}
-
/* shut down the SSL connection and clean up related memory.
this function can be called multiple times on the same connection including
if the SSL connection failed (eg connection made but failed handshake). */
@@ -2489,7 +2490,7 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
if(backend->ctxt) {
infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
- connssl->peer.hostname, connssl->port);
+ connssl->peer.hostname, connssl->peer.port);
}
if(backend->cred && backend->ctxt) {
@@ -2554,7 +2555,7 @@ static int schannel_shutdown(struct Curl_cfilter *cf,
/* free SSPI Schannel API credential handle */
if(backend->cred) {
Curl_ssl_sessionid_lock(data);
- schannel_session_free(backend->cred);
+ schannel_session_free(backend->cred, 0);
Curl_ssl_sessionid_unlock(data);
backend->cred = NULL;
}
@@ -2749,7 +2750,7 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct Curl_multi *multi = data->multi;
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
struct schannel_multi_ssl_backend_data *mbackend;
const struct ssl_general_config *cfg = &data->set.general_ssl;
@@ -2818,7 +2819,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
HCERTSTORE cert_store)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct Curl_multi *multi = data->multi;
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
struct schannel_multi_ssl_backend_data *mbackend;
unsigned char *CAinfo_blob_digest = NULL;
@@ -2917,7 +2918,6 @@ const struct Curl_ssl Curl_ssl_schannel = {
schannel_get_internals, /* get_internals */
schannel_close, /* close_one */
Curl_none_close_all, /* close_all */
- schannel_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/schannel_int.h b/libs/libcurl/src/vtls/schannel_int.h
index c460be63aa..92fbc073b0 100644
--- a/libs/libcurl/src/vtls/schannel_int.h
+++ b/libs/libcurl/src/vtls/schannel_int.h
@@ -53,6 +53,16 @@
#define CERT_ALT_NAME_IP_ADDRESS 8
#endif
+#if defined(_MSC_VER) && (_MSC_VER <= 1600)
+/* Workaround for warning:
+ 'type cast' : conversion from 'int' to 'LPCSTR' of greater size */
+#undef CERT_STORE_PROV_MEMORY
+#undef CERT_STORE_PROV_SYSTEM_A
+#undef CERT_STORE_PROV_SYSTEM_W
+#define CERT_STORE_PROV_MEMORY ((LPCSTR)(size_t)2)
+#define CERT_STORE_PROV_SYSTEM_A ((LPCSTR)(size_t)9)
+#define CERT_STORE_PROV_SYSTEM_W ((LPCSTR)(size_t)10)
+#endif
#ifndef SCH_CREDENTIALS_VERSION
diff --git a/libs/libcurl/src/vtls/sectransp.c b/libs/libcurl/src/vtls/sectransp.c
index f62c034e55..6482fb9168 100644
--- a/libs/libcurl/src/vtls/sectransp.c
+++ b/libs/libcurl/src/vtls/sectransp.c
@@ -1453,7 +1453,7 @@ static bool is_cipher_suite_strong(SSLCipherSuite suite_num)
return true;
}
-static bool is_separator(char c)
+static bool sectransp_is_separator(char c)
{
/* Return whether character is a cipher list separator. */
switch(c) {
@@ -1547,7 +1547,7 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
if(!ciphers)
return CURLE_OK;
- while(is_separator(*ciphers)) /* Skip initial separators. */
+ while(sectransp_is_separator(*ciphers)) /* Skip initial separators. */
ciphers++;
if(!*ciphers)
return CURLE_OK;
@@ -1561,14 +1561,14 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
size_t i;
/* Skip separators */
- while(is_separator(*cipher_start))
+ while(sectransp_is_separator(*cipher_start))
cipher_start++;
if(*cipher_start == '\0') {
break;
}
/* Find last position of a cipher in the ciphers string */
cipher_end = cipher_start;
- while(*cipher_end != '\0' && !is_separator(*cipher_end)) {
+ while(*cipher_end != '\0' && !sectransp_is_separator(*cipher_end)) {
++cipher_end;
}
@@ -1636,6 +1636,18 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
return CURLE_OK;
}
+static void sectransp_session_free(void *sessionid, size_t idsize)
+{
+ /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
+ cached session ID inside the Security framework. There is a private
+ function that does this, but I don't want to have to explain to you why I
+ got your application rejected from the App Store due to the use of a
+ private API, so the best we can do is free up our own char array that we
+ created way back in sectransp_connect_step1... */
+ (void)idsize;
+ Curl_safefree(sessionid);
+}
+
static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -2047,8 +2059,8 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
size_t ssl_sessionid_len;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, (void **)&ssl_sessionid,
- &ssl_sessionid_len)) {
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ (void **)&ssl_sessionid, &ssl_sessionid_len)) {
/* we got a session id, use it! */
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
Curl_ssl_sessionid_unlock(data);
@@ -2067,7 +2079,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
aprintf("%s:%d:%d:%s:%d",
ssl_cafile ? ssl_cafile : "(blob memory)",
verifypeer, conn_config->verifyhost, connssl->peer.hostname,
- connssl->port);
+ connssl->peer.port);
ssl_sessionid_len = strlen(ssl_sessionid);
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
@@ -2077,13 +2089,12 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
- result = Curl_ssl_addsessionid(cf, data, ssl_sessionid,
- ssl_sessionid_len, NULL);
+ result = Curl_ssl_addsessionid(cf, data, &connssl->peer, ssl_sessionid,
+ ssl_sessionid_len,
+ sectransp_session_free);
Curl_ssl_sessionid_unlock(data);
- if(result) {
- failf(data, "failed to store ssl session");
+ if(result)
return result;
- }
}
}
@@ -3225,17 +3236,6 @@ static int sectransp_shutdown(struct Curl_cfilter *cf,
return rc;
}
-static void sectransp_session_free(void *ptr)
-{
- /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
- cached session ID inside the Security framework. There is a private
- function that does this, but I don't want to have to explain to you why I
- got your application rejected from the App Store due to the use of a
- private API, so the best we can do is free up our own char array that we
- created way back in sectransp_connect_step1... */
- Curl_safefree(ptr);
-}
-
static size_t sectransp_version(char *buffer, size_t size)
{
return msnprintf(buffer, size, "SecureTransport");
@@ -3469,7 +3469,6 @@ const struct Curl_ssl Curl_ssl_sectransp = {
sectransp_get_internals, /* get_internals */
sectransp_close, /* close_one */
Curl_none_close_all, /* close_all */
- sectransp_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/vtls.c b/libs/libcurl/src/vtls/vtls.c
index e4fcb0dd83..f4633a5f1c 100644
--- a/libs/libcurl/src/vtls/vtls.c
+++ b/libs/libcurl/src/vtls/vtls.c
@@ -534,10 +534,10 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
*/
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ const struct ssl_peer *peer,
void **ssl_sessionid,
size_t *idsize) /* set 0 if unknown */
{
- struct ssl_connect_data *connssl = cf->ctx;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct Curl_ssl_session *check;
@@ -567,14 +567,15 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
if(!check->sessionid)
/* not session ID means blank entry */
continue;
- if(strcasecompare(connssl->peer.hostname, check->name) &&
+ if(strcasecompare(peer->hostname, check->name) &&
((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
(cf->conn->bits.conn_to_host && check->conn_to_host &&
strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) ||
(cf->conn->bits.conn_to_port && check->conn_to_port != -1 &&
cf->conn->conn_to_port == check->conn_to_port)) &&
- (connssl->port == check->remote_port) &&
+ (peer->port == check->remote_port) &&
+ (peer->transport == check->transport) &&
strcasecompare(cf->conn->handler->scheme, check->scheme) &&
match_ssl_primary_config(data, conn_config, &check->ssl_config)) {
/* yes, we have a session ID! */
@@ -591,8 +592,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
no_match? "Didn't find": "Found",
Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
- cf->conn->handler->scheme, connssl->peer.hostname,
- connssl->port));
+ cf->conn->handler->scheme, peer->hostname, peer->port));
return no_match;
}
@@ -605,9 +605,10 @@ void Curl_ssl_kill_session(struct Curl_ssl_session *session)
/* defensive check */
/* free the ID the SSL-layer specific way */
- Curl_ssl->session_free(session->sessionid);
+ session->sessionid_free(session->sessionid, session->idsize);
session->sessionid = NULL;
+ session->sessionid_free = NULL;
session->age = 0; /* fresh */
Curl_free_primary_ssl_config(&session->ssl_config);
@@ -642,45 +643,44 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
*/
CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ const struct ssl_peer *peer,
void *ssl_sessionid,
size_t idsize,
- bool *added)
+ Curl_ssl_sessionid_dtor *sessionid_free_cb)
{
- struct ssl_connect_data *connssl = cf->ctx;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
size_t i;
struct Curl_ssl_session *store;
long oldest_age;
- char *clone_host;
- char *clone_conn_to_host;
+ char *clone_host = NULL;
+ char *clone_conn_to_host = NULL;
int conn_to_port;
long *general_age;
+ CURLcode result = CURLE_OUT_OF_MEMORY;
- if(added)
- *added = FALSE;
+ DEBUGASSERT(ssl_sessionid);
+ DEBUGASSERT(sessionid_free_cb);
- if(!data->state.session)
+ if(!data->state.session) {
+ sessionid_free_cb(ssl_sessionid, idsize);
return CURLE_OK;
+ }
store = &data->state.session[0];
oldest_age = data->state.session[0].age; /* zero if unused */
- (void)ssl_config;
DEBUGASSERT(ssl_config->primary.sessionid);
+ (void)ssl_config;
- clone_host = strdup(connssl->peer.hostname);
+ clone_host = strdup(peer->hostname);
if(!clone_host)
- return CURLE_OUT_OF_MEMORY; /* bail out */
+ goto out;
if(cf->conn->bits.conn_to_host) {
clone_conn_to_host = strdup(cf->conn->conn_to_host.name);
- if(!clone_conn_to_host) {
- free(clone_host);
- return CURLE_OUT_OF_MEMORY; /* bail out */
- }
+ if(!clone_conn_to_host)
+ goto out;
}
- else
- clone_conn_to_host = NULL;
if(cf->conn->bits.conn_to_port)
conn_to_port = cf->conn->conn_to_port;
@@ -713,33 +713,43 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
store = &data->state.session[i]; /* use this slot */
/* now init the session struct wisely */
+ if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
+ Curl_free_primary_ssl_config(&store->ssl_config);
+ store->sessionid = NULL; /* let caller free sessionid */
+ goto out;
+ }
store->sessionid = ssl_sessionid;
store->idsize = idsize;
+ store->sessionid_free = sessionid_free_cb;
store->age = *general_age; /* set current age */
/* free it if there's one already present */
free(store->name);
free(store->conn_to_host);
store->name = clone_host; /* clone host name */
+ clone_host = NULL;
store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
+ clone_conn_to_host = NULL;
store->conn_to_port = conn_to_port; /* connect to port number */
/* port number */
- store->remote_port = connssl->port;
+ store->remote_port = peer->port;
store->scheme = cf->conn->handler->scheme;
+ store->transport = peer->transport;
- if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
- Curl_free_primary_ssl_config(&store->ssl_config);
- store->sessionid = NULL; /* let caller free sessionid */
- free(clone_host);
- free(clone_conn_to_host);
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(added)
- *added = TRUE;
+ result = CURLE_OK;
- DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
- store->scheme, store->name, store->remote_port,
- Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"));
+out:
+ free(clone_host);
+ free(clone_conn_to_host);
+ if(result) {
+ failf(data, "Failed to add Session ID to cache for %s://%s:%d [%s]",
+ store->scheme, store->name, store->remote_port,
+ Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server");
+ sessionid_free_cb(ssl_sessionid, idsize);
+ return result;
+ }
+ CURL_TRC_CF(data, cf, "Added Session ID to cache for %s://%s:%d [%s]",
+ store->scheme, store->name, store->remote_port,
+ Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server");
return CURLE_OK;
}
@@ -1322,7 +1332,6 @@ static const struct Curl_ssl Curl_ssl_multi = {
multissl_get_internals, /* get_internals */
multissl_close, /* close_one */
Curl_none_close_all, /* close_all */
- Curl_none_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
@@ -1533,14 +1542,14 @@ static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
static ssl_peer_type get_peer_type(const char *hostname)
{
if(hostname && hostname[0]) {
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
struct in6_addr addr;
#else
struct in_addr addr;
#endif
if(Curl_inet_pton(AF_INET, hostname, &addr))
return CURL_SSL_PEER_IPV4;
-#ifdef ENABLE_IPV6
+#ifdef USE_IPV6
else if(Curl_inet_pton(AF_INET6, hostname, &addr)) {
return CURL_SSL_PEER_IPV6;
}
@@ -1549,9 +1558,9 @@ static ssl_peer_type get_peer_type(const char *hostname)
return CURL_SSL_PEER_DNS;
}
-CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
+CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf,
+ int transport)
{
- struct ssl_connect_data *connssl = cf->ctx;
const char *ehostname, *edispname;
int eport;
@@ -1594,7 +1603,6 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
}
}
- peer->sni = NULL;
peer->type = get_peer_type(peer->hostname);
if(peer->type == CURL_SSL_PEER_DNS && peer->hostname[0]) {
/* not an IP address, normalize according to RCC 6066 ch. 3,
@@ -1614,7 +1622,8 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
}
}
- connssl->port = eport;
+ peer->port = eport;
+ peer->transport = transport;
return CURLE_OK;
}
@@ -1667,7 +1676,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
goto out;
*done = FALSE;
- result = Curl_ssl_peer_init(&connssl->peer, cf);
+ result = Curl_ssl_peer_init(&connssl->peer, cf, TRNSPRT_TCP);
if(result)
goto out;
@@ -1857,7 +1866,7 @@ struct Curl_cftype Curl_cft_ssl = {
struct Curl_cftype Curl_cft_ssl_proxy = {
"SSL-PROXY",
- CF_TYPE_SSL,
+ CF_TYPE_SSL|CF_TYPE_PROXY,
CURL_LOG_LVL_NONE,
ssl_cf_destroy,
ssl_cf_connect,
@@ -2033,12 +2042,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
{
-#ifndef CURL_DISABLE_PROXY
- return (cf->cft == &Curl_cft_ssl_proxy);
-#else
- (void)cf;
- return FALSE;
-#endif
+ return (cf->cft->flags & CF_TYPE_SSL) && (cf->cft->flags & CF_TYPE_PROXY);
}
struct ssl_config_data *
diff --git a/libs/libcurl/src/vtls/vtls.h b/libs/libcurl/src/vtls/vtls.h
index 0bfefd0502..4eedc707e4 100644
--- a/libs/libcurl/src/vtls/vtls.h
+++ b/libs/libcurl/src/vtls/vtls.h
@@ -37,6 +37,7 @@ struct Curl_ssl_session;
#define SSLSUPP_HTTPS_PROXY (1<<4) /* supports access via HTTPS proxies */
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
#define SSLSUPP_CAINFO_BLOB (1<<6)
+#define SSLSUPP_ECH (1<<7)
#define ALPN_ACCEPTED "ALPN: server accepted "
@@ -107,7 +108,8 @@ void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy);
/**
* Init SSL peer information for filter. Can be called repeatedly.
*/
-CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf);
+CURLcode Curl_ssl_peer_init(struct ssl_peer *peer,
+ struct Curl_cfilter *cf, int transport);
/**
* Free all allocated data and reset peer information.
*/
diff --git a/libs/libcurl/src/vtls/vtls_int.h b/libs/libcurl/src/vtls/vtls_int.h
index 563a5d11a9..d9f73f720d 100644
--- a/libs/libcurl/src/vtls/vtls_int.h
+++ b/libs/libcurl/src/vtls/vtls_int.h
@@ -73,9 +73,7 @@ struct ssl_connect_data {
void *backend; /* vtls backend specific props */
struct cf_call_data call_data; /* data handle used in current call */
struct curltime handshake_done; /* time when handshake finished */
- int port; /* remote port at origin */
BIT(use_alpn); /* if ALPN shall be used in handshake */
- BIT(reused_session); /* session-ID was reused for this */
BIT(peer_closed); /* peer has closed connection */
};
@@ -125,7 +123,6 @@ struct Curl_ssl {
void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data);
void (*close_all)(struct Curl_easy *data);
- void (*session_free)(void *ptr);
CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
CURLcode (*set_engine_default)(struct Curl_easy *data);
@@ -181,18 +178,22 @@ bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf);
*/
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ const struct ssl_peer *peer,
void **ssl_sessionid,
size_t *idsize); /* set 0 if unknown */
/* add a new session ID
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
* Caller must ensure that it has properly shared ownership of this sessionid
* object with cache (e.g. incrementing refcount on success)
+ * Call takes ownership of `ssl_sessionid`, using `sessionid_free_cb`
+ * to destroy it in case of failure or later removal.
*/
CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ const struct ssl_peer *peer,
void *ssl_sessionid,
size_t idsize,
- bool *added);
+ Curl_ssl_sessionid_dtor *sessionid_free_cb);
#include "openssl.h" /* OpenSSL versions */
#include "gtls.h" /* GnuTLS versions */
diff --git a/libs/libcurl/src/vtls/wolfssl.c b/libs/libcurl/src/vtls/wolfssl.c
index fe845c5752..53e7f0e895 100644
--- a/libs/libcurl/src/vtls/wolfssl.c
+++ b/libs/libcurl/src/vtls/wolfssl.c
@@ -74,6 +74,14 @@
#include "curl_memory.h"
#include "memdebug.h"
+#ifdef USE_ECH
+# include "curl_base64.h"
+# define ECH_ENABLED(__data__) \
+ (__data__->set.tls_ech && \
+ !(__data__->set.tls_ech & CURLECH_DISABLE)\
+ )
+#endif /* USE_ECH */
+
/* KEEP_PEER_CERT is a product of the presence of build time symbol
OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
in wolfSSL's settings.h, and the latter two are build time symbols in
@@ -409,11 +417,11 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS)
req_method = TLSv1_client_method();
use_sni(TRUE);
+ break;
#else
failf(data, "wolfSSL does not support TLS 1.0");
return CURLE_NOT_BUILT_IN;
#endif
- break;
case CURL_SSLVERSION_TLSv1_1:
#ifndef NO_OLD_TLS
req_method = TLSv1_1_client_method();
@@ -481,6 +489,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
#endif
+ FALLTHROUGH();
default:
break;
}
@@ -711,7 +720,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_delsessionid(data, ssl_sessionid);
@@ -723,6 +733,82 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
Curl_ssl_sessionid_unlock(data);
}
+#ifdef USE_ECH
+ if(ECH_ENABLED(data)) {
+ int trying_ech_now = 0;
+
+ if(data->set.str[STRING_ECH_PUBLIC]) {
+ infof(data, "ECH: outername not (yet) supported with WolfSSL");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ if(data->set.tls_ech == CURLECH_GREASE) {
+ infof(data, "ECH: GREASE'd ECH not yet supported for wolfSSL");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ if(data->set.tls_ech & CURLECH_CLA_CFG
+ && data->set.str[STRING_ECH_CONFIG]) {
+ char *b64val = data->set.str[STRING_ECH_CONFIG];
+ word32 b64len = 0;
+
+ b64len = (word32) strlen(b64val);
+ if(b64len
+ && wolfSSL_SetEchConfigsBase64(backend->handle, b64val, b64len)
+ != WOLFSSL_SUCCESS) {
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ trying_ech_now = 1;
+ infof(data, "ECH: ECHConfig from command line");
+ }
+ }
+ else {
+ struct Curl_dns_entry *dns = NULL;
+
+ dns = Curl_fetch_addr(data, connssl->peer.hostname, connssl->peer.port);
+ if(!dns) {
+ infof(data, "ECH: requested but no DNS info available");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ struct Curl_https_rrinfo *rinfo = NULL;
+
+ rinfo = dns->hinfo;
+ if(rinfo && rinfo->echconfiglist) {
+ unsigned char *ecl = rinfo->echconfiglist;
+ size_t elen = rinfo->echconfiglist_len;
+
+ infof(data, "ECH: ECHConfig from DoH HTTPS RR");
+ if(wolfSSL_SetEchConfigs(backend->handle, ecl, (word32) elen) !=
+ WOLFSSL_SUCCESS) {
+ infof(data, "ECH: wolfSSL_SetEchConfigs failed");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ trying_ech_now = 1;
+ infof(data, "ECH: imported ECHConfigList of length %ld", elen);
+ }
+ }
+ else {
+ infof(data, "ECH: requested but no ECHConfig available");
+ if(data->set.tls_ech & CURLECH_HARD)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ Curl_resolv_unlock(data, dns);
+ }
+ }
+
+ if(trying_ech_now
+ && SSL_set_min_proto_version(backend->handle, TLS1_3_VERSION) != 1) {
+ infof(data, "ECH: Can't force TLSv1.3 [ERROR]");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ }
+#endif /* USE_ECH */
+
#ifdef USE_BIO_CHAIN
{
WOLFSSL_BIO *bio;
@@ -756,9 +842,13 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
struct wolfssl_ssl_backend_data *backend =
(struct wolfssl_ssl_backend_data *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+#ifndef CURL_DISABLE_PROXY
const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#else
+ const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+#endif
DEBUGASSERT(backend);
@@ -853,6 +943,31 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
#endif
+#ifdef USE_ECH
+ else if(-1 == detail) {
+ /* try access a retry_config ECHConfigList for tracing */
+ byte echConfigs[1000];
+ word32 echConfigsLen = 1000;
+ int rv = 0;
+
+ /* this currently doesn't produce the retry_configs */
+ rv = wolfSSL_GetEchConfigs(backend->handle, echConfigs,
+ &echConfigsLen);
+ if(rv != WOLFSSL_SUCCESS) {
+ infof(data, "Failed to get ECHConfigs");
+ }
+ else {
+ char *b64str = NULL;
+ size_t blen = 0;
+
+ rv = Curl_base64_encode((const char *)echConfigs, echConfigsLen,
+ &b64str, &blen);
+ if(!rv && b64str)
+ infof(data, "ECH: (not yet) retry_configs %s", b64str);
+ free(b64str);
+ }
+ }
+#endif
else if(backend->io_result == CURLE_AGAIN) {
return CURLE_OK;
}
@@ -898,6 +1013,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
pinnedpubkey,
(const unsigned char *)pubkey->header,
(size_t)(pubkey->end - pubkey->header));
+ wolfSSL_FreeX509(x509);
if(result) {
failf(data, "SSL: public key does not match pinned public key");
return result;
@@ -942,6 +1058,13 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
}
+static void wolfssl_session_free(void *sessionid, size_t idsize)
+{
+ (void)idsize;
+ wolfSSL_SESSION_free(sessionid);
+}
+
+
static CURLcode
wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -955,40 +1078,27 @@ wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
if(ssl_config->primary.sessionid) {
- bool incache;
- bool added = FALSE;
- void *old_ssl_sessionid = NULL;
/* wolfSSL_get1_session allocates memory that has to be freed. */
WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle);
if(our_ssl_sessionid) {
+ void *old_ssl_sessionid = NULL;
+ bool incache;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
+ incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
+ &old_ssl_sessionid, NULL));
if(incache) {
- if(old_ssl_sessionid != our_ssl_sessionid) {
- infof(data, "old SSL session ID is stale, removing");
- Curl_ssl_delsessionid(data, old_ssl_sessionid);
- incache = FALSE;
- }
+ Curl_ssl_delsessionid(data, old_ssl_sessionid);
}
- if(!incache) {
- result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL);
- if(result) {
- Curl_ssl_sessionid_unlock(data);
- wolfSSL_SESSION_free(our_ssl_sessionid);
- failf(data, "failed to store ssl session");
- return result;
- }
- else {
- added = TRUE;
- }
- }
+ /* call takes ownership of `our_ssl_sessionid` */
+ result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
+ our_ssl_sessionid, 0,
+ wolfssl_session_free);
Curl_ssl_sessionid_unlock(data);
-
- if(!added) {
- /* If the session info wasn't added to the cache, free our copy. */
- wolfSSL_SESSION_free(our_ssl_sessionid);
+ if(result) {
+ failf(data, "failed to store ssl session");
+ return result;
}
}
}
@@ -1122,12 +1232,6 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
}
-static void wolfssl_session_free(void *ptr)
-{
- wolfSSL_SESSION_free(ptr);
-}
-
-
static size_t wolfssl_version(char *buffer, size_t size)
{
#if LIBWOLFSSL_VERSION_HEX >= 0x03006000
@@ -1386,6 +1490,9 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
#endif
SSLSUPP_CA_PATH |
SSLSUPP_CAINFO_BLOB |
+#ifdef USE_ECH
+ SSLSUPP_ECH |
+#endif
SSLSUPP_SSL_CTX,
sizeof(struct wolfssl_ssl_backend_data),
@@ -1404,7 +1511,6 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
wolfssl_get_internals, /* get_internals */
wolfssl_close, /* close_one */
Curl_none_close_all, /* close_all */
- wolfssl_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
diff --git a/libs/libcurl/src/vtls/x509asn1.c b/libs/libcurl/src/vtls/x509asn1.c
index 50a5fb5e9f..0887b34049 100644
--- a/libs/libcurl/src/vtls/x509asn1.c
+++ b/libs/libcurl/src/vtls/x509asn1.c
@@ -160,6 +160,7 @@ static const struct Curl_OID OIDtable[] = {
{ "2.16.840.1.101.3.4.2.1", "sha256" },
{ "2.16.840.1.101.3.4.2.2", "sha384" },
{ "2.16.840.1.101.3.4.2.3", "sha512" },
+ { "1.2.840.113549.1.9.2", "unstructuredName" },
{ (const char *) NULL, (const char *) NULL }
};
@@ -467,6 +468,8 @@ static CURLcode OID2str(struct dynbuf *store,
const struct Curl_OID *op = searchOID(Curl_dyn_ptr(&buf));
if(op)
result = Curl_dyn_add(store, op->textoid);
+ else
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
Curl_dyn_free(&buf);
}
}
diff --git a/libs/libcurl/src/warnless.h b/libs/libcurl/src/warnless.h
index 7fa00af36c..d0d2117d13 100644
--- a/libs/libcurl/src/warnless.h
+++ b/libs/libcurl/src/warnless.h
@@ -77,20 +77,6 @@ ssize_t curlx_write(int fd, const void *buf, size_t count);
#endif /* _WIN32 */
-#if defined(__INTEL_COMPILER) && defined(__unix__)
-
-int curlx_FD_ISSET(int fd, fd_set *fdset);
-
-void curlx_FD_SET(int fd, fd_set *fdset);
-
-void curlx_FD_ZERO(fd_set *fdset);
-
-unsigned short curlx_htons(unsigned short usnum);
-
-unsigned short curlx_ntohs(unsigned short usnum);
-
-#endif /* __INTEL_COMPILER && __unix__ */
-
#endif /* HEADER_CURL_WARNLESS_H */
#ifndef HEADER_CURL_WARNLESS_H_REDEFS
diff --git a/libs/libcurl/src/ws.c b/libs/libcurl/src/ws.c
index 174b62aa38..aad4b96c33 100644
--- a/libs/libcurl/src/ws.c
+++ b/libs/libcurl/src/ws.c
@@ -114,23 +114,23 @@ static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data,
case 0:
break;
case 1:
- infof(data, "WS-DEC: %s [%s%s]", msg,
- ws_frame_name_of_op(dec->head[0]),
- (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL");
+ CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s]", msg,
+ ws_frame_name_of_op(dec->head[0]),
+ (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL");
break;
default:
if(dec->head_len < dec->head_total) {
- infof(data, "WS-DEC: %s [%s%s](%d/%d)", msg,
- ws_frame_name_of_op(dec->head[0]),
- (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
- dec->head_len, dec->head_total);
+ CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s](%d/%d)", msg,
+ ws_frame_name_of_op(dec->head[0]),
+ (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
+ dec->head_len, dec->head_total);
}
else {
- infof(data, "WS-DEC: %s [%s%s payload=%" CURL_FORMAT_CURL_OFF_T
- "/%" CURL_FORMAT_CURL_OFF_T "]",
- msg, ws_frame_name_of_op(dec->head[0]),
- (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
- dec->payload_offset, dec->payload_len);
+ CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s payload=%"
+ CURL_FORMAT_CURL_OFF_T "/%" CURL_FORMAT_CURL_OFF_T "]",
+ msg, ws_frame_name_of_op(dec->head[0]),
+ (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
+ dec->payload_offset, dec->payload_len);
}
break;
}
@@ -277,9 +277,8 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec,
Curl_bufq_skip(inraw, (size_t)nwritten);
dec->payload_offset += (curl_off_t)nwritten;
remain = dec->payload_len - dec->payload_offset;
- /* infof(data, "WS-DEC: passed %zd bytes payload, %"
- CURL_FORMAT_CURL_OFF_T " remain",
- nwritten, remain); */
+ CURL_TRC_WRITE(data, "websocket, passed %zd bytes payload, %"
+ CURL_FORMAT_CURL_OFF_T " remain", nwritten, remain);
}
return remain? CURLE_AGAIN : CURLE_OK;
@@ -454,10 +453,12 @@ static CURLcode ws_cw_write(struct Curl_easy *data,
pass_ctx.cw_type = type;
result = ws_dec_pass(&ws->dec, data, &ctx->buf,
ws_cw_dec_next, &pass_ctx);
- if(result == CURLE_AGAIN)
+ if(result == CURLE_AGAIN) {
/* insufficient amount of data, keep it for later.
* we pretend to have written all since we have a copy */
+ CURL_TRC_WRITE(data, "websocket, buffered incomplete frame head");
return CURLE_OK;
+ }
else if(result) {
infof(data, "WS: decode error %d", (int)result);
return result;
@@ -717,8 +718,10 @@ CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req)
if(result)
return result;
DEBUGASSERT(randlen < sizeof(keyval));
- if(randlen >= sizeof(keyval))
+ if(randlen >= sizeof(keyval)) {
+ free(randstr);
return CURLE_FAILED_INIT;
+ }
strcpy(keyval, randstr);
free(randstr);
for(i = 0; !result && (i < sizeof(heads)/sizeof(heads[0])); i++) {
@@ -949,10 +952,6 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
*nread = 0;
*metap = NULL;
- /* get a download buffer */
- result = Curl_preconnect(data);
- if(result)
- return result;
memset(&ctx, 0, sizeof(ctx));
ctx.data = data;
@@ -1198,6 +1197,7 @@ const struct Curl_handler Curl_handler_ws = {
ZERO_NULL, /* perform_getsock */
ws_disconnect, /* disconnect */
Curl_http_write_resp, /* write_resp */
+ Curl_http_write_resp_hd, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_HTTP, /* defport */
@@ -1223,6 +1223,7 @@ const struct Curl_handler Curl_handler_wss = {
ZERO_NULL, /* perform_getsock */
ws_disconnect, /* disconnect */
Curl_http_write_resp, /* write_resp */
+ Curl_http_write_resp_hd, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_HTTPS, /* defport */