From 1e6eb7b2eec5520b510b4437a6f13578f0acddc6 Mon Sep 17 00:00:00 2001 From: dartraiden Date: Wed, 31 Jan 2024 18:58:27 +0300 Subject: libcurl: update to 8.6.0 --- libs/libcurl/docs/CHANGES | 13478 +++++++++++++++--------------- libs/libcurl/docs/COPYING | 2 +- libs/libcurl/docs/THANKS | 39 + libs/libcurl/include/curl/curl.h | 10 +- libs/libcurl/include/curl/curlver.h | 8 +- libs/libcurl/include/curl/mprintf.h | 18 +- libs/libcurl/include/curl/system.h | 12 +- libs/libcurl/include/curl/urlapi.h | 1 + libs/libcurl/src/Makefile.in | 132 +- libs/libcurl/src/Makefile.inc | 8 +- libs/libcurl/src/altsvc.c | 11 +- libs/libcurl/src/asyn-ares.c | 156 +- libs/libcurl/src/asyn-thread.c | 265 +- libs/libcurl/src/bufref.c | 6 +- libs/libcurl/src/c-hyper.c | 5 +- libs/libcurl/src/cf-h1-proxy.c | 75 +- libs/libcurl/src/cf-h2-proxy.c | 12 +- libs/libcurl/src/cf-haproxy.c | 4 +- libs/libcurl/src/cf-https-connect.c | 2 +- libs/libcurl/src/cf-socket.c | 91 +- libs/libcurl/src/cf-socket.h | 17 - libs/libcurl/src/cfilters.c | 14 - libs/libcurl/src/cfilters.h | 5 - libs/libcurl/src/config-os400.h | 6 - libs/libcurl/src/config-win32.h | 62 - libs/libcurl/src/config-win32ce.h | 9 - libs/libcurl/src/connect.c | 70 +- libs/libcurl/src/content_encoding.c | 54 +- libs/libcurl/src/cookie.c | 10 +- libs/libcurl/src/curl_config.h.cmake | 18 - libs/libcurl/src/curl_config.h.in | 34 +- libs/libcurl/src/curl_ntlm_wb.c | 6 +- libs/libcurl/src/curl_printf.h | 4 + libs/libcurl/src/curl_rtmp.c | 12 +- libs/libcurl/src/curl_sasl.c | 19 +- libs/libcurl/src/curl_setup.h | 86 +- libs/libcurl/src/curl_trc.c | 2 + libs/libcurl/src/curl_trc.h | 25 +- libs/libcurl/src/dict.c | 5 +- libs/libcurl/src/doh.c | 27 +- libs/libcurl/src/dynbuf.c | 7 +- libs/libcurl/src/dynbuf.h | 4 +- libs/libcurl/src/easy.c | 52 +- libs/libcurl/src/easyoptions.c | 4 +- libs/libcurl/src/file.c | 38 +- libs/libcurl/src/formdata.c | 10 +- libs/libcurl/src/ftp.c | 199 +- libs/libcurl/src/getinfo.c | 5 +- libs/libcurl/src/gopher.c | 4 +- libs/libcurl/src/headers.c | 35 +- libs/libcurl/src/hostasyn.c | 11 +- libs/libcurl/src/hostip.c | 24 +- libs/libcurl/src/hsts.c | 34 +- libs/libcurl/src/http.c | 333 +- libs/libcurl/src/http.h | 24 +- libs/libcurl/src/http2.c | 72 +- libs/libcurl/src/http_aws_sigv4.c | 19 +- libs/libcurl/src/http_chunks.c | 294 +- libs/libcurl/src/http_chunks.h | 60 +- libs/libcurl/src/http_proxy.c | 4 +- libs/libcurl/src/imap.c | 93 +- libs/libcurl/src/inet_pton.c | 3 +- libs/libcurl/src/inet_pton.h | 3 - libs/libcurl/src/krb5.c | 39 +- libs/libcurl/src/ldap.c | 6 +- libs/libcurl/src/libcurl.plist | 6 +- libs/libcurl/src/md4.c | 6 +- libs/libcurl/src/memdebug.c | 37 +- libs/libcurl/src/memdebug.h | 2 +- libs/libcurl/src/mime.c | 21 +- libs/libcurl/src/mime.h | 3 +- libs/libcurl/src/mprintf.c | 1203 +-- libs/libcurl/src/mqtt.c | 29 +- libs/libcurl/src/mqtt.h | 1 + libs/libcurl/src/multi.c | 146 +- libs/libcurl/src/noproxy.c | 1 - libs/libcurl/src/openldap.c | 27 +- libs/libcurl/src/pingpong.c | 268 +- libs/libcurl/src/pingpong.h | 20 +- libs/libcurl/src/pop3.c | 106 +- libs/libcurl/src/progress.c | 10 +- libs/libcurl/src/progress.h | 3 +- libs/libcurl/src/rand.c | 6 +- libs/libcurl/src/rtsp.c | 177 +- libs/libcurl/src/sendf.c | 85 +- libs/libcurl/src/sendf.h | 4 + libs/libcurl/src/setopt.c | 44 +- libs/libcurl/src/setup-win32.h | 62 +- libs/libcurl/src/share.c | 8 +- libs/libcurl/src/smb.c | 4 +- libs/libcurl/src/smtp.c | 32 +- libs/libcurl/src/socketpair.c | 3 - libs/libcurl/src/socks.c | 79 +- libs/libcurl/src/socks_gssapi.c | 7 +- libs/libcurl/src/socks_sspi.c | 12 +- libs/libcurl/src/strdup.c | 12 +- libs/libcurl/src/strdup.h | 2 +- libs/libcurl/src/strerror.c | 58 +- libs/libcurl/src/system_win32.c | 31 +- libs/libcurl/src/system_win32.h | 30 +- libs/libcurl/src/telnet.c | 117 +- libs/libcurl/src/tftp.c | 2 +- libs/libcurl/src/transfer.c | 503 +- libs/libcurl/src/transfer.h | 21 +- libs/libcurl/src/url.c | 62 +- libs/libcurl/src/urlapi.c | 169 +- libs/libcurl/src/urldata.h | 36 +- libs/libcurl/src/vauth/digest_sspi.c | 4 + libs/libcurl/src/vauth/krb5_gssapi.c | 3 +- libs/libcurl/src/vauth/krb5_sspi.c | 3 +- libs/libcurl/src/vauth/ntlm.c | 6 +- libs/libcurl/src/vauth/ntlm_sspi.c | 8 +- libs/libcurl/src/version.c | 8 +- libs/libcurl/src/vquic/curl_msh3.c | 8 +- libs/libcurl/src/vquic/curl_ngtcp2.c | 573 +- libs/libcurl/src/vquic/curl_osslq.c | 2237 +++++ libs/libcurl/src/vquic/curl_osslq.h | 51 + libs/libcurl/src/vquic/curl_quiche.c | 297 +- libs/libcurl/src/vquic/vquic-tls.c | 609 ++ libs/libcurl/src/vquic/vquic-tls.h | 98 + libs/libcurl/src/vquic/vquic.c | 16 +- libs/libcurl/src/vquic/vquic_int.h | 4 +- libs/libcurl/src/vssh/libssh.c | 90 +- libs/libcurl/src/vssh/libssh2.c | 92 +- libs/libcurl/src/vssh/wolfssh.c | 28 +- libs/libcurl/src/vtls/bearssl.c | 32 +- libs/libcurl/src/vtls/gtls.c | 10 +- libs/libcurl/src/vtls/mbedtls.c | 31 +- libs/libcurl/src/vtls/openssl.c | 52 +- libs/libcurl/src/vtls/rustls.c | 12 +- libs/libcurl/src/vtls/schannel.c | 58 +- libs/libcurl/src/vtls/schannel_verify.c | 4 +- libs/libcurl/src/vtls/sectransp.c | 16 +- libs/libcurl/src/vtls/vtls.c | 92 +- libs/libcurl/src/vtls/vtls.h | 2 + libs/libcurl/src/vtls/wolfssl.c | 27 +- libs/libcurl/src/vtls/x509asn1.c | 899 +- libs/libcurl/src/ws.c | 336 +- libs/libcurl/src/ws.h | 13 +- 139 files changed, 14293 insertions(+), 11078 deletions(-) create mode 100644 libs/libcurl/src/vquic/curl_osslq.c create mode 100644 libs/libcurl/src/vquic/curl_osslq.h create mode 100644 libs/libcurl/src/vquic/vquic-tls.c create mode 100644 libs/libcurl/src/vquic/vquic-tls.h (limited to 'libs/libcurl') diff --git a/libs/libcurl/docs/CHANGES b/libs/libcurl/docs/CHANGES index 85fa4522fb..8e70215477 100644 --- a/libs/libcurl/docs/CHANGES +++ b/libs/libcurl/docs/CHANGES @@ -6,10369 +6,10691 @@ Changelog -Version 8.5.0 (6 Dec 2023) +Version 8.6.0 (31 Jan 2024) -Daniel Stenberg (6 Dec 2023) +Daniel Stenberg (31 Jan 2024) - RELEASE-NOTES: synced - The curl 8.5.0 release. + curl 8.6.0 -Dan Fandrich (5 Dec 2023) +- THANKS: new contributors from 8.5.0 -- github/labeler: switch from the beta to labeler v5 +Jay Satiro (31 Jan 2024) - Some keys were renamed and the dot option was made default. +- cd2nroff: use perl 'strict' and 'warnings' - Closes #12458 + - Use strict and warnings pragmas. -Daniel Stenberg (5 Dec 2023) + - If open() fails then show the reason. -- DEPRECATE: remove NTLM_WB in June 2024 + - Set STDIN io layer :crlf so that input is properly read on Windows. - Ref: https://curl.se/mail/lib-2023-12/0010.html + - When STDIN is used as input, the filename $f is now set to "STDIN". - Closes #12451 + Various error messages in single() use $f for the filename and this way + it is not undefined when STDIN. -Jacob Hoffman-Andrews (4 Dec 2023) + Closes https://github.com/curl/curl/pull/12819 -- rustls: implement connect_blocking +Daniel Stenberg (30 Jan 2024) - Closes #11647 +- cd2nroff: fix duplicate output issue -Daniel Stenberg (4 Dec 2023) + Assisted-by: Jay Satiro + Fixes https://github.com/curl/curl-www/issues/321 + Closes #12818 -- examples/rtsp-options.c: add +- lib: error out on multissl + http3 - Just a bare bones RTSP example using CURLOPT_RTSP_SESSION_ID and - CURLOPT_RTSP_REQUEST set to CURL_RTSPREQ_OPTIONS. + Since the QUIC/h3 code has no knowledge or handling of multissl it might + bring unintended consequences if we allow it. - Closes #12452 + configure, cmake and curl_setup.h all now reject this combination. -Stefan Eissing (4 Dec 2023) + Assisted-by: Viktor Szakats + Assisted-by: Gisle Vanem + Ref: #12806 + Closes #12807 -- ngtcp2: ignore errors on unknown streams +Patrick Monnerat (29 Jan 2024) - - expecially in is_alive checks on connections, we might - see incoming packets on streams already forgotten and closed, - leading to errors reported by nghttp3. Ignore those. +- OS400: sync ILE/RPG binding - Closes #12449 + Also do not force git CRLF line endings on *.cmd files for OS400. -Daniel Stenberg (4 Dec 2023) + Closes #12815 -- docs: make all examples in all libcurl man pages compile +Viktor Szakats (28 Jan 2024) - Closes #12448 +- build: delete/replace 3 more clang warning pragmas -- checksrc.pl: support #line instructions + - tool_msgs: delete redundant `-Wformat-nonliteral` suppression pragma. - makes it identify the correct source file and line + - whitespace formatting in `mprintf.h`, lib518, lib537. -- GHA/man-examples: verify libcurl man page examples + - lib518: fix wrong variable in `sizeof()`. -- verify-examples.pl: verify that all man page examples compile clean + - lib518: bump variables to `rlim_t`. + Follow-up to e2b394106d543c4615a60795b7fdce04bd4e5090 #1469 -- RELEASE-NOTES: synced + - lib518: sync error message with lib537 + Follow-up to 365322b8bcf9efb6a361473d227b70f2032212ce -Graham Campbell (2 Dec 2023) + - lib518, lib537: replace `-Wformat-nonliteral` suppression pragmas + by reworking test code. -- http3: bump ngtcp2 and nghttp3 versions + Follow-up to 5b286c250829e06a135a6ba998e80beb7f43a734 #12812 + Follow-up to aee4ebe59161d0a5281743f96e7738ad97fe1cd4 #12803 + Follow-up to 09230127589eccc7e01c1a7217787ef8e64f3328 #12540 + Follow-up to 3829759bd042c03225ae862062560f568ba1a231 #12489 - nghttp3 v1.1.0 - ngtcp2 v1.1.0 + Reviewed-by: Daniel Stenberg + Closes #12814 - In docs and CI +Richard Levitte (27 Jan 2024) - Closes #12446 +- cmake: freshen up docs/INSTALL.cmake -- CI/quiche: use `3.1.4+quic` consistently in CI workflows + - Turn docs/INSTALL.cmake into a proper markdown file, + docs/INSTALL-CMAKE.md + - Move things around to divide the description into configuration, + building and installing sections + - Mention the more modern cmake options to configure, build and install, + but also retain the older variants as fallbacks - Closes #12447 + Closes #12772 -Viktor Szakats (2 Dec 2023) +Viktor Szakats (27 Jan 2024) -- test1545: disable deprecation warnings +- build: delete/replace clang warning pragmas - Fixes: - https://ci.appveyor.com/project/curlorg/curl/builds/48631551/job/bhx74e0i66yr - p6pk#L1205 + - delete redundant warning suppressions for `-Wformat-nonliteral`. + This now relies on `CURL_PRINTF()` and it's theoratically possible + that this macro isn't active but the warning is. We're ignoring this + as a corner-case here. - Same with details: - https://ci.appveyor.com/project/curlorg/curl/builds/48662893/job/ol8a78q9gmil - b6wt#L1263 - ``` - tests/libtest/lib1545.c:38:3: error: 'curl_formadd' is deprecated: since 7.56 - .0. Use curl_mime_init() [-Werror=deprecated-declarations] - 38 | curl_formadd(&m_formpost, &lastptr, CURLFORM_COPYNAME, "file", - | ^~~~~~~~~~~~ - [...] - ``` + - replace two pragmas with code changes to avoid the warnings. - Follow-up to 07a3cd83e0456ca17dfd8c3104af7cf45b7a1ff5 #12421 + Follow-up to aee4ebe59161d0a5281743f96e7738ad97fe1cd4 #12803 + Follow-up to 09230127589eccc7e01c1a7217787ef8e64f3328 #12540 + Follow-up to 3829759bd042c03225ae862062560f568ba1a231 #12489 - Fixes #12445 - Closes #12444 + Reviewed-by: Daniel Stenberg + Closes #12812 -Daniel Stenberg (2 Dec 2023) +Daniel Stenberg (27 Jan 2024) -- INSTALL: update list of ports and CPU archs +- RELEASE-NOTES: synced -- symbols-in-versions: the CLOSEPOLICY options are deprecated +- http: only act on 101 responses when they are HTTP/1.1 - The were used with the CURLOPT_CLOSEPOLICY option, which *never* worked. + For 101 responses claiming to be any other protocol, bail out. This + would previously trigger an assert. -z2_ (1 Dec 2023) + Add test 1704 to verify. -- build: fix builds that disable protocols but not digest auth + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66184 + Closes #12811 - - Build base64 functions if digest auth is not disabled. +Scarlett McAllister (27 Jan 2024) - Prior to this change if some protocols were disabled but not digest auth - then a build error would occur due to missing base64 functions. +- _VARIABLES.md: add missing 'be' into the sentence - Fixes https://github.com/curl/curl/issues/12440 - Closes https://github.com/curl/curl/pull/12442 + Closes #12809 -Michał Antoniak (1 Dec 2023) +Stefan Eissing (27 Jan 2024) -- connect: reduce number of transportation providers +- mqtt, remove remaining use of data->state.buffer - Use only the ones necessary - the ones that are built-in. Saves a few - bytes in the resulting code. + Closes #12799 - Closes #12438 +Daniel Stenberg (27 Jan 2024) -David Benjamin (1 Dec 2023) +- x509asn1: switch from malloc to dynbuf -- vtls: consistently use typedef names for OpenSSL structs + Closes #12808 - The foo_st names don't appear in OpenSSL public API documentation. The - FOO typedefs are more common. This header was already referencing - SSL_CTX via . There is a comment about avoiding - , but OpenSSL actually declares all the typedefs in - , which is already included by (and - every other OpenSSL header), so just use that. Though I've included it - just to be explicit. +- x509asn1: make utf8asn1str() use dynbuf instead of malloc + memcpy - (I'm also fairly sure including already triggers the - Schannel conflicts anyway. The comment was probably just out of date.) + Closes #12808 - Closes #12439 +- x509asn1: reduce malloc in Curl_extract_certinfo -Lau (1 Dec 2023) + Using dynbuf -- libcurl-security.3: fix typo + Closes #12808 - Fixed minimal typo. +Jay Satiro (27 Jan 2024) - Closes #12437 +- THANKS: add Alexander Bartel and Brennan Kinney -Stefan Eissing (1 Dec 2023) + They reported and investigated #10259 which was fixed by 7b2d98df. -- ngtcp2: fix races in stream handling + Ref: https://github.com/curl/curl/issues/10259 - - fix cases where ngtcp2 invokes callbacks on streams that - nghttp3 has already forgotten. Ignore the NGHTTP3_ERR_STREAM_NOT_FOUND - in these cases as it is normal behaviour. +Daniel Stenberg (26 Jan 2024) - Closes #12435 +- krb5: add prototype to silence clang warnings on mvsnprintf() -Emanuele Torre (1 Dec 2023) + "error: format string is not a string literal" -- tool_writeout_json: fix JSON encoding of non-ascii bytes + Follow-up to 09230127589eccc7 which made the warning appear - char variables if unspecified can be either signed or unsigned depending - on the platform according to the C standard; in most platforms, they are - signed. + Assisted-by: Viktor Szakats + Closes #12803 - This meant that the *i<32 waas always true for bytes with the top bit - set. So they were always getting encoded as \uXXXX, and then since they - were also signed negative, they were getting extended with 1s causing - '\xe2' to be expanded to \uffffffe2, for example: +- x509asn1: remove code for WANT_VERIFYHOST - $ curl --variable 'v=“' --expand-write-out '{{v:json}}\n' file:///dev/nul - l - \uffffffe2\uffffff80\uffffff9c + No code ever sets this anymore since we dropped gskit - I fixed this bug by making the code use explicitly unsigned char* - variables instead of char* variables. + Follow-up to 78d6232f1f326b9ab4d - Test 268 verifies + Closes #12804 - Reported-by: iconoclasthero - Closes #12434 +- socks: reduce the buffer size to 600 (from 8K) -Stefan Eissing (1 Dec 2023) + This is malloc'ed memory and it does not more. Test 742 helps us verify + this. -- cf-socket: TCP trace output local address used in connect + Closes #12789 - Closes #12427 +Stefan Eissing (26 Jan 2024) -Jay Satiro (1 Dec 2023) +- file+ftp: use stack buffers instead of data->state.buffer -- CURLINFO_PRETRANSFER_TIME_T.3: fix time explanation + Closes #12789 - - Change CURLINFO_PRETRANSFER_TIME_T explanation to say that it - includes protocol-specific instructions that trigger a transfer. +- vtls: receive max buffer - Prior to this change it explicitly said that it did not include those - instructions in the time, but that is incorrect. + - do not only receive one TLS record, but try to fill + the passed buffer + - consider <4K remaning space is "filled". - The change is a copy of the fixed explanation already in - CURLINFO_PRETRANSFER_TIME, fixed by ec8dcd7b. + Closes #12801 - Reported-by: eeverettrbx@users.noreply.github.com +Daniel Stenberg (26 Jan 2024) - Fixes https://github.com/curl/curl/issues/12431 - Closes https://github.com/curl/curl/pull/12432 +- docs: do not start lines/sentences with So, But nor And -Daniel Stenberg (30 Nov 2023) + Closes #12802 -- multi: during ratelimit multi_getsock should return no sockets +- docs: remove spurious ampersands from markdown - ... as there is nothing to wait for then, it just waits. Otherwise, this - causes much more CPU work and updates than necessary during ratelimit - periods. + They were leftovers from the nroff conversion. - Ref: https://curl.se/mail/lib-2023-11/0056.html - Closes #12430 + Follow-up to eefcc1bda4bccd800f5a5 -Dmitry Karpov (30 Nov 2023) + Closes #12800 -- transfer: abort pause send when connection is marked for closing +Patrick Monnerat (26 Jan 2024) - This handles cases of some bi-directional "upgrade" scenarios - (i.e. WebSockets) where sending is paused until some "upgrade" handshake - is completed, but server rejects the handshake and closes the - connection. +- sasl: make login option string override http auth - Closes #12428 + - Use http authentication mechanisms as a default, not a preset. -Daniel Stenberg (28 Nov 2023) + Consider http authentication options which are mapped to SASL options as + a default (overriding the hardcoded default mask for the protocol) that + is ignored if a login option string is given. -- RELEASE-NOTES: synced + Prior to this change, if some HTTP auth options were given, sasl mapped + http authentication options to sasl ones but merged them with the login + options. -- openssl: when a session-ID is reused, skip OCSP stapling + That caused problems with the cli tool that sets the http login option + CURLAUTH_BEARER as a side-effect of --oauth2-bearer, because this flag + maps to more than one sasl mechanisms and the latter cannot be cleared + individually by the login options string. - Fixes #12399 - Reported-by: Alexey Larikov - Closes #12418 + New test 992 checks this. -- test1545: test doing curl_formadd twice with missing file + Fixes https://github.com/curl/curl/issues/10259 + Closes https://github.com/curl/curl/pull/12790 - Reproduces #12410 - Verifies the fix - Closes #12421 +Stefan Eissing (26 Jan 2024) -- Curl_http_body: cleanup properly when Curl_getformdata errors +- socks: use own buffer instead of data->state.buffer - Reported-by: yushicheng7788 on github - Based-on-work-by: yushicheng7788 on github - Fixes #12410 - Closes #12421 + Closes #12788 -- test1477: verify that libcurl-errors.3 and public headers are synced +Daniel Stenberg (26 Jan 2024) - The script errorcodes.pl extracts all error codes from all headers and - checks that they are all documented, then checks that all documented - error codes are also specified in a header file. +- socks: fix generic output string to say SOCKS instead of SOCKS4 - Closes #12424 + ... since it was also logged for SOCKS5. -- libcurl-errors.3: sync with current public headers + Closes #12797 - Closes #12424 +- test742: test SOCKS5 with max length user, password and hostname -Stefan Eissing (28 Nov 2023) + Adjusted the socksd server accordingly to allow for configuring that + long user name and password. -- test459: fix for parallel runs + Closes #12797 - - change warniing message to work better with varying filename - length. - - adapt test output check to new formatting +Stefan Eissing (25 Jan 2024) - Follow-up to 97ccc4479f77ba3191c6 - Closes #12423 +- ssh: use stack scratch buffer for seeks -Daniel Stenberg (27 Nov 2023) + - instead of data->state.buffer -- tool_cb_prg: make the carriage return fit for wide progress bars + Closes #12794 - When the progress bar was made max width (256 columns), the fly() - function attempted to generate its output buffer too long so that the - trailing carriage return would not fit and then the output would show - wrongly. The fly function is called when the expected total transfer is - unknown, which could be one or more progress calls before the actual - progress meter get shown when the expected transfer size is provided. +Daniel Stenberg (25 Jan 2024) - This new take also replaces the msnprintf() call with a much simpler - memset() for speed. +- krb5: access the response buffer correctly - Reported-by: Tim Hill - Fixes #12407 - Closes #12415 + As the pingpong code no longer uses the download buffer. -- tool_parsecfg: make warning output propose double-quoting + Folllow-up to c2d973627bab12ab + Pointed-out-by: Stefan Eissing + Closes #12796 - When the config file parser detects a word that *probably* should be - quoted, mention double-quotes as a possible remedy. +Stefan Eissing (25 Jan 2024) - Test 459 verifies. +- mqtt: use stack scratch buffer for recv+publish - Proposed-by: Jiehong on github - Fixes #12409 - Closes #12412 + - instead of data->state.buffer -Jay Satiro (26 Nov 2023) + Closes #12792 -- curl.rc: switch out the copyright symbol for plain ASCII +- telnet, use stack scratch buffer for do - .. like we already do for libcurl.rc. + - instead of data->state.buffer - libcurl.rc copyright symbol used to cause a "non-ascii 8-bit codepoint" - warning so it was switched to ascii. + Closes #12793 - Ref: https://github.com/curl/curl/commit/1ca62bb5#commitcomment-133474972 +- http, use stack scratch buffer - Suggested-by: Robert Southee + - instead of data->state.buffer - Closes https://github.com/curl/curl/pull/12403 + Closes #12791 -Daniel Stenberg (26 Nov 2023) +- ntlm_wb: do not use data->state.buf any longer -- conncache: use the closure handle when disconnecting surplus connections + Closes #12787 - Use the closure handle for disconnecting connection cache entries so - that anything that happens during the disconnect is not stored and - associated with the 'data' handle which already just finished a transfer - and it is important that details from the unrelated disconnect does not - taint meta-data in the data handle. +- gitignore: the generated `libcurl-symbols.md` - Like storing the response code. + Closes #12795 - This also adjust test 1506. Unfortunately it also removes a key part of - the test that verifies that a connection is closed since when this - output vanishes (because the closure handle is used), we don't know - exactly that the connection actually gets closed in this test... +Daniel Stenberg (25 Jan 2024) - Reported-by: ohyeaah on github - Fixes #12367 - Closes #12405 +- tool: fix the listhelp generation command -- RELEASE-NOTES: synced + The previous command line to generate the tool_listhelp.c source file + broke with 2494b8dd5175cee7. -Stefan Eissing (24 Nov 2023) + Make 'make listhelp' invoked in src/ generate it. Also update the + comment in the file to mention the right procedure. -- quic: make eyeballers connect retries stop at weird replies + Closes #12786 - - when a connect immediately goes into DRAINING state, do - not attempt retries in the QUIC connection filter. Instead, - return CURLE_WEIRD_SERVER_REPLY - - When eyeballing, interpret CURLE_WEIRD_SERVER_REPLY as an - inconclusive answer. When all addresses have been attempted, - rewind the address list once on an inconclusive answer. - - refs #11832 where connects were retried indefinitely until - the overall timeout fired +- http: check for "Host:" case insensitively - Closes #12400 + When checking if the user wants to replace the header, the check should + be case insensitive. -Daniel Stenberg (24 Nov 2023) + Adding test 461 to verify -- CI: verify libcurl function SYNPOSIS sections + Found-by: Dan Fandrich + Ref: #12782 + Closes #12784 - With the .github/scripits/verify-synopsis.pl script +Tatsuhiro Tsujikawa (25 Jan 2024) - Closes #12402 +- configure: add libngtcp2_crypto_boringssl detection -- docs/libcurl: SYNSOPSIS cleanup + If OpenSSL is found to be BoringSSL or AWS-LC, and ngtcp2 is requested, + try to detect libngtcp2_crypto_boringssl. - - use the correct include file - - make sure they are declared as in the header file - - fix minor nroff syntax mistakes (missing .fi) + Reported-by: ウさん + Fixes #12724 + Closes #12769 - These are verified by verify-synopsis.pl, which extracts the SYNPOSIS - code and runs it through gcc. +Daniel Stenberg (25 Jan 2024) - Closes #12402 +- http: remove comment reference to a removed solution -- sendf: fix comment typo + Follow-up to 58974d25d -- fopen: allocate the dir after fopen + Closes #12785 - Move the allocation of the directory name down to after the fopen() call - to allow that shortcut code path to avoid a superfluous malloc+free - cycle. +Stefan Eissing (25 Jan 2024) - Follow-up to 73b65e94f35311 +- pytest: Scorecard tracking CPU and RSS - Closes #12398 + Closes #12765 -Stefan Eissing (24 Nov 2023) +Graham Campbell (25 Jan 2024) -- transfer: cleanup done+excess handling +- GHA: bump ngtcp2, gnutls, mod_h2, quiche - - add `SingleRequest->download_done` as indicator that - all download bytes have been received - - remove `stop_reading` bool from readwrite functions - - move excess body handling into client download writer + - ngtcp2 to v1.2.0 + - gnutls to 3.8.3 + - mod_h2 to 2.0.26 + - quiche to 0.20.0 - Closes #12371 + Closes #12778 + Closes #12779 + Closes #12780 + Closes #12781 -Daniel Stenberg (23 Nov 2023) +Daniel Stenberg (25 Jan 2024) -- fopen: create new file using old file's mode +- ftpserver.pl: send 213 SIZE response without spurious newline - Because the function renames the temp file to the target name as a last - step, if the file was previously owned by a different user, not ORing - the old mode could otherwise end up creating a file that was no longer - readable by the original owner after save. +- pingpong: stop using the download buffer - Reported-by: Loïc Yhuel - Fixes #12299 - Closes #12395 + The pingpong logic now uses its own dynbuf for receiving command + response data. -- test1476: require proxy + When the "final" response header for a commanad has been received, that + final line is left first in the recvbuf for the protocols to parse at + will. If there is additional data behind the final response line, the + 'overflow' counter is indicate how many bytes. - Follow-up from 323df4261c3542 + Closes #12757 - Closes #12394 +- gen.pl: remove bold from .IP used for ## -- fopen: create short(er) temporary file name + Reported-by: Viktor Szakats + Fixes #12776 + Closes #12777 - Only using random letters in the name plus a ".tmp" extension. Not by - appending characters to the final file name. +Viktor Szakats (24 Jan 2024) - Reported-by: Maksymilian Arciemowicz +- cmake: rework options to enable curl and libcurl docs - Closes #12388 + Rework CMake options for building/using curl tool and libcurl manuals. -Stefan Eissing (23 Nov 2023) + - rename `ENABLE_MANUAL` to `ENABLE_CURL_MANUAL`, meaning: + to build man page and built-in manual for curl tool. -- tests: git ignore generated second-hsts.txt file + - rename `BUILD_DOCS` to `BUILD_LIBCURL_DOCS`, meaning: + to build man pages for libcurl. - File is generated in test lib1900 + - `BUILD_LIBCURL_DOCS` now works without having to enable + `ENABLE_CURL_MANUAL` too. - Follow-up to 7cb03229d9e9c5 + - drop support for existing CMake-level `USE_MANUAL` option to avoid + confusion. (It used to work with the effect of current + `ENABLE_CURL_MANUAL`, but only by accident.) - Closes #12393 + Assisted-by: Richard Levitte + Ref: #12771 + Closes #12773 -Viktor Szakats (23 Nov 2023) +Daniel Stenberg (24 Jan 2024) -- openssl: enable `infof_certstack` for 1.1 and LibreSSL 3.6 +- urlapi: remove assert - Lower the barrier to enable `infof_certstack()` from OpenSSL 3 to - OpenSSL 1.1.x, and LibreSSL 3.6 or upper. + This assert triggers wrongly when CURLU_GUESS_SCHEME and + CURLU_NO_AUTHORITY are both set and the URL is a single path. - With the caveat, that "group name" and "type name" are missing from - the log output with these TLS backends. + I think this assert has played out its role. It was introduced in a + rather big refactor. - Follow-up to b6e6d4ff8f253c8b8055bab9d4d6a10f9be109f3 #12030 + Follow-up to 4cfa5bcc9a - Reviewed-by: Daniel Stenberg - Closes #12385 + Reported-by: promptfuzz_ on hackerone + Closes #12775 -Daniel Stenberg (23 Nov 2023) +Patrick Monnerat (24 Jan 2024) -- urldata: fix typo in comment +- tests: avoid int/size_t conversion size/sign warnings -- CI: codespell + Closes #12768 - The list of words to ignore is in the file - .github/scripts/codespell-ignore.txt +Daniel Stenberg (24 Jan 2024) - Closes #12390 +- GHA: add a job scanning for "bad words" in markdown -- lib: fix comment typos + This means words, phrases or things we have decided not to use - words that + are spelled right according to the dictionary but we want to avoid. In the + name of consistency and better documentation. - Five separate ones, found by codespell + Closes #12764 - Closes #12390 +Viktor Szakats (23 Jan 2024) -- test1476: verify cookie PSL mixed case +- cmake: speed up curldown processing, enable by default -- cookie: lowercase the domain names before PSL checks + - cmake: enable `BUILD_DOCS` by default (this controls converting and + installing `.3` files from `.md` sources) - Reported-by: Harry Sintonen + - cmake: speed up generating `.3` files by using a single command per + directory, instead of a single command per file. This reduces external + commands by about a thousand. (There remains some CMake logic kicking + in resulting in 500 -one per file- external `-E touch_nocreate` calls.) - Closes #12387 + - cd2nroff: add ability to process multiple input files. -Viktor Szakats (23 Nov 2023) + - cd2nroff: add `-k` option to use the source filename to form the + output filename. (instead of the default in-file `Title:` line.) -- openssl: fix building with v3 `no-deprecated` + add CI test + Follow-up to 3f08d80b2244524646ce86915c585509ac54fb4c + Follow-up to ea0b575dab86a3c44dd1d547dc500276266aa382 #12753 + Follow-up to eefcc1bda4bccd800f5a56a0fe17a2f44a96e88b #12730 - - build quictls with `no-deprecated` in CI to have test coverage for - this OpenSSL 3 configuration. + Closes #12762 - - don't call `OpenSSL_add_all_algorithms()`, `OpenSSL_add_all_digests()`. - The caller code is meant for OpenSSL 3, while these two functions were - only necessary before OpenSSL 1.1.0. They are missing from OpenSSL 3 - if built with option `no-deprecated`, causing build errors: - ``` - vtls/openssl.c:4097:3: error: call to undeclared function 'OpenSSL_add_all_ - algorithms'; ISO C99 and later do not support implicit function declaration - s [-Wimplicit-function-declaration] - vtls/openssl.c:4098:3: error: call to undeclared function 'OpenSSL_add_all_ - digests'; ISO C99 and later do not support implicit function declarations [ - -Wimplicit-function-declaration] - ``` - Ref: https://ci.appveyor.com/project/curlorg/curl-for-win/builds/48587418?f - ullLog=true#L7667 +Richard Levitte (23 Jan 2024) - Regression from b6e6d4ff8f253c8b8055bab9d4d6a10f9be109f3 #12030 - Bug: https://github.com/curl/curl/issues/12380#issuecomment-1822944669 - Reviewed-by: Alex Bozarth +- docs: install curl.1 with cmake as well - - vquic/curl_ngtcp2: fix using `SSL_get_peer_certificate` with - `no-deprecated` quictls 3 builds. - Do it by moving an existing solution for this from `vtls/openssl.c` - to `vtls/openssl.h` and adjusting caller code. - ``` - vquic/curl_ngtcp2.c:1950:19: error: implicit declaration of function 'SSL_g - et_peer_certificate'; did you mean 'SSL_get1_peer_certificate'? [-Wimplicit - -function-declaration] - ``` - Ref: https://github.com/curl/curl/actions/runs/6960723097/job/18940818625#s - tep:24:1178 + Closes #12759 - - curl_ntlm_core: fix `-Wunused-parameter`, `-Wunused-variable` and - `-Wunused-function` when trying to build curl with NTLM enabled but - without the necessary TLS backend (with DES) support. +Daniel Stenberg (23 Jan 2024) - Closes #12384 +- osslq: remove the TLS library from the version output -- curl.h: delete Symbian OS references + Since we only support using a single TLS library at any one time, we + know that the TLS library for QUIC is the same that is also shown for + regular TLS. - curl deprecated Symbian OS in 3d64031fa7a80ac4ae3fd09a5939196268b92f81 - via #5989. Delete references to it from public headers, because there - is no fresh release to use those headers with. + Fixes #12763 + Reported-by: Viktor Szakats + Closes #12767 - Reviewed-by: Dan Fandrich - Reviewed-by: Jay Satiro - Closes #12378 +Stefan Eissing (23 Jan 2024) -- windows: use built-in `_WIN32` macro to detect Windows +- CI: remove unnecessary OpenSSL 3 option `enable-tls1_3` - Windows compilers define `_WIN32` automatically. Windows SDK headers - or build env defines `WIN32`, or we have to take care of it. The - agreement seems to be that `_WIN32` is the preferred practice here. - Make the source code rely on that to detect we're building for Windows. + .. and switch OpenSSL 3 libdir from lib64 to lib for consistency. - Public `curl.h` was using `WIN32`, `__WIN32__` and `CURL_WIN32` for - Windows detection, next to the official `_WIN32`. After this patch it - only uses `_WIN32` for this. Also, make it stop defining `CURL_WIN32`. + Closes https://github.com/curl/curl/pull/12758 - There is a slight chance these break compatibility with Windows - compilers that fail to define `_WIN32`. I'm not aware of any obsolete - or modern compiler affected, but in case there is one, one possible - solution is to define this macro manually. +- GHA: bump nghttp2 version to v1.59.0 - grepping for `WIN32` remains useful to discover Windows-specific code. + - Switch to v1.59.0 for GHA CI jobs that use a specific nghttp2-version. - Also: + Closes https://github.com/curl/curl/pull/12766 - - extend `checksrc` to ensure we're not using `WIN32` anymore. +Daniel Stenberg (23 Jan 2024) - - apply minor formatting here and there. +- RELEASE-NOTES: synced - - delete unnecessary checks for `!MSDOS` when `_WIN32` is present. +- docs/cmdline: change to .md for cmdline docs - Co-authored-by: Jay Satiro - Reviewed-by: Daniel Stenberg + - switch all invidual files documenting command line options into .md, + as the documentation is now markdown-looking. - Closes #12376 + - made the parser treat 4-space indents as quotes -Stefan Eissing (22 Nov 2023) + - switch to building the curl.1 manpage using the "mainpage.idx" file, + which lists the files to include to generate it, instead of using the + previous page-footer/headers. Also, those files are now also .md + ones, using the same format. I gave them underscore prefixes to make + them sort separately: + _NAME.md, _SYNOPSIS.md, _DESCRIPTION.md, _URL.md, _GLOBBING.md, + _VARIABLES.md, _OUTPUT.md, _PROTOCOLS.md, _PROGRESS.md, _VERSION.md, + _OPTIONS.md, _FILES.md, _ENVIRONMENT.md, _PROXYPREFIX.md, + _EXITCODES.md, _BUGS.md, _AUTHORS.md, _WWW.md, _SEEALSO.md -- url: ConnectionExists revisited + - updated test cases accordingly - - have common pattern of `if not match, continue` - - revert pages long if()s to return early - - move dead connection check to later since it may - be relatively expensive - - check multiuse also when NOT building with NGHTTP2 - - for MULTIUSE bundles, verify that the inspected - connection indeed supports multiplexing when in use - (bundles may contain a mix of connection, afaict) + Closes #12751 - Closes #12373 +dependabot[bot] (23 Jan 2024) -Daniel Stenberg (22 Nov 2023) +- CI: bump actions/cache from 3 to 4 -- CURLMOPT_MAX_CONCURRENT_STREAMS: make sure the set value is within range + Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. + - [Release notes](https://github.com/actions/cache/releases) + - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) + - [Commits](https://github.com/actions/cache/compare/v3...v4) - ... or use the default value. + --- + updated-dependencies: + - dependency-name: actions/cache + dependency-type: direct:production + update-type: version-update:semver-major + ... - Also clarify the documentation language somewhat. + Signed-off-by: dependabot[bot] + Closes #12756 - Closes #12382 +Daniel Stenberg (23 Jan 2024) -- urldata: make maxconnects a 32 bit value +- openssl: when verifystatus fails, remove session id from cache - "2^32 idle connections ought to be enough for anybody" + To prevent that it gets used in a subsequent transfer that skips the + verifystatus check since that check can't be done when the session id is + reused. - Closes #12375 + Reported-by: Hiroki Kurosawa + Closes #12760 -- FEATURES: update the URL phrasing +Viktor Szakats (23 Jan 2024) - The URL is length limited since a while back so "no limit" simply is not - true anymore. Mention the URL RFC standard used instead. +- cmake: add option to disable building docs - Closes #12383 +Richard Levitte (23 Jan 2024) -- wolfssh: remove redundant static prototypes +- cmake: use curldown to build man pages - vssh/wolfssh.c:346:18: error: redundant redeclaration of ‘wscp_recv’ [-We - rror=redundant-decls] + This throws away the previous HTML and PDF producers, to mimic what + Makefile.am does as faithfully as possible. - Closes #12381 + Closes #12753 -- setopt: remove superfluous use of ternary expressions +Daniel Stenberg (23 Jan 2024) - Closes #12374 +- mksymbolsmanpage.pl: provide references to where the symbol is used -- mime: store "form escape" as a single bit +- docs: introduce "curldown" for libcurl man page format - Closes #12374 + curldown is this new file format for libcurl man pages. It is markdown + inspired with differences: -- setopt: check CURLOPT_TFTP_BLKSIZE range on set + - Each file has a set of leading headers with meta-data + - Supports a small subset of markdown + - Uses .md file extensions for editors/IDE/GitHub to treat them nicely + - Generates man pages very similar to the previous ones + - Generates man pages that still convert nicely to HTML on the website + - Detects and highlights mentions of curl symbols automatically (when + their man page section is specified) - ... instead of later when the transfer is about to happen. + tools: - Closes #12374 + - cd2nroff: converts from curldown to nroff man page + - nroff2cd: convert an (old) nroff man page to curldown + - cdall: convert many nroff pages to curldown versions + - cd2cd: verifies and updates a curldown to latest curldown -Viktor Szakats (21 Nov 2023) + This setup generates .3 versions of all the curldown versions at build time. -- build: add more picky warnings and fix them + CI: - Enable more picky compiler warnings. I've found these options in the - nghttp3 project when implementing the CMake quick picky warning - functionality for it [1]. + Since the documentation is now technically markdown in the eyes of many + things, the CI runs many more tests and checks on this documentation, + including proselint, link checkers and tests that make sure we capitalize the + first letter after a period... - `-Wunused-macros` was too noisy to keep around, but fixed a few issues - it revealed while testing. + Closes #12730 - - autotools: reflect the more precisely-versioned clang warnings. - Follow-up to 033f8e2a08eb1d3102f08c4d8c8e85470f8b460e #12324 - - autotools: sync between clang and gcc the way we set `no-multichar`. - - autotools: avoid setting `-Wstrict-aliasing=3` twice. - - autotools: disable `-Wmissing-noreturn` for MSYS gcc targets [2]. - It triggers in libtool-generated stub code. +Viktor Szakats (22 Jan 2024) - - lib/timeval: delete a redundant `!MSDOS` guard from a `WIN32` branch. +- libssh2: use `libssh2_session_callback_set2()` with v1.11.1 - - lib/curl_setup.h: delete duplicate declaration for `fileno`. - Added in initial commit ae1912cb0d494b48d514d937826c9fe83ec96c4d - (1999-12-29). This suggests this may not be needed anymore, but if - it does, we may restore this for those specific (non-Windows) systems. - - lib: delete unused macro `FTP_BUFFER_ALLOCSIZE` since - c1d6fe2aaa5a26e49a69a4f2495b3cc7a24d9394. - - lib: delete unused macro `isxdigit_ascii` since - f65f750742068f579f4ee6d8539ed9d5f0afcb85. - - lib/mqtt: delete unused macro `MQTT_HEADER_LEN`. - - lib/multi: delete unused macro `SH_READ`/`SH_WRITE`. - - lib/hostip: add `noreturn` function attribute via new `CURL_NORETURN` - macro. - - lib/mprintf: delete duplicate declaration for `Curl_dyn_vprintf`. - - lib/rand: fix `-Wunreachable-code` and related fallouts [3]. - - lib/setopt: fix `-Wunreachable-code-break`. - - lib/system_win32 and lib/timeval: fix double declarations for - `Curl_freq` and `Curl_isVistaOrGreater` in CMake UNITY mode [4]. - - lib/warnless: fix double declarations in CMake UNITY mode [5]. - This was due to force-disabling the header guard of `warnless.h` to - to reapply it to source code coming after `warnless.c` in UNITY - builds. This reapplied declarations too, causing the warnings. - Solved by adding a header guard for the lines that actually need - to be reapplied. - - lib/vauth/digest: fix `-Wunreachable-code-break` [6]. - - lib/vssh/libssh2: fix `-Wunreachable-code-break` and delete redundant - block. - - lib/vtls/sectransp: fix `-Wunreachable-code-break` [7]. - - lib/vtls/sectransp: suppress `-Wunreachable-code`. - Detected in `else` branches of dynamic feature checks, with results - known at compile-time, e.g. - ```c - if(SecCertificateCopySubjectSummary) /* -> true */ - ``` - Likely fixable as a separate micro-project, but given SecureTransport - is deprecated anyway, let's just silence these locally. - - src/tool_help: delete duplicate declaration for `helptext`. - - src/tool_xattr: fix `-Wunreachable-code`. - - tests: delete duplicate declaration for `unitfail` [8]. - - tests: delete duplicate declaration for `strncasecompare`. - - tests/libtest: delete duplicate declaration for `gethostname`. - Originally added in 687df5c8c39c370a59999b9afc0917d808d978b7 - (2010-08-02). - Got complicated later: c49e9683b85ba9d12cbb6eebc4ab2c8dba68fbdc - If there are still systems around with warnings, we may restore the - prototype, but limited for those systems. - - tests/lib2305: delete duplicate declaration for - `libtest_debug_config`. - - tests/h2-download: fix `-Wunreachable-code-break`. + To avoid a local hack to pass function pointers and to avoid + deprecation warnings when building with libssh2 v1.11.1 or newer: + ``` + lib/vssh/libssh2.c:3324:5: warning: 'libssh2_session_callback_set' is depreca + ted: since libssh2 1.11.1. Use libssh2_session_callback_set2() [-Wdeprecated- + declarations] + lib/vssh/libssh2.c:3326:5: warning: 'libssh2_session_callback_set' is depreca + ted: since libssh2 1.11.1. Use libssh2_session_callback_set2() [-Wdeprecated- + declarations] + ``` + Ref: https://github.com/curl/curl-for-win/actions/runs/7609484879/job/2072082 + 1100#step:3:4982 - [1] https://github.com/ngtcp2/nghttp3/blob/a70edb08e954d690e8fb2c1df999b5a056 - f8bf9f/cmake/PickyWarningsC.cmake - [2] https://ci.appveyor.com/project/curlorg/curl/builds/48553586/job/3qkgjaui - qla5fj45?fullLog=true#L1675 - [3] https://github.com/curl/curl/actions/runs/6880886309/job/18716044703?pr=1 - 2331#step:7:72 - https://github.com/curl/curl/actions/runs/6883016087/job/18722707368?pr=1 - 2331#step:7:109 - [4] https://ci.appveyor.com/project/curlorg/curl/builds/48555101/job/9g15qkrr - iklpf1ut#L204 - [5] https://ci.appveyor.com/project/curlorg/curl/builds/48555101/job/9g15qkrr - iklpf1ut#L218 - [6] https://github.com/curl/curl/actions/runs/6880886309/job/18716042927?pr=1 - 2331#step:7:290 - [7] https://github.com/curl/curl/actions/runs/6891484996/job/18746659406?pr=1 - 2331#step:9:1193 - [8] https://github.com/curl/curl/actions/runs/6882803986/job/18722082562?pr=1 - 2331#step:33:1870 + Ref: https://github.com/libssh2/libssh2/pull/1285 + Ref: https://github.com/libssh2/libssh2/commit/c0f69548be902147ce014ffa40b8db + 3cf1d4b0b4 + Reviewed-by: Daniel Stenberg + Closes #12754 - Closes #12331 +Daniel Stenberg (22 Jan 2024) -Daniel Stenberg (21 Nov 2023) +- transfer: make the select_bits_paused condition check both directions -- transfer: avoid unreachable expression + If there is activity in a direction that is not paused, return false. - If curl_off_t and size_t have the same size (which is common on modern - 64 bit systems), a condition cannot occur which Coverity pointed - out. Avoid the warning by having the code conditionally only used if - curl_off_t actually is larger. + Reported-by: Sergey Bronnikov + Bug: https://curl.se/mail/lib-2024-01/0049.html + Closes #12740 - Follow-up to 1cd2f0072fa482e25baa2 +Stefan Eissing (22 Jan 2024) - Closes #12370 +- http3: initial support for OpenSSL 3.2 QUIC stack -Stefan Eissing (21 Nov 2023) + - HTTP/3 for curl using OpenSSL's own QUIC stack together + with nghttp3 + - configure with `--with-openssl-quic` to enable curl to + build this. This requires the nghttp3 library + - implementation with the following restrictions: + * macOS has to use an unconnected UDP socket due to an + issue in OpenSSL's datagram implementation + See https://github.com/openssl/openssl/issues/23251 + This makes connections to non-reponsive servers hang. + * GET requests will send the indicator that they have + no body in a separate QUIC packet. This may result + in processing delays or Transfer-Encodings on proxied + requests + * uploads that encounter blocks will use 100% cpu as + detection of these flow control issue is not working + (we have not figured out to pry that from OpenSSL). -- transfer: readwrite improvements + Closes #12734 - - changed header/chunk/handler->readwrite prototypes to accept `buf`, - `blen` and a `pconsumed` pointer. They now get the buffer to work on - and report back how many bytes they consumed - - eliminated `k->str` in SingleRequest - - improved excess data handling to properly calculate with any body data - left in the headerb buffer - - eliminated `k->badheader` enum to only be a bool +Viktor Szakats (22 Jan 2024) - Closes #12283 +- cmake: fix `ENABLE_MANUAL` option -Daniel Stenberg (21 Nov 2023) + Fix the `ENABLE_MANUAL` option. Set it to default to `OFF`. -- RELEASE-NOTES: synced + Before this patch `ENABLE_MANUAL=ON` was a no-op, even though it was the + option designed to enable building and using the built-in curl manual. + (`USE_MANUAL=ON` option worked for this instead, by accident). -Jiří Hruška (21 Nov 2023) + Ref: https://github.com/curl/curl/pull/12730#issuecomment-1902572409 + Closes #12749 -- transfer: avoid calling the read callback again after EOF +Mohammadreza Hendiani (19 Jan 2024) - Regression since 7f43f3dc5994d01b12 (7.84.0) +- TODO: update broken link to ratelimit-headers draft - Bug: https://curl.se/mail/lib-2023-11/0017.html + Closes #12741 - Closes #12363 +Daniel Stenberg (19 Jan 2024) -Daniel Stenberg (21 Nov 2023) +- cmake: when USE_MANUAL=YES, build the curl.1 man page -- doh: provide better return code for responses w/o addresses + Fixes KNOWN_BUG 15.4 - Previously it was wrongly returning CURLE_OUT_OF_MEMORY when the - response did not contain any addresses. Now it more accurately returns - CURLE_COULDNT_RESOLVE_HOST. + Closes #12742 - Reported-by: lRoccoon on github +- cmdline-opts/write-out.d: remove spurious double quotes - Fixes #12365 - Closes #12366 +Stefan Eissing (19 Jan 2024) -Stefan Eissing (21 Nov 2023) +- rtsp: Convert assertion into debug log -- HTTP/2, HTTP/3: handle detach of onoing transfers + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65934 - - refs #12356 where a UAF is reported when closing a connection - with a stream whose easy handle was cleaned up already - - handle DETACH events same as DONE events in h2/h3 filters + - write excess bytes to the client where the standard excess bytes + checks will report any wrongness and fail the transfer - Fixes #12356 - Reported-by: Paweł Wegner - Closes #12364 + Fixes #12738 + Closes #12739 -Viktor Szakats (20 Nov 2023) +Daniel Stenberg (19 Jan 2024) -- autotools: stop setting `-std=gnu89` with `--enable-warnings` +- headers: remove assert from Curl_headers_push - Do not alter the C standard when building with `--enable-warnings` when - building with gcc. + The fuzzer managed to reach the function without a terminating CR or LF + so let's handle it normally. While there, remove the goto. - On one hand this alters warning results compared to a default build. - On the other, it may produce different binaries, which is unexpected. + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65839 - Also fix new warnings that appeared after removing `-std=gnu89`: + Closes #12721 - - include: fix public curl headers to use the correct printf mask for - `CURL_FORMAT_CURL_OFF_T` and `CURL_FORMAT_CURL_OFF_TU` with mingw-w64 - and Visual Studio 2013 and newer. This fixes the printf mask warnings - in examples and tests. E.g. [1] +- curl_easy_getinfo.3: remove the wrong time value count - - conncache: fix printf format string [2]. + It said "six" time values but they are eight by now. Remove the mention + of the amount. - - http2: fix potential null pointer dereference [3]. - (seen on Slackware with gcc 11.) + Closes #12727 - - libssh: fix printf format string in SFTP code [4]. - Also make MSVC builds compatible with old CRT versions. +Viktor Szakats (18 Jan 2024) - - libssh2: fix printf format string in SFTP code for MSVC. - Applying the same fix as for libssh above. +- mbedtls: fix `-Wnull-dereference` and `-Wredundant-decls` - - unit1395: fix `argument is null` and related issues [5]: - - stop calling `strcmp()` with NULL to avoid undefined behaviour. - - fix checking results if some of them were NULL. - - do not pass NULL to printf `%s`. + - Silence warning in mbedTLS v3.5.1 public headers: + ``` + ./mbedtls/_x64-linux-musl/usr/include/psa/crypto_extra.h:489:14: warning: r + edundant redeclaration of 'psa_set_key_domain_parameters' [-Wredundant-decls] + ./mbedtls/_x64-linux-musl/usr/include/psa/crypto_struct.h:354:14: note: pre + vious declaration of 'psa_set_key_domain_parameters' was here + ``` + Ref: https://github.com/libssh2/libssh2/commit/ecec68a2c13a9c63fe8c2dc457ae + 785a513e157c + Ref: https://github.com/libssh2/libssh2/pull/1226 - - ci: keep a build job with `-std=gnu89` to continue testing for - C89-compliance. We can apply this to other gcc jobs as needed. - Ref: b23ce2cee7329bbf425f18b49973b7a5f23dfcb4 (2022-09-23) #9542 + - Fix compiler warnings seen with gcc 9.2.0 + cmake unity: + ``` + ./curl/lib/vtls/mbedtls.c: In function 'mbedtls_bio_cf_read': + ./curl/lib/vtls/mbedtls.c:189:11: warning: null pointer dereference [-Wnull + -dereference] + 189 | nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &res + ult); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~ + ./curl/lib/vtls/mbedtls.c: In function 'mbedtls_bio_cf_write': + ./curl/lib/vtls/mbedtls.c:168:14: warning: null pointer dereference [-Wnull + -dereference] + 168 | nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, & + result); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~ + ``` - [1] https://dev.azure.com/daniel0244/curl/_build/results?buildId=18581&view=l - ogs&jobId=ccf9cc6d-2ef1-5cf2-2c09-30f0c14f923b - [2] https://github.com/curl/curl/actions/runs/6896854263/job/18763831142?pr=1 - 2346#step:6:67 - [3] https://github.com/curl/curl/actions/runs/6896854253/job/18763839238?pr=1 - 2346#step:30:214 - [4] https://github.com/curl/curl/actions/runs/6896854253/job/18763838007?pr=1 - 2346#step:29:895 - [5] https://github.com/curl/curl/actions/runs/6896854253/job/18763836775?pr=1 - 2346#step:33:1689 + - delete stray `#else`. - Closes #12346 + Closes #12720 -- autotools: fix/improve gcc and Apple clang version detection +Daniel Stenberg (17 Jan 2024) - - Before this patch we expected `n.n` `-dumpversion` output, but Ubuntu - may return `n-win32` (also with `-dumpfullversion`). Causing these - errors and failing to enable picky warnings: - ``` - ../configure: line 23845: test: : integer expression expected - ``` - Ref: https://github.com/libssh2/libssh2/actions/runs/6263453828/job/1700789 - 3718#step:5:143 +- docs: cleanup nroff format use - Fix that by stripping any dash-suffix and handling a dotless (major-only) - version number by assuming `.0` in that case. + - remove use of .BI for code snippet + - stop using .br, just do a blank line + - remove use of .PP + - remove use for .sp + - remove backslash in .IP + - use .IP instead of .TP - `9.3-posix`, `9.3-win32`, `6`, `9.3.0`, `11`, `11.2`, `11.2.0` - Ref: https://github.com/mamedev/mame/pull/9767 + Closes #12731 - - fix Apple clang version detection for releases between - 'Apple LLVM version 7.3.0' and 'Apple LLVM version 10.0.1' where the - version was under-detected as 3.7 llvm/clang equivalent. +Stefan Eissing (17 Jan 2024) - - fix Apple clang version detection for 'Apple clang version 11.0.0' - and newer where the Apple clang version was detected, instead of its - llvm/clang equivalent. +- test2307: fix expected failure code after ws refactoring - - display detected clang/gcc/icc compiler version. + Fixes #12722 + Closes #12728 - Via libssh2: - - https://github.com/libssh2/libssh2/commit/00a3b88c51cdb407fbbb347a2e38c5c7d - 89875ad - https://github.com/libssh2/libssh2/pull/1187 - - https://github.com/libssh2/libssh2/commit/89ccc83c7da73e7ca3a112e3500081319 - 42b592e - https://github.com/libssh2/libssh2/pull/1232 +Jay Satiro (17 Jan 2024) - Closes #12362 +- cf-socket: show errno in tcpkeepalive error messages -- autotools: delete LCC compiler support bits + - If the socket keepalive options (TCP_KEEPIDLE, etc) cannot be set + then show the errno in the verbose error messages. - Follow-up to fd7ef00f4305a2919e6950def1cf83d0110a4acd #12222 + Ref: https://github.com/curl/curl/discussions/12715#discussioncomment-8151652 - Closes #12357 + Closes https://github.com/curl/curl/pull/12726 -- cmake: add test for `DISABLE` options, add `CURL_DISABLE_HEADERS_API` +- tool_getparam: stop supporting `@filename` style for --cookie - - tests: verify CMake `DISABLE` options. + The `@filename` style was never documented for --cookie + but prior to this change curl would accept it anyway and always treat a + @ prefixed string as a filename. - Make an exception for 2 CMake-only ones, and one more that's - using a different naming scheme, also in autotools and source. + That's a problem if the string also contains a = sign because then it is + documented to be interpreted as a cookie string and not a filename. - - cmake: add support for `CURL_DISABLE_HEADERS_API`. + Example: - Suggested-by: Daniel Stenberg - Ref: https://github.com/curl/curl/pull/12345#pullrequestreview-1736238641 + `--cookie @foo=bar` - Closes #12353 + Before: Interpreted as load cookies from filename foo=bar. -Jacob Hoffman-Andrews (20 Nov 2023) + After: Interpreted as cookie `@foo=bar` (name `@foo` and value `bar`). -- hyper: temporarily remove HTTP/2 support + Other curl options with a data/filename option-value use the `@filename` + to distinguish filenames which is probably how this happened. The + --cookie option has never been documented that way. - The current design of the Hyper integration requires rebuilding the - Hyper clientconn for each request. However, building the clientconn - requires resending the HTTP/2 connection preface, which is incorrect - from a protocol perspective. That in turn causes servers to send GOAWAY - frames, effectively degrading performance to "no connection reuse" in - the best case. It may also be triggering some bugs where requests get - dropped entirely and reconnects take too long. + Ref: https://curl.se/docs/manpage.html#-b - This doesn't rule out HTTP/2 support with Hyper, but it may take a - redesign of the Hyper integration in order to make things work. + Closes https://github.com/curl/curl/pull/12645 - Closes #12191 +Stefan Eissing (16 Jan 2024) -Jay Satiro (20 Nov 2023) +- websockets: refactor decode chain -- schannel: fix unused variable warning + - use client writer stack for decoding frames + - move websocket protocol handler to ws.c - Bug: https://github.com/curl/curl/pull/12349#issuecomment-1818000846 - Reported-by: Viktor Szakats + Closes #12713 - Closes https://github.com/curl/curl/pull/12361 +- websockets: check for negative payload lengths -Daniel Stenberg (19 Nov 2023) + - in en- and decoding, check the websocket frame payload lengths for + negative values (from curl_off_t) and error the operation in that case + - add test 2307 to verify -- url: find scheme with a "perfect hash" + Closes #12707 - Instead of a loop to scan over the potentially 30+ scheme names, this - uses a "perfect hash" table. This works fine because the set of schemes - is known and cannot change in a build. The hash algorithm and table size - is made to only make a single scheme index per table entry. +Daniel Stenberg (16 Jan 2024) - The perfect hash is generated by a separate tool (scripts/schemetable.c) +- docs: mention env vars not used by schannel - Closes #12347 + Ref: #12704 -- scripts: add schemetable.c + Co-authored-by: Jay Satiro - This tool generates a scheme-matching table. + Closes #12711 - It iterates over a number of different initial and shift values in order - to find the hash algorithm that needs the smallest possible table. +- tool_operate: make --remove-on-error only remove "real" files - The generated hash function, table and table size then needs to be used - by the url.c:Curl_getn_scheme_handler() function. + Reported-by: Harry Sintonen + Assisted-by: Dan Fandrich -Stefan Eissing (19 Nov 2023) + Closes #12710 -- vtls/vquic, keep peer name information together +Jay Wu (16 Jan 2024) - - add `struct ssl_peer` to keep hostname, dispname and sni - for a filter - - allocate `sni` for use in VTLS backend - - eliminate `Curl_ssl_snihost()` and its use of the download buffer - - use ssl_peer in SSL and QUIC filters +- url: don't set default CA paths for Secure Transport backend - Closes #12349 + As the default for this backend is the native CA store. -Viktor Szakats (18 Nov 2023) + Closes #12704 -- build: always revert `#pragma GCC diagnostic` after use +Lin Sun (16 Jan 2024) - Before this patch some source files were overriding gcc warning options, - but without restoring them at the end of the file. In CMake UNITY builds - these options spilled over to the remainder of the source code, - effecitvely disabling them for a larger portion of the codebase than - intended. +- asyn-ares: with modern c-ares, use its default timeout - `#pragma clang diagnostic` didn't have such issue in the codebase. + Closes #12703 - Reviewed-by: Marcel Raad - Closes #12352 +Daniel Stenberg (15 Jan 2024) -- tidy-up: casing typos, delete unused Windows version aliases +- tool_operate: stop setting the file comment on Amiga - - cmake: fix casing of `UnixSockets` to match the rest of the codebase. + - the URL is capped at 80 cols, which ruins it if longer + - it does not strip off URL credentials + - it is done unconditonally, not on --xattr + - we don't have Amiga in the CI which makes fixing it blindly fragile - - curl-compilers.m4: fix casing in a comment. + Someone who builds and tests on Amiga can add it back correctly in a + future if there is a desire. - - setup-win32: delete unused Windows version constant aliases. + Reported-by: Harry Sintonen + Closes #12709 - Reviewed-by: Marcel Raad - Closes #12351 +Stefan Eissing (15 Jan 2024) -- keylog: disable if unused +- rtsp: deal with borked server responses - Fully disable keylog code if there is no TLS or QUIC subsystem using it. + - enforce a response body length of 0, if the + response has no Content-lenght. This is according + to the RTSP spec. + - excess bytes in a response body are forwarded to + the client writers which will report and fail the + transfer - Closes #12350 + Follow-up to d7b6ce6 + Fixes #12701 + Closes #12706 -- cmake: add `CURL_DISABLE_BINDLOCAL` option +Daniel Stenberg (14 Jan 2024) - To match similar autotools option. +- version: show only the libpsl version, not its dependencies - Default is `ON`. + The libpsl version output otherwise also includes version number for its + dependencies, like IDN lib, but since libcurl does not use libpsl's IDN + functionality those components are not important. - Reviewed-by: Daniel Stenberg - Closes #12345 + Ref: https://github.com/curl/curl-for-win/issues/63 + Closes #12700 -- url: fix `-Wzero-length-array` with no protocols +Brad Harder (14 Jan 2024) - Fixes: - ``` - ./lib/url.c:178:56: warning: use of an empty initializer is a C2x extension [ - -Wc2x-extensions] - 178 | static const struct Curl_handler * const protocols[] = { - | ^ - ./lib/url.c:178:56: warning: zero size arrays are an extension [-Wzero-length - -array] - ``` +- curl.h: CURLOPT_DNS_SERVERS is only available with c-ares - Closes #12344 + Closes #12695 -- url: fix builds with `CURL_DISABLE_HTTP` +Daniel Stenberg (14 Jan 2024) - Fixes: - ``` - ./lib/url.c:456:35: error: no member named 'formp' in 'struct UrlState' - 456 | Curl_mime_cleanpart(data->state.formp); - | ~~~~~~~~~~~ ^ - ``` +- cmdline-opts/gen.pl: error on initital blank line - Regression from 74b87a8af13a155c659227f5acfa78243a8b2aa6 #11682 + After the "---" separator, there should be no blank line and this script + now errors out if one is detected. - Closes #12343 + Ref: #12696 + Closes #12698 -- http: fix `-Wunused-parameter` with no auth and no proxy +- cf-h1-proxy: no CURLOPT_USERAGENT in CONNECT with hyper - ``` - lib/http.c:734:26: warning: unused parameter 'proxy' [-Wunused-parameter] - bool proxy) - ^ - ``` + Follow-up to 693cd1679361828a which was incomplete - Reviewed-by: Marcel Raad - Closes #12338 + Ref #12680 + Closes #12697 -Daniel Stenberg (16 Nov 2023) +- curl_multi_fdset.3: remove mention of null pointer support -- TODO: Some TLS options are not offered for HTTPS proxies + ... since this funtion has not supported null pointer fd_set arguments since + at least 2006. (That's when I stopped my git blame journey) - Closes #12286 - Closes #12342 + Fixes #12691 + Reported-by: sfan5 on github + Closes #12692 -- RELEASE-NOTES: synced +Mark Huang (14 Jan 2024) -- duphandle: make dupset() not return with pointers to old alloced data +- docs/cmdline: remove unnecessary line breaks - As the blob pointers are to be duplicated, the function must not return - mid-function with lingering pointers to the old handle's allocated data, - as that would lead to double-free in OOM situations. + Closes #12696 - Make sure to clear all destination pointers first to avoid this risk. +Daniel Stenberg (14 Jan 2024) - Closes #12337 +- transfer: remove warning: Value stored to 'blen' is never read -Viktor Szakats (16 Nov 2023) + Detected by scan-build -- http: fix `-Wunused-variable` compiler warning + Follow-up from 1cd2f0072f - Fix compiler warnings in builds with disabled auths, NTLM and SPNEGO. + Closes #12693 - E.g. with `CURL_DISABLE_BASIC_AUTH` + `CURL_DISABLE_BEARER_AUTH` + - `CURL_DISABLE_DIGEST_AUTH` + `CURL_DISABLE_NEGOTIATE_AUTH` + - `CURL_DISABLE_NTLM` on non-Windows. +Stefan Eissing (13 Jan 2024) + +- lib: replace readwrite with write_resp + + This clarifies the handling of server responses by folding the code for + the complicated protocols into their protocol handlers. This concerns + mainly HTTP and its bastard sibling RTSP. + The terms "read" and "write" are often used without clear context if + they refer to the connect or the client/application side of a + transfer. This PR uses "read/write" for operations on the client side + and "send/receive" for the connection, e.g. server side. If this is + considered useful, we can revisit renaming of further methods in another + PR. + + Curl's protocol handler `readwrite()` method been changed: + + ```diff + - CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn, + - const char *buf, size_t blen, + - size_t *pconsumed, bool *readmore); + + CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t ble + n, + + bool is_eos, bool *done); ``` - ./curl/lib/http.c:737:12: warning: unused variable 'result' [-Wunused-variabl - e] - CURLcode result = CURLE_OK; - ^ - ./curl/lib/http.c:995:18: warning: variable 'availp' set but not used [-Wunus - ed-but-set-variable] - unsigned long *availp; - ^ - ./curl/lib/http.c:996:16: warning: variable 'authp' set but not used [-Wunuse - d-but-set-variable] - struct auth *authp; - ^ + + The name was changed to clarify that this writes reponse data to the + client side. The parameter changes are: + + * `conn` removed as it always operates on `data->conn` + * `pconsumed` removed as the method needs to handle all data on success + * `readmore` removed as no longer necessary + * `is_eos` as indicator that this is the last call for the transfer + response (end-of-stream). + * `done` TRUE on return iff the transfer response is to be treated as + finished + + This change affects many files only because of updated comments in + handlers that provide no implementation. The real change is that the + HTTP protocol handlers now provide an implementation. + + The HTTP protocol handlers `write_resp()` implementation will get passed + **all** raw data of a server response for the transfer. The HTTP/1.x + formatted status and headers, as well as the undecoded response + body. `Curl_http_write_resp_hds()` is used internally to parse the + response headers and pass them on. This method is public as the RTSP + protocol handler also uses it. + + HTTP/1.1 "chunked" transport encoding is now part of the general + *content encoding* writer stack, just like other encodings. A new flag + `CLIENTWRITE_EOS` was added for the last client write. This allows + writers to verify that they are in a valid end state. The chunked + decoder will check if it indeed has seen the last chunk. + + The general response handling in `transfer.c:466` happens in function + `readwrite_data()`. This mainly operates now like: + + ``` + static CURLcode readwrite_data(data, ...) + { + do { + Curl_xfer_recv_resp(data, buf) + ... + Curl_xfer_write_resp(data, buf) + ... + } while(interested); + ... + } ``` - Regression from e92edfbef64448ef461117769881f3ed776dec4e #11490 + All the response data handling is implemented in + `Curl_xfer_write_resp()`. It calls the protocol handler's `write_resp()` + implementation if available, or does the default behaviour. - Fixes #12228 - Closes #12335 + All raw response data needs to pass through this function. Which also + means that anyone in possession of such data may call + `Curl_xfer_write_resp()`. -Jay Satiro (16 Nov 2023) + Closes #12480 -- tool: support bold headers in Windows +Daniel Stenberg (13 Jan 2024) - - If virtual terminal processing is enabled in Windows then use ANSI - escape codes Esc[1m and Esc[22m to turn bold on and off. +- RELEASE-NOTES: synced - Suggested-by: Gisle Vanem +- TODO: TFTP doesn't convert LF to CRLF for mode=netascii - Ref: https://github.com/curl/curl/discussions/11770 + Closes #12655 + Closes #12690 - Closes https://github.com/curl/curl/pull/12321 +- gen: do italics/bold for a range of letters, not just single word -Viktor Szakats (15 Nov 2023) + Previously it would match only on a sequence of non-space, which made it + miss to highlight for example "public suffix list". -- build: fix libssh2 + `CURL_DISABLE_DIGEST_AUTH` + `CURL_DISABLE_AWS` + Updated the recent cookie.d edit from 5da57193b732 to use bold instead + of italics. - Builds with libssh2 + `-DCURL_DISABLE_DIGEST_AUTH=ON` + - `-DCURL_DISABLE_AWS=ON` in combination with either Schannel on Windows, - or `-DCURL_DISABLE_NTLM=ON` on other operating systems failed while - compiling due to a missing HMAC declaration. + Closes #12689 - The reason is that HMAC is required by `lib/sha256.c` which publishes - `Curl_sha256it()` which is required by `lib/vssh/libssh2.c` when - building for libssh2 v1.8.2 (2019-05-25) or older. +- docs: describe and highlight super cookies - Make sure to compile the HMAC bits for a successful build. + Reported-by: Yadhu Krishna M - Both HMAC and `Curl_sha256it()` rely on the same internals, so splitting - them into separate sources isn't practical. + Closes #12687 - Fixes: - ``` - [...] - In file included from ./curl/_x64-win-ucrt-cmake-llvm-bld/lib/CMakeFiles/libc - url_object.dir/Unity/unity_0_c.c:310: - ./curl/lib/sha256.c:527:42: error: array has incomplete element type 'const s - truct HMAC_params' - 527 | const struct HMAC_params Curl_HMAC_SHA256[] = { - | ^ - ./curl/lib/curl_sha256.h:34:21: note: forward declaration of 'struct HMAC_par - ams' - [...] - ``` +- configure: when enabling QUIC, check that TLS supports QUIC - Regression from e92edfbef64448ef461117769881f3ed776dec4e #11490 + Most importantly perhaps is when using OpenSSL that the used + build/flavor has the QUIC API: the vanilla OpenSSL does not, only + BoringSSL, libressl, AWS-LC and quictls do. - Fixes #12273 - Closes #12332 + Ref: https://github.com/curl/curl/commit/5d044ad9480a9f556f4b6a252d7533b1ba7f + e57e#r136780413 -Daniel Stenberg (15 Nov 2023) + Closes #12683 -- duphandle: also free 'outcurl->cookies' in error path +Stefan Eissing (11 Jan 2024) - Fixes memory-leak when OOM mid-function +- vquic: extract TLS setup into own source - Use plain free instead of safefree, since the entire struct is - freed below. + - separate ngtcp2 specific parts out + - provide callback during init to allow ngtcp2 to apply its defaults - Remove some free calls that is already freed in Curl_freeset() + Closes #12678 - Closes #12329 +Sergey Markelov (11 Jan 2024) -Viktor Szakats (15 Nov 2023) +- multi: remove total timer reset in file_do() while fetching file:// -- config-win32: set `HAVE_SNPRINTF` for mingw-w64 + The total timer is properly reset in MSTATE_INIT. MSTATE_CONNECT starts + with resetting the timer that is a start point for further multi states. + If file://, MSTATE_DO calls file_do() that should not reset the total + timer. Otherwise, the total time is always less than the pre-transfer + and the start transfer times. - It's available in all mingw-w64 releases. We already pre-fill this - detection in CMake. + Closes #12682 - Closes #12325 +Daniel Stenberg (11 Jan 2024) -- sasl: fix `-Wunused-function` compiler warning +- http_proxy: a blank CURLOPT_USERAGENT should not be used in CONNECT - In builds with disabled auths. + Extended test 80 to verify this. - ``` - lib/curl_sasl.c:266:17: warning: unused function 'get_server_message' [-Wunus - ed-function] - static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data, - ^ - 1 warning generated. - ``` - Ref: https://github.com/curl/trurl/actions/runs/6871732122/job/18689066151#st - ep:3:3822 + Reported-by: Stefan Eissing + Fixes #12680 + Closes #12681 - Reviewed-by: Daniel Stenberg - Closes #12326 +- sectransp: do verify_cert without memdup for blobs -- build: picky warning updates + Since the information is then already stored in memory, this can avoid + an extra set of malloc + free calls. - - cmake: sync some picky gcc warnings with autotools. - - cmake, autotools: add `-Wold-style-definition` for clang too. - - cmake: more precise version info for old clang options. - - cmake: use `IN LISTS` syntax in `foreach()`. + Closes #12679 - Reviewed-by: Daniel Stenberg - Reviewed-by: Marcel Raad - Closes #12324 +- hsts: remove assert for zero length domain -Daniel Stenberg (15 Nov 2023) + A zero length domain can happen if the HSTS parser is given invalid + input data which is not unheard of and is done by the fuzzer. -- urldata: move cookielist from UserDefined to UrlState + Follow-up from cfe7902111ae547873 - 1. Because the value is not strictly set with a setopt option. + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65661 - 2. Because otherwise when duping a handle when all the set.* fields are - first copied and an error happens (think out of memory mid-function), - the function would easily free the list *before* it was deep-copied, - which could lead to a double-free. + Closes #12676 - Closes #12323 +- headers: make sure the trailing newline is not stored -Viktor Szakats (14 Nov 2023) + extended test1940 to verify blank header fields too -- autotools: avoid passing `LDFLAGS` twice to libcurl + Bug: https://curl.se/mail/lib-2024-01/0019.html + Reported-by: Dmitry Karpov + Closes #12675 - autotools passes `LDFLAGS` automatically linker commands. curl's - `lib/Makefile.am` customizes libcurl linker flags. In that - customization, it added `LDFLAGS` to the custom flags. This resulted in - passing `LDFLAGS` _twice_ to the `libtool` command. +- curl_easy_header.3: tiny language fix - Most of the time this is benign, but some `LDFLAGS` options can break - the build when passed twice. One such example is passing `.o` files, - e.g. `crt*.o` files necessary when customizing the C runtime, e.g. for - MUSL builds. + Closes #12672 - Passing them twice resulted in duplicate symbol errors: - ``` - libtool: link: clang-15 --target=aarch64-unknown-linux-musl [...] /usr/lib/a - arch64-linux-musl/crt1.o [...] /usr/lib/aarch64-linux-musl/crt1.o [...] - ld.lld-15: error: duplicate symbol: _start - >>> defined at crt1.c - >>> /usr/lib/aarch64-linux-musl/crt1.o:(.text+0x0) - >>> defined at crt1.c - >>> /usr/lib/aarch64-linux-musl/crt1.o:(.text+0x0) - [...] - clang: error: linker command failed with exit code 1 (use -v to see invocatio - n) - ``` +- examples/range.c: add - This behaviour came with commit 1a593191c2769a47b8c3e4d9715ec9f6dddf5e36 - (2013-07-23) as a fix for bug https://curl.haxx.se/bug/view.cgi?id=1217. - The patch was a works-for-me hack that ended up merged in curl: - https://sourceforge.net/p/curl/bugs/1217/#06ef - With the root cause remaining unclear. + Closes #12671 - Perhaps the SUNPro 12 linker was sensitive to `-L` `-l` order, requiring - `-L` first? This would be unusual and suggests a bug in either the - linker or in `libtool`. +- examples/netrc.c: add - The curl build does pass the list of detected libs via its own - `LIBCURL_LIBS` variable, which ends up before `LDFLAGS` on the `libtool` - command line, but it's the job of `libtool` to ensure that even - a peculiar linker gets the options in the expected order. Also because - autotools passes `LDFLAGS` last, making it hardly possible to pass - anything after it. + Closes #12671 - Perhaps in the 10 years since this issue, this already got a fix - upstream. +- examples/ipv6.c: new example showing IPv6-only internet transfer - This patch deletes `LDFLAGS` from our customized libcurl options, - leaving a single copy of them as passed by autotools automatically. + Closes #12671 - Reverts 1a593191c2769a47b8c3e4d9715ec9f6dddf5e36 - Closes #12310 +- examples/address-scope.c: renamed from ipv6.c -- autotools: accept linker flags via `CURL_LDFLAGS_{LIB,BIN}` + It shows address scope use really - To allow passing `LDFLAGS` specific to libcurl (`CURL_LDFLAGS_LIB`) and - curl tool (`CURL_LDFLAGS_BIN`). + Closes #12671 - This makes it possible to build libcurl and curl with a single - invocation with lib- and tool-specific custom linker flags. +Stefan Eissing (9 Jan 2024) - Such flag can be enabling `.map` files, a `.def` file for libcurl DLL, - controlling static/shared, incl. requesting a static curl tool (with - `-static-libtool-libs`) while building both shared and static libcurl. +- multi: pollset adjust, init with FIRSTSOCKET during connect - curl-for-win uses the above and some more. + - `conn->sockfd` is set by `Curl_setup_transfer()`, but that + is called *after* the connection has been established + - use `conn->sock[FIRSTSOCKET]` instead - These options are already supported in `Makefile.mk`. CMake has built-in - variables for this. + Follow-up to a0f94800d507de + Closes #12664 - Closes #12312 +Daniel Stenberg (9 Jan 2024) -Jay Satiro (14 Nov 2023) +- WEBSOCKET.md: remove dead link -- tool_cb_hdr: add an additional parsing check +- CI: spellcheck/appveyor: invoke configure --without-libpsl - - Don't dereference the past-the-end element when parsing the server's - Content-disposition header. + Follow-up to 2998874bb61ac6 - As 'p' is advanced it can point to the past-the-end element and prior - to this change 'p' could be dereferenced in that case. +- cmdline/docs/*.d: switch to using ## instead of .IP - Technically the past-the-end element is not out of bounds because dynbuf - (which manages the header line) automatically adds a null terminator to - every buffer and that is not included in the buffer length passed to - the header callback. + To make the editing easier. To write and to read. - Closes https://github.com/curl/curl/pull/12320 + Closes #12667 -Philip Heiduck (14 Nov 2023) +- gen.pl: support ## for doing .IP in table-like lists -- .cirrus.yml: freebsd 14 + Warn on use of .RS/.IP/.RE - ensure curl works on latest freebsd version + Closes #12667 - Closes #12053 +Jay Satiro (9 Jan 2024) -Daniel Stenberg (13 Nov 2023) +- cookie.d: Document use of empty string to enable cookie engine -- easy: in duphandle, init the cookies for the new handle + - Explain that --cookie "" can be used to enable the cookie engine + without reading any initial cookies. - ... not the source handle. + As is documented in CURLOPT_COOKIEFILE. - Closes #12318 + Ref: https://curl.se/libcurl/c/CURLOPT_COOKIEFILE.html -- duphandle: use strdup to clone *COPYPOSTFIELDS if size is not set + Bug: https://github.com/curl/curl/issues/12643#issuecomment-1879844420 + Reported-by: janko-js@users.noreply.github.com - Previously it would unconditionally use the size, which is set to -1 - when strlen is requested. + Closes https://github.com/curl/curl/pull/12646 - Updated test 544 to verify. +Daniel Stenberg (9 Jan 2024) - Closes #12317 +- setopt: use memdup0 when cloning COPYPOSTFIELDS -- RELEASE-NOTES: synced + Closes #12651 -- curl_easy_duphandle.3: clarify how HSTS and alt-svc are duped +- telnet: use dynbuf instad of malloc for escape buffer - Closes #12315 + Previously, send_telnet_data() would malloc + free a buffer every time + for escaping IAC codes. Now, it reuses a dynbuf for this purpose. -- urldata: move hstslist from 'set' to 'state' + Closes #12652 - To make it work properly with curl_easy_duphandle(). This, because - duphandle duplicates the entire 'UserDefined' struct by plain copy while - 'hstslist' is a linked curl_list of file names. This would lead to a - double-free when the second of the two involved easy handles were - closed. +- CI: install libpsl or configure --without-libpsl in builds - Closes #12315 + As a follow-up to the stricted libpsl check in configure -- test1900: verify duphandle with HSTS using multiple files +- configure: make libpsl detection failure cause error - Closes #12315 + To force users to explictily disable it if they really don't want it + used and make it harder to accidentally miss it. -Goro FUJI (13 Nov 2023) + --without-libpsl is the option to use if PSL is not wanted. -- http: allow longer HTTP/2 request method names + Closes #12661 - - Increase the maximum request method name length from 11 to 23. +- RELEASE-NOTES: synced - For HTTP/1.1 and earlier there's not a specific limit in libcurl for - method length except that it is limited by the initial HTTP request - limit (DYN_HTTP_REQUEST). Prior to fc2f1e54 HTTP/2 was treated the same - and there was no specific limit. +- pop3: replace calloc + memcpy with memdup0 - According to Internet Assigned Numbers Authority (IANA) the longest - registered method is UPDATEREDIRECTREF which is 17 characters. + ... and make sure to return error on out of memory. - Also there are unregistered methods used by some companies that are - longer than 11 characters. + Closes #12650 - The limit was originally added by 61f52a97 but not used until fc2f1e54. +- lib: add debug log outputs for CURLE_BAD_FUNCTION_ARGUMENT - Ref: https://www.iana.org/assignments/http-methods/http-methods.xhtml + Closes #12658 - Closes https://github.com/curl/curl/pull/12311 +- mime: use memdup0 instead of malloc + memcpy -Jay Satiro (12 Nov 2023) + Closes #12649 -- CURLOPT_CAINFO_BLOB.3: explain what CURL_BLOB_COPY does +- tool_getparam: move the --rate logic into set_rate() - - Add an explanation of the CURL_BLOB_COPY flag to CURLOPT_CAINFO_BLOB - and CURLOPT_PROXY_CAINFO_BLOB docs. +- tool_getparam: switch to an enum for every option - All the other _BLOB option docs already have the same explanation. + To make the big switch much easier to read/understand and to make it + easier to add new options. - Closes https://github.com/curl/curl/pull/12277 +- tool_getparam: build post data using dynbuf (more) -Viktor Szakats (11 Nov 2023) +- tool_getparam: replace malloc + copy by dynbuf for --data -- tidy-up: dedupe Windows system libs in cmake +- tool_getparam: make data_urlencode avoid direct malloc - Reviewed-by: Daniel Stenberg - Closes #12307 + use aprintf() instead -Junho Choi (11 Nov 2023) +- tool_getparam: move the --url-query logic into url_query() -- ci: test with latest quiche release (0.19.0) + This function is not doing post at all so it was always weirdly placed. - Closes #12180 +- tool_getparam: move the --data logic into set_data() -- quiche: use quiche_conn_peer_transport_params() +- tool_getparam: unify the cmdline switch() into a single one - In recent quiche, transport parameter API is separated - with quiche_conn_peer_transport_params(). - (https://github.com/cloudflare/quiche/pull/1575) - It breaks with bulding with latest(post 0.18.0) quiche. + - easier to follow, easier to modify, easier to extend, possibly slightly + faster - Closes #12180 + - each case now has the long option as a comment -Daniel Stenberg (11 Nov 2023) +- tool_getparam: bsearch cmdline options -- Makefile: generate the VC 14.20 project files at dist-time + - the option names are now alpha sorted and lookup is a lot faster - Follow-up to 28287092cc5a6d6ef8 (#12282) + - use case sensitive matching. It was previously case insensitive, but that + was not documented nor tested. - Closes #12290 + - remove "partial match" feature. It was not documented, not tested and + was always fragile as existing use could break when we add a new + option -Sam James (11 Nov 2023) + - lookup short options via a table -- misc: fix -Walloc-size warnings + Closes #12631 - GCC 14 introduces a new -Walloc-size included in -Wextra which gives: +Gabe (8 Jan 2024) - ``` - src/tool_operate.c: In function ‘add_per_transfer’: - src/tool_operate.c:213:5: warning: allocation of insufficient size ‘1’ fo - r type ‘struct per_transfer’ with size ‘480’ [-Walloc-size] - 213 | p = calloc(sizeof(struct per_transfer), 1); - | ^ - src/var.c: In function ‘addvariable’: - src/var.c:361:5: warning: allocation of insufficient size ‘1’ for type - struct var’ with size ‘32’ [-Walloc-size] - 361 | p = calloc(sizeof(struct var), 1); - | ^ - ``` +- COPYING: update copyright year - The calloc prototype is: - ``` - void *calloc(size_t nmemb, size_t size); - ``` + Closes #12654 - So, just swap the number of members and size arguments to match the - prototype, as we're initialising 1 struct of size `sizeof(struct - ...)`. GCC then sees we're not doing anything wrong. +Stefan Eissing (8 Jan 2024) - Closes #12292 +- url: init conn->sockfd and writesockfd to CURL_SOCKET_BAD -Mark Gaiser (11 Nov 2023) + Also add more tracing to test 19 -- IPFS: bugfixes + Follow-up to a0f9480 - - Fixed endianness bug in gateway file parsing - - Use IPFS_PATH in tests where IPFS_DATA was used - - Fixed typos from traling -> trailing - - Fixed broken link in IPFS.md + Fixes #12657 + Closes #12659 - Follow-up to 859e88f6533f9e +Daniel Stenberg (8 Jan 2024) - Reported-by: Michael Kaufmann - Bug: https://github.com/curl/curl/pull/12152#issuecomment-1798214137 - Closes #12305 +- connect: remove margin from eyeballer alloc -Daniel Stenberg (11 Nov 2023) + Presumably leftovers from debugging -- VULN-DISCLOSURE-POLIC: remove broken link to hackerone + Closes #12647 - It should ideally soon not be done from hackerone anyway +- ftp: only consider entry path if it has a length - Closes #12308 + Follow-up from 8edcfedc1a144f438bd1cdf814a0016cb -Andrew Kurushin (11 Nov 2023) + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65631 -- schannel: add CA cache support for files and memory blobs + Avoids a NULL pointer deref. - - Support CA bundle and blob caching. + Closes #12648 - Cache timeout is 24 hours or can be set via CURLOPT_CA_CACHE_TIMEOUT. +Stefan Eissing (7 Jan 2024) - Closes https://github.com/curl/curl/pull/12261 +- transfer: adjust_pollset improvements -Daniel Stenberg (10 Nov 2023) + - let `multi_getsock()` initialize the pollset in what the + transfer state requires in regards to SEND/RECV + - change connection filters `adjust_pollset()` implementation + to react on the presence of POLLIN/-OUT in the pollset and + no longer check CURL_WANT_SEND/CURL_WANT_RECV + - cf-socket will no longer add POLLIN on its own + - http2 and http/3 filters will only do adjustments if the + passed pollset wants to POLLIN/OUT for the transfer on + the socket. This is similar to the HTTP/2 proxy filter + and works in stacked filters. -- RELEASE-NOTES: synced + Closes #12640 -Charlie C (10 Nov 2023) +Daniel Stenberg (6 Jan 2024) -- cmake: option to disable install & drop `curlu` target when unused +- ftp: use memdup0 to store the OS from a SYST 215 response - This patch makes the following changes: - - adds the option `CURL_DISABLE_INSTALL` - to disable 'install' targets. - - Removes the target `curlu` when the option `BUILD_TESTING` is set to - `OFF` - to prevent it from being loaded in Visual Studio. + avoid malloc + direct buffer fiddle - Closes #12287 + Closes #12639 -Kai Pastor (10 Nov 2023) +- ftp: use dynbuf to store entrypath -- cmake: fix multiple include of CURL package + avoid direct malloc - Fixes errors on second `find_package(CURL)`. This is a frequent case - with transitive dependencies: - ``` - CMake Error at ...: - add_library cannot create ALIAS target "CURL::libcurl" because another - target with the same name already exists. - ``` + Closes #12638 - Test to reproduce: - ```cmake - cmake_minimum_required(VERSION 3.27) # must be 3.18 or higher +Lealem Amedie (6 Jan 2024) - project(curl) +- wolfssl: load certificate *chain* for PEM client certs - set(CURL_DIR "example/lib/cmake/CURL/") - find_package(CURL CONFIG REQUIRED) - find_package(CURL CONFIG REQUIRED) # fails + Closes #12634 - add_executable(main main.c) - target_link_libraries(main CURL::libcurl) - ``` +Stefan Eissing (4 Jan 2024) - Ref: https://cmake.org/cmake/help/latest/release/3.18.html#other-changes - Ref: https://cmake.org/cmake/help/v3.18/policy/CMP0107.html - Ref: #12300 - Assisted-by: Harry Mallon - Closes #11913 +- http: adjust_pollset fix -Viktor Szakats (8 Nov 2023) + do not add a socket for POLLIN when the transfer does not want to send + (for example is paused). -- tidy-up: use `OPENSSL_VERSION_NUMBER` + Follow-up to 47f5b1a - Uniformly use `OPENSSL_VERSION_NUMBER` to check for OpenSSL version. - Before this patch some places used `OPENSSL_VERSION_MAJOR`. - - Also fix `lib/md4.c`, which included `opensslconf.h`, but that doesn't - define any version number in these implementations: BoringSSL, AWS-LC, - LibreSSL, wolfSSL. (Only in mainline OpenSSL/quictls). Switch that to - `opensslv.h`. This wasn't causing a deeper problem because the code is - looking for v3, which is only provided by OpenSSL/quictls as of now. - - According to https://github.com/openssl/openssl/issues/17517, the macro - `OPENSSL_VERSION_NUMBER` is safe to use and not deprecated. + Reported-by: bubbleguuum on github + Fixes #12632 + Closes #12633 - Reviewed-by: Marcel Raad - Closes #12298 +Daniel Stenberg (3 Jan 2024) -Daniel Stenberg (8 Nov 2023) +- tool: make parser reject blank arguments if not supported -- resolve.d: drop a multi use-sentence + Already in the getstr() function that clones the input argument. - Since the `multi:` keyword adds that message. + Closes #12620 - Reported-by: 積丹尼 Dan Jacobson - Fixes https://github.com/curl/curl/discussions/12294 - Closes #12295 +dependabot[bot] (3 Jan 2024) -- content_encoding: make Curl_all_content_encodings allocless +- build(deps): bump github/codeql-action from 2 to 3 - - Fixes a memory leak pointed out by Coverity - - Also found by OSS-Fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail? - id=63947 - - Avoids unncessary allocations + Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 + to 3. + - [Release notes](https://github.com/github/codeql-action/releases) + - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) + - [Commits](https://github.com/github/codeql-action/compare/v2...v3) - Follow-up ad051e1cbec68b2456a22661b + --- + updated-dependencies: + - dependency-name: github/codeql-action + dependency-type: direct:production + update-type: version-update:semver-major + ... - Closes #12289 + Signed-off-by: dependabot[bot] -Michael Kaufmann (7 Nov 2023) + Closes #12625 -- vtls: use ALPN "http/1.1" for HTTP/1.x, including HTTP/1.0 +- build(deps): bump actions/checkout from 3 to 4 - Some servers don't support the ALPN protocol "http/1.0" (e.g. IIS 10), - avoid it and use "http/1.1" instead. + Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. + - [Release notes](https://github.com/actions/checkout/releases) + - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) + - [Commits](https://github.com/actions/checkout/compare/v3...v4) - This reverts commit df856cb5c9 (#10183). + --- + updated-dependencies: + - dependency-name: actions/checkout + dependency-type: direct:production + update-type: version-update:semver-major + ... - Fixes #12259 - Closes #12285 + Signed-off-by: dependabot[bot] -Daniel Stenberg (7 Nov 2023) + Closes #12624 -- Makefile.am: drop vc10, vc11 and vc12 projects from dist +- build(deps): bump actions/upload-artifact from 3 to 4 - They are end of life products. Support for generating them remain in the - repo for a while but this change drops them from distribution. + Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) f + rom 3 to 4. + - [Release notes](https://github.com/actions/upload-artifact/releases) + - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) - Closes #12288 + --- + updated-dependencies: + - dependency-name: actions/upload-artifact + dependency-type: direct:production + update-type: version-update:semver-major + ... -David Suter (7 Nov 2023) + Signed-off-by: dependabot[bot] -- projects: add VC14.20 project files + Closes #12627 - Windows projects included VC14, VC14.10, VC14.30 but not VC14.20. - OpenSSL and Wolf SSL scripts mention VC14.20 so I don't see a reason why - this is missing. Updated the templates to produce a VC14.20 project. - Project opens in Visual Studio 2019 as expected. +- build(deps): bump actions/download-artifact from 3 to 4 - Closes #12282 + Bumps [actions/download-artifact](https://github.com/actions/download-artifac + t) from 3 to 4. + - [Release notes](https://github.com/actions/download-artifact/releases) + - [Commits](https://github.com/actions/download-artifact/compare/v3...v4) -Daniel Stenberg (7 Nov 2023) + --- + updated-dependencies: + - dependency-name: actions/download-artifact + dependency-type: direct:production + update-type: version-update:semver-major + ... -- curl: move IPFS code into src/tool_ipfs.[ch] + Signed-off-by: dependabot[bot] - - convert ensure_trailing into ensure_trailing_slash - - strdup the URL string to own it proper - - use shorter variable names - - combine some expressions - - simplify error handling in ipfs_gateway() - - add MAX_GATEWAY_URL_LEN + proper bailout if maximum is reached - - ipfs-gateway.d polish and simplification - - shorten ipfs error message + make them "synthetic" + Closes #12626 - Closes #12281 +Stefan Eissing (3 Jan 2024) -Viktor Szakats (6 Nov 2023) +- http3/quiche: fix result code on a stream reset -- build: delete support bits for obsolete Windows compilers + - fixes pytest failures in test 07_22 + - aligns CURLcode values on stream reset with ngtcp2 - - Pelles C: Unclear status, failed to obtain a fresh copy a few months - ago. Possible website is HTTP-only. ~10 years ago I left this compiler - dealing with crashes and other issues with no response on the forum - for years. It has seen some activity in curl back in 2021. - - LCC: Last stable release in September 2002. - - Salford C: Misses winsock2 support, possibly abandoned? Last mentioned - in 2006. - - Borland C++: We dropped Borland C++ support in 2018. - - MS Visual C++ 6.0: Released in 1998. curl already requires VS 2010 - (or possibly 2008) as a minimum. + Closes #12629 - Closes #12222 +Daniel Stenberg (2 Jan 2024) -- build: delete `HAVE_STDINT_H` and `HAVE_INTTYPES_H` +- setopt: clear mimepost when formp is freed - We use `stdint.h` unconditionally in all places except one. These uses - are imposed by external dependencies / features. nghttp2, quic, wolfSSL - and `HAVE_MACH_ABSOLUTE_TIME` do require this C99 header. It means that - any of these features make curl require a C99 compiler. (In case of - MSVC, this means Visual Studio 2010 or newer.) + A precaution to avoid a possibly dangling pointer left behind. - This patch changes the single use of `stdint.h` guarded by - `HAVE_STDINT_H` to use `stdint.h` unconditionally. Also stop using - `inttypes.h` as an alternative there. `HAVE_INTTYPES_H` wasn't used - anywhere else, allowing to delete this feature check as well. + Reported-by: Thomas Ferguson + Fixes #12608 + Closes #12621 - Closes #12275 +Andy Alt (2 Jan 2024) -Daniel Stenberg (6 Nov 2023) +- CI: Add dependabot.yml -- tool_operate: do not mix memory models + This will cause dependabot to open a PR when various actions are + updated, provided that the action maintainer has issued a release. - Make sure 'inputpath' only points to memory allocated by libcurl so that - curl_free works correctly. + Closes #12623 - Pointed out by Coverity +Gisle Vanem (2 Jan 2024) - Follow-up to 859e88f6533f9e1f890 +- content_encoding: change return code to typedef'ed enum - Closes #12280 + ... to work around a clang ubsan warning. -Stefan Eissing (6 Nov 2023) + Fixes #12618 + Closes #12622 -- lib: client writer, part 2, accounting + logging +Daniel Stenberg (2 Jan 2024) - This PR has these changes: +- tool: prepend output_dir in header callback - Renaming of unencode_* to cwriter, e.g. client writers - - documentation of sendf.h functions - - move max decode stack checks back to content_encoding.c - - define writer phase which was used as order before - - introduce phases for monitoring inbetween decode phases - - offering default implementations for init/write/close + When Content-Disposition parsing is used and an output dir is prepended, + make sure to store that new file name correctly so that it can be used + for setting the file timestamp when --remote-time is used. - Add type paramter to client writer's do_write() - - always pass all writes through the writer stack - - writers who only care about BODY data will pass other writes unchanged + Extended test 3012 to verify. - add RAW and PROTOCOL client writers - - RAW used for Curl_debug() logging of CURLINFO_DATA_IN - - PROTOCOL used for updates to data->req.bytecount, max_filesize checks and - Curl_pgrsSetDownloadCounter() - - remove all updates of data->req.bytecount and calls to - Curl_pgrsSetDownloadCounter() and Curl_debug() from other code - - adjust test457 expected output to no longer see the excess write + Co-Authored-by: Jay Satiro + Reported-by: hgdagon on github + Fixes #12614 + Closes #12617 - Closes #12184 +- test1254: fix typo in name plus shorten it -Daniel Stenberg (6 Nov 2023) +- RELEASE-NOTES: synced -- VULN-DISCLOSURE-POLICY: escape sequences are not a security flaw +Viktor Szakats (2 Jan 2024) - Closes #12278 +- schannel: fix `-Warith-conversion` gcc 13 warning -Viktor Szakats (6 Nov 2023) + ``` + lib/vtls/schannel.c:1201:22: warning: conversion to 'unsigned int' from 'int' + may change the sign of the result [-Warith-conversion] + 1201 | *extension_len = *list_len + + | ^ + ``` -- rand: fix build error with autotools + LibreSSL + Closes #12616 - autotools unexpectedly detects `arc4random` because it is also looking - into dependency libs. One dependency, LibreSSL, happens to publish an - `arc4random` function (via its shared lib before v3.7, also via static - lib as of v3.8.2). When trying to use this function in `lib/rand.c`, - its protoype is missing. To fix that, curl included a prototype, but - that used a C99 type without including `stdint.h`, causing: +- asyn-thread: silence `-Wcast-align` warning for Windows + Seen with llvm/clang 17: ``` - ../../lib/rand.c:37:1: error: unknown type name 'uint32_t' - 37 | uint32_t arc4random(void); - | ^ - 1 error generated. + lib/asyn-thread.c:310:5: warning: cast from 'PCHAR' (aka 'char *') to 'struct + thread_sync_data *' increases required alignment from 1 to 8 [-Wcast-align] + 310 | CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlap + ped); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~ + .../llvm-mingw/aarch64-w64-mingw32/include/winnt.h:717:48: note: expanded fro + m macro 'CONTAINING_RECORD' + 717 | #define CONTAINING_RECORD(address,type,field) ((type *)((PCHAR)(addre + ss) - (ULONG_PTR)(&((type *)0)->field))) + | ^~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` - This patch improves this by dropping the local prototype and instead - limiting `arc4random` use for non-OpenSSL builds. OpenSSL builds provide - their own random source anyway. + Follow-up to a6bbc87f9e9ffb46a1801dfb983e7534825ed56b #12482 - The better fix would be to teach autotools to not link dependency libs - while detecting `arc4random`. + Ref: https://github.com/curl/curl/pull/12482#issuecomment-1873017261 + Closes #12615 - LibreSSL publishing a non-namespaced `arc4random` tracked here: - https://github.com/libressl/portable/issues/928 +Daniel Stenberg (2 Jan 2024) - Regression from 755ddbe901cd0c921fbc3ac5b3775c0dc683bc73 #10672 +- tool_listhelp: regenerate after recent .d updates - Reviewed-by: Daniel Stenberg - Fixes #12257 - Closes #12274 + Makes it survive test 1478 -Daniel Stenberg (5 Nov 2023) + Closes #12612 -- RELEASE-NOTES: synced +- test1478: verify src/tool_listhelp.c -- strdup: do Curl_strndup without strncpy + Verify that the source file on disk is identical to the output of gen.pl + listhelp, as otherwise they are out of sync and need attention. - To avoid (false positive) gcc-13 compiler warnings. + Closes #12612 - Follow-up to 4855debd8a2c1cb +- testutil: make runtests support %include - Assisted-by: Jay Satiro - Reported-by: Viktor Szakats - Fixes #12258 + Using this instruction, a test case can include the contents of a file + into the test during the preprocessing. -Enno Boland (5 Nov 2023) + Closes #12612 -- HTTP: fix empty-body warning +- runtests: for mode="text" on , fix newlines on both parts - This change fixes a compiler warning with gcc-12.2.0 when - `-DCURL_DISABLE_BEARER_AUTH=ON` is used. + Closes #12612 - /home/tox/src/curl/lib/http.c: In function 'Curl_http_input_auth': - /home/tox/src/curl/lib/http.c:1147:12: warning: suggest braces around emp - ty body in an 'else' statement [-Wempty-body] - 1147 | ; - | ^ +Jay Satiro (2 Jan 2024) - Closes #12262 +- quiche: return CURLE_HTTP3 on send to invalid stream -Daniel Stenberg (5 Nov 2023) + Prior to this change if a send failed on a stream in an invalid state + (according to quiche) and not marked as closed (according to libcurl) + then the send function would return CURLE_SEND_ERROR. -- openssl: identify the "quictls" backend correctly + We already have similar code for ngtcp2 to return CURLE_HTTP3 in this + case. - Since vanilla OpenSSL does not support the QUIC API I think it helps - users to identify the correct OpenSSL fork in version output. The best - (crude) way to do that right now seems to be to check if ngtcp2 support - is enabled. + Caught by test test_07_upload.py: test_07_22_upload_parallel_fail. - Closes #12270 + Fixes https://github.com/curl/curl/issues/12590 + Closes https://github.com/curl/curl/pull/12597 -Mark Gaiser (5 Nov 2023) +Daniel Stenberg (1 Jan 2024) -- curl: improved IPFS and IPNS URL support +- cmdline-opts: update availability for the *-ca-native options - Previously just ipfs:// and ipns:// was supported, which is - too strict for some usecases. + Closes #12613 - This patch allows paths and query arguments to be used too. - Making this work according to normal http semantics: +Patrick Monnerat (31 Dec 2023) - ipfs:///foo/bar?key=val - ipns:///foo/bar?key=val +- openldap: fix STARTTLS - The gateway url support is changed. - It now only supports gateways in the form of: + It was not working anymore since introduction of connection filters. - http:///foo/bar - http:// + Also do not attempt to recover from a failing TLS negotiation with + CURLUSESSL_TRY. - Query arguments here are explicitly not allowed and trigger an intended - malformed url error. + Closes #12610 - There also was a crash when IPFS_PATH was set with a non trailing - forward slash. This has been fixed. +Daniel Stenberg (31 Dec 2023) - Lastly, a load of test cases have been added to verify the above. +- haproxy-clientip.d: document the arg - Reported-by: Steven Allen - Fixes #12148 - Closes #12152 + The arg keyword was missing and therefore not present in the man page. -Harry Mallon (5 Nov 2023) + Closes #12611 -- docs: KNOWN_BUGS cleanup +annalee (29 Dec 2023) - * Remove other mention of hyper memory-leaks from `KNOWN_BUGS`. - Should have been removed in 629723ecf22a8eae78d64cceec2f3bdae703ec95 +- configure: fix no default int compile error in ipv6 detection - * Remove mention of aws-sigv4 sort query string from `KNOWN_BUGS`. - Fixed in #11806 + Closes #12607 - * Remove mention of aws-sigv4 query empty value problems +Dan Fandrich (28 Dec 2023) - * Remove mention of aws-sigv4 missing amz-content-sha256 - Fixed in #9995 +- CI: Fix use of any-glob-to-all-files in the labeler -- http_aws_sigv4: canonicalise valueless query params + Despite its name, this atom acts like one-glob-to-all-files and a + different syntax with braces must be used to get + any-glob-to-all-files semantics. Unfortunately, this makes the file + completely unreadable. - Fixes #8107 - Closes #12244 + Ref: https://github.com/actions/labeler/issues/731 -Michael Kaufmann (4 Nov 2023) +Daniel Stenberg (29 Dec 2023) -- docs: preserve the modification date when copying the prebuilt man page +- CURLOPT_AUTOREFERER.3: mention CURLINFO_REFERER - The previously built man page "curl.1" must be copied with the original - modification date, otherwise the man page is never updated. +- CURLINFO_REFERER.3: clarify that it is the *request* header - This fixes a bug that has been introduced with commit 2568441cab. + That libcurl itself sent in the most recent request - Reviewed-by: Dan Fandrich - Reviewed-by: Daniel Stenberg + Closes #12605 - Closes #12199 +Jay Satiro (28 Dec 2023) -Daniel Stenberg (4 Nov 2023) +- system_win32: fix a function pointer assignment warning -- docs: remove bold from some man page SYNOPSIS sections + - Use CURLX_FUNCTION_CAST to suppress a function pointer assignment + warning. - In the name of consistency + a6bbc87f added lookups of some Windows API functions and then cast them + like `*(FARPROC*)&Curl_funcname = address`. Some versions of gcc warn + about that as breaking strict-aliasing rules so this PR changes those + assignments to use CURLX_FUNCTION_CAST. - Closes #12267 + Bug: https://github.com/curl/curl/pull/12581#issuecomment-1869804317 + Reported-by: Marcel Raad -- openssl: two multi pointer checks should probably rather be asserts + Closes https://github.com/curl/curl/pull/12602 - ... so add the asserts now and consider removing the dynamic checks in a - future. +- verify-examples.pl: fail verification on unescaped backslash - Ref: #12261 - Closes #12264 + - Check that all backslashes in EXAMPLE are properly escaped. -boilingoden (4 Nov 2023) + eg manpage must always use `\\n` never `\n`. -- docs: add supported version for the json write-out + This is because the manpage requires we always double blackslash to show + a single backslash. Prior to this change an erroneous single backslash + would pass through and compile even though it would not show correctly + in the manpage. - xref: https://curl.se/changes.html#7_70_0 + Co-authored-by: Daniel Stenberg - Closes #12266 + Ref: https://github.com/curl/curl/pull/12588 -Viktor Szakats (3 Nov 2023) + Closes https://github.com/curl/curl/pull/12589 -- appveyor: make VS2008-built curl tool runnable +- vtls: fix missing multissl version info - By linking the CRT statically. This avoids the error about missing - runtime DLL `MSVCR90.dll` when running the freshly built `curl.exe`. + - Fix erroneous buffer copy logic from ff74cef5. - Closes #12263 + Prior to this change the MultiSSL version info returned to the user + was empty. -Stefan Eissing (3 Nov 2023) + Closes https://github.com/curl/curl/pull/12599 -- url: proxy ssl connection reuse fix +Daniel Stenberg (27 Dec 2023) - - 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 +- KNOWN_BUGS: [RTSP] Some methods do not support response bodies - Closes #12255 + Closes #12414 -Jay Satiro (3 Nov 2023) +Patrick Monnerat (27 Dec 2023) -- curl_sspi: support more revocation error names in error messages +- openldap: fix an LDAP crash - - 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. + Reported-by: Ozan Cansel + Fixes #12593 + Closes #12600 - Prior to this change those error codes were not matched to their macro - name and instead shown as "unknown error". +Daniel Stenberg (27 Dec 2023) - Before: +- getinfo: CURLINFO_QUEUE_TIME_T - schannel: next InitializeSecurityContext failed: - Unknown error (0x80092013) - The revocation function was - unable to check revocation because the revocation server was offline. + Returns the time, in microseconds, during which this transfer was held + in a waiting queue before it started "for real". A transfer might be put + in a queue if after getting started, it cannot create a new connection + etc due to set conditions and limits imposed by the application. - After: + Ref: #12293 + Closes #12368 - schannel: next InitializeSecurityContext failed: - CRYPT_E_REVOCATION_OFFLINE (0x80092013) - The revocation function was - unable to check revocation because the revocation server was offline. +- RELEASE-NOTES: synced - Bug: https://github.com/curl/curl/issues/12239 - Reported-by: Niracler Li +Jay Satiro (26 Dec 2023) - Closes https://github.com/curl/curl/pull/12241 +- examples/sendrecv: fix comment line length -- strdup: don't allow Curl_strndup to read past a null terminator + Caught by checksrc. - - Use malloc + strncpy instead of Curl_memdup to dupe the string before - null terminating it. +Haydar Alaidrus (23 Dec 2023) - Prior to this change if Curl_strndup was passed a length longer than - the allocated string then it could copy out of bounds. +- CURLOPT_POSTFIELDS.3: fix incorrect C string escape in example - 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. + - Escape inner quotes with two backslashes. - Follow-up to d3b3ba35. + Two backslashes escapes the backslash for the man page and will show as + a single backslash. - Closes https://github.com/curl/curl/pull/12254 + eg: "{\\"name\\": \\"daniel\\"}" shows as "{\"name\": \"daniel\"}". -Daniel Stenberg (2 Nov 2023) + Closes https://github.com/curl/curl/pull/12588 -- lib: add and use Curl_strndup() +Viktor Szakats (23 Dec 2023) - The Curl_strndup() function is similar to memdup(), but copies 'n' bytes - then adds a terminating null byte ('\0'). +- appveyor: tidy-ups - Closes #12251 + - replace two remaining backslashes with forward slashes. + - tidy up the way we form and pass `TFLAGS`. -- CURPOST_POSTFIELDS.3: add CURLOPT_COPYPOSTFIELDS in SEE ALSO + Follow-up to 2d4d0c1fd32f5cc3f946c407c8eccd5477b287df #12572 -Stefan Eissing (2 Nov 2023) + Closes #12582 -- pytest: use lower count in repeat tests +Stefan Eissing (22 Dec 2023) - - lower large iteration counts in some tests somewhat for - the same coverage with less duration +- transfer: fix upload rate limiting, add test cases - Closes #12248 + - add test cases for rate limiting uploads for all + http versions + - fix transfer loop handling of limits. Signal a re-receive + attempt only on exhausting maxloops without an EAGAIN + - fix `data->state.selectbits` forcing re-receive to also + set re-sending when transfer is doing this. -Daniel Stenberg (2 Nov 2023) + Reported-by: Karthikdasari0423 on github + Fixes #12559 + Closes #12586 -- RELEASE-NOTES: synced +Daniel Stenberg (22 Dec 2023) -- docs: clarify that curl passes on input unfiltered +- mbedtls: free the entropy when threaded - ... for several options. + The entropy_free was never done for threaded builds, causing a small + (fixed) memory leak. - Reported-by: Ophir Lojkine + Reported-by: RevaliQaQ on github + Fixes #12584 + Closes #12585 - Closes #12249 +Stefan Eissing (22 Dec 2023) -- urlapi: when URL encoding the fragment, pass in the right length +- http2: improved on_stream_close/data_done handling - A benign bug because it would only add an extra null terminator. + - there seems to be a code path that cleans up easy handles without + triggering DONE or DETACH events to the connection filters. This + would explain wh nghttp2 still holds stream user data + - add GOOD check to easy handle used in on_close_callback to + prevent crashes, ASSERTs in debug builds. + - NULL the stream user data early before submitting RST + - add checks in on_stream_close() to identify UNGOOD easy handles - Made lib1560 get a test that runs this code. + Reported-by: Hans-Christian Egtvedt + Fixes #10936 + Closes #12562 - Closes #12250 +Daniel Stenberg (22 Dec 2023) -Stefan Eissing (2 Nov 2023) +- mprintf: overhaul and bugfixes -- vtls: late clone of connection ssl config + In a test case using lots of snprintf() calls using many commonly used + %-codes per call, this version is around 30% faster than previous + version. - - perform connection cache matching against `data->set.ssl.primary` - and proxy counterpart - - fully clone connection ssl config only when connection is used + It also fixes the #12561 bug which made it not behave correctly when + given unknown %-sequences. Fixing that flaw required a different take on + the problem, which resulted in the new two-arrays model. - Closes #12237 + lib557: extended - Verify the #12561 fix and test more printf features -- msh3: error when built with CURL_DISABLE_SOCKETPAIR set + unit1398: fix test: It used a $ only for one argument, which is not + supported. - Reported-by: Gisle Vanem - Closes #12252 - Fixes #12213 + Fixes #12561 + Closes #12563 -Daniel Stenberg (2 Nov 2023) +Viktor Szakats (21 Dec 2023) -- hsts: skip single-dot hostname +- appveyor: replace PowerShell with bash + parallel autotools - Reported-by: Maksymilian Arciemowicz + PowerShell works (after a steep development curve), but one property of + it stuck and kept causing unresolvable usability issues: With + `$ErrorActionPreference=Stop`, it does abort on failures, but shows only + the first line of the error message. In `Continue` mode, it shows the + full error message, but doesn't stop on all errors. Another issue is + PowerShell considering any stderr output as if the command failed (this + has been improved in 7.2 (2021-Nov), but fixed versions aren't running + in CI and will not be for a long time in all test images.) - Closes #12247 + Thus, we're going with bash. -- vtls: fix build without proxy + Also: + - use `-j2` with autotools tests, making them finish 5-15 minutes per + job faster. + - omit `POSIX_PATH_PREFIX`. + - use `WINDIR`. + - prefer forward slashes. - Follow-up to bf0e278a3c54bc7fee7360da17c + Follow-up to: 75078a415d9c769419aed4153d3d525a8eba95af #11999 + Ref: #12444 - closes #12243 + Fixes #12560 + Closes #12572 -- docs/example/keepalive.c: show TCP keep-alive options +Pavel Pavlov (21 Dec 2023) - Closes #12242 +- asyn-thread: use GetAddrInfoExW on >= Windows 8 -- lib1560: verify appending blank URL encoded query string + For doing async DNS resolution instead of starting a thread for each + request. -- urlapi: skip appending NULL pointer query + Fixes #12481 + Closes #12482 - Reported-by: kirbyn17 on hackerone +Daniel Stenberg (21 Dec 2023) - Closes #12240 +- strerror: repair get_winsock_error() -- lib1560: verify setting host to "" with and without URL encode + It would try to read longer than the provided string and crash. -- urlapi: avoid null deref if setting blank host to url encode + Follow-up to ff74cef5d4a0cf60106517a1c7384 + Reported-by: calvin2021y on github + Fixes #12578 + Closes #12579 - Reported-by: kirbyn17 on hackerone +- CURLOPT_SSH_*_KEYFILE: clarify - Closes #12240 + Closes #12554 -- dynbuf: assert for NULL pointer inputs +ivanfywang (21 Dec 2023) - Help us catch more mistakes. +- ngtcp2: put h3 at the front of alpn - Closes #12238 + Closes #12576 -- HTTP3: ngtcp2 builds are no longer experimental +Daniel Stenberg (21 Dec 2023) - The other HTTP/3 backends are still experimental. +- test460: verify a command line using --expand with no argument - Closes #12235 + This verifies the fix for #12565 -Stefan Eissing (31 Oct 2023) +- tool_getparam: do not try to expand without an argument -- vtls: cleanup SSL config management + This would lead to a segfault. - - remove `Curl_ssl_get_config()`, no longer needed + Fixes #12565 + Reported-by: Geeknik Labs + Closes #12575 - Closes #12204 +- RELEASE-NOTES: synced -Daniel Stenberg (31 Oct 2023) + Bumped version to 8.6.0 because of changes -- libcurl-thread.3: simplify the TLS section +- Makefile.am: fix the MSVC project generation - All TLS libraries curl can use are threadsafe since OpenSSL 1.1.x, August - 2016. + It made the vcxproj files not get included in dist tarballs. - Closes #12233 + Regression since 74423b5df4c8117891eb89 (8.5.0) -- configure: better --disable-http + Reported-by: iAroc on github + Fixes #12564 + Closes #12567 - - disable HTTPS-proxy as well, since it can't work without HTTP +zengwei2000 (21 Dec 2023) - - curl_setup: when HTTP is disabled, also disable all features that are - HTTP-only +- altsvc: free 'as' when returning error - - version: HTTPS-proxy only exists if HTTP support exists + Closes #12570 - Closes #12223 + Signed-off-by: zengwei -- http: consider resume with CURLOPT_FAILONERRROR and 416 to be fine +Viktor Szakats (20 Dec 2023) - Finding a 'Content-Range:' in the response changed the handling. +- build: fix `-Wconversion`/`-Wsign-conversion` warnings - 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. + Fix remaining warnings in examples and tests which are not suppressed + by the pragma in `lib/curl_setup.h`. - Fixes #10521 - Reported-by: Smackd0wn - Fixes #12174 - Reported-by: Anubhav Rai - Closes #12176 + Silence a toolchain issue causing warnings in `FD_SET()` calls with + older Cygwin/MSYS2 builds. Likely fixed on 2020-08-03 by: + https://cygwin.com/git/?p=newlib-cygwin.git;a=commitdiff;h=5717262b8ecfed0f7f + ab63e2c09c78991e36f9dd -Stefan Eissing (30 Oct 2023) + Follow-up to 2dbe75bd7f3c36837aa06fd87a442bdf3fb7faef #12492 -- GHA: fix checkout of quictls repository to use correct branch name + Closes #12557 - Follow-up to c868b0e30f10cd0ac7 +- build: fix some `-Wsign-conversion`/`-Warith-conversion` warnings - Closes #12232 + - enable `-Wsign-conversion` warnings, but also setting them to not + raise errors. + - fix `-Warith-conversion` warnings seen in CI. + These are triggered by `-Wsign-converion` and causing errors unless + explicitly silenced. It makes more sense to fix them, there just a few + of them. + - fix some `-Wsign-conversion` warnings. + - hide `-Wsign-conversion` warnings with a `#pragma`. + - add macro `CURL_WARN_SIGN_CONVERSION` to unhide them on a per-build + basis. + - update a CI job to unhide them with the above macro: + https://github.com/curl/curl/actions/workflows/linux.yml -> OpenSSL -O3 -Daniel Stenberg (30 Oct 2023) + Closes #12492 -- docs/example/localport.c: show off CURLOPT_LOCALPORT +- cmake: tidy-up `OtherTests.cmake` - Closes #12230 + - make more obvious which detection uses which prep steps. + - merge and streamline conditions. + - these should not alter detection results. -- docs/examples/interface.c: show CURLOPT_INTERFACE use + Also align log output messages from + `Macros.cmake` / `curl_internal_test` with rest of the build. - Although super simple. + Closes #12551 - Closes #12229 +- appveyor: switch to out-of-tree builds -Viktor Szakats (30 Oct 2023) + With cmake and autotools. -- build: fix compiler warning with auths disabled + Closes #12550 - ``` - ./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. - ``` +Daniel Stenberg (19 Dec 2023) - Follow-up to e92edfbef64448ef461117769881f3ed776dec4e #11490 +- DEPRECATE.md: mention that NTLM_WB no longer works - Closes #12227 + Ref: #12479 + Closes #12553 -- build: require Windows XP or newer +- CURLOPT_SERVER_RESPONSE_TIMEOUT_MS: add - 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. + Proposed-by: Yifei Kong + Ref: https://curl.se/mail/lib-2023-11/0023.html + Closes #12369 - TODO: assume these also in autotools. +Viktor Szakats (18 Dec 2023) - Ref: https://github.com/curl/curl/pull/12221#issuecomment-1783761806 - Closes #12225 +- build: more `-Wformat` fixes -- appveyor: bump one job to OpenSSL 3.1 (was 1.1.1) + - memdebug: update to not trigger `-Wformat-nonliteral` warnings. + - imap: mark `imap_sendf()` with `CURL_PRINTF()`. + - tool_msgs: mark static function with `CURL_PRINTF()`. - Use 3.1 with the modern runner image. + Follow-up to 3829759bd042c03225ae862062560f568ba1a231 #12489 - We still use 1.1.1 in 8 jobs. + Closes #12540 - 1.1.1 is EOL since 2023-09-11: - https://www.openssl.org/blog/blog/2023/03/28/1.1.1-EOL/ +- windows: delete redundant headers - Also: - - add missing SSL-backend to job descriptions. - - tidy up CPU in job descriptions. + `winsock2.h` pulls in `windows.h`. `ws2tcpip.h` pulls in `winsock2.h`. + `winsock2.h` and `ws2tcpip.h` are also pulled by `curl/curl.h`. - Closes #12226 + Keep only those headers that are not already included, or the code under + it uses something from that specific header. -Daniel Stenberg (30 Oct 2023) + Closes #12539 -- RELEASE-NOTES: synced +- cmake: prefill/cache `HAVE_STRUCT_SOCKADDR_STORAGE` -- GHA: bump ngtcp2, nghttp3, nghttp2 and quictls versions + Also add missing include to `OtherTests.cmake`. It didn't cause an issue + because the parent already included this earlier by chance. - ngtcp2 1.0.1 - nghttp3 1.0.0 - nghttp2 1.58.0 - quictls 3.1.4+quic + Closes #12537 - also sync HTTP3.md with these changes +Daniel Stenberg (18 Dec 2023) - Closes #12132 +- runner.pm: fix perl warning when running tests -Kareem (29 Oct 2023) + Use of uninitialized value $runner::gdbthis in numeric eq (==) at runner. + pm -- wolfssl: add default case for wolfssl_connect_step1 switch + Follow-up from 3dcf301752a09d9 - Closes #12218 + Closes #12549 -Jay Satiro (29 Oct 2023) +- runtests: support -gl. Like -g but for lldb. -- curl_setup: disallow Windows IPv6 builds missing getaddrinfo + Follow-up to 63b5748 - - On Windows if IPv6 is enabled but getaddrinfo is missing then #error - the build. + Invokes the test case via lldb instead of gdb. Since using gdb is such a + pain on mac, using lldb is sometimes less quirky. - 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. + Closes #12547 - Such a bad configuration has already given us a bug that was hard to - diagnose. See #12134 and #12136 for discussion. +- curl.h: add CURLE_TOO_LARGE - Ref: https://github.com/curl/curl/issues/12134 - Ref: https://github.com/curl/curl/pull/12136 + A new error code to be used when an internal field grows too large, like + when a dynbuf reaches its maximum. Previously it would return + CURLE_OUT_OF_MEMORY for this, which is highly misleading. - Closes https://github.com/curl/curl/pull/12221 + Ref: #12268 + Closes #12269 -Nico Rieck (29 Oct 2023) +- CI/circleci: disable MQTT in the HTTP-only build -- openssl: make CURLSSLOPT_NATIVE_CA import Windows intermediate CAs + And remove the use of configure options that don't actually exist - - If CURLSSLOPT_NATIVE_CA on Windows then import from intermediate CA - "CA" store after importing from root CA "ROOT" store. + Closes #12546 - 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. +Yedaya Katsman (18 Dec 2023) - 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. +- tests: respect $TMPDIR when creating unix domain sockets - Prior to this change CURLSSLOPT_NATIVE_CA only imported "ROOT" certs. + When running on termux, where $TMPDIR isn't /tmp, running the tests + failed, since the server config tried creating sockets in /tmp, without + checking the temp dir config. Use the TMPDIR variable that makes it find + the correct directory everywhere [0] - Fixes https://github.com/curl/curl/issues/12155 - Closes https://github.com/curl/curl/pull/12185 + [0] https://perldoc.perl.org/File::Temp#tempfile -Viktor Szakats (28 Oct 2023) + Closes #12545 -- Makefile.mk: fix `-rtmp` option for non-Windows [ci skip] +Viktor Szakats (17 Dec 2023) -Daniel Stenberg (28 Oct 2023) +- ssh: fix namespace of two local macros -- asyn-ares: handle no connection in the addrinfo callback + Avoid using the libssh and libssh2 macro namespaces by prefixing + these local macro names with `CURL_`. - To avoid crashing. + Follow-up to 413a0fedd02c8c6df1d294534b8c6e306fcca7a2 #12346 - Follow-up from 56a4db2 - Closes #12219 + Reviewed-by: Daniel Stenberg + Closes #12544 -Jay Satiro (28 Oct 2023) +- cmake: whitespace tidy-up in `OtherTests.cmake` -- hostip6: fix DEBUG_ADDRINFO builds + Closes #12538 - - Removed unused and incorrect parameter from dump_addrinfo(). +Mark Sinkovics (16 Dec 2023) - Bug: https://github.com/curl/curl/commit/56a4db2e#commitcomment-131050442 - Reported-by: Gisle Vanem +- cmake: fix generation for system name iOS - Closes https://github.com/curl/curl/pull/12212 + This PR fixes a problem that happens during CMake configuration when + the `CMAKE_SYSTEM_NAME` set to `iOS` and not `Darwin`. This value is + available (as far as I remember) version 3.14. The final solution + (thanks to @vszakats) is to use `APPLE` which contains all the Apple + platforms https://cmake.org/cmake/help/latest/variable/APPLE.html. -Viktor Szakats (28 Oct 2023) + This issue was found when during vcpkg installation. Running command + `vcpkg install curl:arm64-ios` and `vcpkg install curl:x64-ios` failed + with message: + ``` + CMake Error: try_run() invoked in cross-compiling mode, please set the follow + ing cache variables appropriately: + HAVE_H_ERRNO_ASSIGNABLE_EXITCODE (advanced) + ``` + After this fix, I was able to compile the compile the binary without + any issue. -- Makefile.mk: restore `_mingw.h` for default `_WIN32_WINNT` + In addition to that fix, this PR also contains an simplification to + check if the platform is not APPLE. - 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. + Co-authored-by: Viktor Szakats + Closes #12515 - Restore this header and update its comment to tell why we continue - to need it. +Daniel Stenberg (16 Dec 2023) - 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.) +- RELEASE-NOTES: synced - Regression from 38029101e2d78ba125732b3bab6ec267b80a0e72 #11625 +Baruch Siach (16 Dec 2023) - Reported-by: zhengqwe on github - Helped-by: Nico Rieck - Fixes #12134 - Fixes #12136 - Closes #12217 +- gnutls: fix build with --disable-verbose -- hostip: silence compiler warning `-Wparentheses-equality` + infof() parameters must be defined event with --disable-verbose since + commit dac293cfb702 ("lib: apache style infof and trace + macros/functions"). - Seen with LLVM 17. + Move also 'ptr' definition under !CURL_DISABLE_VERBOSE_STRINGS. - ``` - 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. - ``` + Fixes the following build failure: - Follow-up to b651aba0962bb31353f55de4dc35f745952a1b10 #12145 + In file included from ../lib/sendf.h:29, + from vtls/gtls.c:44: + vtls/gtls.c: In function 'Curl_gtls_verifyserver': + vtls/gtls.c:841:34: error: 'version' undeclared (first use in this function); + did you mean 'session'? + 841 | gnutls_protocol_get_name(version), ptr); + | ^~~~~~~ - Reviewed-by: Daniel Stenberg - Closes #12215 + Closes #12505 -Stefan Eissing (27 Oct 2023) +Viktor Szakats (16 Dec 2023) -- doh: use PIPEWAIT when HTTP/2 is attempted +- build: delete unused `HAVE_{GSSHEIMDAL,GSSMIT,HEIMDAL}` - Closes #12214 + Stop setting `HAVE_GSSHEIMDAL`, `HAVE_GSSMIT` and `HAVE_HEIMDAL`. + There was no place in the build system or source code that used them. -Daniel Stenberg (27 Oct 2023) + Reviewed-by: Daniel Stenberg + Closes #12506 -- setopt: remove outdated cookie comment +- build: remove redundant `CURL_PULL_*` settings - Closes #12206 + These macros were not propagated to the source code from CMake. -Stefan Eissing (27 Oct 2023) + autotools set only one of them (`CURL_PULL_SYS_POLL_H`), initially to + address an AIX issue [1]. This later broke when introducing `system.h` + [2] without the logic it enabled. A subsequent fix [3] re-added the + logic, and also enabled it for AIX before its use, directly in + `system.h`. -- cfilter: provide call to tell connection to forget a socket + [1] 2012-11-23: 665adcd4b7bcdb7deb638cdc499fbe71f8d777f2 + [2] 2017-03-29: 9506d01ee50d5908138ebad0fd9fbd39b66bd64d #1373 + [3] 2017-08-25: 8a84fcc4b59e8b78d2acc6febf44a43d6bc81b59 #1828 #1833 - - 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 + Reviewed-by: Daniel Stenberg + Closes #12502 - Closes #12207 +- system.h: sync mingw `CURL_TYPEOF_CURL_SOCKLEN_T` with other compilers -- url: protocol handler lookup tidy-up + Align mingw with the other Windows compilers and use the `int` type for + `CURL_TYPEOF_CURL_SOCKLEN_T` (and thus for `curl_socklent_t`). This + makes it unnecessary to make a mingw-specific trick and pull all Windows + headers early just for this type definition. This type is specific to + Windows, not to the compiler. mingw-w64's Windows header maps it to + `int` too. - - rename lookup to what it does - - use ARRAYSIZE instead of NULL check for end - - offer alternate lookup for 0-terminated strings + With this we also delete all remaining uses of `CURL_PULL_WS2TCPIP_H`. - Closes #12216 + [ The official solution is to use `socklen_t` for all Windows compilers. + In this case we may want to update `curl/curl.h` to pull in Windows + headers before `system.h`. ] -Viktor Szakats (27 Oct 2023) + Reviewed-by: Daniel Stenberg + Reviewed-by: Jay Satiro + Closes #12501 + +- windows: simplify detecting and using system headers + + - autotools, cmake: assume that if we detect Windows, `windows.h`, + `winsock2.h` and `ws2tcpip.h` do exist. + - lib: fix 3 outlier `#if` conditions to use `USE_WINSOCK` instead of + looking for `winsock2.h`. + - autotools: merge 3 Windows check methods into one. + - move Watt-32 and lwIP socket support to `setup-win32.h` from + `config-win32.h`. It opens up using these with all build tools. Also + merge logic with Windows Sockets. + - fix to assume Windows sockets with the mingw32ce toolchain. + Follow-up to: 2748c64d605b19fb419ae56810ad8da36487a2d4 + - cmake: delete unused variable `signature_call_conv` since + eb33ccd5332435fa50f1758e5debb869c6942b7f. + - autotools: simplify `CURL_CHECK_WIN32_LARGEFILE` detection. + - examples/externalsocket: fix header order. + - cmake/OtherTests.cmake: delete Windows-specific `_source_epilogue` + that wasn't used anymore. + - cmake/OtherTests.cmake: set `WIN32_LEAN_AND_MEAN` for test + `SIZEOF_STRUCT_SOCKADDR_STORAGE`. + + After this patch curl universally uses `_WIN32` to guard + Windows-specific logic. It guards Windows Sockets-specific logic with + `USE_WINSOCK` (this might need further work). -- build: variadic macro tidy-ups + Reviewed-by: Jay Satiro + Closes #12495 + +- build: enable missing OpenSSF-recommended warnings, with fixes + + https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening + -Guide-for-C-and-C++.html + as of 2023-11-29 [1]. + + Enable new recommended warnings (except `-Wsign-conversion`): + + - enable `-Wformat=2` for clang (in both cmake and autotools). + - add `CURL_PRINTF()` internal attribute and mark functions accepting + printf arguments with it. This is a copy of existing + `CURL_TEMP_PRINTF()` but using `__printf__` to make it compatible + with redefinting the `printf` symbol: + https://gcc.gnu.org/onlinedocs/gcc-3.0.4/gcc_5.html#SEC94 + - fix `CURL_PRINTF()` and existing `CURL_TEMP_PRINTF()` for + mingw-w64 and enable it on this platform. + - enable `-Wimplicit-fallthrough`. + - enable `-Wtrampolines`. + - add `-Wsign-conversion` commented with a FIXME. + - cmake: enable `-pedantic-errors` the way we do it with autotools. + Follow-up to d5c0351055d5709da8f3e16c91348092fdb481aa #2747 + - lib/curl_trc.h: use `CURL_FORMAT()`, this also fixes it to enable format + checks. Previously it was always disabled due to the internal `printf` + macro. - - 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. + Fix them: - Follow-up to dac293cfb7026b1ca4175d88b80f1432d3d3c684 #12167 + - fix bug where an `set_ipv6_v6only()` call was missed in builds with + `--disable-verbose` / `CURL_DISABLE_VERBOSE_STRINGS=ON`. + - add internal `FALLTHROUGH()` macro. + - replace obsolete fall-through comments with `FALLTHROUGH()`. + - fix fallthrough markups: Delete redundant ones (showing up as + warnings in most cases). Add missing ones. Fix indentation. + - silence `-Wformat-nonliteral` warnings with llvm/clang. + - fix one `-Wformat-nonliteral` warning. + - fix new `-Wformat` and `-Wformat-security` warnings. + - fix `CURL_FORMAT_SOCKET_T` value for mingw-w64. Also move its + definition to `lib/curl_setup.h` allowing use in `tests/server`. + - lib: fix two wrongly passed string arguments in log outputs. + Co-authored-by: Jay Satiro + - fix new `-Wformat` warnings on mingw-w64. - Cherry-picked from #12105 - Closes #12210 + [1] https://github.com/ossf/wg-best-practices-os-developers/blob/56c0fde3895b + fc55c8a973ef49a2572c507b2ae1/docs/Compiler-Hardening-Guides/Compiler-Options- + Hardening-Guide-for-C-and-C%2B%2B.md -- cmake: speed up threads setup for Windows + Closes #12489 - 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). +- Makefile.mk: drop Windows support - 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. + And DLL-support with it. This leaves `Makefile.mk` for MS-DOS and Amiga. - This saves 1-3 slow CMake configuration steps. + We recommend CMake instead. With unity mode it's much faster, and about + the same without. + Ref: https://github.com/curl/curl/pull/12221#issuecomment-1783761806 Reviewed-by: Daniel Stenberg - Closes #12202 + Closes #12224 -- cmake: speed up zstd detection +Daniel Stenberg (16 Dec 2023) - 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). +- cmdline-docs: use .IP consistently - 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. + Remove use of .TP and some .B. The idea is to reduce nroff syntax as + much as possible and to use it consistently. Ultimately, we should be + able to introduce our own easier-to-use-and-read syntax/formatting and + convert on generation time. - We use the same version detection method as zstd itself, via its public - C header. + Closes #12535 - 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. +Tatsuhiko Miyagawa (16 Dec 2023) - 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 +- http: fix off-by-one error in request method length check - Reviewed-by: Daniel Stenberg - Closes #12200 + It should allow one more byte. -Daniel Stenberg (26 Oct 2023) + Closes #12534 -- openssl: fix infof() to avoid compiler warning for %s with null +Daniel Stenberg (15 Dec 2023) - 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", - | ^~ +- curl: show ipfs and ipns as supported "protocols" - Follow-up to b6e6d4ff8f253c8b8055bab - Closes #12196 + They are accepted schemes in URLs passed to curl (the tool, not the + library). -Stefan Eissing (26 Oct 2023) + Also makes curl-config show the same list. -- lib: apache style infof and trace macros/functions + Co-Authored-by: Jay Satiro + Reported-by: Chara White + Bug: https://curl.se/mail/archive-2023-12/0026.html + Closes #12508 - - test for a simplified C99 variadic check - - args to infof() in --disable-verbose are no longer disregarded but - must compile. +- Revert "urldata: move async resolver state from easy handle to connectdata" - Closes #12167 - Fixes #12083 - Fixes #11880 - Fixes #11891 + This reverts commit 56a4db2e4e2bcb9a0dcb75b83560a78ef231fcc8 (#12198) -Daniel Stenberg (26 Oct 2023) + We want the c-ares channel to be held in the easy handle, not per + connection - for performance. -- RELEASE-NOTES: synced + Closes #12524 -Stefan Eissing (26 Oct 2023) +Viktor Szakats (15 Dec 2023) -- urldata: move async resolver state from easy handle to connectdata +- openssl: re-match LibreSSL deinit with init - - 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. + Earlier we switched to use modern initialization with LibreSSL v2.7.0 + and up, but did not touch deinitialization [1]. Fix it in this patch. - Closes #12198 + Regression from bec0c5bbf34369920598678161d2df8bea0e243b #11611 -Daniel Stenberg (26 Oct 2023) + [1] https://github.com/curl/curl/pull/11611#issuecomment-1668654014 -- CURLOPT_WRITEFUNCTION.3: clarify what libcurl returns for CURL_WRITEFUNC_ERRO - R + Reported-by: Mike Hommey + Reviewed-by: Daniel Stenberg + Fixes #12525 + Closes #12526 - It returns CURLE_WRITE_ERROR. It was not previously stated clearly. +Daniel Stenberg (14 Dec 2023) - Reported-by: enWILLYado on github - Fixes #12201 - Closes #12203 +- libssh: supress warnings without version check -Viktor Szakats (25 Oct 2023) + Define unconditionally. -- autotools: update references to deleted `crypt-auth` option + Follow-up from d21bd2190c46ad7fa - Delete leftovers of the `crypt-auth` `./configure` option and - add the new ones that replaced them. + Closes #12523 - Follow-up to e92edfbef64448ef461117769881f3ed776dec4e #11490 +- hostip: return error immediately when Curl_ip2addr() fails - Reviewed-by: Daniel Stenberg - Closes #12194 + Closes #12522 -Stefan Eissing (25 Oct 2023) +Theo (14 Dec 2023) -- lib: introduce struct easy_poll_set for poll information +- libssh: improve the deprecation warning dismissal - 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. + Previous code was compiler dependant, and dismissed all deprecation warnings + indiscriminately. - 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. + libssh provides a way to disable the deprecation warnings for libssh only, an + d + naturally this is the preferred way. - 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. + This commit uses that, to prevent the erroneous hiding of potential, unrelate + d + deprecation warnings. - 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. + Fixes #12519 + Closes #12520 - 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. +Daniel Stenberg (14 Dec 2023) - Example: +- test1474: removed - * 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. + The test was already somewhat flaky and disabled on several platforms, + and after 1da640abb688 even more unstable. - Use of `SEND_HOLD` is no longer necessary in the filters. +- readwrite_data: loop less - 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. + This function is made to loop in order to drain incoming data + faster. Completely removing the loop has a measerably negative impact on + transfer speeds. - 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. + Downsides with the looping include - No noticeable difference in performance was detected in local scorecard - runs. + - it might call the progress callback much more seldom. Especially if + the write callback is slow. - Closes #11833 + - rate limiting becomes less exact -Daniel Stenberg (25 Oct 2023) + - a single transfer might "starve out" other parallel transfers -- tests/README: SOCKS tests are not using OpenSSH, it has its own server + - QUIC timers for other connections can't be maintained correctly - Follow-up to 04fd67555cc + The long term fix should be to remove the loop and optimize coming back + to avoid the transfer speed penalty. - Closes #12195 + This fix lower the max loop count to reduce the starvation problem, and + avoids the loop completely for when rate-limiting is in progress. -Jacob Hoffman-Andrews (25 Oct 2023) + Ref: #12488 + Ref: https://curl.se/mail/lib-2023-12/0012.html + Closes #12504 -- tets: make test documentation more user-friendly +Stefan Eissing (14 Dec 2023) - Put the instructions to run tests right at the top of tests/README.md. +- lib: eliminate `conn->cselect_bits` - Give instructions to read the runtests.1 man page for information - about flags. Delete redundant copy of the flags documentation in the - README. + - use `data->state.dselect_bits` everywhere instead + - remove `bool *comeback` parameter as non-zero + `data->state.dselect_bits` will indicate that IO is + incomplete. - Add a mention in README.md of the important parallelism flag, to make - test runs go much faster. + Closes #12512 - Move documentation of output line format into the runtests.1 man page, - and update it with missing flags. +- connect: refactor `Curl_timeleft()` - Fix the order of two flags in the man page. + - less local vars, "better" readability + - added documentation - Closes #12193 + Closes #12518 -Viktor Szakats (24 Oct 2023) +Dmitry Karpov (14 Dec 2023) -- cmake: pre-fill rest of detection values for Windows +- cookie: avoid fopen with empty file name - 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. + Closes #12514 - - pre-fill remaining detection values in Windows CMake builds. +Viktor Szakats (13 Dec 2023) - Based on actual detection results observed in CI runs, preceding - similar work over libssh2 and matching up values with - `lib/config-win32.h`. +- tests/server: delete workaround for old-mingw - This brings down CMake configuration time from 58 to 14 seconds on the - same local machine. + mingw-w64 1.0 comes with w32api v3.12, thus doesn't need this. - 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 + Follow-up to 38029101e2d78ba125732b3bab6ec267b80a0e72 #11625 - 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.) + Reviewed-by: Jay Satiro + Closes #12510 - - stop detecting `idn2.h` if idn2 was deselected. - autotools does this. +- cmake: delete obsolete TODOs more [ci skip] - - 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. + - manual completed: 898b012a9bf388590c4be7f526815b5ab74feca1 #1288 + - soname completed: 5de6848f104d7cb0017080e31216265ac19d0dde #10023 + - bunch of others that are completed + - `NTLM_WB_ENABLED` is implemented in a basic form, and now also + scheduled for removal, so a TODO at this point isn't useful. - - limit `ADDRESS_FAMILY` detection to Windows. + And this 'to-check' item: - - normalize `HAVE_WIN32_WINNT` value to lowercase `0x0a12` format. + Q: "The cmake build selected to run gcc with -fPIC on my box while the + plain configure script did not." - - pre-fill `HAVE_WIN32_WINNT`-dependent detection results. - Saving 4 (slow) feature-detections in most builds: `getaddrinfo`, - `freeaddrinfo`, `inet_ntop`, `inet_pton` + A: With CMake, since 2ebc74c36a19a1700af394c16855ce144d9878e3 #11546 + and fc9bfb14520712672b4784e8b48256fb29204011 #11627, we explicitly + enable PIC for libcurl shared lib. Or when building libcurl for + shared and static lib in a single pass. We do this by default for + Windows or when enabled by the user via `SHARE_LIB_OBJECT`. + Otherwise we don't touch this setting. Meaning the default set by + CMake (if any) or the toolchain is used. On Debian Bookworm, this + means that PIC is disabled for static libs by default. Some platforms + (like macOS), has PIC enabled by default. + autotools supports the double-pass mode only, and in that case + CMake seems to match PIC behaviour now (as tested on Linux with gcc.) - - 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. + Follow-up to 5d5dfdbd1a6c40bd75e982b66f49e1fa3a7eeae7 #12500 - - 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. + Reviewed-by: Jay Satiro + Closes #12509 - - 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. +Stefan Eissing (12 Dec 2023) - - delete redundant `HAVE_MACRO_SIGSETJMP` feature check. - It was the same check as `HAVE_SIGSETJMP`. +- CLIENT-WRITERS: design and use documentation - - delete 'experimental' marking from `CURL_USE_OPENSSL`. + Closes #12507 - - 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 +Viktor Szakats (12 Dec 2023) - - make `CMake/CurlTests.c` pass `checksrc`. +- cmake: delete obsolete TODO items [ci skip] - - `CMake/WindowsCache.cmake` tidy-ups. + There is always room for improvement, but CMake is up to par now with + autotools, so there is no longer a good reason to keep around these + inline TODO items. - - replace `WIN32` guard with `_WIN32` in `CMake/CurlTests.c`. + Answering one of questions: - Closes #12044 + Q: "The gcc command line use neither -g nor any -O options. As a + developer, I also treasure our configure scripts's --enable-debug + option that sets a long range of "picky" compiler options." -Jay Satiro (24 Oct 2023) + A: CMake offers the `CMAKE_BUILD_TYPE` variable to control debug info + and optimization level. E.g.: + - `Release` = `-O3` + no debug info + - `MinSizeRel` = `-Os` + no debug info + - `Debug` = `-O0` + debug info -- page-footer: clarify exit code 25 + https://stackoverflow.com/questions/48754619/what-are-cmake-build-type-deb + ug-release-relwithdebinfo-and-minsizerel/59314670#59314670 + https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#defaul + t-and-custom-configurations - - Clarify that curl tool exit code 25 means an upload failed to start. + For picky warnings we have the `PICKY_COMPILER` options, enabled by + default. - Exit code 25 is equivalent to CURLE_UPLOAD_FAILED (25). Prior to this - change the documentation only mentioned the case of FTP STOR failing. + Closes #12500 - Reported-by: Emanuele Torre +Stefan Eissing (11 Dec 2023) - Ref: https://github.com/curl/curl/blob/curl-8_4_0/docs/libcurl/libcurl-errors - .3#L113-L115 +- CONNECTION-FILTERS: update documentation - Fixes https://github.com/curl/curl/issues/12189 - Closes https://github.com/curl/curl/pull/12190 + Closes #12497 -Daniel Stenberg (24 Oct 2023) +Daniel Stenberg (11 Dec 2023) -- scripts/cijobs.pl: adjust for appveyor +- lib: reduce use of strncpy - Follow-up to a1d73a6bb + - bearssl: select cipher without buffer copies + - http_aws_sigv4: avoid strncpy, require exact timestamp length + - http_aws_sigv4: use memcpy isntead of strncpy + - openssl: avoid strncpy calls + - schannel: check for 1.3 algos without buffer copies + - strerror: avoid strncpy calls + - telnet: avoid strncpy, return error on too long inputs + - vtls: avoid strncpy in multissl_version() -Alex Bozarth (24 Oct 2023) + Closes #12499 -- OpenSSL: Include SIG and KEM algorithms in verbose +- CI/distcheck: run full tests - 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. + To be able to detect missing files better, this now runs the full CI + test suite. If done before, it would have detected #12462 before + release. - 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 + Closes #12503 - Based-on-patch-by: Martin Schmatz - Closes #12030 +- docs: clean up Protocols: for cmdline options -Daniel Stenberg (23 Oct 2023) + ... and some other minor polish. -- http2: provide an error callback and failf the message + Closes #12496 - 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. +- cmdline/gen: fix the sorting of the man page options - Example: + They were previously sorted based on the file names, which use a .d + extension, making "data" get placed after "data-binary" etc. Making the + sort ignore the extention fixes the ordering. - curl: (92) Invalid HTTP header field was received: frame type: 1, - stream: 1, name: [upgrade], value: [h2,h2c] + Reported-by: Boris Verkhovskiy + Bug: https://curl.se/mail/archive-2023-12/0014.html + Closes #12494 - Ref: #12172 - Closes #12179 +Daniel Gustafsson (9 Dec 2023) -Turiiya (23 Oct 2023) +- doh: remove unused local variable -- BINDINGS: add V binding + The nurl variable is no longer used during probing following + a refactoring, so remove. - Closes #12182 + Closes #12491 -Daniel Stenberg (22 Oct 2023) +Jay Satiro (8 Dec 2023) -- configure: check for the fseeko declaration too +- build: fix Windows ADDRESS_FAMILY detection - ... and make the code require both symbol and declaration. + - Include winsock2.h for Windows ADDRESS_FAMILY detection. - This is because for Android, the symbol is always present in the lib at - build-time even when not actually available in run-time. + Prior to this change cmake detection didn't work because it included + ws2def.h by itself, which is missing needed types from winsock2.h. - Assisted-by: Viktor Szakats - Reported-by: 12932 on github - Fixes #12086 - Closes #12158 - -Viktor Szakats (22 Oct 2023) + Prior to this change autotools detection didn't work because it did not + include any Windows header. -- 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. + In both cases libcurl would fall back on unsigned short as the address + family type, which is the same as ADDRESS_FAMILY. - Regression from dee310d54261f9a8416e87d50bccfe2cbe404949 #11555 + Co-authored-by: Viktor Szakats - Reported-by: Casey Bodley - Fixes #12160 - Closes #12162 + Closes https://github.com/curl/curl/pull/12441 -Daniel Stenberg (22 Oct 2023) +Daniel Stenberg (8 Dec 2023) -- RELEASE-NOTES: synced +- lib: rename Curl_strndup to Curl_memdup0 to avoid misunderstanding - bump to 8.5.0 for pending release + Since the copy does not stop at a null byte, let's not call it anything + that makes you think it works like the common strndup() function. -Dan Fandrich (21 Oct 2023) + Based on feedback from Jay Satiro, Stefan Eissing and Patrick Monnerat -- test3103: add missing quotes around a test tag attribute + Closes #12490 -Loïc Yhuel (21 Oct 2023) +- convsrctest.pl: removed: not used, not shipped in tarballs -- tool: fix --capath when proxy support is disabled +- tests: rename tests scripts to the test number - After 95e8515ca0, --capath always sets CURLOPT_PROXY_CAPATH, which fails - with CURLE_UNKNOWN_OPTION when proxy support is disabled. + It is hard to name the scripts sensibly. Lots of them are similarly + named and the name did not tell which test that used them. - Closes #12089 + The new approach is rather to name them based on the test number that + runs them. Also helps us see which scripts are for individual tests + rather than for general test infra. -Daniel Stenberg (21 Oct 2023) + - badsymbols.pl -> test1167.pl + - check-deprecated.pl -> test1222.pl + - check-translatable-options.pl -> test1544.pl + - disable-scan.pl -> test1165.pl + - error-codes.pl -> test1175.pl + - errorcodes.pl -> test1477.pl + - extern-scan.pl -> test1135.pl + - manpage-scan.pl -> test1139.pl + - manpage-syntax.pl -> test1173.pl + - markdown-uppercase.pl -> test1275.pl + - mem-include-scan.pl -> test1132.pl + - nroff-scan.pl -> test1140.pl + - option-check.pl -> test1276.pl + - options-scan.pl -> test971.pl + - symbol-scan.pl -> test1119.pl + - version-scan.pl -> test1177.pl -- openldap: move the alloc of ldapconninfo to *connect() + Closes #12487 - Fixes a minor memory leak on LDAP connection reuse. +Michał Antoniak (8 Dec 2023) - Doing the allocation already in *setup_connection() is wrong since that - connect struct might get discarded early when an existing connection is - reused instead. +- sendf: fix compiler warning with CURL_DISABLE_HEADERS_API - Closes #12166 + fix MSVC warning C4189: 'htype': local variable is initialized but not + referenced - when CURL_DISABLE_HEADERS_API is defined. -- openldap: set the callback argument in oldap_do + Closes #12485 - ... to make sure it has the current 'data' pointer and not a stale old - one. +Viktor Szakats (8 Dec 2023) - Reported-by: Dan Fandrich - Closes #12166 +- tidy-up: whitespace -- gnutls: support CURLSSLOPT_NATIVE_CA + Closes #12484 - 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. +Stefan Eissing (7 Dec 2023) - The native CA store loading is now asked for with this option. +- test_02_download: fix paramters to test_02_27 - Follow-up to 7b55279d1d856 + - it is a special client that only ever uses http/2 - Co-authored-by: Jay Satiro + Closes #12467 - Closes #12137 +Michał Antoniak (7 Dec 2023) -Stefan Eissing (21 Oct 2023) +- vtls: remove the Curl_cft_ssl_proxy object if CURL_DISABLE_PROXY -- RTSP: improved RTP parser + Closes #12459 - - 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 +Daniel Stenberg (7 Dec 2023) - Closes #12052 +- lib: strndup/memdup instead of malloc, memcpy and null-terminate -- http2: header conversion tightening + - bufref: use strndup + - cookie: use strndup + - formdata: use strndup + - ftp: use strndup + - gtls: use aprintf instead of malloc + strcpy * 2 + - http: use strndup + - mbedtls: use strndup + - md4: use memdup + - ntlm: use memdup + - ntlm_sspi: use strndup + - pingpong: use memdup + - rtsp: use strndup instead of malloc, memcpy and null-terminate + - sectransp: use strndup + - socks_gssapi.c: use memdup + - vtls: use dynbuf instead of malloc, snprintf and memcpy + - vtls: use strdup instead of malloc + memcpy + - wolfssh: use strndup - - fold the code to convert dynhds to the nghttp2 structs - into a dynhds internal method - - saves code duplication - - pacifies compiler analyzers + Closes #12453 - Closes #12097 +- strdup: remove the memchr check from Curl_strndup -Daniel Stenberg (21 Oct 2023) + It makes it possible to clone a binary chunk of data. -- curl_ntlm_wb: fix elif typo + Closes #12453 - Reported-by: Manfred Schwarb - Follow-up to d4314cdf65ae - Bug: https://github.com/curl/curl/commit/d4314cdf65aee295db627016934bd9eb621a - b077#r130551295 +- ftp: handle the PORT parsing without allocation -Dan Fandrich (20 Oct 2023) + Also reduces amount of *cpy() calls. -- test1683: remove commented-out check alternatives + Closes #12456 - 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. +- RELEASE-NOTES: synced -Daniel Stenberg (20 Oct 2023) + Bumped to 8.5.1 -- hostip: show the list of IPs when resolving is done +- url: for disabled protocols, mention if found in redirect - Getting 'curl.se' today then gets this verbose output which might help - debugging connectivity related matters. + To help users better understand where the URL (and denied scheme) comes + from. Also removed "in libcurl" from the message, since the disabling + can be done by the application. - * 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 + The error message now says "not supported" or "disabled" depending on + why it was denied: - Co-authored-by: Jay Satiro - Closes #12145 + Protocol "hej" not supported + Protocol "http" disabled -rilysh (20 Oct 2023) + And in redirects: -- docs: fix function typo in curl_easy_option_next.3 + Protocol "hej" not supported (in redirect) + Protocol "http" disabled (in redirect) - Closes #12170 + Reported-by: Mauricio Scheffer + Fixes #12465 + Closes #12469 -Daniel Stenberg (20 Oct 2023) +Stefan Eissing (6 Dec 2023) -- vssh: remove the #ifdef for Curl_ssh_init, use empty macro +- sectransp_ make TLSCipherNameForNumber() available in non-verbose config - In the same style as other init calls + Reported-by: Cajus Pollmeier + Closes #12476 + Fixes #12474 -- easy: remove duplicate wolfSSH init call +YX Hao (6 Dec 2023) - It is already done in Curl_ssh_init() where it belongs. +- lib: fix variable undeclared error caused by `infof` changes - Closes #12168 + `--disable-verbose` yields `CURL_DISABLE_VERBOSE_STRINGS` defined. + `infof` isn't `Curl_nop_stmt` anymore: dac293c. -- socks: make SOCKS5 use the CURLOPT_IPRESOLVE choice + Follow-up to dac293c - Fixes #11949 - Reported-by: Ammar Faizi - Closes #12163 + Closes #12470 -- urldata: move the 'internal' boolean to the state struct +Viktor Szakats (6 Dec 2023) - ... where all the other state bits for the easy handles live. +- tidy-up: fix yamllint whitespace issues in labeler.yml - Closes #12165 + Follow-up to bda212911457c6fadfbba50be61afc4ca513fa56 #12466 -- url: don't touch the multi handle when closing internal handles + Reviewed-by: Dan Fandrich + Closes #12475 - Reported-by: Maksymilian Arciemowicz - Closes #12165 +- tidy-up: fix yamllint whitespace issues -Faraz Fallahi (19 Oct 2023) + Closes #12466 -- getenv: PlayStation doesn't have getenv() +Chris Sauer (6 Dec 2023) - Closes #12140 +- cmake: fix typo -Daniel Stenberg (19 Oct 2023) + Follow-up to aace27b + Closes #12464 -- transfer: only reset the FTP wildcard engine in CLEAR state +Daniel Stenberg (6 Dec 2023) - To avoid the state machine to start over and redownload all the files - *again*. +- dist: add tests/errorcodes.pl to the tarball - Reported-by: lkordos on github - Regression from 843b3baa3e3cb228 (shipped in 8.1.0) - Bisect-by: Dan Fandrich - Fixes #11775 - Closes #12156 + Used by test 1477 -Stefan Eissing (19 Oct 2023) + Reported-by: Xi Ruoyao + Follow-up to 0ca3a4ec9a7 + Fixes #12462 + Closes #12463 -- GHA: move mod_h2 version in CI to v2.0.25 +Dan Fandrich (6 Dec 2023) - Closes #12157 +- github/labeler: update a missed key in the v5 upgrade -Daniel Stenberg (19 Oct 2023) + Follow-up to ce03fe3ba -- ntlm_wb: use pipe instead of socketpair when possible +Version 8.5.0 (6 Dec 2023) - Closes #12149 +Daniel Stenberg (6 Dec 2023) - 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 + The curl 8.5.0 release. -Dan Fandrich (17 Oct 2023) +Dan Fandrich (5 Dec 2023) -- tests: Fix Windows test helper tool search & use it for handle64 +- github/labeler: switch from the beta to labeler v5 - 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. + Some keys were renamed and the dot option was made default. - 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 + Closes #12458 - The running command stopped because the preference variable - "ErrorActionPreference" or common parameter is set to Stop: - sh: handle64.exe: command not found +Daniel Stenberg (5 Dec 2023) - Closes #12115 +- DEPRECATE: remove NTLM_WB in June 2024 -Daniel Stenberg (17 Oct 2023) + Ref: https://curl.se/mail/lib-2023-12/0010.html -- multi: use pipe instead of socketpair to *wakeup() + Closes #12451 - If pipe() is present. Less overhead. +Jacob Hoffman-Andrews (4 Dec 2023) - Closes #12142 +- rustls: implement connect_blocking -Jay Satiro (17 Oct 2023) + Closes #11647 -- build: fix 'threadsafe' feature detection for older gcc +Daniel Stenberg (4 Dec 2023) - - Add 'threadsafe' to the feature list shown during build if POSIX - threads are being used. +- examples/rtsp-options.c: add - 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. + Just a bare bones RTSP example using CURLOPT_RTSP_SESSION_ID and + CURLOPT_RTSP_REQUEST set to CURL_RTSPREQ_OPTIONS. - Reported-by: Dan Fandrich - Co-authored-by: Dan Fandrich + Closes #12452 - Fixes https://github.com/curl/curl/issues/12125 - Closes https://github.com/curl/curl/pull/12127 +Stefan Eissing (4 Dec 2023) -Daniel Stenberg (16 Oct 2023) +- ngtcp2: ignore errors on unknown streams -- test729: verify socks4a with excessive proxy user name length + - expecially in is_alive checks on connections, we might + see incoming packets on streams already forgotten and closed, + leading to errors reported by nghttp3. Ignore those. -- socks: better buffer size checks for socks4a user and hostname + Closes #12449 - Also limit the proxy user name to 255 bytes, which is the same limit as - in SOCKS5. +Daniel Stenberg (4 Dec 2023) - Reported-by: sd0 on hackerone - Closes #12139 +- docs: make all examples in all libcurl man pages compile -- curl.h: on FreeBSD include sys/param.h instead of osreldate.h + Closes #12448 - Should things build on Playstation as well +- checksrc.pl: support #line instructions - Fixes #12107 - Reported-by: Faraz Fallahi - Closes #12123 + makes it identify the correct source file and line -Marcin Rataj (16 Oct 2023) +- GHA/man-examples: verify libcurl man page examples -- tool_operate: fix links in ipfs errors +- verify-examples.pl: verify that all man page examples compile clean - URL fragment links generated from headers in - https://curl.se/docs/ipfs.html are lowercase. +- RELEASE-NOTES: synced - Closes #12133 +Graham Campbell (2 Dec 2023) -Viktor Szakats (15 Oct 2023) +- http3: bump ngtcp2 and nghttp3 versions -- cmake: replace `check_library_exists_concat()` + nghttp3 v1.1.0 + ngtcp2 v1.1.0 - 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. + In docs and CI - 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). + Closes #12446 - 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. +- CI/quiche: use `3.1.4+quic` consistently in CI workflows - (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.) + Closes #12447 - Ref: #11537 #11558 - Fixes #11285 - Fixes #11648 - Closes #12070 +Viktor Szakats (2 Dec 2023) -LoRd_MuldeR (15 Oct 2023) +- test1545: disable deprecation warnings -- tool_cb_wrt: fix write output for very old Windows versions + Fixes: + https://ci.appveyor.com/project/curlorg/curl/builds/48631551/job/bhx74e0i66yr + p6pk#L1205 - - Pass missing parameter for 'lpNumberOfCharsWritten' to WriteConsoleW() - function. + Same with details: + https://ci.appveyor.com/project/curlorg/curl/builds/48662893/job/ol8a78q9gmil + b6wt#L1263 + ``` + tests/libtest/lib1545.c:38:3: error: 'curl_formadd' is deprecated: since 7.56 + .0. Use curl_mime_init() [-Werror=deprecated-declarations] + 38 | curl_formadd(&m_formpost, &lastptr, CURLFORM_COPYNAME, "file", + | ^~~~~~~~~~~~ + [...] + ``` - Apparently this parameter was *not* optional on older Windows versions. + Follow-up to 07a3cd83e0456ca17dfd8c3104af7cf45b7a1ff5 #12421 - Issue observed on Windows XP SP2. Issue not observed on Windows 7 SP1. - So at some point between those two Microsoft changed the behavior. + Fixes #12445 + Closes #12444 - Prior to this change, on those versions if parameter is NULL then the - function call fails with error ERROR_INVALID_ACCESS. +Daniel Stenberg (2 Dec 2023) - Regression since af3f4e41. +- INSTALL: update list of ports and CPU archs - Ref: https://github.com/MicrosoftDocs/Console-Docs/issues/299 +- symbols-in-versions: the CLOSEPOLICY options are deprecated - Fixes https://github.com/curl/curl/issues/12131 - Closes https://github.com/curl/curl/pull/12130 + The were used with the CURLOPT_CLOSEPOLICY option, which *never* worked. -Jay Satiro (15 Oct 2023) +z2_ (1 Dec 2023) -- tool_urlglob: fix build for old gcc versions +- build: fix builds that disable protocols but not digest auth - - Don't use __builtin_mul_overflow for GCC 4 and earlier. + - Build base64 functions if digest auth is not disabled. - The function was added in GCC 5. + Prior to this change if some protocols were disabled but not digest auth + then a build error would occur due to missing base64 functions. - Ref: https://gcc.gnu.org/gcc-5/changes.html + Fixes https://github.com/curl/curl/issues/12440 + Closes https://github.com/curl/curl/pull/12442 - Reported-by: Dan Fandrich +Michał Antoniak (1 Dec 2023) - Fixes https://github.com/curl/curl/issues/12124 - Closes https://github.com/curl/curl/pull/12128 +- connect: reduce number of transportation providers -Carlos Henrique Lima Melara (14 Oct 2023) + Use only the ones necessary - the ones that are built-in. Saves a few + bytes in the resulting code. -- docs/libcurl: fix three minor man page format mistakes + Closes #12438 - Reported-by: Samuel Henrique +David Benjamin (1 Dec 2023) - Closes https://github.com/curl/curl/pull/12126 +- vtls: consistently use typedef names for OpenSSL structs -Jay Satiro (14 Oct 2023) + The foo_st names don't appear in OpenSSL public API documentation. The + FOO typedefs are more common. This header was already referencing + SSL_CTX via . There is a comment about avoiding + , but OpenSSL actually declares all the typedefs in + , which is already included by (and + every other OpenSSL header), so just use that. Though I've included it + just to be explicit. -- tests/server: add more SOCKS5 handshake error checking + (I'm also fairly sure including already triggers the + Schannel conflicts anyway. The comment was probably just out of date.) - - Add additional checking for missing and too-short SOCKS5 handshake - messages. + Closes #12439 - 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. +Lau (1 Dec 2023) - 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. +- libcurl-security.3: fix typo - Reported-by: Dan Fandrich + Fixed minimal typo. - Fixes https://github.com/curl/curl/issues/12117 - Closes https://github.com/curl/curl/pull/12118 + Closes #12437 -Daniel Stenberg (14 Oct 2023) +Stefan Eissing (1 Dec 2023) -- RELEASE-NOTES: synced +- ngtcp2: fix races in stream handling -Sohom Datta (14 Oct 2023) + - fix cases where ngtcp2 invokes callbacks on streams that + nghttp3 has already forgotten. Ignore the NGHTTP3_ERR_STREAM_NOT_FOUND + in these cases as it is normal behaviour. -- tool_getparam: limit --rate to be smaller than number of ms + Closes #12435 - 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). +Emanuele Torre (1 Dec 2023) - 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 +- tool_writeout_json: fix JSON encoding of non-ascii bytes - Closes #12116 + char variables if unspecified can be either signed or unsigned depending + on the platform according to the C standard; in most platforms, they are + signed. -Daniel Stenberg (14 Oct 2023) + This meant that the *i<32 waas always true for bytes with the top bit + set. So they were always getting encoded as \uXXXX, and then since they + were also signed negative, they were getting extended with 1s causing + '\xe2' to be expanded to \uffffffe2, for example: -- opts: fix two minor man page format mistakes + $ curl --variable 'v=“' --expand-write-out '{{v:json}}\n' file:///dev/nul + l + \uffffffe2\uffffff80\uffffff9c -Jay Satiro (14 Oct 2023) + I fixed this bug by making the code use explicitly unsigned char* + variables instead of char* variables. -- curl_trc: remove a bad assertion + Test 268 verifies - - Remove DEBUGASSERT that an internal handle must not have user - private_data set before calling the user's debug callback. + Reported-by: iconoclasthero + Closes #12434 - 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. +Stefan Eissing (1 Dec 2023) - Bug: https://github.com/curl/curl/pull/12060#issuecomment-1754594697 - Reported-by: Daniel Stenberg +- cf-socket: TCP trace output local address used in connect - Closes https://github.com/curl/curl/pull/12104 + Closes #12427 -Dan Fandrich (13 Oct 2023) +Jay Satiro (1 Dec 2023) -- test613: stop showing an error on missing output file +- CURLINFO_PRETRANSFER_TIME_T.3: fix time explanation - 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. + - Change CURLINFO_PRETRANSFER_TIME_T explanation to say that it + includes protocol-specific instructions that trigger a transfer. -Stefan Eissing (13 Oct 2023) + Prior to this change it explicitly said that it did not include those + instructions in the time, but that is incorrect. -- quic: manage connection idle timeouts + The change is a copy of the fixed explanation already in + CURLINFO_PRETRANSFER_TIME, fixed by ec8dcd7b. - - 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: eeverettrbx@users.noreply.github.com - Reported-by: calvin2021y on github - Fixes #12064 - Closes #12077 + Fixes https://github.com/curl/curl/issues/12431 + Closes https://github.com/curl/curl/pull/12432 -Dan Fandrich (13 Oct 2023) +Daniel Stenberg (30 Nov 2023) -- CI: ignore test 286 on Appveyor gcc 9 build +- multi: during ratelimit multi_getsock should return no sockets - 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. + ... as there is nothing to wait for then, it just waits. Otherwise, this + causes much more CPU work and updates than necessary during ratelimit + periods. - Fixes #12040 - Closes #12106 + Ref: https://curl.se/mail/lib-2023-11/0056.html + Closes #12430 -Viktor Szakats (13 Oct 2023) +Dmitry Karpov (30 Nov 2023) -- lib: fix gcc warning in printf call +- transfer: abort pause send when connection is marked for closing - Do not pass NULL to printf %s. + This handles cases of some bi-directional "upgrade" scenarios + (i.e. WebSockets) where sending is paused until some "upgrade" handshake + is completed, but server rejects the handshake and closes the + connection. - 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 + Closes #12428 - Ref: #10284 - Co-authored-by: Jay Satiro - Closes #12082 +Daniel Stenberg (28 Nov 2023) -Alex Klyubin (13 Oct 2023) +- RELEASE-NOTES: synced -- http2: safer invocation of populate_binsettings +- openssl: when a session-ID is reused, skip OCSP stapling - 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. + Fixes #12399 + Reported-by: Alexey Larikov + Closes #12418 - 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... +- test1545: test doing curl_formadd twice with missing file - Closes #12101 + Reproduces #12410 + Verifies the fix + Closes #12421 -Daniel Stenberg (13 Oct 2023) +- Curl_http_body: cleanup properly when Curl_getformdata errors -- openssl: avoid BN_num_bits() NULL pointer derefs + Reported-by: yushicheng7788 on github + Based-on-work-by: yushicheng7788 on github + Fixes #12410 + Closes #12421 - Reported-by: icy17 on github - Fixes #12099 - Closes #12100 +- test1477: verify that libcurl-errors.3 and public headers are synced -- wolfssl: require WOLFSSL_SYS_CA_CERTS for loading system CA + The script errorcodes.pl extracts all error codes from all headers and + checks that they are all documented, then checks that all documented + error codes are also specified in a header file. - 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 #12424 - Closes #12108 +- libcurl-errors.3: sync with current public headers -- tool_urlglob: make multiply() bail out on negative values + Closes #12424 - - Does not work correctly with negative values - - use __builtin_mul_overflow() on gcc +Stefan Eissing (28 Nov 2023) - Reported-by: Torben Dury - Closes #12102 +- test459: fix for parallel runs -Loïc Yhuel (13 Oct 2023) + - change warniing message to work better with varying filename + length. + - adapt test output check to new formatting -- cmake: fix CURL_DISABLE_GETOPTIONS + Follow-up to 97ccc4479f77ba3191c6 + Closes #12423 - - 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. +Daniel Stenberg (27 Nov 2023) - Closes https://github.com/curl/curl/pull/12091 +- tool_cb_prg: make the carriage return fit for wide progress bars -- easy_lock: add a pthread_mutex_t fallback + When the progress bar was made max width (256 columns), the fly() + function attempted to generate its output buffer too long so that the + trailing carriage return would not fit and then the output would show + wrongly. The fly function is called when the expected total transfer is + unknown, which could be one or more progress calls before the actual + progress meter get shown when the expected transfer size is provided. - This allows to keep the init threadsafe with gcc < 4.9.0 (no C11 - atomics). + This new take also replaces the msnprintf() call with a much simpler + memset() for speed. - Closes https://github.com/curl/curl/pull/12090 + Reported-by: Tim Hill + Fixes #12407 + Closes #12415 -Viktor Szakats (12 Oct 2023) +- tool_parsecfg: make warning output propose double-quoting -- CI: add autotools, out-of-tree, debug build to distro check job + When the config file parser detects a word that *probably* should be + quoted, mention double-quotes as a possible remedy. - Add a job that builds curl from a generated source tarball sample, with - autotools, out-of-tree, in debug mode. + Test 459 verifies. - Ref: #12085 - Closes #12088 + Proposed-by: Jiehong on github + Fixes #12409 + Closes #12412 -Daniel Stenberg (12 Oct 2023) +Jay Satiro (26 Nov 2023) -- http: avoid Expect: 100-continue if Upgrade: is used +- curl.rc: switch out the copyright symbol for plain ASCII - Reported-by: Daniel Jelinski - Fixes #12022 - Closes #12062 + .. like we already do for libcurl.rc. -Jan Alexander Steffens (heftig) (12 Oct 2023) + libcurl.rc copyright symbol used to cause a "non-ascii 8-bit codepoint" + warning so it was switched to ascii. -- docs: use SOURCE_DATE_EPOCH for generated manpages + Ref: https://github.com/curl/curl/commit/1ca62bb5#commitcomment-133474972 - This should make builds from Git reproducible. + Suggested-by: Robert Southee - Closes #12092 + Closes https://github.com/curl/curl/pull/12403 -Daniel Stenberg (12 Oct 2023) +Daniel Stenberg (26 Nov 2023) -- RELEASE-NOTES: synced +- conncache: use the closure handle when disconnecting surplus connections - Bumped to 8.4.1 + Use the closure handle for disconnecting connection cache entries so + that anything that happens during the disconnect is not stored and + associated with the 'data' handle which already just finished a transfer + and it is important that details from the unrelated disconnect does not + taint meta-data in the data handle. -Viktor Szakats (12 Oct 2023) + Like storing the response code. -- cmake: fix `HAVE_H_ERRNO_ASSIGNABLE` detection + This also adjust test 1506. Unfortunately it also removes a key part of + the test that verifies that a connection is closed since when this + output vanishes (because the closure handle is used), we don't know + exactly that the connection actually gets closed in this test... - 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. + Reported-by: ohyeaah on github + Fixes #12367 + Closes #12405 - We used this detection result to enable `HAVE_GETADDRINFO_THREADSAFE`. +- RELEASE-NOTES: synced - Follow-up to 04a3a377d83fd72c4cf7a96c9cb6d44785e33264 #11979 - Ref: #12095 (closed in favour of this patch) - Ref: #11964 (effort to sync cmake detections with autotools) +Stefan Eissing (24 Nov 2023) - Reported-by: Kartatz on Github - Assisted-by: Kartatz on Github - Fixes #12093 - Closes #12094 +- quic: make eyeballers connect retries stop at weird replies -- build: add `src/.checksrc` to source tarball + - when a connect immediately goes into DRAINING state, do + not attempt retries in the QUIC connection filter. Instead, + return CURLE_WEIRD_SERVER_REPLY + - When eyeballing, interpret CURLE_WEIRD_SERVER_REPLY as an + inconclusive answer. When all addresses have been attempted, + rewind the address list once on an inconclusive answer. + - refs #11832 where connects were retried indefinitely until + the overall timeout fired - Regression from e5bb88b8f824ed87620bd923552534c83c2a516e #11958 + Closes #12400 - Bug: https://github.com/curl/curl/pull/11958#issuecomment-1757079071 - Reported-by: Romain Geissler - Fixes #12084 - Closes #12085 +Daniel Stenberg (24 Nov 2023) -Version 8.4.0 (11 Oct 2023) +- CI: verify libcurl function SYNPOSIS sections -Daniel Stenberg (11 Oct 2023) + With the .github/scripits/verify-synopsis.pl script -- RELEASE-NOTES: synced + Closes #12402 -- THANKS: add contributors from 8.4.0 +- docs/libcurl: SYNSOPSIS cleanup -Jay Satiro (11 Oct 2023) + - use the correct include file + - make sure they are declared as in the header file + - fix minor nroff syntax mistakes (missing .fi) -- socks: return error if hostname too long for remote resolve + These are verified by verify-synopsis.pl, which extracts the SYNPOSIS + code and runs it through gcc. - 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. + Closes #12402 - Bug: https://curl.se/docs/CVE-2023-38545.html +- sendf: fix comment typo -Stefan Eissing (10 Oct 2023) +- fopen: allocate the dir after fopen -- CI: remove slowed-network tests + Move the allocation of the directory name down to after the fopen() call + to allow that shortcut code path to avoid a superfluous malloc+free + cycle. - - remove these tests as they are currently not reliable in our CI - setups. + Follow-up to 73b65e94f35311 - 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 #12398 - Closes https://github.com/curl/curl/pull/12075 +Stefan Eissing (24 Nov 2023) -Jay Satiro (10 Oct 2023) +- transfer: cleanup done+excess handling -- libcurl-env-dbg.3: move debug variables from libcurl-env.3 + - add `SingleRequest->download_done` as indicator that + all download bytes have been received + - remove `stop_reading` bool from readwrite functions + - move excess body handling into client download writer - - Move documentation of libcurl environment variables used only in debug - builds from libcurl-env into a separate document libcurl-env-dbg. + Closes #12371 - - Document more debug environment variables. +Daniel Stenberg (23 Nov 2023) - Previously undocumented or missing a description: +- fopen: create new file using old file's mode - 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. + Because the function renames the temp file to the target name as a last + step, if the file was previously owned by a different user, not ORing + the old mode could otherwise end up creating a file that was no longer + readable by the original owner after save. - Closes https://github.com/curl/curl/pull/11811 + Reported-by: Loïc Yhuel + Fixes #12299 + Closes #12395 -Dan Fandrich (9 Oct 2023) +- test1476: require proxy -- test670: increase the test timeout + Follow-up from 323df4261c3542 - This should make it more immune to loaded servers. + Closes #12394 - Ref: #11328 +- fopen: create short(er) temporary file name -Stefan Eissing (9 Oct 2023) + Only using random letters in the name plus a ".tmp" extension. Not by + appending characters to the final file name. -- MQTT: improve receive of ACKs + Reported-by: Maksymilian Arciemowicz - - 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 #12388 - Closes #12071 +Stefan Eissing (23 Nov 2023) -Viktor Szakats (9 Oct 2023) +- tests: git ignore generated second-hsts.txt file -- quic: fix BoringSSL build + File is generated in test lib1900 - Add guard around `SSL_CTX_set_ciphersuites()` use. + Follow-up to 7cb03229d9e9c5 - Bug: https://github.com/curl/curl/pull/12065#issuecomment-1752171885 + Closes #12393 - Follow-up to aa9a6a177017e4b74d33cdf85a3594900f4a7f81 +Viktor Szakats (23 Nov 2023) - Co-authored-by: Jay Satiro - Reviewed-by: Daniel Stenberg - Closes #12067 +- openssl: enable `infof_certstack` for 1.1 and LibreSSL 3.6 -Stefan Eissing (9 Oct 2023) + Lower the barrier to enable `infof_certstack()` from OpenSSL 3 to + OpenSSL 1.1.x, and LibreSSL 3.6 or upper. -- test1540: improve reliability + With the caveat, that "group name" and "type name" are missing from + the log output with these TLS backends. - - print that bytes have been received on pausing, but not how many + Follow-up to b6e6d4ff8f253c8b8055bab9d4d6a10f9be109f3 #12030 - Closes #12069 + Reviewed-by: Daniel Stenberg + Closes #12385 -- test2302: improve reliability +Daniel Stenberg (23 Nov 2023) - - 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 +- urldata: fix typo in comment - Closes #12068 +- CI: codespell -Daniel Stenberg (9 Oct 2023) + The list of words to ignore is in the file + .github/scripts/codespell-ignore.txt -- curl_easy_pause: set "in callback" true on exit if true + Closes #12390 - Because it might have called another callback in the mean time that then - set the bit FALSE on exit. +- lib: fix comment typos - Reported-by: Jay Satiro - Fixes #12059 - Closes #12061 + Five separate ones, found by codespell -Viktor Szakats (8 Oct 2023) + Closes #12390 -- h3: add support for ngtcp2 with AWS-LC builds +- test1476: verify cookie PSL mixed case - ``` - 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 - ``` +- cookie: lowercase the domain names before PSL checks - Also delete an obsolete GnuTLS TODO and update the header comment in - `FindNGTCP2.cmake`. + Reported-by: Harry Sintonen - Reviewed-by: Daniel Stenberg - Closes #12066 + Closes #12387 -- build: do not publish `HAVE_BORINGSSL`, `HAVE_AWSLC` macros +Viktor Szakats (23 Nov 2023) - Syncing this up with CMake. +- openssl: fix building with v3 `no-deprecated` + add CI test - 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 + - build quictls with `no-deprecated` in CI to have test coverage for + this OpenSSL 3 configuration. -Marc Hoersken (8 Oct 2023) + - don't call `OpenSSL_add_all_algorithms()`, `OpenSSL_add_all_digests()`. + The caller code is meant for OpenSSL 3, while these two functions were + only necessary before OpenSSL 1.1.0. They are missing from OpenSSL 3 + if built with option `no-deprecated`, causing build errors: + ``` + vtls/openssl.c:4097:3: error: call to undeclared function 'OpenSSL_add_all_ + algorithms'; ISO C99 and later do not support implicit function declaration + s [-Wimplicit-function-declaration] + vtls/openssl.c:4098:3: error: call to undeclared function 'OpenSSL_add_all_ + digests'; ISO C99 and later do not support implicit function declarations [ + -Wimplicit-function-declaration] + ``` + Ref: https://ci.appveyor.com/project/curlorg/curl-for-win/builds/48587418?f + ullLog=true#L7667 -- CI: move distcheck job from Azure Pipelines to GitHub Actions + Regression from b6e6d4ff8f253c8b8055bab9d4d6a10f9be109f3 #12030 + Bug: https://github.com/curl/curl/issues/12380#issuecomment-1822944669 + Reviewed-by: Alex Bozarth - This will allow for more trigger excludes within Azure Pipelines. + - vquic/curl_ngtcp2: fix using `SSL_get_peer_certificate` with + `no-deprecated` quictls 3 builds. + Do it by moving an existing solution for this from `vtls/openssl.c` + to `vtls/openssl.h` and adjusting caller code. + ``` + vquic/curl_ngtcp2.c:1950:19: error: implicit declaration of function 'SSL_g + et_peer_certificate'; did you mean 'SSL_get1_peer_certificate'? [-Wimplicit + -function-declaration] + ``` + Ref: https://github.com/curl/curl/actions/runs/6960723097/job/18940818625#s + tep:24:1178 - Also fixes seemingly broken check with scripts/installcheck.sh. - Ref: 190374c74ec4e5247d9066544c86e8d095e1d7b5 + - curl_ntlm_core: fix `-Wunused-parameter`, `-Wunused-variable` and + `-Wunused-function` when trying to build curl with NTLM enabled but + without the necessary TLS backend (with DES) support. - Assisted-by: Philip Heiduck - Closes #9532 + Closes #12384 -Daniel Stenberg (8 Oct 2023) +- curl.h: delete Symbian OS references -- url: fall back to http/https proxy env-variable if ws/wss not set + curl deprecated Symbian OS in 3d64031fa7a80ac4ae3fd09a5939196268b92f81 + via #5989. Delete references to it from public headers, because there + is no fresh release to use those headers with. - Reported-by: Craig Andrews - Fixes #12031 - Closes #12058 + Reviewed-by: Dan Fandrich + Reviewed-by: Jay Satiro + Closes #12378 -Stefan Eissing (8 Oct 2023) +- windows: use built-in `_WIN32` macro to detect Windows -- cf-socket: simulate slow/blocked receives in debug + Windows compilers define `_WIN32` automatically. Windows SDK headers + or build env defines `WIN32`, or we have to take care of it. The + agreement seems to be that `_WIN32` is the preferred practice here. + Make the source code rely on that to detect we're building for Windows. - 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 + Public `curl.h` was using `WIN32`, `__WIN32__` and `CURL_WIN32` for + Windows detection, next to the official `_WIN32`. After this patch it + only uses `_WIN32` for this. Also, make it stop defining `CURL_WIN32`. - Closes #12035 + There is a slight chance these break compatibility with Windows + compilers that fail to define `_WIN32`. I'm not aware of any obsolete + or modern compiler affected, but in case there is one, one possible + solution is to define this macro manually. -- http2: refused stream handling for retry + grepping for `WIN32` remains useful to discover Windows-specific code. - - 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 + Also: - Reported-by: black-desk on github - Ref #11859 - Closes #12054 + - extend `checksrc` to ensure we're not using `WIN32` anymore. -Jay Satiro (8 Oct 2023) + - apply minor formatting here and there. -- CURLOPT_DEBUGFUNCTION.3: warn about internal handles + - delete unnecessary checks for `!MSDOS` when `_WIN32` is present. - - Warn that the user's debug callback may be called with the handle - parameter set to an internal handle. + Co-authored-by: Jay Satiro + Reviewed-by: Daniel Stenberg - 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. + Closes #12376 - 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. +Stefan Eissing (22 Nov 2023) - Closes https://github.com/curl/curl/pull/12034 +- url: ConnectionExists revisited -- url: fix typo + - have common pattern of `if not match, continue` + - revert pages long if()s to return early + - move dead connection check to later since it may + be relatively expensive + - check multiuse also when NOT building with NGHTTP2 + - for MULTIUSE bundles, verify that the inspected + connection indeed supports multiplexing when in use + (bundles may contain a mix of connection, afaict) -Daniel Stenberg (8 Oct 2023) + Closes #12373 -- test458: verify --expand-output, expanding a file name accepting option +Daniel Stenberg (22 Nov 2023) - Verifies the fix in #12055 (commit f2c8086ff15e6e995e1) +- CURLMOPT_MAX_CONCURRENT_STREAMS: make sure the set value is within range -- tool_getparam: accept variable expansion on file names too + ... or use the default value. - Reported-by: PBudmark on github - Fixes #12048 - Closes #12055 + Also clarify the documentation language somewhat. -- RELEASE-NOTES: synced + Closes #12382 -- multi: do CURLM_CALL_MULTI_PERFORM at two more places +- urldata: make maxconnects a 32 bit value - ... 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. + "2^32 idle connections ought to be enough for anybody" - Reported-by: Dan Fandrich. - Fixes #12033 - Closes #12056 + Closes #12375 -Viktor Szakats (7 Oct 2023) +- FEATURES: update the URL phrasing -- GHA/linux: mbedtls 3.5.0 + minor dep bumps + The URL is length limited since a while back so "no limit" simply is not + true anymore. Mention the URL RFC standard used instead. - Closes #12057 + Closes #12383 -Dan Fandrich (7 Oct 2023) +- wolfssh: remove redundant static prototypes -- CI: bump OpenLDAP package version on FreeBSD + vssh/wolfssh.c:346:18: error: redundant redeclaration of ‘wscp_recv’ [-We + rror=redundant-decls] - The old one is no longer available. + Closes #12381 -Marc Hoersken (7 Oct 2023) +- setopt: remove superfluous use of ternary expressions -- docs/libcurl/opts/Makefile.inc: add missing manpage files + Closes #12374 - Detected with #9532 +- mime: store "form escape" as a single bit -Dan Fandrich (7 Oct 2023) + Closes #12374 -- tests: fix a race condition in ftp server disconnect +- setopt: check CURLOPT_TFTP_BLKSIZE range on set - 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. + ... instead of later when the transfer is about to happen. - Fixes #12002 - Closes #12049 + Closes #12374 -Viktor Szakats (7 Oct 2023) +Viktor Szakats (21 Nov 2023) -- appveyor: bump mingw-w64 job to gcc 13 (was: 8) +- build: add more picky warnings and fix them - This sets gcc 6, 7, 9, 13 in our test mix (was: 6, 7, 8, 9). - Adding a modern gcc version to the tests. + Enable more picky compiler warnings. I've found these options in the + nghttp3 project when implementing the CMake quick picky warning + functionality for it [1]. - (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.) + `-Wunused-macros` was too noisy to keep around, but fixed a few issues + it revealed while testing. - It also adds a modern CMake version and OS env to our mingw-w64 builds. + - autotools: reflect the more precisely-versioned clang warnings. + Follow-up to 033f8e2a08eb1d3102f08c4d8c8e85470f8b460e #12324 + - autotools: sync between clang and gcc the way we set `no-multichar`. + - autotools: avoid setting `-Wstrict-aliasing=3` twice. + - autotools: disable `-Wmissing-noreturn` for MSYS gcc targets [2]. + It triggers in libtool-generated stub code. - Closes #12051 + - lib/timeval: delete a redundant `!MSDOS` guard from a `WIN32` branch. -David Benjamin (6 Oct 2023) + - lib/curl_setup.h: delete duplicate declaration for `fileno`. + Added in initial commit ae1912cb0d494b48d514d937826c9fe83ec96c4d + (1999-12-29). This suggests this may not be needed anymore, but if + it does, we may restore this for those specific (non-Windows) systems. + - lib: delete unused macro `FTP_BUFFER_ALLOCSIZE` since + c1d6fe2aaa5a26e49a69a4f2495b3cc7a24d9394. + - lib: delete unused macro `isxdigit_ascii` since + f65f750742068f579f4ee6d8539ed9d5f0afcb85. + - lib/mqtt: delete unused macro `MQTT_HEADER_LEN`. + - lib/multi: delete unused macro `SH_READ`/`SH_WRITE`. + - lib/hostip: add `noreturn` function attribute via new `CURL_NORETURN` + macro. + - lib/mprintf: delete duplicate declaration for `Curl_dyn_vprintf`. + - lib/rand: fix `-Wunreachable-code` and related fallouts [3]. + - lib/setopt: fix `-Wunreachable-code-break`. + - lib/system_win32 and lib/timeval: fix double declarations for + `Curl_freq` and `Curl_isVistaOrGreater` in CMake UNITY mode [4]. + - lib/warnless: fix double declarations in CMake UNITY mode [5]. + This was due to force-disabling the header guard of `warnless.h` to + to reapply it to source code coming after `warnless.c` in UNITY + builds. This reapplied declarations too, causing the warnings. + Solved by adding a header guard for the lines that actually need + to be reapplied. + - lib/vauth/digest: fix `-Wunreachable-code-break` [6]. + - lib/vssh/libssh2: fix `-Wunreachable-code-break` and delete redundant + block. + - lib/vtls/sectransp: fix `-Wunreachable-code-break` [7]. + - lib/vtls/sectransp: suppress `-Wunreachable-code`. + Detected in `else` branches of dynamic feature checks, with results + known at compile-time, e.g. + ```c + if(SecCertificateCopySubjectSummary) /* -> true */ + ``` + Likely fixable as a separate micro-project, but given SecureTransport + is deprecated anyway, let's just silence these locally. + - src/tool_help: delete duplicate declaration for `helptext`. + - src/tool_xattr: fix `-Wunreachable-code`. + - tests: delete duplicate declaration for `unitfail` [8]. + - tests: delete duplicate declaration for `strncasecompare`. + - tests/libtest: delete duplicate declaration for `gethostname`. + Originally added in 687df5c8c39c370a59999b9afc0917d808d978b7 + (2010-08-02). + Got complicated later: c49e9683b85ba9d12cbb6eebc4ab2c8dba68fbdc + If there are still systems around with warnings, we may restore the + prototype, but limited for those systems. + - tests/lib2305: delete duplicate declaration for + `libtest_debug_config`. + - tests/h2-download: fix `-Wunreachable-code-break`. -- openssl: use X509_ALGOR_get0 instead of reaching into X509_ALGOR + [1] https://github.com/ngtcp2/nghttp3/blob/a70edb08e954d690e8fb2c1df999b5a056 + f8bf9f/cmake/PickyWarningsC.cmake + [2] https://ci.appveyor.com/project/curlorg/curl/builds/48553586/job/3qkgjaui + qla5fj45?fullLog=true#L1675 + [3] https://github.com/curl/curl/actions/runs/6880886309/job/18716044703?pr=1 + 2331#step:7:72 + https://github.com/curl/curl/actions/runs/6883016087/job/18722707368?pr=1 + 2331#step:7:109 + [4] https://ci.appveyor.com/project/curlorg/curl/builds/48555101/job/9g15qkrr + iklpf1ut#L204 + [5] https://ci.appveyor.com/project/curlorg/curl/builds/48555101/job/9g15qkrr + iklpf1ut#L218 + [6] https://github.com/curl/curl/actions/runs/6880886309/job/18716042927?pr=1 + 2331#step:7:290 + [7] https://github.com/curl/curl/actions/runs/6891484996/job/18746659406?pr=1 + 2331#step:9:1193 + [8] https://github.com/curl/curl/actions/runs/6882803986/job/18722082562?pr=1 + 2331#step:33:1870 - 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 #12331 - Closes #12038 +Daniel Stenberg (21 Nov 2023) -Daniel Stenberg (6 Oct 2023) +- transfer: avoid unreachable expression -- curl_easy_pause.3: mention it works within callbacks + If curl_off_t and size_t have the same size (which is common on modern + 64 bit systems), a condition cannot occur which Coverity pointed + out. Avoid the warning by having the code conditionally only used if + curl_off_t actually is larger. - Reported-by: Maxim Dzhura - Bug: https://curl.se/mail/lib-2023-10/0010.html - Closes #12046 + Follow-up to 1cd2f0072fa482e25baa2 -- curl_easy_pause.3: mention h2/h3 buffering + Closes #12370 - Asked-by: Maxim Dzhura - Ref: https://curl.se/mail/lib-2023-10/0011.html +Stefan Eissing (21 Nov 2023) - Closes #12045 +- transfer: readwrite improvements -Viktor Szakats (6 Oct 2023) + - changed header/chunk/handler->readwrite prototypes to accept `buf`, + `blen` and a `pconsumed` pointer. They now get the buffer to work on + and report back how many bytes they consumed + - eliminated `k->str` in SingleRequest + - improved excess data handling to properly calculate with any body data + left in the headerb buffer + - eliminated `k->badheader` enum to only be a bool -- cmake: re-add missed C89 headers for specific detections + Closes #12283 - 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. +Daniel Stenberg (21 Nov 2023) - [1] Follow-up to 3795fcde995d96db641ddbcc8a04f9f0f03bef9f #11951 - [2] Follow-up to 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940 +- RELEASE-NOTES: synced - Closes #12043 +Jiří Hruška (21 Nov 2023) -Daniel Stenberg (6 Oct 2023) +- transfer: avoid calling the read callback again after EOF -- multi: set CURLM_CALL_MULTI_PERFORM after switch to DOING_MORE + Regression since 7f43f3dc5994d01b12 (7.84.0) - Since there is nothing to wait for there. Avoids the test 1233 hang - reported in #12033. + Bug: https://curl.se/mail/lib-2023-11/0017.html - Reported-by: Dan Fandrich - Closes #12042 + Closes #12363 -Dan Fandrich (5 Oct 2023) +Daniel Stenberg (21 Nov 2023) -- test1903: actually verify the cookies after the test +- doh: provide better return code for responses w/o addresses - 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. + Previously it was wrongly returning CURLE_OUT_OF_MEMORY when the + response did not contain any addresses. Now it more accurately returns + CURLE_COULDNT_RESOLVE_HOST. - Closes #12041 + Reported-by: lRoccoon on github -- test: add missing s + Fixes #12365 + Closes #12366 - The tests will otherwise fail if curl has them disabled. +Stefan Eissing (21 Nov 2023) -- test1906: set a lower timeout since it's hit on Windows +- HTTP/2, HTTP/3: handle detach of onoing transfers - msys2 builds actually hit the connect timeout in normal operation, so - lower the timeout from 5 minutes to 5 seconds to reduce test time. + - refs #12356 where a UAF is reported when closing a connection + with a stream whose easy handle was cleaned up already + - handle DETACH events same as DONE events in h2/h3 filters - Ref: #11328 - Closes #12036 + Fixes #12356 + Reported-by: Paweł Wegner + Closes #12364 -Daniel Stenberg (5 Oct 2023) +Viktor Szakats (20 Nov 2023) -- RELEASE-NOTES: synced +- autotools: stop setting `-std=gnu89` with `--enable-warnings` -Jay Satiro (5 Oct 2023) + Do not alter the C standard when building with `--enable-warnings` when + building with gcc. -- idn: fix WinIDN null ptr deref on bad host + On one hand this alters warning results compared to a default build. + On the other, it may produce different binaries, which is unexpected. - - Return CURLE_URL_MALFORMAT if IDN hostname cannot be converted from - UTF-8 to UTF-16. + Also fix new warnings that appeared after removing `-std=gnu89`: - 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. + - include: fix public curl headers to use the correct printf mask for + `CURL_FORMAT_CURL_OFF_T` and `CURL_FORMAT_CURL_OFF_TU` with mingw-w64 + and Visual Studio 2013 and newer. This fixes the printf mask warnings + in examples and tests. E.g. [1] - Closes https://github.com/curl/curl/pull/11983 + - conncache: fix printf format string [2]. -Dan Fandrich (4 Oct 2023) + - http2: fix potential null pointer dereference [3]. + (seen on Slackware with gcc 11.) -- tests: close the shell used to start sshd + - libssh: fix printf format string in SFTP code [4]. + Also make MSVC builds compatible with old CRT versions. - This shell isn't needed once sshd starts, so use "exec" so it doesn't - stick around. + - libssh2: fix printf format string in SFTP code for MSVC. + Applying the same fix as for libssh above. - Closes #12032 + - unit1395: fix `argument is null` and related issues [5]: + - stop calling `strcmp()` with NULL to avoid undefined behaviour. + - fix checking results if some of them were NULL. + - do not pass NULL to printf `%s`. -Daniel Stenberg (4 Oct 2023) + - ci: keep a build job with `-std=gnu89` to continue testing for + C89-compliance. We can apply this to other gcc jobs as needed. + Ref: b23ce2cee7329bbf425f18b49973b7a5f23dfcb4 (2022-09-23) #9542 -- base64: also build for curl + [1] https://dev.azure.com/daniel0244/curl/_build/results?buildId=18581&view=l + ogs&jobId=ccf9cc6d-2ef1-5cf2-2c09-30f0c14f923b + [2] https://github.com/curl/curl/actions/runs/6896854263/job/18763831142?pr=1 + 2346#step:6:67 + [3] https://github.com/curl/curl/actions/runs/6896854253/job/18763839238?pr=1 + 2346#step:30:214 + [4] https://github.com/curl/curl/actions/runs/6896854253/job/18763838007?pr=1 + 2346#step:29:895 + [5] https://github.com/curl/curl/actions/runs/6896854253/job/18763836775?pr=1 + 2346#step:33:1689 - 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. + Closes #12346 - Follow-up to 2e160c9c6525 +- autotools: fix/improve gcc and Apple clang version detection - Closes #12010 + - Before this patch we expected `n.n` `-dumpversion` output, but Ubuntu + may return `n-win32` (also with `-dumpfullversion`). Causing these + errors and failing to enable picky warnings: + ``` + ../configure: line 23845: test: : integer expression expected + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/6263453828/job/1700789 + 3718#step:5:143 -Eduard Strehlau (4 Oct 2023) + Fix that by stripping any dash-suffix and handling a dotless (major-only) + version number by assuming `.0` in that case. -- tests: Fix zombie processes left behind by FTP tests. + `9.3-posix`, `9.3-win32`, `6`, `9.3.0`, `11`, `11.2`, `11.2.0` + Ref: https://github.com/mamedev/mame/pull/9767 - 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. + - fix Apple clang version detection for releases between + 'Apple LLVM version 7.3.0' and 'Apple LLVM version 10.0.1' where the + version was under-detected as 3.7 llvm/clang equivalent. - Fixes #12018 - Closes #12020 + - fix Apple clang version detection for 'Apple clang version 11.0.0' + and newer where the Apple clang version was detected, instead of its + llvm/clang equivalent. -Dan Fandrich (4 Oct 2023) + - display detected clang/gcc/icc compiler version. -- github/labeler: improve labeler matches + Via libssh2: + - https://github.com/libssh2/libssh2/commit/00a3b88c51cdb407fbbb347a2e38c5c7d + 89875ad + https://github.com/libssh2/libssh2/pull/1187 + - https://github.com/libssh2/libssh2/commit/89ccc83c7da73e7ca3a112e3500081319 + 42b592e + https://github.com/libssh2/libssh2/pull/1232 -- test574: add a timeout to the test + Closes #12362 - This one hangs occasionally, so this will speed up a test run and allow - logs to be seen when it does. +- autotools: delete LCC compiler support bits - Closes #12025 + Follow-up to fd7ef00f4305a2919e6950def1cf83d0110a4acd #12222 -- tests: propagate errors in libtests + Closes #12357 - 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. +- cmake: add test for `DISABLE` options, add `CURL_DISABLE_HEADERS_API` -- tests: set --expect100-timeout to improve test reliability + - tests: verify CMake `DISABLE` options. - 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. + Make an exception for 2 CMake-only ones, and one more that's + using a different naming scheme, also in autotools and source. - Ref: #11328 + - cmake: add support for `CURL_DISABLE_HEADERS_API`. -- CI: ignore the "flaky" and "timing-dependent" test results in CMake + Suggested-by: Daniel Stenberg + Ref: https://github.com/curl/curl/pull/12345#pullrequestreview-1736238641 - This was already done for automake builds but CMake builds were missed. - Test 1086 actually causes the test harness to crash with: + Closes #12353 - Warning: unable to close filehandle DWRITE properly: Broken pipe at C:/projec - ts/curl/tests/ftpserver.pl line 527 +Jacob Hoffman-Andrews (20 Nov 2023) - Rather than fix it now, this change leaves test 1086 entirely skipped on - those builds that show this problem. +- hyper: temporarily remove HTTP/2 support - Follow-up to 589dca761 + The current design of the Hyper integration requires rebuilding the + Hyper clientconn for each request. However, building the clientconn + requires resending the HTTP/2 connection preface, which is incorrect + from a protocol perspective. That in turn causes servers to send GOAWAY + frames, effectively degrading performance to "no connection reuse" in + the best case. It may also be triggering some bugs where requests get + dropped entirely and reconnects take too long. - Ref: #11865 + This doesn't rule out HTTP/2 support with Hyper, but it may take a + redesign of the Hyper integration in order to make things work. -Viktor Szakats (4 Oct 2023) + Closes #12191 -- cmake: improve OpenLDAP builds +Jay Satiro (20 Nov 2023) - - 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] - ``` +- schannel: fix unused variable warning - - cmake: delete LDAP TODO comment no longer relevant. + Bug: https://github.com/curl/curl/pull/12349#issuecomment-1818000846 + Reported-by: Viktor Szakats - Also: + Closes https://github.com/curl/curl/pull/12361 - - autotools: replace domain name `dummy` with `0.0.0.0` in LDAP feature - detection functions. +Daniel Stenberg (19 Nov 2023) - Ref: #11964 (effort to sync cmake detections with autotools) +- url: find scheme with a "perfect hash" - Closes #12024 + Instead of a loop to scan over the potentially 30+ scheme names, this + uses a "perfect hash" table. This works fine because the set of schemes + is known and cannot change in a build. The hash algorithm and table size + is made to only make a single scheme index per table entry. -- cmake: fix unity builds for more build combinations + The perfect hash is generated by a separate tool (scripts/schemetable.c) - By using unique static function/variable names in source files - implementing these interfaces. + Closes #12347 - - OpenLDAP combined with any SSH backend. +- scripts: add schemetable.c - - MultiSSL with mbedTLS, OpenSSL, wolfSSL, SecureTransport. + This tool generates a scheme-matching table. - Closes #12027 + It iterates over a number of different initial and shift values in order + to find the hash algorithm that needs the smallest possible table. -Daniel Stenberg (4 Oct 2023) + The generated hash function, table and table size then needs to be used + by the url.c:Curl_getn_scheme_handler() function. -- tests: remove leading spaces from some tags +Stefan Eissing (19 Nov 2023) - The threee tags ``, `` and `` 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. +- vtls/vquic, keep peer name information together - Hence, fixing them all now might curb this practice from now on. + - add `struct ssl_peer` to keep hostname, dispname and sni + for a filter + - allocate `sni` for use in VTLS backend + - eliminate `Curl_ssl_snihost()` and its use of the download buffer + - use ssl_peer in SSL and QUIC filters - Closes #12028 + Closes #12349 -Viktor Szakats (4 Oct 2023) +Viktor Szakats (18 Nov 2023) -- GHA: bump actions/checkout +- build: always revert `#pragma GCC diagnostic` after use - Follow-up to 2e0fa50fc16b9339f51e0a7bfff0352829323acb #11964 - Follow-up to c39585d9b7ef3cbfc1380812dec60e7b275b6af3 #12000 + Before this patch some source files were overriding gcc warning options, + but without restoring them at the end of the file. In CMake UNITY builds + these options spilled over to the remainder of the source code, + effecitvely disabling them for a larger portion of the codebase than + intended. - Closes #12023 + `#pragma clang diagnostic` didn't have such issue in the codebase. -- spelling: fix codespell 2.2.6 typos + Reviewed-by: Marcel Raad + Closes #12352 - Closes #12019 +- tidy-up: casing typos, delete unused Windows version aliases -Daniel Stenberg (3 Oct 2023) + - cmake: fix casing of `UnixSockets` to match the rest of the codebase. -- GHA: add workflow to compare configure vs cmake outputs + - curl-compilers.m4: fix casing in a comment. - 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. + - setup-win32: delete unused Windows version constant aliases. - The script also shows the matches that were *not* used. Possibly - subjects for removal. + Reviewed-by: Marcel Raad + Closes #12351 - Closes #11964 +- keylog: disable if unused -- appveyor: enable test 571 + Fully disable keylog code if there is no TLS or QUIC subsystem using it. - Follow-up from 8a940fd55c175f7 / #12013 + Closes #12350 - Closes #12017 +- cmake: add `CURL_DISABLE_BINDLOCAL` option -Viktor Szakats (3 Oct 2023) + To match similar autotools option. -- build: alpha-sort source files for lib and src + Default is `ON`. - Closes #12014 + Reviewed-by: Daniel Stenberg + Closes #12345 -- cmake: delete old `HAVE_LDAP_URL_PARSE` logic +- url: fix `-Wzero-length-array` with no protocols - Left there by accident after adding proper detection for this. + Fixes: + ``` + ./lib/url.c:178:56: warning: use of an empty initializer is a C2x extension [ + -Wc2x-extensions] + 178 | static const struct Curl_handler * const protocols[] = { + | ^ + ./lib/url.c:178:56: warning: zero size arrays are an extension [-Wzero-length + -array] + ``` - Follow-up to 772f0d8edf1c3c2745543f42388ccec5a16ee2c0 #12006 + Closes #12344 - Ref: #11964 (effort to sync cmake detections with autotools) +- url: fix builds with `CURL_DISABLE_HTTP` - Closes #12015 + Fixes: + ``` + ./lib/url.c:456:35: error: no member named 'formp' in 'struct UrlState' + 456 | Curl_mime_cleanpart(data->state.formp); + | ~~~~~~~~~~~ ^ + ``` -Stefan Eissing (3 Oct 2023) + Regression from 74b87a8af13a155c659227f5acfa78243a8b2aa6 #11682 -- tests: increase lib571 timeout from 3s to 30s + Closes #12343 - - 3s is too short for our CI, making this test fail occasionally - - test usually experiences no delay run locally, so 30s wont hurt +- http: fix `-Wunused-parameter` with no auth and no proxy - Closes #12013 + ``` + lib/http.c:734:26: warning: unused parameter 'proxy' [-Wunused-parameter] + bool proxy) + ^ + ``` -Viktor Szakats (3 Oct 2023) + Reviewed-by: Marcel Raad + Closes #12338 -- cmake: fix unity with Windows Unicode + TrackMemory +Daniel Stenberg (16 Nov 2023) - Found the root cause of the startup crash in unity builds with Unicode - and TrackMemory enabled at the same time. +- TODO: Some TLS options are not offered for HTTPS proxies - 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. + Closes #12286 + Closes #12342 - 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. +- RELEASE-NOTES: synced - Follow-up to d82b080f6374433ce7c98241329189ad2d3976f8 #12005 - Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 #11095 +- duphandle: make dupset() not return with pointers to old alloced data - Closes #11928 + As the blob pointers are to be duplicated, the function must not return + mid-function with lingering pointers to the old handle's allocated data, + as that would lead to double-free in OOM situations. -- cmake: disable unity mode with Windows Unicode + TrackMemory + Make sure to clear all destination pointers first to avoid this risk. - "TrackMemory" is `ENABLE_DEBUG=ON` (aka `ENABLE_CURLDEBUG=ON`, - aka `-DCURLDEBUG`). + Closes #12337 - 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. +Viktor Szakats (16 Nov 2023) - 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. +- http: fix `-Wunused-variable` compiler warning - 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) + Fix compiler warnings in builds with disabled auths, NTLM and SPNEGO. - Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 #11095 + E.g. with `CURL_DISABLE_BASIC_AUTH` + `CURL_DISABLE_BEARER_AUTH` + + `CURL_DISABLE_DIGEST_AUTH` + `CURL_DISABLE_NEGOTIATE_AUTH` + + `CURL_DISABLE_NTLM` on non-Windows. - Ref: #11928 - Closes #12005 + ``` + ./curl/lib/http.c:737:12: warning: unused variable 'result' [-Wunused-variabl + e] + CURLcode result = CURLE_OK; + ^ + ./curl/lib/http.c:995:18: warning: variable 'availp' set but not used [-Wunus + ed-but-set-variable] + unsigned long *availp; + ^ + ./curl/lib/http.c:996:16: warning: variable 'authp' set but not used [-Wunuse + d-but-set-variable] + struct auth *authp; + ^ + ``` -- cmake: tidy-up `NOT_NEED_LBER_H` detection + Regression from e92edfbef64448ef461117769881f3ed776dec4e #11490 - Follow-up to 772f0d8edf1c3c2745543f42388ccec5a16ee2c0 #12006 + Fixes #12228 + Closes #12335 -- appveyor: rewrite batch in PowerShell + CI improvements +Jay Satiro (16 Nov 2023) - 1. Rewrite in PowerShell: +- tool: support bold headers in Windows - - 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`. + - If virtual terminal processing is enabled in Windows then use ANSI + escape codes Esc[1m and Esc[22m to turn bold on and off. - 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. + Suggested-by: Gisle Vanem - 2. CI improvements: + Ref: https://github.com/curl/curl/discussions/11770 - - 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). + Closes https://github.com/curl/curl/pull/12321 - 3. Style: +Viktor Szakats (15 Nov 2023) - - 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.) +- build: fix libssh2 + `CURL_DISABLE_DIGEST_AUTH` + `CURL_DISABLE_AWS` - Closes #11999 + Builds with libssh2 + `-DCURL_DISABLE_DIGEST_AUTH=ON` + + `-DCURL_DISABLE_AWS=ON` in combination with either Schannel on Windows, + or `-DCURL_DISABLE_NTLM=ON` on other operating systems failed while + compiling due to a missing HMAC declaration. -- 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. + The reason is that HMAC is required by `lib/sha256.c` which publishes + `Curl_sha256it()` which is required by `lib/vssh/libssh2.c` when + building for libssh2 v1.8.2 (2019-05-25) or older. - - 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. + Make sure to compile the HMAC bits for a successful build. - - enable LDAP[S] for a CMake macOS CI job. Target OS X 10.9 (Mavericks) - to avoid deprecation warnings for LDAP API. + Both HMAC and `Curl_sha256it()` rely on the same internals, so splitting + them into separate sources isn't practical. - - 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. + Fixes: + ``` + [...] + In file included from ./curl/_x64-win-ucrt-cmake-llvm-bld/lib/CMakeFiles/libc + url_object.dir/Unity/unity_0_c.c:310: + ./curl/lib/sha256.c:527:42: error: array has incomplete element type 'const s + truct HMAC_params' + 527 | const struct HMAC_params Curl_HMAC_SHA256[] = { + | ^ + ./curl/lib/curl_sha256.h:34:21: note: forward declaration of 'struct HMAC_par + ams' + [...] + ``` - - fix benign typo in variable name. + Regression from e92edfbef64448ef461117769881f3ed776dec4e #11490 - Ref: #11964 (effort to sync cmake detections with autotools) + Fixes #12273 + Closes #12332 - Closes #12006 +Daniel Stenberg (15 Nov 2023) -- autotools: restore `HAVE_IOCTL_*` detections +- duphandle: also free 'outcurl->cookies' in error path - 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`. + Fixes memory-leak when OOM mid-function - Regression from 4d73854462f30948acab12984b611e9e33ee41e6 + Use plain free instead of safefree, since the entire struct is + freed below. - Ref: #11964 (effort to sync cmake detections with autotools) + Remove some free calls that is already freed in Curl_freeset() - Closes #12008 + Closes #12329 -Daniel Stenberg (2 Oct 2023) +Viktor Szakats (15 Nov 2023) -- RELEASE-PROCEDURE.md: updated coming release dates +- config-win32: set `HAVE_SNPRINTF` for mingw-w64 -- RELEASE-NOTES: synced + It's available in all mingw-w64 releases. We already pre-fill this + detection in CMake. -Viktor Szakats (1 Oct 2023) + Closes #12325 -- cmake: pre-cache `HAVE_POLL_FINE` on Windows +- sasl: fix `-Wunused-function` compiler warning - Windows doesn't support `poll()`, so we can safely skip checking for - fine poll. + In builds with disabled auths. - Closes #12003 + ``` + lib/curl_sasl.c:266:17: warning: unused function 'get_server_message' [-Wunus + ed-function] + static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data, + ^ + 1 warning generated. + ``` + Ref: https://github.com/curl/trurl/actions/runs/6871732122/job/18689066151#st + ep:3:3822 -- gha: bump actions to latest versions + Reviewed-by: Daniel Stenberg + Closes #12326 - - actions@checkout@v4 (from v3 and v2) +- build: picky warning updates - - fsfe/reuse-action@v2 (from v1) + - cmake: sync some picky gcc warnings with autotools. + - cmake, autotools: add `-Wold-style-definition` for clang too. + - cmake: more precise version info for old clang options. + - cmake: use `IN LISTS` syntax in `foreach()`. - Closes #12000 + Reviewed-by: Daniel Stenberg + Reviewed-by: Marcel Raad + Closes #12324 -Stefan Eissing (30 Sep 2023) +Daniel Stenberg (15 Nov 2023) -- h2: testcase and fix for pausing h2 streams +- urldata: move cookielist from UserDefined to UrlState - - 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 + 1. Because the value is not strictly set with a setopt option. - Closes #11989 - Fixes #11982 - Reported-by: Harry Sintonen + 2. Because otherwise when duping a handle when all the set.* fields are + first copied and an error happens (think out of memory mid-function), + the function would easily free the list *before* it was deep-copied, + which could lead to a double-free. -Viktor Szakats (30 Sep 2023) + Closes #12323 -- cmake: validate `CURL_DEFAULT_SSL_BACKEND` config value +Viktor Szakats (14 Nov 2023) - 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. +- autotools: avoid passing `LDFLAGS` twice to libcurl - This improves reproducibility and brings CMake in sync with autotools - which already worked like described above. + autotools passes `LDFLAGS` automatically linker commands. curl's + `lib/Makefile.am` customizes libcurl linker flags. In that + customization, it added `LDFLAGS` to the custom flags. This resulted in + passing `LDFLAGS` _twice_ to the `libtool` command. - Follow-up to 26c7feb8b9d51a57fab3325571b4bbfa03b11af0 #11774 + Most of the time this is benign, but some `LDFLAGS` options can break + the build when passed twice. One such example is passing `.o` files, + e.g. `crt*.o` files necessary when customizing the C runtime, e.g. for + MUSL builds. - Closes #11998 + Passing them twice resulted in duplicate symbol errors: + ``` + libtool: link: clang-15 --target=aarch64-unknown-linux-musl [...] /usr/lib/a + arch64-linux-musl/crt1.o [...] /usr/lib/aarch64-linux-musl/crt1.o [...] + ld.lld-15: error: duplicate symbol: _start + >>> defined at crt1.c + >>> /usr/lib/aarch64-linux-musl/crt1.o:(.text+0x0) + >>> defined at crt1.c + >>> /usr/lib/aarch64-linux-musl/crt1.o:(.text+0x0) + [...] + clang: error: linker command failed with exit code 1 (use -v to see invocatio + n) + ``` -- autotools: adjust `CURL_CA_PATH` value to CMake + This behaviour came with commit 1a593191c2769a47b8c3e4d9715ec9f6dddf5e36 + (2013-07-23) as a fix for bug https://curl.haxx.se/bug/view.cgi?id=1217. + The patch was a works-for-me hack that ended up merged in curl: + https://sourceforge.net/p/curl/bugs/1217/#06ef + With the root cause remaining unclear. - autotools was using the same value as CMake, but with an ending - slash. Delete the ending slash to match configurations. + Perhaps the SUNPro 12 linker was sensitive to `-L` `-l` order, requiring + `-L` first? This would be unusual and suggests a bug in either the + linker or in `libtool`. - Ref: #11964 (effort to sync cmake detections with autotools) + The curl build does pass the list of detected libs via its own + `LIBCURL_LIBS` variable, which ends up before `LDFLAGS` on the `libtool` + command line, but it's the job of `libtool` to ensure that even + a peculiar linker gets the options in the expected order. Also because + autotools passes `LDFLAGS` last, making it hardly possible to pass + anything after it. - Closes #11997 + Perhaps in the 10 years since this issue, this already got a fix + upstream. -- cmake: detect `sys/wait.h` and `netinet/udp.h` + This patch deletes `LDFLAGS` from our customized libcurl options, + leaving a single copy of them as passed by autotools automatically. - Ref: #11964 (effort to sync cmake detections with autotools) + Reverts 1a593191c2769a47b8c3e4d9715ec9f6dddf5e36 + Closes #12310 - Closes #11996 +- autotools: accept linker flags via `CURL_LDFLAGS_{LIB,BIN}` -Daniel Stenberg (30 Sep 2023) + To allow passing `LDFLAGS` specific to libcurl (`CURL_LDFLAGS_LIB`) and + curl tool (`CURL_LDFLAGS_BIN`). -- lib: provide and use Curl_hexencode + This makes it possible to build libcurl and curl with a single + invocation with lib- and tool-specific custom linker flags. - Generates a lower case ASCII hex output from a binary input. + Such flag can be enabling `.map` files, a `.def` file for libcurl DLL, + controlling static/shared, incl. requesting a static curl tool (with + `-static-libtool-libs`) while building both shared and static libcurl. - Closes #11990 + curl-for-win uses the above and some more. -- configure: check for the capath by default + These options are already supported in `Makefile.mk`. CMake has built-in + variables for this. - ... if the chosen TLS backend supports it: OpenSSL, GnuTLS, mbedTLS or wolfSS - L + Closes #12312 - cmake: synced +Jay Satiro (14 Nov 2023) - Assisted-by: Viktor Szakats - Closes #11987 +- tool_cb_hdr: add an additional parsing check -- wolfssl: ignore errors in CA path + - Don't dereference the past-the-end element when parsing the server's + Content-disposition header. - 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. + As 'p' is advanced it can point to the past-the-end element and prior + to this change 'p' could be dereferenced in that case. - With the *_ex() function and its WOLFSSL_LOAD_FLAG_IGNORE_ERR flag, it - behaves more similar to what OpenSSL does by default. + Technically the past-the-end element is not out of bounds because dynbuf + (which manages the header line) automatically adds a null terminator to + every buffer and that is not included in the buffer length passed to + the header callback. - Even the set of default certs on my Debian unstable has several expired - ones. + Closes https://github.com/curl/curl/pull/12320 - Assisted-by: Juliusz Sosinowicz - Assisted-by: Michael Osipov +Philip Heiduck (14 Nov 2023) - Closes #11987 +- .cirrus.yml: freebsd 14 -- create-dirs.d: clarify it also uses --output-dirs + ensure curl works on latest freebsd version - Reported-by: Robert Simpson - Fixes #11991 - Closes #11995 + Closes #12053 -Viktor Szakats (30 Sep 2023) +Daniel Stenberg (13 Nov 2023) -- appveyor: fix yamlint issues, indent +- easy: in duphandle, init the cookies for the new handle - Also: - - use double quotes in all batch if statements. + ... not the source handle. - Closes #11994 + Closes #12318 -- cmake: detect `HAVE_CLOCK_GETTIME_MONOTONIC_RAW` +- duphandle: use strdup to clone *COPYPOSTFIELDS if size is not set - Based on existing autotools logic. + Previously it would unconditionally use the size, which is set to -1 + when strlen is requested. - Ref: #11964 (effort to sync cmake detections with autotools) + Updated test 544 to verify. - Closes #11981 + Closes #12317 -- cmake: detect `HAVE_GETADDRINFO_THREADSAFE` +- RELEASE-NOTES: synced - Based on existing autotools logic. +- curl_easy_duphandle.3: clarify how HSTS and alt-svc are duped - 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. + Closes #12315 - 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. +- urldata: move hstslist from 'set' to 'state' - 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. + To make it work properly with curl_easy_duphandle(). This, because + duphandle duplicates the entire 'UserDefined' struct by plain copy while + 'hstslist' is a linked curl_list of file names. This would lead to a + double-free when the second of the two involved easy handles were + closed. - Ref: #11964 (effort to sync cmake detections with autotools) + Closes #12315 - Closes #11979 +- test1900: verify duphandle with HSTS using multiple files -- cmake: fix `HAVE_WRITABLE_ARGV` detection + Closes #12315 - Move detection before the creation of detection results in - `curl_config.h`. +Goro FUJI (13 Nov 2023) - Ref: #11964 (effort to sync cmake detections with autotools) +- http: allow longer HTTP/2 request method names - Closes #11978 + - Increase the maximum request method name length from 11 to 23. -- appveyor: minor improvements + For HTTP/1.1 and earlier there's not a specific limit in libcurl for + method length except that it is limited by the initial HTTP request + limit (DYN_HTTP_REQUEST). Prior to fc2f1e54 HTTP/2 was treated the same + and there was no specific limit. - - 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. + According to Internet Assigned Numbers Authority (IANA) the longest + registered method is UPDATEREDIRECTREF which is 17 characters. - - 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.) + Also there are unregistered methods used by some companies that are + longer than 11 characters. - - list the DLLs and EXEs present after the builds. + The limit was originally added by 61f52a97 but not used until fc2f1e54. - - add `DEBUG` variable for CMake builds to allow disabling it, for - testing non-debug builds. (currently enabled for all) + Ref: https://www.iana.org/assignments/http-methods/http-methods.xhtml - - add commented lines that dump CMake configuration logs for debugging - build/auto-detection issues. + Closes https://github.com/curl/curl/pull/12311 - - add gcc version to jobs where missing. +Jay Satiro (12 Nov 2023) - - switch a job to the native MSYS2 mingw-w64 toolchain. This adds gcc 9 - to the build mix. +- CURLOPT_CAINFO_BLOB.3: explain what CURL_BLOB_COPY does - - make `SHARED=OFF` and `OPENSSL=OFF` defaults global. + - Add an explanation of the CURL_BLOB_COPY flag to CURLOPT_CAINFO_BLOB + and CURLOPT_PROXY_CAINFO_BLOB docs. - - delete a duplicate backslash. + All the other _BLOB option docs already have the same explanation. - Closes #11976 + Closes https://github.com/curl/curl/pull/12277 -- configure: replace adhoc domain with `localhost` in tests +Viktor Szakats (11 Nov 2023) + +- tidy-up: dedupe Windows system libs in cmake Reviewed-by: Daniel Stenberg - Closes #11988 + Closes #12307 -- tidy-up: use more example domains +Junho Choi (11 Nov 2023) - Also make use of the example TLD: - https://en.wikipedia.org/wiki/.example +- ci: test with latest quiche release (0.19.0) - Reviewed-by: Daniel Stenberg - Closes #11992 + Closes #12180 -Dan Fandrich (29 Sep 2023) +- quiche: use quiche_conn_peer_transport_params() -- runtests: display the test status if tests appear hung + In recent quiche, transport parameter API is separated + with quiche_conn_peer_transport_params(). + (https://github.com/cloudflare/quiche/pull/1575) + It breaks with bulding with latest(post 0.18.0) quiche. - 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. + Closes #12180 - 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. +Daniel Stenberg (11 Nov 2023) - Closes #11980 +- Makefile: generate the VC 14.20 project files at dist-time -- github/labeler: remove workaround for labeler + Follow-up to 28287092cc5a6d6ef8 (#12282) - 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. + Closes #12290 - Follow-up to b2b0534e7 +Sam James (11 Nov 2023) -Viktor Szakats (29 Sep 2023) +- misc: fix -Walloc-size warnings -- docs: upgrade an URL to HTTPS in `BINDINGS.md` [ci skip] + GCC 14 introduces a new -Walloc-size included in -Wextra which gives: -Daniel Stenberg (29 Sep 2023) + ``` + src/tool_operate.c: In function ‘add_per_transfer’: + src/tool_operate.c:213:5: warning: allocation of insufficient size ‘1’ fo + r type ‘struct per_transfer’ with size ‘480’ [-Walloc-size] + 213 | p = calloc(sizeof(struct per_transfer), 1); + | ^ + src/var.c: In function ‘addvariable’: + src/var.c:361:5: warning: allocation of insufficient size ‘1’ for type + struct var’ with size ‘32’ [-Walloc-size] + 361 | p = calloc(sizeof(struct var), 1); + | ^ + ``` -- docs: replace made up domains with example.com + The calloc prototype is: + ``` + void *calloc(size_t nmemb, size_t size); + ``` - in FAQ and MANUAL.md + So, just swap the number of members and size arguments to match the + prototype, as we're initialising 1 struct of size `sizeof(struct + ...)`. GCC then sees we're not doing anything wrong. - - example.com was made for this purpose. + Closes #12292 - - reduces the risk that one of those domains suddenly start hosting - something nasty and we provide links to them +Mark Gaiser (11 Nov 2023) - Closes #11986 +- IPFS: bugfixes -Michael Osipov (29 Sep 2023) + - Fixed endianness bug in gateway file parsing + - Use IPFS_PATH in tests where IPFS_DATA was used + - Fixed typos from traling -> trailing + - Fixed broken link in IPFS.md -- acinclude.m4: Document proper system truststore on FreeBSD + Follow-up to 859e88f6533f9e - 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. + Reported-by: Michael Kaufmann + Bug: https://github.com/curl/curl/pull/12152#issuecomment-1798214137 + Closes #12305 - Closes #11985 +Daniel Stenberg (11 Nov 2023) -Daniel Stenberg (29 Sep 2023) +- VULN-DISCLOSURE-POLIC: remove broken link to hackerone -- FAQ: How do I upgrade curl.exe in Windows? + It should ideally soon not be done from hackerone anyway - This is a growing question, better answer it here to get somewhere to - point users to. + Closes #12308 - Closes #11984 +Andrew Kurushin (11 Nov 2023) -Viktor Szakats (28 Sep 2023) +- schannel: add CA cache support for files and memory blobs -- cmake: pre-cache `HAVE_BASENAME` for mingw-w64 and MSVC + - Support CA bundle and blob caching. - `basename` is present in mingw-w64, missing from MSVC. Pre-cache - accordingly to make configure faster. + Cache timeout is 24 hours or can be set via CURLOPT_CA_CACHE_TIMEOUT. - 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 https://github.com/curl/curl/pull/12261 - Closes #11974 +Daniel Stenberg (10 Nov 2023) -Daniel Stenberg (28 Sep 2023) +- RELEASE-NOTES: synced -- cmake: add missing checks +Charlie C (10 Nov 2023) - - 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 +- cmake: option to disable install & drop `curlu` target when unused - Ref: #11964 + This patch makes the following changes: + - adds the option `CURL_DISABLE_INSTALL` - to disable 'install' targets. + - Removes the target `curlu` when the option `BUILD_TESTING` is set to + `OFF` - to prevent it from being loaded in Visual Studio. - Co-authored-by: Viktor Szakats - Closes #11973 + Closes #12287 -- configure: remove unused checks +Kai Pastor (10 Nov 2023) - - for sys/uio.h - - for fork - - for connect +- cmake: fix multiple include of CURL package - Ref: #11964 + Fixes errors on second `find_package(CURL)`. This is a frequent case + with transitive dependencies: + ``` + CMake Error at ...: + add_library cannot create ALIAS target "CURL::libcurl" because another + target with the same name already exists. + ``` - Closes #11973 + Test to reproduce: + ```cmake + cmake_minimum_required(VERSION 3.27) # must be 3.18 or higher -- lib: remove TIME_WITH_SYS_TIME + project(curl) - It is not used in any code anywhere. + set(CURL_DIR "example/lib/cmake/CURL/") + find_package(CURL CONFIG REQUIRED) + find_package(CURL CONFIG REQUIRED) # fails - Ref: #11964 - Closes #11975 + add_executable(main main.c) + target_link_libraries(main CURL::libcurl) + ``` -- docs: update curl man page references + Ref: https://cmake.org/cmake/help/latest/release/3.18.html#other-changes + Ref: https://cmake.org/cmake/help/v3.18/policy/CMP0107.html + Ref: #12300 + Assisted-by: Harry Mallon + Closes #11913 - Detected by the manpage-syntax update +Viktor Szakats (8 Nov 2023) - Closes #11963 +- tidy-up: use `OPENSSL_VERSION_NUMBER` -- manpage-syntax: verify curl man page references + Uniformly use `OPENSSL_VERSION_NUMBER` to check for OpenSSL version. + Before this patch some places used `OPENSSL_VERSION_MAJOR`. - 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. + Also fix `lib/md4.c`, which included `opensslconf.h`, but that doesn't + define any version number in these implementations: BoringSSL, AWS-LC, + LibreSSL, wolfSSL. (Only in mainline OpenSSL/quictls). Switch that to + `opensslv.h`. This wasn't causing a deeper problem because the code is + looking for v3, which is only provided by OpenSSL/quictls as of now. - Allowlist curl.1 since it is not always built in builds + According to https://github.com/openssl/openssl/issues/17517, the macro + `OPENSSL_VERSION_NUMBER` is safe to use and not deprecated. - 2. References to curl symbols that lack section now causes warning, since tha - t - will prevent them from getting linked properly + Reviewed-by: Marcel Raad + Closes #12298 - 3. Check for "bare" references to curl functions and warn, they should be - references +Daniel Stenberg (8 Nov 2023) - Closes #11963 +- resolve.d: drop a multi use-sentence -- cmake: add check for suseconds_t - - And fix the HAVE_LONGLONG define + Since the `multi:` keyword adds that message. - Ref: #11964 - Closes #11977 + Reported-by: 積丹尼 Dan Jacobson + Fixes https://github.com/curl/curl/discussions/12294 + Closes #12295 -Viktor Szakats (28 Sep 2023) +- content_encoding: make Curl_all_content_encodings allocless -- tidy-up: whitespace fixes + - Fixes a memory leak pointed out by Coverity + - Also found by OSS-Fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail? + id=63947 + - Avoids unncessary allocations - Closes #11972 + Follow-up ad051e1cbec68b2456a22661b -- cmake: detect TLS-SRP in OpenSSL/wolfSSL/GnuTLS + Closes #12289 - With new option `CURL_DISABLE_SRP=ON` to force-disable it. - To match existing option and detection logic in autotools. +Michael Kaufmann (7 Nov 2023) - 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. +- vtls: use ALPN "http/1.1" for HTTP/1.x, including HTTP/1.0 - Ref: #11964 + Some servers don't support the ALPN protocol "http/1.0" (e.g. IIS 10), + avoid it and use "http/1.1" instead. - Closes #11967 + This reverts commit df856cb5c9 (#10183). -- tool: use our own stderr variable + Fixes #12259 + Closes #12285 - 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. +Daniel Stenberg (7 Nov 2023) - 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`. +- Makefile.am: drop vc10, vc11 and vc12 projects from dist - Follow-up to 06133d3e9b8aeb9e9ca0b3370c246bdfbfc8619e - Follow-up to 2f17a9b654121dd1ecf4fc043c6d08a9da3522db + They are end of life products. Support for generating them remain in the + repo for a while but this change drops them from distribution. - Closes #11958 + Closes #12288 -Loïc Yhuel (28 Sep 2023) +David Suter (7 Nov 2023) -- connect: only start the happy eyeballs timer when needed +- projects: add VC14.20 project files - The timeout is only used when there is a second address family, for the - delayed eyeballer. + Windows projects included VC14, VC14.10, VC14.30 but not VC14.20. + OpenSSL and Wolf SSL scripts mention VC14.20 so I don't see a reason why + this is missing. Updated the templates to produce a VC14.20 project. + Project opens in Visual Studio 2019 as expected. - Closes #11939 + Closes #12282 -Daniel Stenberg (28 Sep 2023) +Daniel Stenberg (7 Nov 2023) -- tool_operate: free 'gateway' correctly +- curl: move IPFS code into src/tool_ipfs.[ch] - Pointed out by Coverity. The fix in 93885cf3a8d4e was incomplete. + - convert ensure_trailing into ensure_trailing_slash + - strdup the URL string to own it proper + - use shorter variable names + - combine some expressions + - simplify error handling in ipfs_gateway() + - add MAX_GATEWAY_URL_LEN + proper bailout if maximum is reached + - ipfs-gateway.d polish and simplification + - shorten ipfs error message + make them "synthetic" - Also removed repeated wording in IPFS related error messages. + Closes #12281 - Closes #11969 +Viktor Szakats (6 Nov 2023) -Stefan Eissing (28 Sep 2023) +- build: delete support bits for obsolete Windows compilers -- lib: move handling of `data->req.writer_stack` into Curl_client_write() + - Pelles C: Unclear status, failed to obtain a fresh copy a few months + ago. Possible website is HTTP-only. ~10 years ago I left this compiler + dealing with crashes and other issues with no response on the forum + for years. It has seen some activity in curl back in 2021. + - LCC: Last stable release in September 2002. + - Salford C: Misses winsock2 support, possibly abandoned? Last mentioned + in 2006. + - Borland C++: We dropped Borland C++ support in 2018. + - MS Visual C++ 6.0: Released in 1998. curl already requires VS 2010 + (or possibly 2008) as a minimum. - - 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 #12222 - Closes #11908 +- build: delete `HAVE_STDINT_H` and `HAVE_INTTYPES_H` -Loïc Yhuel (28 Sep 2023) + We use `stdint.h` unconditionally in all places except one. These uses + are imposed by external dependencies / features. nghttp2, quic, wolfSSL + and `HAVE_MACH_ABSOLUTE_TIME` do require this C99 header. It means that + any of these features make curl require a C99 compiler. (In case of + MSVC, this means Visual Studio 2010 or newer.) -- multi: round the timeout up to prevent early wakeups + This patch changes the single use of `stdint.h` guarded by + `HAVE_STDINT_H` to use `stdint.h` unconditionally. Also stop using + `inttypes.h` as an alternative there. `HAVE_INTTYPES_H` wasn't used + anywhere else, allowing to delete this feature check as well. - 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. + Closes #12275 - 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. +Daniel Stenberg (6 Nov 2023) - Closes #11938 +- tool_operate: do not mix memory models -Daniel Stenberg (28 Sep 2023) + Make sure 'inputpath' only points to memory allocated by libcurl so that + curl_free works correctly. -- RELEASE-NOTES: spell out that IPFS is via gateway + Pointed out by Coverity -- RELEASE-NOTES: synced + Follow-up to 859e88f6533f9e1f890 -- tool_operate: avoid strlen() -1 on zero length content from file + Closes #12280 - Follow-up to 65b563a96a226649ba12cb1e +Stefan Eissing (6 Nov 2023) - Closes #11959 +- lib: client writer, part 2, accounting + logging -- tool_operate: fix memory mixups + This PR has these changes: - 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. + Renaming of unencode_* to cwriter, e.g. client writers + - documentation of sendf.h functions + - move max decode stack checks back to content_encoding.c + - define writer phase which was used as order before + - introduce phases for monitoring inbetween decode phases + - offering default implementations for init/write/close - Coverity found issues and a memory leak. + Add type paramter to client writer's do_write() + - always pass all writes through the writer stack + - writers who only care about BODY data will pass other writes unchanged - Follow-up to 65b563a96a226649ba12cb1e + add RAW and PROTOCOL client writers + - RAW used for Curl_debug() logging of CURLINFO_DATA_IN + - PROTOCOL used for updates to data->req.bytecount, max_filesize checks and + Curl_pgrsSetDownloadCounter() + - remove all updates of data->req.bytecount and calls to + Curl_pgrsSetDownloadCounter() and Curl_debug() from other code + - adjust test457 expected output to no longer see the excess write - Closes #11959 + Closes #12184 -Viktor Szakats (27 Sep 2023) +Daniel Stenberg (6 Nov 2023) -- curl-functions.m4: fixup recent bad edits +- VULN-DISCLOSURE-POLICY: escape sequences are not a security flaw - Follow-up to 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940 + Closes #12278 - Closes #11966 +Viktor Szakats (6 Nov 2023) -Daniel Stenberg (27 Sep 2023) +- rand: fix build error with autotools + LibreSSL -- curl-functions.m4: fix include line + autotools unexpectedly detects `arc4random` because it is also looking + into dependency libs. One dependency, LibreSSL, happens to publish an + `arc4random` function (via its shared lib before v3.7, also via static + lib as of v3.8.2). When trying to use this function in `lib/rand.c`, + its protoype is missing. To fix that, curl included a prototype, but + that used a C99 type without including `stdint.h`, causing: - 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! + ``` + ../../lib/rand.c:37:1: error: unknown type name 'uint32_t' + 37 | uint32_t arc4random(void); + | ^ + 1 error generated. + ``` - Follow-up to 96c29900bcec (#11940) + This patch improves this by dropping the local prototype and instead + limiting `arc4random` use for non-OpenSSL builds. OpenSSL builds provide + their own random source anyway. - Closes #11965 + The better fix would be to teach autotools to not link dependency libs + while detecting `arc4random`. -- inet_ntop: add typecast to silence Coverity + LibreSSL publishing a non-namespaced `arc4random` tracked here: + https://github.com/libressl/portable/issues/928 - CID 1024653: Integer handling issues (SIGN_EXTENSION) + Regression from 755ddbe901cd0c921fbc3ac5b3775c0dc683bc73 #10672 - 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. + Reviewed-by: Daniel Stenberg + Fixes #12257 + Closes #12274 - 111 words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); +Daniel Stenberg (5 Nov 2023) - The value will not be greater than 0x7FFFFFFF so this still cannot - happen. +- RELEASE-NOTES: synced - 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. +- strdup: do Curl_strndup without strncpy - Closes #11960 + To avoid (false positive) gcc-13 compiler warnings. -- docs: adapt SEE ALSO sections to new requirements + Follow-up to 4855debd8a2c1cb - To please manpage-syntax.pl used by test 1173 + Assisted-by: Jay Satiro + Reported-by: Viktor Szakats + Fixes #12258 - Closes #11957 +Enno Boland (5 Nov 2023) -- manpage-syntax.pl: verify SEE ALSO syntax +- HTTP: fix empty-body warning - - 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 + This change fixes a compiler warning with gcc-12.2.0 when + `-DCURL_DISABLE_BEARER_AUTH=ON` is used. - - List the entries alpha-sorted, not enforced just recommended + /home/tox/src/curl/lib/http.c: In function 'Curl_http_input_auth': + /home/tox/src/curl/lib/http.c:1147:12: warning: suggest braces around emp + ty body in an 'else' statement [-Wempty-body] + 1147 | ; + | ^ - Closes #11957 + Closes #12262 -- connect: expire the timeout when trying next +Daniel Stenberg (5 Nov 2023) - ... so that it gets called again immediately and can continue trying - addresses to connect to. Otherwise it might unnecessarily wait for a - while there. +- openssl: identify the "quictls" backend correctly - Fixes #11920 - Reported-by: Loïc Yhuel - Closes #11935 + Since vanilla OpenSSL does not support the QUIC API I think it helps + users to identify the correct OpenSSL fork in version output. The best + (crude) way to do that right now seems to be to check if ngtcp2 support + is enabled. -- http: remove wrong comment for http_should_fail + Closes #12270 - Reported-by: Christian Schmitz - Ref: #11936 - Closes #11941 +Mark Gaiser (5 Nov 2023) -Dan Fandrich (26 Sep 2023) +- curl: improved IPFS and IPNS URL support -- tool_setopt: remove unused function tool_setopt_flags + Previously just ipfs:// and ipns:// was supported, which is + too strict for some usecases. - This function is identical to tool_setopt_bitmask except that it treats - the argument as unsigned. + This patch allows paths and query arguments to be used too. + Making this work according to normal http semantics: - Closes #11943 + ipfs:///foo/bar?key=val + ipns:///foo/bar?key=val -Viktor Szakats (26 Sep 2023) + The gateway url support is changed. + It now only supports gateways in the form of: -- cmake: add feature checks for `memrchr` and `getifaddrs` + http:///foo/bar + http:// - - `HAVE_MEMRCHR` for `memrchr`. - - `HAVE_GETIFADDRS` for `getifaddrs`. - This was present in `lib/curl_config.h.cmake` but missed the detection - logic. + Query arguments here are explicitly not allowed and trigger an intended + malformed url error. - To match existing autotools feature checks. + There also was a crash when IPFS_PATH was set with a non trailing + forward slash. This has been fixed. - Closes #11954 + Lastly, a load of test cases have been added to verify the above. -- cmake: move global headers to specific checks + Reported-by: Steven Allen + Fixes #12148 + Closes #12152 - 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. +Harry Mallon (5 Nov 2023) - I've used autotools' `m4/curl-functions.m4` to figure out these - dependencies. +- docs: KNOWN_BUGS cleanup - Also delete checking for the C89 standard header `time.h`, that I - missed in the earlier commit. + * Remove other mention of hyper memory-leaks from `KNOWN_BUGS`. + Should have been removed in 629723ecf22a8eae78d64cceec2f3bdae703ec95 - Ref: 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940 + * Remove mention of aws-sigv4 sort query string from `KNOWN_BUGS`. + Fixed in #11806 - Closes #11951 + * Remove mention of aws-sigv4 query empty value problems -- src/mkhelp: make generated code pass `checksrc` + * Remove mention of aws-sigv4 missing amz-content-sha256 + Fixed in #9995 - Closes #11955 +- http_aws_sigv4: canonicalise valueless query params -- tests: show which curl tool `runtests.pl` is using + Fixes #8107 + Closes #12244 - To help debugging when there is issue finding or running it. +Michael Kaufmann (4 Nov 2023) - Closes #11953 +- docs: preserve the modification date when copying the prebuilt man page -- CI/azure: make `MAKEFLAGS` global to parallelize all jobs + The previously built man page "curl.1" must be copied with the original + modification date, otherwise the man page is never updated. - 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) + This fixes a bug that has been introduced with commit 2568441cab. - Closes #11952 + Reviewed-by: Dan Fandrich + Reviewed-by: Daniel Stenberg -- CI/azure: migrate old mingw MSYS1 jobs to MSYS2 + Closes #12199 - Also delete an accidental variable reference. +Daniel Stenberg (4 Nov 2023) - Follow-up to 38029101e2d78ba125732b3bab6ec267b80a0e72 +- docs: remove bold from some man page SYNOPSIS sections - Closes #11945 + In the name of consistency -Daniel Stenberg (26 Sep 2023) + Closes #12267 -- docs: add see also curl_multi_get_handles to some man pages +- openssl: two multi pointer checks should probably rather be asserts - Assisted-by: Jay Satiro + ... so add the asserts now and consider removing the dynamic checks in a + future. - Closes #11942 + Ref: #12261 + Closes #12264 -Viktor Szakats (26 Sep 2023) +boilingoden (4 Nov 2023) -- cmake: assume `_fseeki64` and no `fseeko` on Windows +- docs: add supported version for the json write-out - `_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]. + xref: https://curl.se/changes.html#7_70_0 - `fseeko` is not present in any of these. + Closes #12266 - (mingw-w64 1.0 also offers `fseeko64`.) +Viktor Szakats (3 Nov 2023) - [1] https://github.com/curl/curl/pull/11944#issuecomment-1734995004 +- appveyor: make VS2008-built curl tool runnable - Follow-up to 9c7165e96a3a9a2d0b7059c87c699b5ca8cdae93 #11918 + By linking the CRT statically. This avoids the error about missing + runtime DLL `MSVCR90.dll` when running the freshly built `curl.exe`. - Closes #11950 + Closes #12263 -- build: delete checks for C89 standard headers +Stefan Eissing (3 Nov 2023) - 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`. +- url: proxy ssl connection reuse fix - Some of these we already used unconditionally, some others we only used - for feature checks. + - 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 - Follow-up to 9c7165e96a3a9a2d0b7059c87c699b5ca8cdae93 #11918 (for `stdio.h` i - n CMake) + Closes #12255 - Closes #11940 +Jay Satiro (3 Nov 2023) -Stefan Eissing (26 Sep 2023) +- curl_sspi: support more revocation error names in error messages -- multiif.h: remove Curl_multi_dump declaration + - 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. - Follow-up to d850eea2 which removed the Curl_multi_dump definition. + Prior to this change those error codes were not matched to their macro + name and instead shown as "unknown error". - Closes https://github.com/curl/curl/pull/11946 + Before: -Jay Satiro (26 Sep 2023) + schannel: next InitializeSecurityContext failed: + Unknown error (0x80092013) - The revocation function was + unable to check revocation because the revocation server was offline. -- config-win32: define HAVE__FSEEKI64 + After: - Follow-up to 9c7165e9 which added an fseeko wrapper to the lib that - calls _fseeki64 if it is available. + schannel: next InitializeSecurityContext failed: + CRYPT_E_REVOCATION_OFFLINE (0x80092013) - The revocation function was + unable to check revocation because the revocation server was offline. - Closes https://github.com/curl/curl/pull/11944 + Bug: https://github.com/curl/curl/issues/12239 + Reported-by: Niracler Li -- docs: explain how PINNEDPUBLICKEY is independent of VERIFYPEER + Closes https://github.com/curl/curl/pull/12241 - - Explain that peer verification via CURLOPT_PINNEDPUBLICKEY takes place - even if peer verification via CURLOPT_SSL_VERIFYPEER is turned off. +- strdup: don't allow Curl_strndup to read past a null terminator - The behavior is verified by test2048. + - Use malloc + strncpy instead of Curl_memdup to dupe the string before + null terminating it. - Bug: https://github.com/curl/curl/issues/2935#issuecomment-418371872 - Reported-by: claudiusaiz@users.noreply.github.com + Prior to this change if Curl_strndup was passed a length longer than + the allocated string then it could copy out of bounds. - Bug: https://github.com/curl/curl/discussions/11910 - Reported-by: Hakan Sunay Halil + 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. - Closes https://github.com/curl/curl/pull/11930 + Follow-up to d3b3ba35. -Stefan Eissing (26 Sep 2023) + Closes https://github.com/curl/curl/pull/12254 -- openssl: improve ssl shutdown handling +Daniel Stenberg (2 Nov 2023) - - If SSL shutdown is not finished then make an additional call to - SSL_read to gather additional tracing. +- lib: add and use Curl_strndup() - - Fix http2 and h2-proxy filters to forward do_close() calls to the next - filter. + The Curl_strndup() function is similar to memdup(), but copies 'n' bytes + then adds a terminating null byte ('\0'). - For example h2 and SSL shutdown before and after this change: + Closes #12251 - Before: +- CURPOST_POSTFIELDS.3: add CURLOPT_COPYPOSTFIELDS in SEE ALSO - Curl_conn_close -> cf_hc_close -> Curl_conn_cf_discard_chain -> - ssl_cf_destroy +Stefan Eissing (2 Nov 2023) - After: +- pytest: use lower count in repeat tests - Curl_conn_close -> cf_hc_close -> cf_h2_close -> cf_setup_close -> - ssl_cf_close + - lower large iteration counts in some tests somewhat for + the same coverage with less duration - Note that currently the tracing does not show output on the connection - closure handle. Refer to discussion in #11878. + Closes #12248 - Ref: https://github.com/curl/curl/discussions/11878 +Daniel Stenberg (2 Nov 2023) - Closes https://github.com/curl/curl/pull/11858 +- RELEASE-NOTES: synced -Loïc Yhuel (26 Sep 2023) +- docs: clarify that curl passes on input unfiltered -- multi: fix small timeouts + ... for several options. - 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. + Reported-by: Ophir Lojkine - Closes #11937 + Closes #12249 -Viktor Szakats (25 Sep 2023) +- urlapi: when URL encoding the fragment, pass in the right length -- cmake: fix stderr initialization in unity builds + A benign bug because it would only add an extra null terminator. - Before this patch, in certain build configurations the curl tool may - not have displayed anything (debug, macOS), or crashed at startup - (debug, Windows). + Made lib1560 get a test that runs this code. - Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 - Necessary after 2f17a9b654121dd1ecf4fc043c6d08a9da3522db + Closes #12250 - Closes #11929 +Stefan Eissing (2 Nov 2023) -- cmake: fix missing `zlib.h` when compiling `libcurltool` +- vtls: late clone of connection ssl config - 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. + - perform connection cache matching against `data->set.ssl.primary` + and proxy counterpart + - fully clone connection ssl config only when connection is used - ``` - [ 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 - | ^~~~~~~~ - ``` + Closes #12237 - Follow-up to 39e7c22bb459c2e818f079984989a26a09741860 +- msh3: error when built with CURL_DISABLE_SOCKETPAIR set - Closes #11927 + Reported-by: Gisle Vanem + Closes #12252 + Fixes #12213 -- cmake: fix duplicate symbols when linking tests +Daniel Stenberg (2 Nov 2023) - 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. +- hsts: skip single-dot hostname - Regression from 39e7c22bb459c2e818f079984989a26a09741860 + Reported-by: Maksymilian Arciemowicz - 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 + Closes #12247 - 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 - ``` +- vtls: fix build without proxy - Closes #11926 + Follow-up to bf0e278a3c54bc7fee7360da17c -- cmake: lib `CURL_STATICLIB` fixes (Windows) + closes #12243 - - always define `CURL_STATICLIB` when building libcurl for Windows. +- docs/example/keepalive.c: show TCP keep-alive options - 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. + Closes #12242 - Regression from 1199308dbc902c52be67fc805c72dd2582520d30 +- lib1560: verify appending blank URL encoded query string - Fixes #11844 +- urlapi: skip appending NULL pointer query - - fix to omit `libcurl.def` when not hiding private symbols. + Reported-by: kirbyn17 on hackerone - Regression from 2ebc74c36a19a1700af394c16855ce144d9878e3 + Closes #12240 - - 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. +- lib1560: verify setting host to "" with and without URL encode - - delete `INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB"` for "objects" - target. +- urlapi: avoid null deref if setting blank host to url encode - Follow-up to 2ebc74c36a19a1700af394c16855ce144d9878e3 + Reported-by: kirbyn17 on hackerone - - delete duplicate `BUILDING_LIBCURL` definitions. + Closes #12240 - - fix `HIDES_CURL_PRIVATE_SYMBOLS` to not overwrite earlier build settings. +- dynbuf: assert for NULL pointer inputs - Follow-up to 1199308dbc902c52be67fc805c72dd2582520d30 + Help us catch more mistakes. - Closes #11914 + Closes #12238 -Daniel Stenberg (25 Sep 2023) +- HTTP3: ngtcp2 builds are no longer experimental -- RELEASE-NOTES: synced + The other HTTP/3 backends are still experimental. -Dan Fandrich (25 Sep 2023) + Closes #12235 -- tests: fix log directory path in IPFS tests +Stefan Eissing (31 Oct 2023) - Hard-coding the log directory name fails with parallel tests. +- vtls: cleanup SSL config management - Follow-up to 65b563a96 + - remove `Curl_ssl_get_config()`, no longer needed - Ref: #8805 + Closes #12204 -Daniel Stenberg (25 Sep 2023) +Daniel Stenberg (31 Oct 2023) -- curl_multi_get_handles: get easy handles from a multi handle +- libcurl-thread.3: simplify the TLS section - Closes #11750 + All TLS libraries curl can use are threadsafe since OpenSSL 1.1.x, August + 2016. -Stefan Eissing (25 Sep 2023) + Closes #12233 -- http: h1/h2 proxy unification +- configure: better --disable-http - - 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` + - disable HTTPS-proxy as well, since it can't work without HTTP - Closes #11808 + - curl_setup: when HTTP is disabled, also disable all features that are + HTTP-only -Natanael Copa (25 Sep 2023) + - version: HTTPS-proxy only exists if HTTP support exists -- lib: use wrapper for curl_mime_data fseek callback + Closes #12223 - 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. +- http: consider resume with CURLOPT_FAILONERRROR and 416 to be fine - Use a wrapper to solve this and use fseeko which uses off_t instead of - long. + Finding a 'Content-Range:' in the response changed the handling. - Thanks to the nice people at Libera IRC #musl for helping finding this - out. + 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 #11882 - Fixes #11900 - Closes #11918 + Fixes #10521 + Reported-by: Smackd0wn + Fixes #12174 + Reported-by: Anubhav Rai + Closes #12176 -- configure: sort AC_CHECK_FUNCS +Stefan Eissing (30 Oct 2023) - No functional changes. +- GHA: fix checkout of quictls repository to use correct branch name -Daniel Stenberg (25 Sep 2023) + Follow-up to c868b0e30f10cd0ac7 -- warnless: remove unused functions + Closes #12232 - Previously put there for use with the intel compiler +Daniel Stenberg (30 Oct 2023) - Closes #11932 +- docs/example/localport.c: show off CURLOPT_LOCALPORT -- GHA/linux: run singleuse to detect single-use global functions + Closes #12230 - Use --unit for configure --enable-debug builds +- docs/examples/interface.c: show CURLOPT_INTERFACE use - Closes #11932 + Although super simple. -- singleuse: add scan for use in other source codes + Closes #12229 - 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. +Viktor Szakats (30 Oct 2023) - Closes #11932 +- build: fix compiler warning with auths disabled -- multi: remove Curl_multi_dump + ``` + ./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. + ``` - 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. + Follow-up to e92edfbef64448ef461117769881f3ed776dec4e #11490 - Closes #11931 + Closes #12227 -Viktor Szakats (24 Sep 2023) +- build: require Windows XP or newer -- tests: fix compiler warnings + 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. - Seen with llvm 17 on Windows x64. + TODO: assume these also in autotools. - ``` - .../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)( ) - ``` + Ref: https://github.com/curl/curl/pull/12221#issuecomment-1783761806 + Closes #12225 - ``` - .../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. +- appveyor: bump one job to OpenSSL 3.1 (was 1.1.1) - .../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. + Use 3.1 with the modern runner image. - .../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; - | ~~~~~~~ ^ ~~~~~~~~~~~~~ + 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. ``` - 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. - ``` + 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: - Closes #11925 + * 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. -Jay Satiro (24 Sep 2023) + Use of `SEND_HOLD` is no longer necessary in the filters. -- url: fix netrc info message + 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. - - Fix netrc info message to use the generic ".netrc" filename if the - user did not specify a netrc location. + 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. - - Update --netrc doc to add that recent versions of curl on Windows - prefer .netrc over _netrc. + No noticeable difference in performance was detected in local scorecard + runs. - Before: - * Couldn't find host google.com in the (nil) file; using defaults + Closes #11833 - After: - * Couldn't find host google.com in the .netrc file; using defaults +Daniel Stenberg (25 Oct 2023) - Closes https://github.com/curl/curl/pull/11904 +- tests/README: SOCKS tests are not using OpenSSH, it has its own server -Dan Fandrich (23 Sep 2023) + Follow-up to 04fd67555cc -- wolfssh: do cleanup in Curl_ssh_cleanup + Closes #12195 - Closes: #11921 +Jacob Hoffman-Andrews (25 Oct 2023) -Daniel Stenberg (24 Sep 2023) +- tets: make test documentation more user-friendly -- tool_listhelp: regenerated + Put the instructions to run tests right at the top of tests/README.md. - Polished the --ipfs-gateway description + Give instructions to read the runtests.1 man page for information + about flags. Delete redundant copy of the flags documentation in the + README. - Fixed the --trace-config description + Add a mention in README.md of the important parallelism flag, to make + test runs go much faster. - The script also fixed some other small mistakes + Move documentation of output line format into the runtests.1 man page, + and update it with missing flags. - Closes #11923 + Fix the order of two flags in the man page. -Viktor Szakats (23 Sep 2023) + Closes #12193 -- Makefile.mk: always set `CURL_STATICLIB` for lib (Windows) +Viktor Szakats (24 Oct 2023) - Also fix to export all symbols in Windows debug builds, making - `-debug-dyn` builds work with `-DCURL_STATICLIB` set. +- cmake: pre-fill rest of detection values for Windows - Ref: https://github.com/curl/curl/pull/11914 (same for CMake) + 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. - Closes #11924 + - pre-fill remaining detection values in Windows CMake builds. -Daniel Stenberg (23 Sep 2023) + Based on actual detection results observed in CI runs, preceding + similar work over libssh2 and matching up values with + `lib/config-win32.h`. -- quic: set ciphers/curves the same way regular TLS does + This brings down CMake configuration time from 58 to 14 seconds on the + same local machine. - for OpenSSL/BoringSSL + 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 - Fixes #11796 - Reported-by: Karthikdasari0423 on github - Assisted-by: Jay Satiro - Closes #11836 + 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.) -- test457: verify --max-filesize with chunked encoding + - stop detecting `idn2.h` if idn2 was deselected. + autotools does this. -- lib: let the max filesize option stop too big transfers too + - 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. - Previously it would only stop them from getting started if the size is - known to be too big then. + - limit `ADDRESS_FAMILY` detection to Windows. - Update the libcurl and curl docs accordingly. + - normalize `HAVE_WIN32_WINNT` value to lowercase `0x0a12` format. - Fixes #11810 - Reported-by: Elliot Killick - Assisted-by: Jay Satiro - Closes #11820 + - pre-fill `HAVE_WIN32_WINNT`-dependent detection results. + Saving 4 (slow) feature-detections in most builds: `getaddrinfo`, + `freeaddrinfo`, `inet_ntop`, `inet_pton` -Viktor Szakats (23 Sep 2023) + - 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. -- mingw: delete support for legacy mingw.org toolchain + - 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. - 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. + - 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. - 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.) + - delete redundant `HAVE_MACRO_SIGSETJMP` feature check. + It was the same check as `HAVE_SIGSETJMP`. - Closes #11625 + - delete 'experimental' marking from `CURL_USE_OPENSSL`. -Mark Gaiser (23 Sep 2023) + - 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 -- curl: add support for the IPFS protocols: + - make `CMake/CurlTests.c` pass `checksrc`. - - ipfs:// - - ipns:// + - `CMake/WindowsCache.cmake` tidy-ups. - This allows you tu use ipfs in curl like: - curl ipfs:// - and - curl ipns:// + - replace `WIN32` guard with `_WIN32` in `CMake/CurlTests.c`. - For more information consult the readme at: - https://curl.se/docs/ipfs.html + Closes #12044 - Closes #8805 +Jay Satiro (24 Oct 2023) -Daniel Stenberg (23 Sep 2023) +- page-footer: clarify exit code 25 -- bufq: remove Curl_bufq_skip_and_shift (unused) + - Clarify that curl tool exit code 25 means an upload failed to start. - Closes #11915 + Exit code 25 is equivalent to CURLE_UPLOAD_FAILED (25). Prior to this + change the documentation only mentioned the case of FTP STOR failing. -- scripts/singleuse.pl: add curl_global_trace + Reported-by: Emanuele Torre -Viktor Szakats (22 Sep 2023) + Ref: https://github.com/curl/curl/blob/curl-8_4_0/docs/libcurl/libcurl-errors + .3#L113-L115 -- cmake: fix unity symbol collisions in h2 builds + Fixes https://github.com/curl/curl/issues/12189 + Closes https://github.com/curl/curl/pull/12190 - Regression from 331b89a319d0067fa1e6441719307cfef9c7960f +Daniel Stenberg (24 Oct 2023) - Reviewed-by: Daniel Stenberg - Reviewed-by: Jay Satiro - Closes #11912 +- scripts/cijobs.pl: adjust for appveyor -Daniel Stenberg (22 Sep 2023) + Follow-up to a1d73a6bb -- RELEASE-NOTES: synced +Alex Bozarth (24 Oct 2023) -Dan Fandrich (21 Sep 2023) +- OpenSSL: Include SIG and KEM algorithms in verbose -- github/labeler: improve the match patterns + 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 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. + 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 -Daniel Stenberg (21 Sep 2023) + Based-on-patch-by: Martin Schmatz + Closes #12030 -- upload-file.d: describe the file name slash/backslash handling +Daniel Stenberg (23 Oct 2023) - Closes #11911 +- http2: provide an error callback and failf the message -Jakub Jelen (21 Sep 2023) + 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. -- libssh: cap SFTP packet size sent + Example: - Due to libssh limitations + curl: (92) Invalid HTTP header field was received: frame type: 1, + stream: 1, name: [upgrade], value: [h2,h2c] - Signed-off-by: Jakub Jelen + Ref: #12172 + Closes #12179 - Closes #11804 +Turiiya (23 Oct 2023) -Daniel Stenberg (21 Sep 2023) +- BINDINGS: add V binding -- curl.h: mark CURLSSLBACKEND_NSS as deprecated since 8.3.0 + Closes #12182 - Closes #11905 +Daniel Stenberg (22 Oct 2023) -- mailmap: unify Michael Osipov under a single email +- configure: check for the fseeko declaration too -Ted Lyngmo (21 Sep 2023) + ... and make the code require both symbol and declaration. -- docs: use CURLSSLBACKEND_NONE + This is because for Android, the symbol is always present in the lib at + build-time even when not actually available in run-time. - [ssl] use CURLSSLBACKEND_NONE instead of (curl_sslbackend)-1 in - documentation and examples. + Assisted-by: Viktor Szakats + Reported-by: 12932 on github + Fixes #12086 + Closes #12158 - Signed-off-by: Ted Lyngmo +Viktor Szakats (22 Oct 2023) - Closes #11909 +- cmake: fix OpenSSL quic detection in quiche builds -Dan Fandrich (21 Sep 2023) + 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. -- github/labeler: give the sync-labels config item a default value + Regression from dee310d54261f9a8416e87d50bccfe2cbe404949 #11555 - This shouldn't be necessary and is likely a bug with this beta version - of the labeller. + Reported-by: Casey Bodley + Fixes #12160 + Closes #12162 - Also, fix the negative matches for the documentation label. +Daniel Stenberg (22 Oct 2023) - Follow-up to dd12b452a - Closes #11907 +- RELEASE-NOTES: synced -- github/labeler: fix up more the labeler config format + bump to 8.5.0 for pending release - 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. +Dan Fandrich (21 Oct 2023) - Follow-up to dd12b452a - Closes #11906 +- test3103: add missing quotes around a test tag attribute -- github/labeler: fix indenting to try to appease labeller +Loïc Yhuel (21 Oct 2023) - Follow-up to dd12b452a +- tool: fix --capath when proxy support is disabled -Jay Satiro (21 Sep 2023) + After 95e8515ca0, --capath always sets CURLOPT_PROXY_CAPATH, which fails + with CURLE_UNKNOWN_OPTION when proxy support is disabled. -- libssh2: fix error message on failed pubkey-from-file + Closes #12089 - - If libssh2_userauth_publickey_fromfile_ex returns -1 then show error - message "SSH public key authentication failed: Reason unknown (-1)". +Daniel Stenberg (21 Oct 2023) - 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. +- openldap: move the alloc of ldapconninfo to *connect() - 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. + Fixes a minor memory leak on LDAP connection reuse. - Bug: https://github.com/curl/curl/issues/11837#issue-1891827355 - Reported-by: consulion@users.noreply.github.com + 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 https://github.com/curl/curl/pull/11881 + Closes #12166 -Stefan Eissing (21 Sep 2023) +- openldap: set the callback argument in oldap_do -- pytest: exclude test_03_goaway in CI runs due to timing dependency + ... to make sure it has the current 'data' pointer and not a stale old + one. - Closes #11860 + Reported-by: Dan Fandrich + Closes #12166 -- lib: disambiguate Curl_client_write flag semantics +- gnutls: support CURLSSLOPT_NATIVE_CA - - 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 + 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. - Closes #11885 + The native CA store loading is now asked for with this option. -Patrick Monnerat (21 Sep 2023) + Follow-up to 7b55279d1d856 -- tftpd: always use curl's own tftp.h + Co-authored-by: Jay Satiro - Using the system's provided arpa/tftp.h and optimizing, GCC 12 detects - and reports a stringop-overread warning: + Closes #12137 - 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 */ - | ^~~~~~~ +Stefan Eissing (21 Oct 2023) - 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. +- RTSP: improved RTP parser - This commit always uses curl's own version of tftp.h where the - target field is last in its structure, effectively avoiding the - warning. + - 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 - As HAVE_ARPA_TFTP_H is not used anymore, cmake/configure checks for - arpa/tftp.h are removed. + Closes #12052 - Closes #11897 +- http2: header conversion tightening -Dan Fandrich (20 Sep 2023) + - fold the code to convert dynhds to the nghttp2 structs + into a dynhds internal method + - saves code duplication + - pacifies compiler analyzers -- test1474: make precheck more robust on non-Solaris systems + Closes #12097 - If uname -r returns something odd, perl could return an error code and - the test would be erroneously skipped. The qx// syntax avoid this. +Daniel Stenberg (21 Oct 2023) - Followup to 08f9b2148 +- curl_ntlm_wb: fix elif typo -- github/labeler: switch to the 5 beta version + Reported-by: Manfred Schwarb + Follow-up to d4314cdf65ae + Bug: https://github.com/curl/curl/commit/d4314cdf65aee295db627016934bd9eb621a + b077#r130551295 - 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. +Dan Fandrich (20 Oct 2023) -Daniel Stenberg (20 Sep 2023) +- test1683: remove commented-out check alternatives -- lib: enable hmac for digest as well + 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. - 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. +Daniel Stenberg (20 Oct 2023) - Follow-up to e92edfbef64448ef +- hostip: show the list of IPs when resolving is done - Fixes #11890 - Reported-by: Aleksander Mazur - Closes #11896 + Getting 'curl.se' today then gets this verbose output which might help + debugging connectivity related matters. -- idn: if idn2_check_version returns NULL, return error + * 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 - ... this avoids a NULL dereference for this unusual case. + Co-authored-by: Jay Satiro + Closes #12145 - Reported-by: s0urc3_ on hackerone - Closes #11898 +rilysh (20 Oct 2023) -- http: fix CURL_DISABLE_BEARER_AUTH breakage +- docs: fix function typo in curl_easy_option_next.3 - When bearer auth was disabled, the if/else logic got wrong and caused - problems. + Closes #12170 - Follow-up to e92edfbef64448ef461 - Fixes #11892 - Reported-by: Aleksander Mazur - Closes #11895 +Daniel Stenberg (20 Oct 2023) -Michael Osipov (20 Sep 2023) +- vssh: remove the #ifdef for Curl_ssh_init, use empty macro -- wolfssl: allow capath with CURLOPT_CAINFO_BLOB + In the same style as other init calls - Remain consistent with OpenSSL. While CAfile is nulled as documented - with CURLOPT_CAINFO_BLOB, CApath remains intact. +- easy: remove duplicate wolfSSH init call - Closes #11886 + It is already done in Curl_ssh_init() where it belongs. -- wolfssl: use ssl_cafile/ssl_capath variables consistent with openssl.c + Closes #12168 - Closes #11886 +- socks: make SOCKS5 use the CURLOPT_IPRESOLVE choice -Dan Fandrich (19 Sep 2023) + Fixes #11949 + Reported-by: Ammar Faizi + Closes #12163 -- test1474: disable test on NetBSD, OpenBSD and Solaris 10 +- urldata: move the 'internal' boolean to the state struct - 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. + ... where all the other state bits for the easy handles live. - Assisted-by: Christian Weisgerber - Ref: https://curl.se/mail/lib-2023-09/0021.html - Closes #11888 + Closes #12165 -Ryan Schmidt (20 Sep 2023) +- url: don't touch the multi handle when closing internal handles -- cmake, configure: also link with CoreServices + Reported-by: Maksymilian Arciemowicz + Closes #12165 - 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. +Faraz Fallahi (19 Oct 2023) - Fixes #11893 - Closes #11894 +- getenv: PlayStation doesn't have getenv() -Marc Hoersken (19 Sep 2023) + Closes #12140 -- CI/azure: remove pip, wheel, cryptography, pyopenssl and impacket +Daniel Stenberg (19 Oct 2023) - These dependencies are now already included in the Docker image. +- transfer: only reset the FTP wildcard engine in CLEAR state - Ref: https://github.com/mback2k/curl-docker-winbuildenv/commit/2607a31bcab544 - b41d15606e97f38cf312c1ce56 + To avoid the state machine to start over and redownload all the files + *again*. - Closes #11889 + Reported-by: lkordos on github + Regression from 843b3baa3e3cb228 (shipped in 8.1.0) + Bisect-by: Dan Fandrich + Fixes #11775 + Closes #12156 -Daniel Stenberg (19 Sep 2023) +Stefan Eissing (19 Oct 2023) -- wolfssl: if CURLOPT_CAINFO_BLOB is set, ignore the CA files +- GHA: move mod_h2 version in CI to v2.0.25 - Ref: #11883 - Reported-by: Michael Osipov - Closes #11884 + Closes #12157 -- RELEASE-NOTES: synced +Daniel Stenberg (19 Oct 2023) -- test3103: CURLOPT_COOKIELIST test +- ntlm_wb: use pipe instead of socketpair when possible -- cookie: set ->running in cookie_init even if data is NULL + Closes #12149 - This is a regression introduced in b1b326ec500 (shipped in curl 8.1.0) +- RELEASE-NOTES: synced - Test 3103 verifies. +- asyn-thread: use pipe instead of socketpair for IPC when available - Fixes #11875 - Reported-by: wangp on github - Closes #11876 + If pipe() is present. Less overhead. -- test498: total header size for all redirects is larger than accepted + Helped-by: Viktor Szakats + Closes #12146 -- http: use per-request counter to check too large headers +Dan Fandrich (17 Oct 2023) - Not the counter that accumulates all headers over all redirects. +- tests: Fix Windows test helper tool search & use it for handle64 - Follow-up to 3ee79c1674fd6 + 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. - Do a second check for 20 times the limit for the accumulated size for - all headers. + 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 - Fixes #11871 - Reported-by: Joshix-1 on github - Closes #11872 + The running command stopped because the preference variable + "ErrorActionPreference" or common parameter is set to Stop: + sh: handle64.exe: command not found -Jay Satiro (18 Sep 2023) + Closes #12115 -- THANKS: add Eric Murphy +Daniel Stenberg (17 Oct 2023) - He reported #11850 (quiche build error) but I forgot to add a - 'reported-by' entry in the fix 267e14f1. +- multi: use pipe instead of socketpair to *wakeup() -Daniel Stenberg (18 Sep 2023) + If pipe() is present. Less overhead. -- h2-proxy: remove left-over mistake in drain_tunnel() + Closes #12142 - Left-over from 331b89a319 +Jay Satiro (17 Oct 2023) - Reported-by: 南宫雪珊 +- build: fix 'threadsafe' feature detection for older gcc - Closes https://github.com/curl/curl/pull/11877 + - Add 'threadsafe' to the feature list shown during build if POSIX + threads are being used. -vvb2060 (18 Sep 2023) + 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. -- lib: failf/infof compiler warnings + Reported-by: Dan Fandrich + Co-authored-by: Dan Fandrich - Closes #11874 + Fixes https://github.com/curl/curl/issues/12125 + Closes https://github.com/curl/curl/pull/12127 -Daniel Stenberg (17 Sep 2023) +Daniel Stenberg (16 Oct 2023) -- rand: fix 'alnum': array is too small to include a terminating null character +- test729: verify socks4a with excessive proxy user name length - It was that small on purpose, but this change now adds the null byte to - avoid the error. +- socks: better buffer size checks for socks4a user and hostname - Follow-up to 3aa3cc9b052353b1 + Also limit the proxy user name to 255 bytes, which is the same limit as + in SOCKS5. - Reported-by: Dan Fandrich - Ref: #11838 - Closes #11870 + Reported-by: sd0 on hackerone + Closes #12139 -Mathias Fuchs (16 Sep 2023) +- curl.h: on FreeBSD include sys/param.h instead of osreldate.h -- cmake: fix the help text to the static build option in CMakeLists.txt + Should things build on Playstation as well - Closes #11843 + Fixes #12107 + Reported-by: Faraz Fallahi + Closes #12123 -John Haugabook (16 Sep 2023) +Marcin Rataj (16 Oct 2023) -- MANUAL.md: change domain to example.com +- tool_operate: fix links in ipfs errors - Closes #11866 + URL fragment links generated from headers in + https://curl.se/docs/ipfs.html are lowercase. -Daniel Stenberg (16 Sep 2023) + Closes #12133 -- doh: inherit DEBUGFUNCTION/DATA +Viktor Szakats (15 Oct 2023) - 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. +- cmake: replace `check_library_exists_concat()` - Reported-by: calvin2021y on github - Fixes #11864 - Closes #11869 + 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. -Dan Fandrich (16 Sep 2023) + 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). -- http_aws_sigv4: fix sorting with empty parts + 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. - 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. + (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.) - Fixes #11855 - Closes #11868 + Ref: #11537 #11558 + Fixes #11285 + Fixes #11648 + Closes #12070 -- CI: ignore the "flaky" and "timing-dependent" test results +LoRd_MuldeR (15 Oct 2023) - 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. +- tool_cb_wrt: fix write output for very old Windows versions - This change only adds two additional tests to be ignored, since the - others already had the flaky keyword. + - Pass missing parameter for 'lpNumberOfCharsWritten' to WriteConsoleW() + function. - Closes #11865 + Apparently this parameter was *not* optional on older Windows versions. -- runtests: eliminate a warning on old perl 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. - The warning "Use of implicit split to @_ is deprecated" showed between - perl versions about 5.8 through 5.11. + Prior to this change, on those versions if parameter is NULL then the + function call fails with error ERROR_INVALID_ACCESS. -- tests: log the test result code after each libtest + Regression since af3f4e41. - This makes it easier to determine the test status. Also, capitalize - FAILURE and ABORT messages in log lines to make them easier to spot. + Ref: https://github.com/MicrosoftDocs/Console-Docs/issues/299 -Harry Sintonen (16 Sep 2023) + Fixes https://github.com/curl/curl/issues/12131 + Closes https://github.com/curl/curl/pull/12130 -- misc: better random strings +Jay Satiro (15 Oct 2023) - Generate alphanumerical random strings. +- tool_urlglob: fix build for old gcc versions - 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. + - Don't use __builtin_mul_overflow for GCC 4 and earlier. - 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. + The function was added in GCC 5. - Closes #11838 + Ref: https://gcc.gnu.org/gcc-5/changes.html -Daniel Stenberg (15 Sep 2023) + Reported-by: Dan Fandrich -- cookie: reduce variable scope, add const + Fixes https://github.com/curl/curl/issues/12124 + Closes https://github.com/curl/curl/pull/12128 -- cookie: do not store the expire or max-age strings +Carlos Henrique Lima Melara (14 Oct 2023) - Convert it to an expire time at once and save memory. +- docs/libcurl: fix three minor man page format mistakes - Closes #11862 + Reported-by: Samuel Henrique -- cookie: remove unnecessary struct fields + Closes https://github.com/curl/curl/pull/12126 - 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. +Jay Satiro (14 Oct 2023) - Closes #11862 +- tests/server: add more SOCKS5 handshake error checking -- RELEASE-NOTES: synced + - Add additional checking for missing and too-short SOCKS5 handshake + messages. - Bumped to 8.4.0, the next presumed version + 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. -Dan Fandrich (14 Sep 2023) + 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. -- test2600: remove special case handling for USE_ALARM_TIMEOUT + Reported-by: Dan Fandrich - 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. + Fixes https://github.com/curl/curl/issues/12117 + Closes https://github.com/curl/curl/pull/12118 - The need for this special-case was removed in commit 8627416, which - increased the connect timeout in all cases to well above 1 second. +Daniel Stenberg (14 Oct 2023) - Fixes #11767 - Closes #11849 +- RELEASE-NOTES: synced -Daniel Stenberg (14 Sep 2023) +Sohom Datta (14 Oct 2023) -- SECURITY-PROCESS.md. call it vulnerability disclosure policy +- tool_getparam: limit --rate to be smaller than number of ms - SECURITY-PROCESS.md -> VULN-DISCLOSURE-POLICY.md + 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 a name commonly used for a document like this. This name helps - users find it. + 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 #11852 + Closes #12116 -Junho Choi (14 Sep 2023) +Daniel Stenberg (14 Oct 2023) -- quiche: fix build error with --with-ca-fallback +- opts: fix two minor man page format mistakes - - Fix build error when curl is built with --with-quiche - and --with-ca-fallback. +Jay Satiro (14 Oct 2023) - - Add --with-ca-fallback to the quiche CI job. +- curl_trc: remove a bad assertion - Fixes https://github.com/curl/curl/issues/11850 - Closes https://github.com/curl/curl/pull/11847 + - Remove DEBUGASSERT that an internal handle must not have user + private_data set before calling the user's debug callback. -Jay Satiro (14 Sep 2023) + 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. -- escape: replace Curl_isunreserved with ISUNRESERVED + Bug: https://github.com/curl/curl/pull/12060#issuecomment-1754594697 + Reported-by: Daniel Stenberg - - Use the ALLCAPS version of the macro so that it is clear a macro is - being called that evaluates the variable multiple times. + Closes https://github.com/curl/curl/pull/12104 - - Also capitalize macro isurlpuntcs => ISURLPUNTCS since it evaluates - a variable multiple times. +Dan Fandrich (13 Oct 2023) - 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. +- test613: stop showing an error on missing output file - For example, ISUNRESERVED(*foo++) is easily identifiable as wrong but - Curl_isunreserved(*foo++) is not even though they both are the same. + 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. - Closes https://github.com/curl/curl/pull/11846 +Stefan Eissing (13 Oct 2023) -Dan Fandrich (13 Sep 2023) +- quic: manage connection idle timeouts -- tests: increase the default server logs lock timeout + - 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 - 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. + Reported-by: calvin2021y on github + Fixes #12064 + Closes #12077 - Ref: #11328 - Closes #11834 +Dan Fandrich (13 Oct 2023) -- tests: increase TEST_HANG_TIMEOUT in two tests +- CI: ignore test 286 on Appveyor gcc 9 build - 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. + 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. - Ref: #11328 + Fixes #12040 + Closes #12106 -- test1056: disable on Windows +Viktor Szakats (13 Oct 2023) - 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. +- lib: fix gcc warning in printf call -- test587: add a slight delay after test + Do not pass NULL to printf %s. - 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. + 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: #11328 + Ref: #10284 + Co-authored-by: Jay Satiro + Closes #12082 -- tests: stop overriding the lock timeout +Alex Klyubin (13 Oct 2023) - 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. +- http2: safer invocation of populate_binsettings - Ref: #11328 + 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. -- tests: add some --expect100-timeout to reduce timing dependencies + 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... - 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. + Closes #12101 - Ref: #11328 +Daniel Stenberg (13 Oct 2023) -- test661: return from test early in case of curl error +- openssl: avoid BN_num_bits() NULL pointer derefs -- tests: add the timing-dependent keyword on several tests + Reported-by: icy17 on github + Fixes #12099 + Closes #12100 - 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. +- wolfssl: require WOLFSSL_SYS_CA_CERTS for loading system CA -- test1592: greatly increase the maximum test timeout + 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. - 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. + Closes #12108 - Ref: #11328 +- tool_urlglob: make multiply() bail out on negative values -- test: minor test cleanups + - Does not work correctly with negative values + - use __builtin_mul_overflow() on gcc - Remove an obsolete block of code in tests 2032 & 576. - Add a comment in test 1474. + Reported-by: Torben Dury + Closes #12102 -- tests: quadruple the %FTPTIME2 and %FTPTIME3 timeouts +Loïc Yhuel (13 Oct 2023) - This gives more of a margin for error when running on overloaded CI - servers. +- cmake: fix CURL_DISABLE_GETOPTIONS - Ref: #11328 + - Add CURL_DISABLE_GETOPTIONS to curl_config.h.cmake. -- tests: improve SLOWDOWN test reliability by reducing sent data + Prior to this change the option had no effect because it was missing + from that file. - 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. + Closes https://github.com/curl/curl/pull/12091 - Ref: #11328 +- easy_lock: add a pthread_mutex_t fallback -- test650: fix an end tag typo + This allows to keep the init threadsafe with gcc < 4.9.0 (no C11 + atomics). -Jay Satiro (13 Sep 2023) + Closes https://github.com/curl/curl/pull/12090 -- tool_cb_wrt: fix debug assertion +Viktor Szakats (12 Oct 2023) - - Fix off-by-one out-of-bounds array index in Windows debug assertion. +- CI: add autotools, out-of-tree, debug build to distro check job - Bug: https://github.com/curl/curl/commit/af3f4e41#r127212213 - Reported-by: Gisle Vanem + Add a job that builds curl from a generated source tarball sample, with + autotools, out-of-tree, in debug mode. -Daniel Stenberg (13 Sep 2023) + Ref: #12085 + Closes #12088 -- ctype: add ISUNRESERVED() +Daniel Stenberg (12 Oct 2023) - ... and make Curl_isunreserved() use that macro instead of providing a - separate funtion for the purpose. +- http: avoid Expect: 100-continue if Upgrade: is used - Closes #11840 + Reported-by: Daniel Jelinski + Fixes #12022 + Closes #12062 -Version 8.3.0 (13 Sep 2023) +Jan Alexander Steffens (heftig) (12 Oct 2023) -Daniel Stenberg (13 Sep 2023) +- docs: use SOURCE_DATE_EPOCH for generated manpages -- RELEASE-NOTES: syn ced + This should make builds from Git reproducible. - curl 8.3.0 release + Closes #12092 -- THANKS: contributors from 8.3.0 +Daniel Stenberg (12 Oct 2023) -Thorsten Klein (12 Sep 2023) +- RELEASE-NOTES: synced -- cmake: set SIZEOF_LONG_LONG in curl_config.h + Bumped to 8.4.1 - in order to support 32bit builds regarding wolfssl CTC_SETTINGS +Viktor Szakats (12 Oct 2023) - Closes #11839 +- cmake: fix `HAVE_H_ERRNO_ASSIGNABLE` detection -Jay Satiro (12 Sep 2023) + 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. -- curl_ngtcp2: fix error message + We used this detection result to enable `HAVE_GETADDRINFO_THREADSAFE`. -- http_aws_sigv4: handle no-value user header entries + Follow-up to 04a3a377d83fd72c4cf7a96c9cb6d44785e33264 #11979 + Ref: #12095 (closed in favour of this patch) + Ref: #11964 (effort to sync cmake detections with autotools) - - Handle user headers in format 'name:' and 'name;' with no value. + Reported-by: Kartatz on Github + Assisted-by: Kartatz on Github + Fixes #12093 + Closes #12094 - 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). +- build: add `src/.checksrc` to source tarball - Prior to this change the AWS header import code did not special case - either of those and the generated AWS SignedHeaders would be incorrect. + Regression from e5bb88b8f824ed87620bd923552534c83c2a516e #11958 - Reported-by: apparentorder@users.noreply.github.com + Bug: https://github.com/curl/curl/pull/11958#issuecomment-1757079071 + Reported-by: Romain Geissler + Fixes #12084 + Closes #12085 - Ref: https://curl.se/docs/manpage.html#-H +Version 8.4.0 (11 Oct 2023) - Fixes https://github.com/curl/curl/issues/11664 - Closes https://github.com/curl/curl/pull/11668 +Daniel Stenberg (11 Oct 2023) -Dan Fandrich (11 Sep 2023) +- RELEASE-NOTES: synced -- CI: run pytest with the -v option +- THANKS: add contributors from 8.4.0 - This lists of the test cases being run so it can be tracked over time. +Jay Satiro (11 Oct 2023) - Closes #11824 +- socks: return error if hostname too long for remote resolve -Daniel Stenberg (11 Sep 2023) + 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. -- HTTP3: the msquic backend is not functional + Bug: https://curl.se/docs/CVE-2023-38545.html - I ask that we do not submit bugs for this backend just yet as we know it - does not fully work. +Stefan Eissing (10 Oct 2023) - Closes #11831 - Closes #11819 +- CI: remove slowed-network tests -- aws_sigv4: the query canon code miscounted URL encoded input + - remove these tests as they are currently not reliable in our CI + setups. - Added some extra ampersands to test 439 to verify "blank" query parts + 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. - Follow-up to fc76a24c53b08cdf + Closes https://github.com/curl/curl/pull/12075 - Closes #11829 +Jay Satiro (10 Oct 2023) -vvb2060 (11 Sep 2023) +- libcurl-env-dbg.3: move debug variables from libcurl-env.3 -- quic: don't set SNI if hostname is an IP address + - Move documentation of libcurl environment variables used only in debug + builds from libcurl-env into a separate document libcurl-env-dbg. - We already do this for TLS connections. + - Document more debug environment variables. - RFC 6066 says: Literal IPv4 and IPv6 addresses are not permitted in - "HostName". + Previously undocumented or missing a description: - Ref: https://www.rfc-editor.org/rfc/rfc6066#section-3 + 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. - Fixes https://github.com/curl/curl/issues/11827 - Closes https://github.com/curl/curl/pull/11828 + Closes https://github.com/curl/curl/pull/11811 -Daniel Stenberg (10 Sep 2023) +Dan Fandrich (9 Oct 2023) -- RELEASE-NOTES: synced +- test670: increase the test timeout -Benoit Pierre (10 Sep 2023) + This should make it more immune to loaded servers. -- configure: fix `HAVE_TIME_T_UNSIGNED` check + Ref: #11328 - The syntax was incorrect (need a proper main body), and the test - condition was wrong (resulting in a signed `time_t` detected as - unsigned). +Stefan Eissing (9 Oct 2023) - Closes #11825 +- MQTT: improve receive of ACKs -Daniel Stenberg (9 Sep 2023) + - add `mq->recvbuf` to provide buffering of incomplete + ACK responses + - continue ACK reading until sufficient bytes available + - fixes test failures on low network receives -- THANKS-filter: pszlazak on github + Closes #12071 -pszlazak (9 Sep 2023) +Viktor Szakats (9 Oct 2023) -- include.d: explain headers not printed with --fail before 7.75.0 +- quic: fix BoringSSL build - Prior to 7.75.0 response headers were not printed if -f/--fail was used - and an error was reported by server. This was fixed in ab525c0 - (precedes 7.75.0). + Add guard around `SSL_CTX_set_ciphersuites()` use. - Closes #11822 + Bug: https://github.com/curl/curl/pull/12065#issuecomment-1752171885 -Daniel Stenberg (8 Sep 2023) + Follow-up to aa9a6a177017e4b74d33cdf85a3594900f4a7f81 -- http_aws_sigv4: skip the op if the query pair is zero bytes + Co-authored-by: Jay Satiro + Reviewed-by: Daniel Stenberg + Closes #12067 - Follow-up to fc76a24c53b08cdf +Stefan Eissing (9 Oct 2023) - Spotted by OSS-Fuzz +- test1540: improve reliability - Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=62175 - Closes #11823 + - print that bytes have been received on pausing, but not how many -- cmdline-docs: use present tense, not future + Closes #12069 - + some smaller cleanups +- test2302: improve reliability - Closes #11821 + - 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 -- cmdline-docs: make sure to phrase it as "added in ...." + Closes #12068 - References to things that were added or changed in a specific version - should be specified as "(added in [version]) for two reasons: +Daniel Stenberg (9 Oct 2023) - 1 - consistency +- curl_easy_pause: set "in callback" true on exit if true - 2 - to allow gen.pl to strip them out if deemed referring to too old - versions + Because it might have called another callback in the mean time that then + set the bit FALSE on exit. - Closes #11821 + Reported-by: Jay Satiro + Fixes #12059 + Closes #12061 -Jay Satiro (8 Sep 2023) +Viktor Szakats (8 Oct 2023) -- docs: mark --ssl-revoke-best-effort as Schannel specific +- h3: add support for ngtcp2 with AWS-LC builds - Closes https://github.com/curl/curl/pull/11760 + ``` + 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 + ``` -Nathan Moinvaziri (8 Sep 2023) + Also delete an obsolete GnuTLS TODO and update the header comment in + `FindNGTCP2.cmake`. -- schannel: fix ordering of cert chain info + Reviewed-by: Daniel Stenberg + Closes #12066 - - Use CERT_CONTEXT's pbCertEncoded to determine chain order. +- build: do not publish `HAVE_BORINGSSL`, `HAVE_AWSLC` macros - CERT_CONTEXT from SECPKG_ATTR_REMOTE_CERT_CONTEXT contains - end-entity/server certificate in pbCertEncoded. We can use this pointer - to determine the order of certificates when enumerating hCertStore using - CertEnumCertificatesInStore. + Syncing this up with CMake. - This change is to help ensure that the ordering of the certificate chain - requested by the user via CURLINFO_CERTINFO has the same ordering on all - versions of Windows. + 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. - Prior to this change Schannel certificate order was reversed in 8986df80 - but that was later reverted in f540a39b when it was discovered that - Windows 11 22H2 does the reversal on its own. + 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 - Ref: https://github.com/curl/curl/issues/9706 + 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). - Closes https://github.com/curl/curl/pull/11632 + Ref: #11964 -Chris Talbot (8 Sep 2023) + Reviewed-by: Daniel Stenberg + Reviewed-by: Jay Satiro + Closes #12065 -- digest: Use hostname to generate spn instead of realm +Marc Hoersken (8 Oct 2023) - In https://www.rfc-editor.org/rfc/rfc2831#section-2.1.2 +- CI: move distcheck job from Azure Pipelines to GitHub Actions - digest-uri-value should be serv-type "/" host , where host is: + This will allow for more trigger excludes within Azure Pipelines. - The DNS host name or IP address for the service requested. The - DNS host name must be the fully-qualified canonical name of the - host. The DNS host name is the preferred form; see notes on server - processing of the digest-uri. + Also fixes seemingly broken check with scripts/installcheck.sh. + Ref: 190374c74ec4e5247d9066544c86e8d095e1d7b5 - Realm may not be the host, so we must specify the host explicitly. + Assisted-by: Philip Heiduck + Closes #9532 - Note this change only affects the non-SSPI digest code. The digest code - used by SSPI builds already uses the hostname to generate the spn. +Daniel Stenberg (8 Oct 2023) - Ref: https://github.com/curl/curl/issues/11369 +- url: fall back to http/https proxy env-variable if ws/wss not set - Closes https://github.com/curl/curl/pull/11395 + Reported-by: Craig Andrews + Fixes #12031 + Closes #12058 -Daniel Stenberg (7 Sep 2023) +Stefan Eissing (8 Oct 2023) -- docs: remove use of the word 'very' +- cf-socket: simulate slow/blocked receives in debug - It is mostly superfluous. proselint would complain. + 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 #11818 + Closes #12035 -- curl_multi_remove_handle.3: clarify what happens with connection +- http2: refused stream handling for retry - Closes #11817 + - 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 -- RELEASE-NOTES: synced + Reported-by: black-desk on github + Ref #11859 + Closes #12054 -- test439: verify query canonization for aws-sigv4 +Jay Satiro (8 Oct 2023) -- tool_operate: make aws-sigv4 not require TLS to be used +- CURLOPT_DEBUGFUNCTION.3: warn about internal handles - Maybe not used too often, but we want it for testing and it should work. + - Warn that the user's debug callback may be called with the handle + parameter set to an internal handle. -- http_aws_sigv4: canonicalize the query + 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. - Percent encoding needs to be done using uppercase, and most - non-alphanumerical must be percent-encoded. + 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. - Fixes #11794 - Reported-by: John Walker - Closes #11806 + Closes https://github.com/curl/curl/pull/12034 -Wyatt O'Day (7 Sep 2023) +- url: fix typo -- lib: add ability to disable auths individually +Daniel Stenberg (8 Oct 2023) - Both with configure and cmake +- test458: verify --expand-output, expanding a file name accepting option - Closes #11490 + Verifies the fix in #12055 (commit f2c8086ff15e6e995e1) -Stefan Eissing (7 Sep 2023) +- tool_getparam: accept variable expansion on file names too -- ngtcp2: fix handling of large requests + Reported-by: PBudmark on github + Fixes #12048 + Closes #12055 - - requests >64K are send in parts to the filter - - fix parsing of the request to assemble it correctly - from several sends - - open a QUIC stream only when the complete request has - been collected +- RELEASE-NOTES: synced - Closes #11815 +- multi: do CURLM_CALL_MULTI_PERFORM at two more places -- openssl: when CURLOPT_SSL_CTX_FUNCTION is registered, init x509 store before + ... 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. - - we delay loading the x509 store to shorten the handshake time. - However an application callback installed via CURLOPT_SSL_CTX_FUNCTION - may need to have the store loaded and try to manipulate it. - - load the x509 store before invoking the app callback + Reported-by: Dan Fandrich. + Fixes #12033 + Closes #12056 - Fixes #11800 - Reported-by: guoxinvmware on github - Cloes #11805 +Viktor Szakats (7 Oct 2023) -Daniel Stenberg (7 Sep 2023) +- GHA/linux: mbedtls 3.5.0 + minor dep bumps -- krb5: fix "implicit conversion loses integer precision" warnings + Closes #12057 - conversions to/from enum and unsigned chars +Dan Fandrich (7 Oct 2023) - Closes #11814 +- CI: bump OpenLDAP package version on FreeBSD -Stefan Eissing (7 Sep 2023) + The old one is no longer available. -- pytest: improvements +Marc Hoersken (7 Oct 2023) - - set CURL_CI for pytest runs in CI environments - - exclude timing sensitive tests from CI runs - - for failed results, list only the log and stat of - the failed transfer +- docs/libcurl/opts/Makefile.inc: add missing manpage files - - fix type in http.c comment + Detected with #9532 - Closes #11812 +Dan Fandrich (7 Oct 2023) -- CI: move on to ngtcp2 v0.19.1 +- tests: fix a race condition in ftp server disconnect - Closes #11809 + 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. -Dan Fandrich (5 Sep 2023) + Fixes #12002 + Closes #12049 -- CI: run Circle macOS builds on x86 for now +Viktor Szakats (7 Oct 2023) - The ARM machines aren't ready for us and requesting them now causes - warnings e-mails to be sent to some PR pushers. +- appveyor: bump mingw-w64 job to gcc 13 (was: 8) - Ref: #11771 + This sets gcc 6, 7, 9, 13 in our test mix (was: 6, 7, 8, 9). + Adding a modern gcc version to the tests. -Viktor Szakats (5 Sep 2023) + (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.) -- http3: adjust cast for ngtcp2 v0.19.0 + It also adds a modern CMake version and OS env to our mingw-w64 builds. - ngtcp2 v0.19.0 made size of `ecn` member of `ngtcp2_pkt_info` - an `uint8_t` (was: `uint32_t`). Adjust our local cast accordingly. + Closes #12051 - Fixes: - ``` - ./curl/lib/vquic/curl_ngtcp2.c:1912:12: warning: implicit conversion loses in - teger precision: 'uint32_t' (aka 'unsigned int') to 'uint8_t' (aka 'unsigned - char') [-Wimplicit-int-conversion] - pi.ecn = (uint32_t)ecn; - ~ ^~~~~~~~~~~~~ - ``` +David Benjamin (6 Oct 2023) - Also bump ngtcp2, nghttp3 and nghttp2 to their latest versions in our - docs and CI. +- openssl: use X509_ALGOR_get0 instead of reaching into X509_ALGOR - Ref: https://github.com/ngtcp2/ngtcp2/commit/80447281bbc94af53f8aa7a4cfc19175 - 782894a3 - Ref: https://github.com/ngtcp2/ngtcp2/pull/877 - Closes #11798 + 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. -Stefan Eissing (5 Sep 2023) + Closes #12038 -- http: fix sending of large requests +Daniel Stenberg (6 Oct 2023) - - refs #11342 where errors with git https interactions - were observed - - problem was caused by 1st sends of size larger than 64KB - which resulted in later retries of 64KB only - - limit sending of 1st block to 64KB - - adjust h2/h3 filters to cope with parsing the HTTP/1.1 - formatted request in chunks +- curl_easy_pause.3: mention it works within callbacks - - introducing Curl_nwrite() as companion to Curl_write() - for the many cases where the sockindex is already known + Reported-by: Maxim Dzhura + Bug: https://curl.se/mail/lib-2023-10/0010.html + Closes #12046 - Fixes #11342 (again) - Closes #11803 +- curl_easy_pause.3: mention h2/h3 buffering -- pytest: fix check for slow_network skips to only apply when intended + Asked-by: Maxim Dzhura + Ref: https://curl.se/mail/lib-2023-10/0011.html - Closes #11801 + Closes #12045 -Daniel Stenberg (5 Sep 2023) +Viktor Szakats (6 Oct 2023) -- curl_url_get/set.3: add missing semicolon in SYNOPSIS +- cmake: re-add missed C89 headers for specific detections -- CURLOPT_URL.3: explain curl_url_set() uses the same parser + 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. -- CURLOPT_URL.3: add two URL API calls in the see-also section + [1] Follow-up to 3795fcde995d96db641ddbcc8a04f9f0f03bef9f #11951 + [2] Follow-up to 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940 -Dan Fandrich (4 Sep 2023) + Closes #12043 -- CI: add a 32-bit i686 Linux build +Daniel Stenberg (6 Oct 2023) - This is done by cross-compiling under regular x86_64 Linux. Since the - kernel offers backwards compatibility, the binaries can be tested as - normal. +- multi: set CURLM_CALL_MULTI_PERFORM after switch to DOING_MORE - Closes #11799 + Since there is nothing to wait for there. Avoids the test 1233 hang + reported in #12033. -- tests: fix a type warning on 32-bit x86 + Reported-by: Dan Fandrich + Closes #12042 -Viktor Szakats (4 Sep 2023) +Dan Fandrich (5 Oct 2023) -- tests: delete stray `.orig` file +- test1903: actually verify the cookies after the test - Follow-up to 331b89a319d0067fa1e6441719307cfef9c7960f - Closes #11797 + 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. -Daniel Stenberg (4 Sep 2023) + Closes #12041 -- RELEASE-NOTES: synced +- test: add missing s -Viktor Szakats (4 Sep 2023) + The tests will otherwise fail if curl has them disabled. -- lib: silence compiler warning in inet_ntop6 +- test1906: set a lower timeout since it's hit on Windows - ``` - ./curl/lib/inet_ntop.c:121:21: warning: possible misuse of comma operator her - e [-Wcomma] - cur.base = i, cur.len = 1; - ^ - ./curl/lib/inet_ntop.c:121:9: note: cast expression to void to silence warnin - g - cur.base = i, cur.len = 1; - ^~~~~~~~~~~~ - (void)( ) - ``` + msys2 builds actually hit the connect timeout in normal operation, so + lower the timeout from 5 minutes to 5 seconds to reduce test time. - Closes #11790 + Ref: #11328 + Closes #12036 -Daniel Stenberg (4 Sep 2023) +Daniel Stenberg (5 Oct 2023) -- transfer: also stop the sending on closed connection +- RELEASE-NOTES: synced - Previously this cleared the receiving bit only but in some cases it is - also still sending (like a request-body) when disconnected and neither - direction can continue then. +Jay Satiro (5 Oct 2023) - Fixes #11769 - Reported-by: Oleg Jukovec - Closes #11795 +- idn: fix WinIDN null ptr deref on bad host -John Bampton (4 Sep 2023) + - Return CURLE_URL_MALFORMAT if IDN hostname cannot be converted from + UTF-8 to UTF-16. -- docs: change `sub-domain` to `subdomain` + 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. - https://en.wikipedia.org/wiki/Subdomain + Closes https://github.com/curl/curl/pull/11983 - Closes #11793 +Dan Fandrich (4 Oct 2023) -Stefan Eissing (4 Sep 2023) +- tests: close the shell used to start sshd -- multi: more efficient pollfd count for poll + This shell isn't needed once sshd starts, so use "exec" so it doesn't + stick around. - - do not use separate pollfds for sockets that have POLLIN+POLLOUT + Closes #12032 - Closes #11792 +Daniel Stenberg (4 Oct 2023) -- http2: polish things around POST +- base64: also build for curl - - added test cases for various code paths - - fixed handling of blocked write when stream had - been closed inbetween attempts - - re-enabled DEBUGASSERT on send with smaller data size + 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. - - in debug builds, environment variables can be set to simulate a slow - network when sending data. cf-socket.c and vquic.c support - * CURL_DBG_SOCK_WBLOCK: percentage of send() calls that should be - answered with a EAGAIN. TCP/UNIX sockets. - This is chosen randomly. - * CURL_DBG_SOCK_WPARTIAL: percentage of data that shall be written - to the network. TCP/UNIX sockets. - Example: 80 means a send with 1000 bytes would only send 800 - This is applied to every send. - * CURL_DBG_QUIC_WBLOCK: percentage of send() calls that should be - answered with EAGAIN. QUIC only. - This is chosen randomly. + Follow-up to 2e160c9c6525 - Closes #11756 + Closes #12010 -Daniel Stenberg (4 Sep 2023) +Eduard Strehlau (4 Oct 2023) -- docs: add curl_global_trace to some SEE ALSO sections +- tests: Fix zombie processes left behind by FTP tests. - Closes #11791 + 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. -- os400: fix checksrc nits + Fixes #12018 + Closes #12020 - Closes #11789 +Dan Fandrich (4 Oct 2023) -Nicholas Nethercote (3 Sep 2023) +- github/labeler: improve labeler matches -- hyper: remove `hyptransfer->endtask` +- test574: add a timeout to the test - `Curl_hyper_stream` needs to distinguish between two kinds of - `HYPER_TASK_EMPTY` tasks: (a) the `foreach` tasks it creates itself, and - (b) background tasks that hyper produces. It does this by recording the - address of any `foreach` task in `hyptransfer->endtask` before pushing - it into the executor, and then comparing that against the address of - tasks later polled out of the executor. + This one hangs occasionally, so this will speed up a test run and allow + logs to be seen when it does. - This works right now, but there is no guarantee from hyper that the - addresses are stable. `hyper_executor_push` says "The executor takes - ownership of the task, which should not be accessed again unless - returned back to the user with `hyper_executor_poll`". That wording is a - bit ambiguous but with my Rust programmer's hat on I read it as meaning - the task returned with `hyper_executor_poll` may be conceptually the - same as a task that was pushed, but that there are no other guarantees - and comparing addresses is a bad idea. + Closes #12025 - This commit instead uses `hyper_task_set_userdata` to mark the `foreach` - task with a `USERDATA_RESP_BODY` value which can then be checked for, - removing the need for `hyptransfer->endtask`. This makes the code look - more like that hyper C API examples, which use userdata for every task - and never look at task addresses. +- tests: propagate errors in libtests - Closes #11779 + 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. -Dave Cottlehuber (3 Sep 2023) +- tests: set --expect100-timeout to improve test reliability -- ws: fix spelling mistakes in examples and tests + 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. - Closes #11784 + Ref: #11328 -Daniel Stenberg (3 Sep 2023) +- CI: ignore the "flaky" and "timing-dependent" test results in CMake -- tool_filetime: make -z work with file dates before 1970 + This was already done for automake builds but CMake builds were missed. + Test 1086 actually causes the test harness to crash with: - Fixes #11785 - Reported-by: Harry Sintonen - Closes #11786 + Warning: unable to close filehandle DWRITE properly: Broken pipe at C:/projec + ts/curl/tests/ftpserver.pl line 527 -Dan Fandrich (1 Sep 2023) + Rather than fix it now, this change leaves test 1086 entirely skipped on + those builds that show this problem. -- build: fix portability of mancheck and checksrc targets + Follow-up to 589dca761 - At least FreeBSD preserves cwd across makefile lines, so rules - consisting of more than one "cd X; do_something" must be explicitly run - in a subshell to avoid this. This problem caused the Cirrus FreeBSD - build to fail when parallel make jobs were enabled. + Ref: #11865 -- CI: adjust labeler match patterns for new & obsolete files +Viktor Szakats (4 Oct 2023) -- configure: trust pkg-config when it's used for zlib +- cmake: improve OpenLDAP builds - The library flags retrieved from pkg-config were later thrown out and - harded-coded, which negates the whole reason to use pkg-config. - Also, previously, the assumption was made that --libs-only-l and - --libs-only-L are the full decomposition of --libs, which is untrue and - would not allow linking against a static zlib. The new approach is - better in that it uses --libs, although only if --libs-only-l returns - nothing. + - 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. - Bug: https://curl.se/mail/lib-2023-08/0081.html - Reported-by: Randall - Closes #11778 + - 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] + ``` -Stefan Eissing (1 Sep 2023) + - cmake: delete LDAP TODO comment no longer relevant. -- CI/ngtcp2: clear wolfssl for when cache is ignored + Also: - Closes #11783 + - autotools: replace domain name `dummy` with `0.0.0.0` in LDAP feature + detection functions. -Daniel Stenberg (1 Sep 2023) + Ref: #11964 (effort to sync cmake detections with autotools) -- RELEASE-NOTES: synced + Closes #12024 -Nicholas Nethercote (1 Sep 2023) +- cmake: fix unity builds for more build combinations -- hyper: fix a progress upload counter bug + By using unique static function/variable names in source files + implementing these interfaces. - `Curl_pgrsSetUploadCounter` should be a passed a total count, not an - increment. + - OpenLDAP combined with any SSH backend. - This changes the failing diff for test 579 with hyper from this: - ``` - Progress callback called with UL 0 out of 0[LF] - -Progress callback called with UL 8 out of 0[LF] - -Progress callback called with UL 16 out of 0[LF] - -Progress callback called with UL 26 out of 0[LF] - -Progress callback called with UL 61 out of 0[LF] - -Progress callback called with UL 66 out of 0[LF] - +Progress callback called with UL 29 out of 0[LF] - ``` - to this: - ``` - Progress callback called with UL 0 out of 0[LF] - -Progress callback called with UL 8 out of 0[LF] - -Progress callback called with UL 16 out of 0[LF] - -Progress callback called with UL 26 out of 0[LF] - -Progress callback called with UL 61 out of 0[LF] - -Progress callback called with UL 66 out of 0[LF] - +Progress callback called with UL 40 out of 0[LF] - ``` - Presumably a step in the right direction. + - MultiSSL with mbedTLS, OpenSSL, wolfSSL, SecureTransport. - Closes #11780 + Closes #12027 -Daniel Stenberg (1 Sep 2023) +Daniel Stenberg (4 Oct 2023) -- awssiv4: avoid freeing the date pointer on error +- tests: remove leading spaces from some tags - Since it was not allocated, don't free it even if it was wrong syntax + The threee tags ``, `` and `` 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. - Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=61908 + Hence, fixing them all now might curb this practice from now on. - Follow-up to b137634ba3adb + Closes #12028 - Closes #11782 +Viktor Szakats (4 Oct 2023) -Stefan Eissing (1 Sep 2023) +- GHA: bump actions/checkout -- CI: ngtcp2-linux: use separate caches for tls libraries + Follow-up to 2e0fa50fc16b9339f51e0a7bfff0352829323acb #11964 + Follow-up to c39585d9b7ef3cbfc1380812dec60e7b275b6af3 #12000 - allow ever changing master for wolfssl + Closes #12023 - Closes #11766 +- spelling: fix codespell 2.2.6 typos -- replace `master` as wolfssl-version with recent commit + Closes #12019 -- wolfssl, use master again in CI +Daniel Stenberg (3 Oct 2023) - - with the shared session update fix landed in master, it - is time to use that in our CI again +- GHA: add workflow to compare configure vs cmake outputs -Nicholas Nethercote (31 Aug 2023) + 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. -- tests: fix formatting errors in `FILEFORMAT.md`. + The script also shows the matches that were *not* used. Possibly + subjects for removal. - Without the surrounding backticks, these tags get swallowed when the - markdown is rendered. + Closes #11964 - Closes #11777 +- appveyor: enable test 571 -Viktor Szakats (31 Aug 2023) + Follow-up from 8a940fd55c175f7 / #12013 -- cmake: add support for `CURL_DEFAULT_SSL_BACKEND` + Closes #12017 - Allow overriding the default TLS backend via a CMake setting. +Viktor Szakats (3 Oct 2023) - E.g.: - `cmake [...] -DCURL_DEFAULT_SSL_BACKEND=mbedtls` +- build: alpha-sort source files for lib and src - Accepted values: bearssl, gnutls, mbedtls, openssl, rustls, - schannel, secure-transport, wolfssl + Closes #12014 - The passed string is baked into the curl/libcurl binaries. - The value is case-insensitive. +- cmake: delete old `HAVE_LDAP_URL_PARSE` logic - We added a similar option to autotools in 2017 via - c7170e20d0a18ec8a514b4daa53bcdbb4dcb3a05. + Left there by accident after adding proper detection for this. - TODO: Convert to lowercase to improve reproducibility. + Follow-up to 772f0d8edf1c3c2745543f42388ccec5a16ee2c0 #12006 - Closes #11774 + Ref: #11964 (effort to sync cmake detections with autotools) -- sectransp: fix compiler warnings + Closes #12015 - https://github.com/curl/curl-for-win/actions/runs/6037489221/job/16381860220# - step:3:11046 - ``` - /Users/runner/work/curl-for-win/curl-for-win/curl/lib/vtls/sectransp.c:2435:1 - 4: warning: unused variable 'success' [-Wunused-variable] - OSStatus success; - ^ - /Users/runner/work/curl-for-win/curl-for-win/curl/lib/vtls/sectransp.c:3300:4 - 4: warning: unused parameter 'sha256len' [-Wunused-parameter] - size_t sha256len) - ^ - ``` +Stefan Eissing (3 Oct 2023) - Closes #11773 +- tests: increase lib571 timeout from 3s to 30s -- tidy-up: mostly whitespace nits + - 3s is too short for our CI, making this test fail occasionally + - test usually experiences no delay run locally, so 30s wont hurt - - delete completed TODO from `./CMakeLists.txt`. - - convert a C++ comment to C89 in `./CMake/CurlTests.c`. - - delete duplicate EOLs from EOF. - - add missing EOL at EOF. - - delete whitespace at EOL (except from expected test results). - - convert tabs to spaces. - - convert CRLF EOLs to LF in GHA yaml. - - text casing fixes in `./CMakeLists.txt`. - - fix a codespell typo in `packages/OS400/initscript.sh`. + Closes #12013 - Closes #11772 +Viktor Szakats (3 Oct 2023) -Dan Fandrich (31 Aug 2023) +- cmake: fix unity with Windows Unicode + TrackMemory -- CI: remove Windows builds from Cirrus, without replacement + Found the root cause of the startup crash in unity builds with Unicode + and TrackMemory enabled at the same time. - If we don't do this, all coverage on Cirrus will cease in a few days. By - removing the Windows builds, the FreeBSD one should still continue - as before. The Windows builds will need be moved to another service to - maintain test coverage. + 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. - Closes #11771 + 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. -- CI: switch macOS ARM build from Cirrus to Circle CI + Follow-up to d82b080f6374433ce7c98241329189ad2d3976f8 #12005 + Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 #11095 - Cirrus is drastically reducing their free tier on Sept. 1, so they will - no longer perform all these builds for us. All but one build has been - moved, with the LibreSSL one being dropped because of linking problems - on Circle. + Closes #11928 - One important note about this change is that Circle CI is currently - directing all these builds to x86_64 hardware, despite them requesting - ARM. This is because ARM nodes are scheduled to be available on the - free tier only in December. This reduces our architectural diversity - until then but it should automatically come back once those machines are - enabled. +- cmake: disable unity mode with Windows Unicode + TrackMemory -- CI: use the right variable for BSD make + "TrackMemory" is `ENABLE_DEBUG=ON` (aka `ENABLE_CURLDEBUG=ON`, + aka `-DCURLDEBUG`). - BSD uses MAKEFLAGS instead of MAKE_FLAGS so it wasn't doing parallel - builds before. + 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. -- CI: drop the FreeBSD 12.X build + 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. - Cirrus' new free tier won't let us have many builds, so drop the - nonessential ones. The FreeBSD 13.X build will still give us the most - relevant FreeBSD coverage. + 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) -- CI: move the Alpine build from Cirrus to GHA + Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 #11095 - Cirrus is reducing their free tier to next to nothing, so we must move - builds elsewhere. + Ref: #11928 + Closes #12005 -Stefan Eissing (30 Aug 2023) +- cmake: tidy-up `NOT_NEED_LBER_H` detection -- test_07_upload.py: fix test_07_34 curl args + Follow-up to 772f0d8edf1c3c2745543f42388ccec5a16ee2c0 #12006 - - Pass correct filename to --data-binary. +- appveyor: rewrite batch in PowerShell + CI improvements - Prior to this change --data-binary was passed an incorrect filename due - to a missing separator in the arguments list. Since aacbeae7 curl will - error on incorrect filenames for POST. + 1. Rewrite in PowerShell: - Fixes https://github.com/curl/curl/issues/11761 - Closes https://github.com/curl/curl/pull/11763 + - 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`. -Nicholas Nethercote (30 Aug 2023) + 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. -- tests: document which tests fail due to hyper's lack of trailer support. + 2. CI improvements: - Closes #11762 + - 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). -- docs: removing "pausing transfers" from HYPER.md. + 3. Style: - It's a reference to #8600, which was fixed by #9070. + - 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 #11764 + Closes #11999 -Patrick Monnerat (30 Aug 2023) +- cmake: fix `HAVE_LDAP_SSL`, `HAVE_LDAP_URL_PARSE` on non-Windows -- os400: handle CURL_TEMP_PRINTF() while building bind source + - 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. - Closes #11547 + - 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. -- os400: build test servers + - enable LDAP[S] for a CMake macOS CI job. Target OS X 10.9 (Mavericks) + to avoid deprecation warnings for LDAP API. - Also fix a non-compliant main prototype in disabled.c. + - 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. - Closes #11547 + - fix benign typo in variable name. -- tests: fix compilation error for os400 + Ref: #11964 (effort to sync cmake detections with autotools) - OS400 uses BSD 4.3 setsockopt() prototype by default: this does not - define parameter as const, resulting in an error if actual parameter is - const. Remove the const keyword from the actual parameter cast: this - works in all conditions, even if the formal parameter uses it. + Closes #12006 - Closes #11547 +- autotools: restore `HAVE_IOCTL_*` detections -- os400: make programs and command name configurable + 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`. - Closes #11547 + Regression from 4d73854462f30948acab12984b611e9e33ee41e6 -- os400: move build configuration parameters to a separate script + Ref: #11964 (effort to sync cmake detections with autotools) - They can then easily be overriden in a script named "config400.override" - that is not part of the distribution. + Closes #12008 - Closes #11547 +Daniel Stenberg (2 Oct 2023) -- os400: implement CLI tool +- RELEASE-PROCEDURE.md: updated coming release dates - This is provided as a QADRT (ascii) program, a link to it in the IFS and - a minimal CL command. +- RELEASE-NOTES: synced - Closes #11547 +Viktor Szakats (1 Oct 2023) -Matthias Gatto (30 Aug 2023) +- cmake: pre-cache `HAVE_POLL_FINE` on Windows -- lib: fix aws-sigv4 having date header twice in some cases + Windows doesn't support `poll()`, so we can safely skip checking for + fine poll. - When the user was providing the header X-XXX-Date, the header was - re-added during signature computation, and we had it twice in the - request. + Closes #12003 - Reported-by: apparentorder@users.noreply.github.com +- gha: bump actions to latest versions - Signed-off-by: Matthias Gatto + - actions@checkout@v4 (from v3 and v2) - Fixes: https://github.com/curl/curl/issues/11738 - Closes: https://github.com/curl/curl/pull/11754 + - fsfe/reuse-action@v2 (from v1) -Jay Satiro (30 Aug 2023) + Closes #12000 -- multi: remove 'processing: ' debug message +Stefan Eissing (30 Sep 2023) - - Remove debug message added by e024d566. +- h2: testcase and fix for pausing h2 streams - Closes https://github.com/curl/curl/pull/11759 + - 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 -- ftp: fix temp write of ipv6 address + Closes #11989 + Fixes #11982 + Reported-by: Harry Sintonen - - During the check to differentiate between a port and IPv6 address - without brackets, write the binary IPv6 address to an in6_addr. +Viktor Szakats (30 Sep 2023) - Prior to this change the binary IPv6 address was erroneously written to - a sockaddr_in6 'sa6' when it should have been written to its in6_addr - member 'sin6_addr'. There's no fallout because no members of 'sa6' are - accessed before it is later overwritten. +- cmake: validate `CURL_DEFAULT_SSL_BACKEND` config value - Closes https://github.com/curl/curl/pull/11747 + 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. -- tool: change some fopen failures from warnings to errors + This improves reproducibility and brings CMake in sync with autotools + which already worked like described above. - - Error on missing input file for --data, --data-binary, - --data-urlencode, --header, --variable, --write-out. + Follow-up to 26c7feb8b9d51a57fab3325571b4bbfa03b11af0 #11774 - Prior to this change if a user of the curl tool specified an input file - for one of the above options and that file could not be opened then it - would be treated as zero length data instead of an error. For example, a - POST using `--data @filenametypo` would cause a zero length POST which - is probably not what the user intended. + Closes #11998 - Closes https://github.com/curl/curl/pull/11677 +- autotools: adjust `CURL_CA_PATH` value to CMake -- hostip: fix typo + autotools was using the same value as CMake, but with an ending + slash. Delete the ending slash to match configurations. -Davide Masserut (29 Aug 2023) + Ref: #11964 (effort to sync cmake detections with autotools) -- tool: avoid including leading spaces in the Location hyperlink + Closes #11997 - Co-authored-by: Dan Fandrich +- cmake: detect `sys/wait.h` and `netinet/udp.h` - Closes #11735 + Ref: #11964 (effort to sync cmake detections with autotools) -Daniel Stenberg (29 Aug 2023) + Closes #11996 -- SECURITY-PROCESS.md: not a sec issue: Tricking user to run a cmdline +Daniel Stenberg (30 Sep 2023) - Closes #11757 +- lib: provide and use Curl_hexencode -- connect: stop halving the remaining timeout when less than 600 ms left + Generates a lower case ASCII hex output from a binary input. - When curl wants to connect to a host, it always has a TIMEOUT. The - maximum time it is allowed to spend until a connect is confirmed. + Closes #11990 - curl will try to connect to each of the IP adresses returned for the - host. Two loops, one for each IP family. +- configure: check for the capath by default - During the connect loop, while curl has more than one IP address left to - try within a single address family, curl has traditionally allowed (time - left/2) for *this* connect attempt. This, to not get stuck on the - initial addresses in case the timeout but still allow later addresses to - get attempted. + ... if the chosen TLS backend supports it: OpenSSL, GnuTLS, mbedTLS or wolfSS + L - This has the downside that when users set a very short timeout and the - host has a large number of IP addresses, the effective result might be - that every attempt gets a little too short time. + cmake: synced - This change stop doing the divided-by-two if the total time left is - below a threshold. This threshold is 600 milliseconds. + Assisted-by: Viktor Szakats + Closes #11987 - Closes #11693 +- wolfssl: ignore errors in CA path -- asyn-ares: reduce timeout to 2000ms + 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. - When UDP packets get lost this makes for slightly faster retries. This - lower timeout is used by @c-ares itself by default starting next - release. + With the *_ex() function and its WOLFSSL_LOAD_FLAG_IGNORE_ERR flag, it + behaves more similar to what OpenSSL does by default. - Closes #11753 + Even the set of default certs on my Debian unstable has several expired + ones. -John Bampton (29 Aug 2023) + Assisted-by: Juliusz Sosinowicz + Assisted-by: Michael Osipov -- misc: remove duplicate words + Closes #11987 - Closes #11740 +- create-dirs.d: clarify it also uses --output-dirs -Daniel Stenberg (29 Aug 2023) + Reported-by: Robert Simpson + Fixes #11991 + Closes #11995 -- RELEASE-NOTES: synced +Viktor Szakats (30 Sep 2023) -- wolfSSL: avoid the OpenSSL compat API when not needed +- appveyor: fix yamlint issues, indent - ... and instead call wolfSSL functions directly. + Also: + - use double quotes in all batch if statements. - Closes #11752 + Closes #11994 -Viktor Szakats (28 Aug 2023) +- cmake: detect `HAVE_CLOCK_GETTIME_MONOTONIC_RAW` -- lib: fix null ptr derefs and uninitialized vars (h2/h3) + Based on existing autotools logic. - Fixing compiler warnings with gcc 13.2.0 in unity builds. + Ref: #11964 (effort to sync cmake detections with autotools) - Assisted-by: Jay Satiro - Assisted-by: Stefan Eissing - Closes #11739 + Closes #11981 -Jay Satiro (28 Aug 2023) +- cmake: detect `HAVE_GETADDRINFO_THREADSAFE` -- secureserver.pl: fix stunnel version parsing + Based on existing autotools logic. - - Allow the stunnel minor-version version part to be zero. + 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. - Prior to this change with the stunnel version scheme of . - if either part was 0 then version parsing would fail, causing - secureserver.pl to fail with error "No stunnel", causing tests that use - the SSL protocol to be skipped. As a practical matter this bug can only - be caused by a minor-version part of 0, since the major-version part is - always greater than 0. + 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. - Closes https://github.com/curl/curl/pull/11722 + 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. -- secureserver.pl: fix stunnel path quoting + Ref: #11964 (effort to sync cmake detections with autotools) - - Store the stunnel path in the private variable $stunnel unquoted and - instead quote it in the command strings. + Closes #11979 - Prior to this change the quoted stunnel path was passed to perl's file - operators which cannot handle quoted paths. For example: +- cmake: fix `HAVE_WRITABLE_ARGV` detection - $stunnel = "\"/C/Program Files (x86)/stunnel/bin/tstunnel\""; - if(-x $stunnel or -x "$stunnel") - # false even if path exists and is executable + Move detection before the creation of detection results in + `curl_config.h`. - Our other test scripts written in perl, unlike this one, use servers.pm - which has a global $stunnel variable with the path stored unquoted and - therefore those scripts don't have this problem. + Ref: #11964 (effort to sync cmake detections with autotools) - Closes https://github.com/curl/curl/pull/11721 + Closes #11978 -Daniel Stenberg (28 Aug 2023) +- appveyor: minor improvements -- altsvc: accept and parse IPv6 addresses in response headers + - 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. - Store numerical IPv6 addresses in the alt-svc file with the brackets - present. + - 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.) - Verify with test 437 and 438 + - list the DLLs and EXEs present after the builds. - Fixes #11737 - Reported-by: oliverpool on github - Closes #11743 + - add `DEBUG` variable for CMake builds to allow disabling it, for + testing non-debug builds. (currently enabled for all) -- libtest: use curl_free() to free libcurl allocated data + - add commented lines that dump CMake configuration logs for debugging + build/auto-detection issues. - In several test programs. These mistakes are not detected or a problem - as long as memdebug.h is included, as that provides the debug wrappers - for all memory functions in the same style libcurl internals do it, - which makes curl_free and free effectively the same call. + - add gcc version to jobs where missing. - Reported-by: Nicholas Nethercote - Closes #11746 + - switch a job to the native MSYS2 mingw-w64 toolchain. This adds gcc 9 + to the build mix. -Jay Satiro (28 Aug 2023) + - make `SHARED=OFF` and `OPENSSL=OFF` defaults global. -- disable.d: explain --disable not implemented prior to 7.50.0 + - delete a duplicate backslash. - Option -q/--disable was added in 5.0 but only -q was actually - implemented. Later --disable was implemented in e200034 (precedes - 7.49.0), but incorrectly, and fixed in 6dbc23c (precedes 7.50.0). + Closes #11976 - Reported-by: pszlazak@users.noreply.github.com +- configure: replace adhoc domain with `localhost` in tests - Fixes https://github.com/curl/curl/issues/11710 - Closes #11712 + Reviewed-by: Daniel Stenberg + Closes #11988 -Nicholas Nethercote (28 Aug 2023) +- tidy-up: use more example domains -- hyper: fix ownership problems + Also make use of the example TLD: + https://en.wikipedia.org/wiki/.example - Some of these changes come from comparing `Curl_http` and - `start_CONNECT`, which are similar, and adding things to them that are - present in one and missing in another. + Reviewed-by: Daniel Stenberg + Closes #11992 - The most important changes: - - In `start_CONNECT`, add a missing `hyper_clientconn_free` call on the - happy path. - - In `start_CONNECT`, add a missing `hyper_request_free` on the error - path. - - In `bodysend`, add a missing `hyper_body_free` on an early-exit path. - - In `bodysend`, remove an unnecessary `hyper_body_free` on a different - error path that would cause a double-free. - https://docs.rs/hyper/latest/hyper/ffi/fn.hyper_request_set_body.html - says of `hyper_request_set_body`: "This takes ownership of the - hyper_body *, you must not use it or free it after setting it on the - request." This is true even if `hyper_request_set_body` returns an - error; I confirmed this by looking at the hyper source code. +Dan Fandrich (29 Sep 2023) - Other changes are minor but make things slightly nicer. +- runtests: display the test status if tests appear hung - Closes #11745 + 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. -Daniel Stenberg (28 Aug 2023) + 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. -- multi.h: the 'revents' field of curl_waitfd is supported + Closes #11980 - Since 6d30f8ebed34e7276 +- github/labeler: remove workaround for labeler - Reported-by: Nicolás Ojeda Bär - Ref: #11748 - Closes #11749 + 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. -Gerome Fournier (27 Aug 2023) + Follow-up to b2b0534e7 -- tool_paramhlp: improve str2num(): avoid unnecessary call to strlen() +Viktor Szakats (29 Sep 2023) - Closes #11742 +- docs: upgrade an URL to HTTPS in `BINDINGS.md` [ci skip] -Daniel Stenberg (27 Aug 2023) +Daniel Stenberg (29 Sep 2023) -- docs: mention critical files in same directories as curl saves +- docs: replace made up domains with example.com - ... cannot be fully protected. Don't do it. + in FAQ and MANUAL.md - Co-authored-by: Jay Satiro - Reported-by: Harry Sintonen - Fixes #11530 - Closes #11701 + - example.com was made for this purpose. -John Hawthorn (26 Aug 2023) + - reduces the risk that one of those domains suddenly start hosting + something nasty and we provide links to them -- OpenSSL: clear error queue after SSL_shutdown + Closes #11986 - We've seen errors left in the OpenSSL error queue (specifically, - "shutdown while in init") by adding some logging it revealed that the - source was this file. +Michael Osipov (29 Sep 2023) - Since we call SSL_read and SSL_shutdown here, but don't check the return - code for an error, we should clear the OpenSSL error queue in case one - was raised. +- acinclude.m4: Document proper system truststore on FreeBSD - This didn't affect curl because we call ERR_clear_error before every - write operation (a0dd9df9ab35528eb9eb669e741a5df4b1fb833c), but when - libcurl is used in a process with other OpenSSL users, they may detect - an OpenSSL error pushed by libcurl's SSL_shutdown as if it was their - own. + 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. - Co-authored-by: Satana de Sant'Ana + Closes #11985 - Closes #11736 +Daniel Stenberg (29 Sep 2023) -Alexander Kanavin (25 Aug 2023) +- FAQ: How do I upgrade curl.exe in Windows? -- tests: update cookie expiry dates to far in the future + This is a growing question, better answer it here to get somewhere to + point users to. - This allows testing Y2038 with system time set to after that, so that - actual Y2038 issues can be exposed, and not masked by expiry errors. + Closes #11984 - Fixes #11576 - Closes #11610 +Viktor Szakats (28 Sep 2023) -John Bampton (25 Aug 2023) +- cmake: pre-cache `HAVE_BASENAME` for mingw-w64 and MSVC -- misc: fix spelling + `basename` is present in mingw-w64, missing from MSVC. Pre-cache + accordingly to make configure faster. - Closes #11733 + 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 -Daniel Stenberg (25 Aug 2023) + Closes #11974 -- cmdline-opts/page-header: clarify stronger that !opt == URL +Daniel Stenberg (28 Sep 2023) - Everything provided on the command line that is not an option (or an - argument to an option) is treated as a URL. +- cmake: add missing checks - Closes #11734 + - 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 -- tests/runner: fix %else handling + Ref: #11964 - Getting the show state proper for %else and %endif did not properly work - in nested cases. + Co-authored-by: Viktor Szakats + Closes #11973 - Follow-up to 3d089c41ea9 +- configure: remove unused checks - Closes #11731 + - for sys/uio.h + - for fork + - for connect -Nicholas Nethercote (25 Aug 2023) + Ref: #11964 -- docs: Remove mention of #10803 from `KNOWN_BUGS`. + Closes #11973 - Because the leaks have been fixed. +- lib: remove TIME_WITH_SYS_TIME -- c-hyper: fix another memory leak in `Curl_http`. + It is not used in any code anywhere. - There is a `hyper_clientconn_free` call on the happy path, but not one - on the error path. This commit adds one. + Ref: #11964 + Closes #11975 - Fixes the second memory leak reported by Valgrind in #10803. +- docs: update curl man page references - Fixes #10803 - Closes #11729 + Detected by the manpage-syntax update -- c-hyper: fix a memory leak in `Curl_http`. + Closes #11963 - A request created with `hyper_request_new` must be consumed by either - `hyper_clientconn_send` or `hyper_request_free`. +- manpage-syntax: verify curl man page references - This is not terrifically clear from the hyper docs -- - `hyper_request_free` is documented only with "Free an HTTP request if - not going to send it on a client" -- but a perusal of the hyper code - confirms it. + 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. - This commit adds a `hyper_request_free` to the `error:` path in - `Curl_http` so that the request is consumed when an error occurs after - the request is created but before it is sent. + Allowlist curl.1 since it is not always built in builds - Fixes the first memory leak reported by Valgrind in #10803. + 2. References to curl symbols that lack section now causes warning, since tha + t + will prevent them from getting linked properly - Closes #11729 + 3. Check for "bare" references to curl functions and warn, they should be + references -Daniel Stenberg (25 Aug 2023) + Closes #11963 -- RELEASE-NOTES: synced +- cmake: add check for suseconds_t + + And fix the HAVE_LONGLONG define + + Ref: #11964 + Closes #11977 -John Bampton (25 Aug 2023) +Viktor Szakats (28 Sep 2023) -- misc: spellfixes +- tidy-up: whitespace fixes - Closes #11730 + Closes #11972 -Daniel Stenberg (25 Aug 2023) +- cmake: detect TLS-SRP in OpenSSL/wolfSSL/GnuTLS -- tests: add support for nested %if conditions + With new option `CURL_DISABLE_SRP=ON` to force-disable it. + To match existing option and detection logic in autotools. - Provides more flexiblity to test cases. + 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. - Also warn and bail out if there is an '%else' or %endif' without a - preceeding '%if'. + Ref: #11964 - Ref: #11610 - Closes #11728 + Closes #11967 -- time-cond.d: mention what happens on a missing file +- tool: use our own stderr variable - Closes #11727 + 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. -Christian Hesse (24 Aug 2023) + 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`. -- docs/cmdline-opts: match the current output + Follow-up to 06133d3e9b8aeb9e9ca0b3370c246bdfbfc8619e + Follow-up to 2f17a9b654121dd1ecf4fc043c6d08a9da3522db - The release date has been added in output, reflect that in documentation. + Closes #11958 - Closes #11723 +Loïc Yhuel (28 Sep 2023) -Daniel Stenberg (24 Aug 2023) +- connect: only start the happy eyeballs timer when needed -- lib: minor comment corrections + The timeout is only used when there is a second address family, for the + delayed eyeballer. -- docs: rewrite to present tense + Closes #11939 - ... instead of using future tense. +Daniel Stenberg (28 Sep 2023) - + numerous cleanups and improvements - + stick to "reuse" not "re-use" - + fewer contractions +- tool_operate: free 'gateway' correctly - Closes #11713 + Pointed out by Coverity. The fix in 93885cf3a8d4e was incomplete. -- urlapi: setting a blank URL ("") is not an ok URL + Also removed repeated wording in IPFS related error messages. - Test it in 1560 - Fixes #11714 - Reported-by: ad0p on github - Closes #11715 + Closes #11969 -- spelling: use 'reuse' not 're-use' in code and elsewhere +Stefan Eissing (28 Sep 2023) - Unify the spelling as both versions were previously used intermittently +- lib: move handling of `data->req.writer_stack` into Curl_client_write() - Closes #11717 + - 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 -Michael Osipov (23 Aug 2023) + Closes #11908 -- system.h: add CURL_OFF_T definitions on HP-UX with HP aCC +Loïc Yhuel (28 Sep 2023) - HP-UX on IA64 provides two modes: 32 and 64 bit while 32 bit being the - default one. Use "long long" in 32 bit mode and just "long" in 64 bit - mode. +- multi: round the timeout up to prevent early wakeups - Closes #11718 + 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. -Dan Fandrich (22 Aug 2023) + 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. -- tests: don't call HTTP errors OK in test cases + Closes #11938 - Some HTTP errors codes were accompanied by the text OK, which causes - some cognitive dissonance when reading them. +Daniel Stenberg (28 Sep 2023) -- http: close the connection after a late 417 is received +- RELEASE-NOTES: spell out that IPFS is via gateway - In this situation, only part of the data has been sent before aborting - so the connection is no longer usable. +- RELEASE-NOTES: synced - Assisted-by: Jay Satiro - Fixes #11678 - Closes #11679 +- tool_operate: avoid strlen() -1 on zero length content from file -- runtests: slightly increase the longest log file displayed + Follow-up to 65b563a96a226649ba12cb1e - The new limit provides enough space for a 64 KiB data block to be logged - in a trace file, plus a few lines at the start and end for context. This - happens to be the amount of data sent at a time in a PUT request. + Closes #11959 -- tests: add delay command to the HTTP server +- tool_operate: fix memory mixups - This adds a delay after client connect. + 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. -Daniel Stenberg (22 Aug 2023) + Coverity found issues and a memory leak. -- cirrus: install everthing with pkg, avoid pip + Follow-up to 65b563a96a226649ba12cb1e - Assisted-by: Sevan Janiyan + Closes #11959 - Closes #11711 +Viktor Szakats (27 Sep 2023) -- curl_url*.3: update function descriptions +- curl-functions.m4: fixup recent bad edits - - expand and clarify several descriptions - - avoid using future tense all over + Follow-up to 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940 - Closes #11708 + Closes #11966 -- RELEASE-NOTES: synced +Daniel Stenberg (27 Sep 2023) -Stefan Eissing (21 Aug 2023) +- curl-functions.m4: fix include line -- CI/cirrus: disable python install on FreeBSD + 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! - - python cryptography package does not build build FreeBSD - - install just mentions "error" - - this gets the build and the main test suite going again + Follow-up to 96c29900bcec (#11940) - Closes #11705 + Closes #11965 -- test2600: fix flakiness on low cpu +- inet_ntop: add typecast to silence Coverity - - refs #11355 where failures to to low cpu resources in CI - are reported - - vastly extend CURLOPT_CONNECTTIMEOUT_MS and max durations - to test cases - - trigger Curl_expire() in test filter to allow re-checks before - the usual 1second interval + CID 1024653: Integer handling issues (SIGN_EXTENSION) - Closes #11690 + 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. -Maksim Sciepanienka (20 Aug 2023) + 111 words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); -- tool_urlglob: use the correct format specifier for curl_off_t in msnprintf + The value will not be greater than 0x7FFFFFFF so this still cannot + happen. - Closes #11698 + 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. -Daniel Stenberg (20 Aug 2023) + Closes #11960 -- test687/688: two more basic --xattr tests +- docs: adapt SEE ALSO sections to new requirements - Closes #11697 + To please manpage-syntax.pl used by test 1173 -- cmdline-opts/docs: mentioned the negative option part + Closes #11957 - ... for --no-alpn and --no-buffer in the same style done for other --no- - options: +- manpage-syntax.pl: verify SEE ALSO syntax - "Note that this is the negated option name documented." + - 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 - Closes #11695 + - List the entries alpha-sorted, not enforced just recommended -Emanuele Torre (19 Aug 2023) + Closes #11957 -- tool/var: also error when expansion result starts with NUL +- connect: expire the timeout when trying next - Expansions whose output starts with NUL were being expanded to the empty - string, and not being recognised as values that contain a NUL byte, and - should error. + ... so that it gets called again immediately and can continue trying + addresses to connect to. Otherwise it might unnecessarily wait for a + while there. - Closes #11694 + Fixes #11920 + Reported-by: Loïc Yhuel + Closes #11935 -Daniel Stenberg (19 Aug 2023) +- http: remove wrong comment for http_should_fail -- tests: add 'large-time' as a testable feature + Reported-by: Christian Schmitz + Ref: #11936 + Closes #11941 - This allows test cases to require this feature to run and to be used in - %if conditions. +Dan Fandrich (26 Sep 2023) - Large here means larger than 32 bits. Ie does not suffer from y2038. +- tool_setopt: remove unused function tool_setopt_flags - Closes #11696 + This function is identical to tool_setopt_bitmask except that it treats + the argument as unsigned. -- tests/Makefile: add check-translatable-options.pl to tarball + Closes #11943 - Used in test 1544 +Viktor Szakats (26 Sep 2023) - Follow-up to ae806395abc8c +- cmake: add feature checks for `memrchr` and `getifaddrs` -- gen.pl: fix a long version generation mistake + - `HAVE_MEMRCHR` for `memrchr`. + - `HAVE_GETIFADDRS` for `getifaddrs`. + This was present in `lib/curl_config.h.cmake` but missed the detection + logic. - Too excessive escaping made the parsing not find the correct long names - later and instead add "wrong" links. + To match existing autotools feature checks. - Follow-up to 439ff2052e219 + Closes #11954 - Reported-by: Lukas Tribus - Fixes #11688 - Closes #11689 +- cmake: move global headers to specific checks -- lib: move mimepost data from ->req.p.http to ->state + 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. - When the legacy CURLOPT_HTTPPOST option is used, it gets converted into - the modem mimpost struct at first use. This data is (now) kept for the - entire transfer and not only per single HTTP request. This re-enables - rewind in the beginning of the second request instead of in end of the - first, as brought by 1b39731. + I've used autotools' `m4/curl-functions.m4` to figure out these + dependencies. - The request struct is per-request data only. + Also delete checking for the C89 standard header `time.h`, that I + missed in the earlier commit. - Extend test 650 to verify. + Ref: 96c29900bcec32dd6bc8e9857c8871ff4b8b8ed9 #11940 - Fixes #11680 - Reported-by: yushicheng7788 on github - Closes #11682 + Closes #11951 -Patrick Monnerat (17 Aug 2023) +- src/mkhelp: make generated code pass `checksrc` -- os400: do not check translatable options at build time + Closes #11955 - Now that there is a test for this, the build time check is not needed - anymore. +- tests: show which curl tool `runtests.pl` is using - Closes #11650 + To help debugging when there is issue finding or running it. -- test1554: check translatable string options in OS400 wrapper + Closes #11953 - This test runs a perl script that checks all string options are properly - translated by the OS400 character code conversion wrapper. It also - verifies these options are listed in alphanumeric order in the wrapper - switch statement. +- CI/azure: make `MAKEFLAGS` global to parallelize all jobs - Closes #11650 + 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) -Daniel Stenberg (17 Aug 2023) + Closes #11952 -- unit3200: skip testing if function is not present +- CI/azure: migrate old mingw MSYS1 jobs to MSYS2 - Fake a successful run since we have no easy mechanism to skip this test - for this advanced condition. + Also delete an accidental variable reference. -- unit2600: fix build warning if built without verbose messages + Follow-up to 38029101e2d78ba125732b3bab6ec267b80a0e72 -- test1608: make it build and get skipped without shuffle DNS support + Closes #11945 -- lib: --disable-bindlocal builds curl without local binding support +Daniel Stenberg (26 Sep 2023) -- test1304: build and skip without netrc support +- docs: add see also curl_multi_get_handles to some man pages -- lib: build fixups when built with most things disabled + Assisted-by: Jay Satiro - Closes #11687 + Closes #11942 -- workflows/macos.yml: disable zstd and alt-svc in the http-only build +Viktor Szakats (26 Sep 2023) - Closes #11683 +- cmake: assume `_fseeki64` and no `fseeko` on Windows -Stefan Eissing (17 Aug 2023) + `_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]. -- bearssl: handshake fix, provide proper get_select_socks() implementation + `fseeko` is not present in any of these. - - bring bearssl handshake times down from +200ms down to other TLS backends - - vtls: improve generic get_select_socks() implementation - - tests: provide Apache with a suitable ssl session cache + (mingw-w64 1.0 also offers `fseeko64`.) - Closes #11675 + [1] https://github.com/curl/curl/pull/11944#issuecomment-1734995004 -- tests: TLS session sharing test + Follow-up to 9c7165e96a3a9a2d0b7059c87c699b5ca8cdae93 #11918 - - test TLS session sharing with special test client - - expect failure with wolfSSL - - disable flaky wolfSSL test_02_07b + Closes #11950 - Closes #11675 +- build: delete checks for C89 standard headers -Daniel Stenberg (17 Aug 2023) + 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`. -- CURLOPT_*TIMEOUT*: extend and clarify + Some of these we already used unconditionally, some others we only used + for feature checks. - Closes #11686 + Follow-up to 9c7165e96a3a9a2d0b7059c87c699b5ca8cdae93 #11918 (for `stdio.h` i + n CMake) -- urlapi: return CURLUE_BAD_HOSTNAME if puny2idn encoding fails + Closes #11940 - And document it. Only return out of memory when it actually is a memory - problem. +Stefan Eissing (26 Sep 2023) - Pointed-out-by: Jacob Mealey - Closes #11674 +- multiif.h: remove Curl_multi_dump declaration -Mathew Benson (17 Aug 2023) + Follow-up to d850eea2 which removed the Curl_multi_dump definition. -- cmake: add GnuTLS option + Closes https://github.com/curl/curl/pull/11946 - - Option to use GNUTLS was missing. Hence was not able to use GNUTLS - with ngtcp2 for http3. +Jay Satiro (26 Sep 2023) - Closes #11685 +- config-win32: define HAVE__FSEEKI64 -Daniel Stenberg (16 Aug 2023) + Follow-up to 9c7165e9 which added an fseeko wrapper to the lib that + calls _fseeki64 if it is available. -- RELEASE-NOTES: synced + Closes https://github.com/curl/curl/pull/11944 -- http: remove the p_pragma struct field +- docs: explain how PINNEDPUBLICKEY is independent of VERIFYPEER - unused since 40e8b4e52 (2008) + - Explain that peer verification via CURLOPT_PINNEDPUBLICKEY takes place + even if peer verification via CURLOPT_SSL_VERIFYPEER is turned off. - Closes #11681 + The behavior is verified by test2048. -Jay Satiro (16 Aug 2023) + Bug: https://github.com/curl/curl/issues/2935#issuecomment-418371872 + Reported-by: claudiusaiz@users.noreply.github.com -- CURLINFO_CERTINFO.3: better explain curl_certinfo struct + Bug: https://github.com/curl/curl/discussions/11910 + Reported-by: Hakan Sunay Halil - Closes https://github.com/curl/curl/pull/11666 + Closes https://github.com/curl/curl/pull/11930 -- CURLINFO_TLS_SSL_PTR.3: clarify a recommendation +Stefan Eissing (26 Sep 2023) - - Remove the out-of-date SSL backend list supported by - CURLOPT_SSL_CTX_FUNCTION. +- openssl: improve ssl shutdown handling - It makes more sense to just refer to that document instead of having - a separate list that has to be kept in sync. + - If SSL shutdown is not finished then make an additional call to + SSL_read to gather additional tracing. - Closes https://github.com/curl/curl/pull/11665 + - Fix http2 and h2-proxy filters to forward do_close() calls to the next + filter. -- write-out.d: clarify %{time_starttransfer} + For example h2 and SSL shutdown before and after this change: - sync it up with CURLINFO_STARTTRANSFER_TIME_T + Before: -Daniel Stenberg (15 Aug 2023) + Curl_conn_close -> cf_hc_close -> Curl_conn_cf_discard_chain -> + ssl_cf_destroy -- transfer: don't set TIMER_STARTTRANSFER on first send + After: - The time stamp is for measuring the first *received* byte + Curl_conn_close -> cf_hc_close -> cf_h2_close -> cf_setup_close -> + ssl_cf_close - Fixes #11669 - Reported-by: JazJas on github - Closes #11670 + Note that currently the tracing does not show output on the connection + closure handle. Refer to discussion in #11878. -trrui-huawei (15 Aug 2023) + Ref: https://github.com/curl/curl/discussions/11878 -- quiche: enable quiche to handle timeout events + Closes https://github.com/curl/curl/pull/11858 - In parallel with ngtcp2, quiche also offers the `quiche_conn_on_timeout` - interface for the application to invoke upon timer - expiration. Therefore, invoking the `on_timeout` function of the - Connection is crucial to ensure seamless functionality of quiche with - timeout events. +Loïc Yhuel (26 Sep 2023) - Closes #11654 +- multi: fix small timeouts -- quiche: adjust quiche `QUIC_IDLE_TIMEOUT` to 60s + 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. - Set the `QUIC_IDLE_TIMEOUT` parameter to match ngtcp2 for consistency. + Closes #11937 -Daniel Stenberg (15 Aug 2023) +Viktor Szakats (25 Sep 2023) -- KNOWN_BUGS: LDAPS requests to ActiveDirectory server hang +- cmake: fix stderr initialization in unity builds - Closes #9580 + Before this patch, in certain build configurations the curl tool may + not have displayed anything (debug, macOS), or crashed at startup + (debug, Windows). -- imap: add a check for failing strdup() + Follow-up to 3f8fc25720900b14b7432f4bd93407ca15311719 + Necessary after 2f17a9b654121dd1ecf4fc043c6d08a9da3522db -- imap: remove the only sscanf() call in the IMAP code + Closes #11929 - Avoids the use of a stack buffer. +- cmake: fix missing `zlib.h` when compiling `libcurltool` - Closes #11673 + 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. -- imap: use a dynbuf in imap_atom + ``` + [ 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 + | ^~~~~~~~ + ``` - Avoid a calculation + malloc. Build the output in a dynbuf. + Follow-up to 39e7c22bb459c2e818f079984989a26a09741860 - Closes #11672 + Closes #11927 -Marin Hannache (14 Aug 2023) +- cmake: fix duplicate symbols when linking tests -- http: do not require a user name when using CURLAUTH_NEGOTIATE + 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 - In order to get Negotiate (SPNEGO) authentication to work in HTTP you - used to be required to provide a (fake) user name (this concerned both - curl and the lib) because the code wrongly only considered - authentication if there was a user name provided, as in: + 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 + ``` - curl -u : --negotiate https://example.com/ + Closes #11926 - This commit leverages the `struct auth` want member to figure out if the - user enabled CURLAUTH_NEGOTIATE, effectively removing the requirement of - setting a user name both in curl and the lib. +- cmake: lib `CURL_STATICLIB` fixes (Windows) - Signed-off-by: Marin Hannache - Reported-by: Enrico Scholz - Fixes https://sourceforge.net/p/curl/bugs/440/ - Fixes #1161 - Closes #9047 + - always define `CURL_STATICLIB` when building libcurl for Windows. -Viktor Szakats (13 Aug 2023) + 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. -- build: streamline non-UWP wincrypt detections + Regression from 1199308dbc902c52be67fc805c72dd2582520d30 - - with CMake, use the variable `WINDOWS_STORE` to detect an UWP build - and disable our non-UWP-compatible use the Windows crypto API. This - allows to drop two dynamic feature checks. + Fixes #11844 - `WINDOWS_STORE` is true when invoking CMake with - `CMAKE_SYSTEM_NAME` == `WindowsStore`. Introduced in CMake v3.1. + - fix to omit `libcurl.def` when not hiding private symbols. - Ref: https://cmake.org/cmake/help/latest/variable/WINDOWS_STORE.html + Regression from 2ebc74c36a19a1700af394c16855ce144d9878e3 - - with autotools, drop the separate feature check for `wincrypt.h`. On - one hand this header has been present for long (even Borland C 5.5 had - it from year 2000), on the other we used the check result solely to - enable another check for certain crypto functions. This fails anyway - with the header not present. We save one dynamic feature check at the - configure stage. + - 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. - Reviewed-by: Marcel Raad - Closes #11657 + - delete `INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB"` for "objects" + target. -Nicholas Nethercote (13 Aug 2023) + Follow-up to 2ebc74c36a19a1700af394c16855ce144d9878e3 -- docs/HYPER.md: update hyper build instructions + - delete duplicate `BUILDING_LIBCURL` definitions. - Nightly Rust and `-Z unstable-options` are not needed. + - fix `HIDES_CURL_PRIVATE_SYMBOLS` to not overwrite earlier build settings. - The instructions here now match the hyper docs exactly: - https://github.com/hyperium/hyper/commit/bd7928f3dd6a8461f0f0fdf7ee0fd95c2f15 - 6f88 + Follow-up to 1199308dbc902c52be67fc805c72dd2582520d30 - Closes #11662 + Closes #11914 -Daniel Stenberg (13 Aug 2023) +Daniel Stenberg (25 Sep 2023) - RELEASE-NOTES: synced -- urlapi: CURLU_PUNY2IDN - convert from punycode to IDN name - - Asssisted-by: Jay Satiro - Closes #11655 - -- spellcheck: adapt to backslashed minuses - - As the curl.1 has more backslashed minus, the cleanup sed lines xneed to - adapt. - - Adjusted some docs slighly. - - Follow-up to 439ff2052e +Dan Fandrich (25 Sep 2023) - Closes #11663 +- tests: fix log directory path in IPFS tests -- gen: escape more minus + Hard-coding the log directory name fails with parallel tests. - Detected since it was still hard to search for option names using dashes - in the middle in the man page. + Follow-up to 65b563a96 - Closes #11660 + Ref: #8805 -- cookie-jar.d: enphasize that this option is ONLY writing cookies +Daniel Stenberg (25 Sep 2023) - Reported-by: Dan Jacobson - Tweaked-by: Jay Satiro - Ref: #11642 - Closes #11661 +- curl_multi_get_handles: get easy handles from a multi handle -Nicholas Nethercote (11 Aug 2023) + Closes #11750 -- docs/HYPER.md: document a workaround for a link error +Stefan Eissing (25 Sep 2023) - Closes #11653 +- http: h1/h2 proxy unification -Jay Satiro (11 Aug 2023) + - 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` -- schannel: verify hostname independent of verify cert + Closes #11808 - Prior to this change when CURLOPT_SSL_VERIFYPEER (verifypeer) was off - and CURLOPT_SSL_VERIFYHOST (verifyhost) was on we did not verify the - hostname in schannel code. +Natanael Copa (25 Sep 2023) - This fixes KNOWN_BUG 2.8 "Schannel disable CURLOPT_SSL_VERIFYPEER and - verify hostname". We discussed a fix several years ago in #3285 but it - went stale. +- lib: use wrapper for curl_mime_data fseek callback - Assisted-by: Daniel Stenberg + 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. - Bug: https://curl.haxx.se/mail/lib-2018-10/0113.html - Reported-by: Martin Galvan + Use a wrapper to solve this and use fseeko which uses off_t instead of + long. - Ref: https://github.com/curl/curl/pull/3285 + Thanks to the nice people at Libera IRC #musl for helping finding this + out. - Fixes https://github.com/curl/curl/issues/3284 - Closes https://github.com/curl/curl/pull/10056 + Fixes #11882 + Fixes #11900 + Closes #11918 -Daniel Stenberg (11 Aug 2023) +- configure: sort AC_CHECK_FUNCS -- curl_quiche: remove superfluous NULL check + No functional changes. - 'stream' is always non-NULL at this point +Daniel Stenberg (25 Sep 2023) - Pointed out by Coverity +- warnless: remove unused functions - Closes #11656 + Previously put there for use with the intel compiler -- curl/urlapi.h: tiny typo + Closes #11932 -- github/labeler: make HYPER.md set Hyper and not TLS +- GHA/linux: run singleuse to detect single-use global functions -- docs/cmdline-opts/gen.pl: hide "added in" before 7.50.0 + Use --unit for configure --enable-debug builds - 7.50.0 shipped on Jul 21 2016, over seven years ago. We no longer need - to specify version changes for earlier releases in the generated output. + Closes #11932 - This ups the limit from the previous 7.30.0 (Apr 12 2013) +- singleuse: add scan for use in other source codes - This hides roughly 35 "added in" mentions. + 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 #11651 + Closes #11932 -Jay Satiro (10 Aug 2023) +- multi: remove Curl_multi_dump -- bug_report: require reporters to specify curl and os versions + 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. - - Change curl version and os sections from single-line input to - multi-line textarea. + Closes #11931 - - Require curl version and os sections to be filled out before report - can be submitted. +Viktor Szakats (24 Sep 2023) - Closes https://github.com/curl/curl/pull/11636 +- tests: fix compiler warnings -Daniel Stenberg (9 Aug 2023) + Seen with llvm 17 on Windows x64. -- gen.pl: replace all single quotes with aq + ``` + .../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)( ) + ``` - - this prevents man from using a unicode sequence for them - - which then allows search to work properly + ``` + .../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. - Closes #11645 + .../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. -Viktor Szakats (9 Aug 2023) + .../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. + ``` -- cmake: fix to use variable for the curl namespace + 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. + ``` - Replace (wrong) literal with a variable to specify the curl - namespace. + Closes #11925 - Follow-up to 1199308dbc902c52be67fc805c72dd2582520d30 #11505 +Jay Satiro (24 Sep 2023) - Reported-by: balikalina on Github - Fixes https://github.com/curl/curl/commit/1199308dbc902c52be67fc805c72dd25825 - 20d30#r123923098 - Closes #11629 +- url: fix netrc info message -- cmake: allow `SHARE_LIB_OBJECT=ON` on all platforms + - Fix netrc info message to use the generic ".netrc" filename if the + user did not specify a netrc location. - 2ebc74c36a19a1700af394c16855ce144d9878e3 #11546 introduced sharing - libcurl objects for shared and static targets. + - Update --netrc doc to add that recent versions of curl on Windows + prefer .netrc over _netrc. - The above automatically enabled for Windows builds, with an option to - disable with `SHARE_LIB_OBJECT=OFF`. + Before: + * Couldn't find host google.com in the (nil) file; using defaults - This patch extend this feature to all platforms as a manual option. - You can enable it by setting `SHARE_LIB_OBJECT=ON`. Then shared objects - are built in PIC mode, meaning the static lib will also have PIC code. + After: + * Couldn't find host google.com in the .netrc file; using defaults - [EXPERIMENTAL] + Closes https://github.com/curl/curl/pull/11904 - Closes #11627 +Dan Fandrich (23 Sep 2023) -- cmake: assume `wldap32` availability on Windows +- wolfssh: do cleanup in Curl_ssh_cleanup - This system library first shipped with Windows ME, available as an extra - install for some older releases (according to [1]). The import library - was present already in old MinGW 3.4.2 (year 2007). + Closes: #11921 - Drop the feature check and its associated `HAVE_WLDAP32` variable. +Daniel Stenberg (24 Sep 2023) - To manually disable `wldap32`, you can use the `USE_WIN32_LDAP=OFF` - CMake option, like before. +- tool_listhelp: regenerated - [1]: https://dlcdn.apache.org/httpd/binaries/win32/LEGACY.html + Polished the --ipfs-gateway description - Reviewed-by: Jay Satiro - Closes #11624 + Fixed the --trace-config description -Daniel Stenberg (9 Aug 2023) + The script also fixed some other small mistakes -- page-header: move up a URL paragraph from GLOBBING to URL + Closes #11923 -- variable.d: output the function names table style +Viktor Szakats (23 Sep 2023) - Also correct the url function name in the header +- Makefile.mk: always set `CURL_STATICLIB` for lib (Windows) - Closes #11641 + Also fix to export all symbols in Windows debug builds, making + `-debug-dyn` builds work with `-DCURL_STATICLIB` set. -- haproxy-clientip.d: remove backticks + Ref: https://github.com/curl/curl/pull/11914 (same for CMake) - This is not markdown + Closes #11924 - Follow-up to 0a75964d0d94a4 +Daniel Stenberg (23 Sep 2023) - Closes #11639 +- quic: set ciphers/curves the same way regular TLS does -- RELEASE-NOTES: synced + for OpenSSL/BoringSSL -- gen.pl: escape all dashes (ascii minus) to avoid unicode hyphens + Fixes #11796 + Reported-by: Karthikdasari0423 on github + Assisted-by: Jay Satiro + Closes #11836 - Reported-by: FC Stegerman - Fixes #11635 - Closes #11637 +- test457: verify --max-filesize with chunked encoding -- cmdline-opts/page-header: reorder, clean up +- lib: let the max filesize option stop too big transfers too - - removed some unnecessary blurb to focus - - moved up the more important URL details - - put "globbing" into its own subtitle and moved down a little - - mention the online man page in the version section + Previously it would only stop them from getting started if the size is + known to be too big then. - Closes #11638 + Update the libcurl and curl docs accordingly. -- c-hyper: adjust the hyper to curlcode conversion + Fixes #11810 + Reported-by: Elliot Killick + Assisted-by: Jay Satiro + Closes #11820 - Closes #11621 +Viktor Szakats (23 Sep 2023) -- test2306: make it use a persistent connection +- mingw: delete support for legacy mingw.org toolchain - + enable verbose already from the start + 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. - Closes #11621 + 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.) -eppesuig (8 Aug 2023) + Closes #11625 -- list-only.d: mention SFTP as supported protocol +Mark Gaiser (23 Sep 2023) - Closes #11628 +- curl: add support for the IPFS protocols: -Daniel Stenberg (8 Aug 2023) + - ipfs:// + - ipns:// -- request.d: use .TP for protocol "labels" + This allows you tu use ipfs in curl like: + curl ipfs:// + and + curl ipns:// - To render the section nicer in man page. + For more information consult the readme at: + https://curl.se/docs/ipfs.html - Closes #11630 + Closes #8805 -- cf-haproxy: make CURLOPT_HAPROXY_CLIENT_IP set the *source* IP +Daniel Stenberg (23 Sep 2023) - ... as documented. +- bufq: remove Curl_bufq_skip_and_shift (unused) - Update test 3201 and 3202 accordingly. + Closes #11915 - Reported-by: Markus Sommer - Fixes #11619 - Closes #11626 +- scripts/singleuse.pl: add curl_global_trace -- page-footer: QLOGDIR works with ngtcp2 and quiche +Viktor Szakats (22 Sep 2023) - It previously said "both" backends which is confusing as we currently - have three... +- cmake: fix unity symbol collisions in h2 builds - Closes #11631 + Regression from 331b89a319d0067fa1e6441719307cfef9c7960f -Stefan Eissing (8 Aug 2023) + Reviewed-by: Daniel Stenberg + Reviewed-by: Jay Satiro + Closes #11912 -- http3: quiche, handshake optimization, trace cleanup +Daniel Stenberg (22 Sep 2023) - - load x509 store after clienthello - - cleanup of tracing +- RELEASE-NOTES: synced - Closes #11618 +Dan Fandrich (21 Sep 2023) -Daniel Stenberg (8 Aug 2023) +- github/labeler: improve the match patterns -- ngtcp2: remove dead code + 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. - 'result' is always zero (CURLE_OK) at this point +Daniel Stenberg (21 Sep 2023) - Detected by Coverity +- upload-file.d: describe the file name slash/backslash handling - Closes #11622 + Closes #11911 -Viktor Szakats (8 Aug 2023) +Jakub Jelen (21 Sep 2023) -- openssl: auto-detect `SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED` +- libssh: cap SFTP packet size sent - OpenSSL 1.1.1 defines this macro, but no ealier version, or any of the - popular forks (yet). Use the macro itself to detect its presence, - replacing the hard-wired fork-specific conditions. + Due to libssh limitations - This way the feature will enable automatically when forks implement it, - while also shorter and possibly requiring less future maintenance. + Signed-off-by: Jakub Jelen - Follow-up to 94241a9e78397a2aaf89a213e6ada61e7de7ee02 #6721 + Closes #11804 - Reviewed-by: Jay Satiro - Closes #11617 +Daniel Stenberg (21 Sep 2023) -- openssl: use `SSL_CTX_set_ciphersuites` with LibreSSL 3.4.1 +- curl.h: mark CURLSSLBACKEND_NSS as deprecated since 8.3.0 - LibreSSL 3.4.1 (2021-10-14) added support for - `SSL_CTX_set_ciphersuites`. + Closes #11905 - Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.4.1-relnotes.txt +- mailmap: unify Michael Osipov under a single email - Reviewed-by: Jay Satiro - Closes #11616 +Ted Lyngmo (21 Sep 2023) -- openssl: use `SSL_CTX_set_keylog_callback` with LibreSSL 3.5.0 +- docs: use CURLSSLBACKEND_NONE - LibreSSL 3.5.0 (2022-02-24) added support for - `SSL_CTX_set_keylog_callback`. + [ssl] use CURLSSLBACKEND_NONE instead of (curl_sslbackend)-1 in + documentation and examples. - Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0-relnotes.txt + Signed-off-by: Ted Lyngmo - Reviewed-by: Jay Satiro - Closes #11615 + Closes #11909 -- cmake: drop `HAVE_LIBWINMM` and `HAVE_LIBWS2_32` feature checks +Dan Fandrich (21 Sep 2023) - - `HAVE_LIBWINMM` was detected but unused. The `winmm` system library is - also not used by curl, but it is by its optional dependency `librtmp`. - Change the logic to always add `winmm` when `USE_LIBRTMP` is set. This - library has been available since the early days of Windows. +- github/labeler: give the sync-labels config item a default value - - `HAVE_LIBWS2_32` detected `ws2_32` lib on Windows. This lib is present - since Windows 95 OSR2 (AFAIR). Winsock1 already wasn't supported and - other existing logic already assumed this lib being present, so delete - the check and replace the detection variable with `WIN32` and always - add `ws2_32` on Windows. + This shouldn't be necessary and is likely a bug with this beta version + of the labeller. - Closes #11612 + Also, fix the negative matches for the documentation label. -Daniel Gustafsson (8 Aug 2023) + Follow-up to dd12b452a + Closes #11907 -- crypto: ensure crypto initialization works +- github/labeler: fix up more the labeler config format - Make sure that context initialization during hash setup works to avoid - going forward with the risk of a null pointer dereference. + 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. - Reported-by: Philippe Antoine on HackerOne - Assisted-by: Jay Satiro - Assisted-by: Daniel Stenberg + Follow-up to dd12b452a + Closes #11906 - Closes #11614 +- github/labeler: fix indenting to try to appease labeller -Viktor Szakats (7 Aug 2023) + Follow-up to dd12b452a -- openssl: switch to modern init for LibreSSL 2.7.0+ +Jay Satiro (21 Sep 2023) - LibreSSL 2.7.0 (2018-03-21) introduced automatic initialization, - `OPENSSL_init_ssl()` function and deprecated the old, manual init - method, as seen in OpenSSL 1.1.0. Switch to the modern method when - available. +- libssh2: fix error message on failed pubkey-from-file - Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.7.0-relnotes.txt + - If libssh2_userauth_publickey_fromfile_ex returns -1 then show error + message "SSH public key authentication failed: Reason unknown (-1)". - Reviewed-by: Daniel Stenberg - Closes #11611 + 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. -Daniel Stenberg (7 Aug 2023) + 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. -- gskit: remove + Bug: https://github.com/curl/curl/issues/11837#issue-1891827355 + Reported-by: consulion@users.noreply.github.com - We remove support for building curl with gskit. + Closes https://github.com/curl/curl/pull/11881 - - This is a niche TLS library, only running on some IBM systems - - no regular curl contributors use this backend - - no CI builds use or verify this backend - - gskit, or the curl adaption for it, lacks many modern TLS features - making it an inferior solution - - build breakages in this code take weeks or more to get detected - - fixing gskit code is mostly done "flying blind" +Stefan Eissing (21 Sep 2023) - This removal has been advertized in DEPRECATED in Jan 2, 2023 and it has - been mentioned on the curl-library mailing list. +- pytest: exclude test_03_goaway in CI runs due to timing dependency - It could be brought back, this is not a ban. Given proper effort and - will, gskit support is welcome back into the curl TLS backend family. + Closes #11860 - Closes #11460 +- lib: disambiguate Curl_client_write flag semantics -- RELEASE-NOTES: synced + - 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 -Dan Fandrich (7 Aug 2023) + Closes #11885 -- THANKS-filter: add a name typo +Patrick Monnerat (21 Sep 2023) -Stefan Eissing (7 Aug 2023) +- tftpd: always use curl's own tftp.h -- http3/ngtcp2: shorten handshake, trace cleanup + Using the system's provided arpa/tftp.h and optimizing, GCC 12 detects + and reports a stringop-overread warning: - - shorten handshake timing by delayed x509 store load (OpenSSL) - as we do for HTTP/2 - - cleanup of trace output, align with HTTP/2 output + 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 */ + | ^~~~~~~ - Closes #11609 + 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. -Daniel Stenberg (7 Aug 2023) + This commit always uses curl's own version of tftp.h where the + target field is last in its structure, effectively avoiding the + warning. -- headers: accept leading whitespaces on first response header + As HAVE_ARPA_TFTP_H is not used anymore, cmake/configure checks for + arpa/tftp.h are removed. - This is a bad header fold but since the popular browsers accept this - violation, so does curl now. Unless built with hyper. + Closes #11897 - Add test 1473 to verify and adjust test 2306. +Dan Fandrich (20 Sep 2023) - Reported-by: junsik on github - Fixes #11605 - Closes #11607 +- test1474: make precheck more robust on non-Solaris systems -- include/curl/mprintf.h: add __attribute__ for the prototypes + If uname -r returns something odd, perl could return an error code and + the test would be erroneously skipped. The qx// syntax avoid this. - - if gcc or clang is used - - if __STDC_VERSION__ >= 199901L, which means greater than C90 - - if not using mingw - - if CURL_NO_FMT_CHECKS is not defined + Followup to 08f9b2148 - Closes #11589 +- github/labeler: switch to the 5 beta version -- tests: fix bad printf format flags in test code + 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. -- tests: fix header scan tools for attribute edits in mprintf.h +Daniel Stenberg (20 Sep 2023) -- cf-socket: log successful interface bind +- lib: enable hmac for digest as well - When the setsockopt SO_BINDTODEVICE operation succeeds, output that in - the verbose output. + 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. - Ref: #11599 - Closes #11608 + Follow-up to e92edfbef64448ef -- CURLOPT_SSL_VERIFYPEER.3: mention it does not load CA certs when disabled + Fixes #11890 + Reported-by: Aleksander Mazur + Closes #11896 - Ref: #11457 - Closes #11606 +- idn: if idn2_check_version returns NULL, return error -- CURLOPT_SSL_VERIFYPEER.3: add two more see also options + ... this avoids a NULL dereference for this unusual case. - CURLINFO_CAINFO and CURLINFO_CAPATH + Reported-by: s0urc3_ on hackerone + Closes #11898 - Closes #11603 +- http: fix CURL_DISABLE_BEARER_AUTH breakage -- KNOWN_BUGS: aws-sigv4 does not behave well with AWS VPC Lattice + When bearer auth was disabled, the if/else logic got wrong and caused + problems. - Closes #11007 + Follow-up to e92edfbef64448ef461 + Fixes #11892 + Reported-by: Aleksander Mazur + Closes #11895 -Graham Campbell (6 Aug 2023) +Michael Osipov (20 Sep 2023) -- CI: use openssl 3.0.10+quic, nghttp3 0.14.0, ngtcp2 0.18.0 +- wolfssl: allow capath with CURLOPT_CAINFO_BLOB - Closes #11585 + Remain consistent with OpenSSL. While CAfile is nulled as documented + with CURLOPT_CAINFO_BLOB, CApath remains intact. -Daniel Stenberg (6 Aug 2023) + Closes #11886 -- TODO: add *5* entries for aws-sigv4 +- wolfssl: use ssl_cafile/ssl_capath variables consistent with openssl.c - Closes #7559 - Closes #8107 - Closes #8810 - Closes #9717 - Closes #10129 + Closes #11886 -- TODO: LDAP Certificate-Based Authentication +Dan Fandrich (19 Sep 2023) - Closes #9641 +- test1474: disable test on NetBSD, OpenBSD and Solaris 10 -Stefan Eissing (6 Aug 2023) + 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. -- http2: cleanup trace messages + Assisted-by: Christian Weisgerber + Ref: https://curl.se/mail/lib-2023-09/0021.html + Closes #11888 - - more compact format with bracketed stream id - - all frames traced in and out +Ryan Schmidt (20 Sep 2023) - Closes #11592 +- cmake, configure: also link with CoreServices -Daniel Stenberg (6 Aug 2023) + 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. -- tests/tftpd+mqttd: make variables static to silence picky warnings + Fixes #11893 + Closes #11894 - Closes #11594 +Marc Hoersken (19 Sep 2023) -- docs/cmdline: remove repeated working for negotiate + ntlm +- CI/azure: remove pip, wheel, cryptography, pyopenssl and impacket - The extra wording is added automatically by the gen.pl tool + These dependencies are now already included in the Docker image. - Closes #11597 + Ref: https://github.com/mback2k/curl-docker-winbuildenv/commit/2607a31bcab544 + b41d15606e97f38cf312c1ce56 -- docs/cmdline: add small "warning" to verbose options + Closes #11889 - "Note that verbose output of curl activities and network traffic might - contain sensitive data, including user names, credentials or secret data - content. Be aware and be careful when sharing trace logs with others." +Daniel Stenberg (19 Sep 2023) - Closes #11596 +- wolfssl: if CURLOPT_CAINFO_BLOB is set, ignore the CA files + + Ref: #11883 + Reported-by: Michael Osipov + Closes #11884 - RELEASE-NOTES: synced -- pingpong: don't use *bump_headersize +- test3103: CURLOPT_COOKIELIST test - We use that for HTTP(S) only. +- cookie: set ->running in cookie_init even if data is NULL - Follow-up to 3ee79c1674fd6 + This is a regression introduced in b1b326ec500 (shipped in curl 8.1.0) - Closes #11590 + Test 3103 verifies. -- urldata: remove spurious parenthesis to unbreak no-proxy build + Fixes #11875 + Reported-by: wangp on github + Closes #11876 - Follow-up to e12b39e13382 +- test498: total header size for all redirects is larger than accepted - Closes #11591 +- http: use per-request counter to check too large headers -- easy: don't call Curl_trc_opt() in disabled-verbose builds + Not the counter that accumulates all headers over all redirects. - Follow-up to e12b39e133822c6a0 + Follow-up to 3ee79c1674fd6 - Closes #11588 + Do a second check for 20 times the limit for the accumulated size for + all headers. -- http: use %u for printfing int + Fixes #11871 + Reported-by: Joshix-1 on github + Closes #11872 - Follow-up to 3ee79c1674fd6f99e8efca5 +Jay Satiro (18 Sep 2023) - Closes #11587 +- THANKS: add Eric Murphy -Goro FUJI (3 Aug 2023) + He reported #11850 (quiche build error) but I forgot to add a + 'reported-by' entry in the fix 267e14f1. -- vquic: show stringified messages for errno +Daniel Stenberg (18 Sep 2023) - Closes #11584 +- h2-proxy: remove left-over mistake in drain_tunnel() -Stefan Eissing (3 Aug 2023) + Left-over from 331b89a319 -- trace: make tracing available in non-debug builds + Reported-by: 南宫雪珊 - Add --trace-config to curl + Closes https://github.com/curl/curl/pull/11877 - Add curl_global_trace() to libcurl +vvb2060 (18 Sep 2023) - Closes #11421 +- lib: failf/infof compiler warnings -Daniel Stenberg (3 Aug 2023) + Closes #11874 -- TODO: remove "Support intermediate & root pinning for PINNEDPUBLICKEY" +Daniel Stenberg (17 Sep 2023) - See also https://github.com/curl/curl/pull/7507 +- rand: fix 'alnum': array is too small to include a terminating null character -- TODO: add "WebSocket read callback" + 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 - remove "Upgrade to websockets" as we already have this +Mathias Fuchs (16 Sep 2023) - Closes #11402 +- cmake: fix the help text to the static build option in CMakeLists.txt -- test497: verify rejecting too large incoming headers + Closes #11843 -- http: return error when receiving too large header set +John Haugabook (16 Sep 2023) - To avoid abuse. The limit is set to 300 KB for the accumulated size of - all received HTTP headers for a single response. Incomplete research - suggests that Chrome uses a 256-300 KB limit, while Firefox allows up to - 1MB. +- MANUAL.md: change domain to example.com - Closes #11582 + Closes #11866 -Stefan Eissing (3 Aug 2023) +Daniel Stenberg (16 Sep 2023) -- http2: upgrade tests and add fix for non-existing stream +- doh: inherit DEBUGFUNCTION/DATA - - check in h2 filter recv that stream actually exists - and return error if not - - add test for parallel, extreme h2 upgrades that fail if - connections get reused before fully switched - - add h2 upgrade upload test just for completeness + 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. - Closes #11563 + Reported-by: calvin2021y on github + Fixes #11864 + Closes #11869 -Viktor Szakats (3 Aug 2023) +Dan Fandrich (16 Sep 2023) -- tests: ensure `libcurl.def` contains all exports +- http_aws_sigv4: fix sorting with empty parts - Add `test1279` to verify that `libcurl.def` lists all exported API - functions found in libcurl headers. + 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. - Also: + Fixes #11855 + Closes #11868 - - extend test suite XML `stdout` tag with the `loadfile` attribute. +- CI: ignore the "flaky" and "timing-dependent" test results - - fix `tests/extern-scan.pl` and `test1135` to include websocket API. + 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. - - use all headers (sorted) in `test1135` instead of a manual list. + This change only adds two additional tests to be ignored, since the + others already had the flaky keyword. - - add options `--sort`, `--heading=` to `tests/extern-scan.pl`. + Closes #11865 - - add `libcurl.def` to the auto-labeler GHA task. +- runtests: eliminate a warning on old perl versions - Follow-up to 2ebc74c36a19a1700af394c16855ce144d9878e3 + The warning "Use of implicit split to @_ is deprecated" showed between + perl versions about 5.8 through 5.11. - Closes #11570 +- tests: log the test result code after each libtest -Daniel Stenberg (2 Aug 2023) + This makes it easier to determine the test status. Also, capitalize + FAILURE and ABORT messages in log lines to make them easier to spot. -- url: change default value for CURLOPT_MAXREDIRS to 30 +Harry Sintonen (16 Sep 2023) - It was previously unlimited by default, but that's not a sensible - default. While changing this has a remote risk of breaking an existing - use case, I figure it is more likely to actually save users from loops. +- misc: better random strings - Closes #11581 + Generate alphanumerical random strings. -- lib: fix a few *printf() flag mistakes + 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. - Reported-by: Gisle Vanem - Ref: #11574 - Closes #11579 + 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. -Samuel Chiang (2 Aug 2023) + Closes #11838 -- openssl: make aws-lc version support OCSP +Daniel Stenberg (15 Sep 2023) - And bump version in CI +- cookie: reduce variable scope, add const - Closes #11568 +- cookie: do not store the expire or max-age strings -Daniel Stenberg (2 Aug 2023) + Convert it to an expire time at once and save memory. -- tool: make the length argument an int for printf()-.* flags + Closes #11862 - Closes #11578 +- cookie: remove unnecessary struct fields -- tool_operate: fix memory leak when SSL_CERT_DIR is used + 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. - Detected by Coverity + Closes #11862 - Follow-up to 29bce9857a12b6cfa726a5 +- RELEASE-NOTES: synced - Closes #11577 + Bumped to 8.4.0, the next presumed version -- tool/var: free memory on OOM +Dan Fandrich (14 Sep 2023) - Coverity detected this memory leak in OOM situation +- test2600: remove special case handling for USE_ALARM_TIMEOUT - Follow-up to 2e160c9c652504e + 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. - Closes #11575 + The need for this special-case was removed in commit 8627416, which + increased the connect timeout in all cases to well above 1 second. -Viktor Szakats (2 Aug 2023) + Fixes #11767 + Closes #11849 -- gha: bump libressl and mbedtls versions +Daniel Stenberg (14 Sep 2023) - Closes #11573 +- SECURITY-PROCESS.md. call it vulnerability disclosure policy -Jay Satiro (2 Aug 2023) + SECURITY-PROCESS.md -> VULN-DISCLOSURE-POLICY.md -- schannel: fix user-set legacy algorithms in Windows 10 & 11 + This a name commonly used for a document like this. This name helps + users find it. - - If the user set a legacy algorithm list (CURLOPT_SSL_CIPHER_LIST) then - use the SCHANNEL_CRED legacy structure to pass the list to Schannel. + Closes #11852 - - If the user set both a legacy algorithm list and a TLS 1.3 cipher list - then abort. +Junho Choi (14 Sep 2023) - Although MS doesn't document it, Schannel will not negotiate TLS 1.3 - when SCHANNEL_CRED is used. That means setting a legacy algorithm list - limits the user to earlier versions of TLS. +- quiche: fix build error with --with-ca-fallback - Prior to this change, since 8beff435 (precedes 7.85.0), libcurl would - ignore legacy algorithms in Windows 10 1809 and later. + - Fix build error when curl is built with --with-quiche + and --with-ca-fallback. - Reported-by: zhihaoy@users.noreply.github.com + - Add --with-ca-fallback to the quiche CI job. - Fixes https://github.com/curl/curl/pull/10741 - Closes https://github.com/curl/curl/pull/10746 + Fixes https://github.com/curl/curl/issues/11850 + Closes https://github.com/curl/curl/pull/11847 -Daniel Stenberg (2 Aug 2023) +Jay Satiro (14 Sep 2023) -- variable.d: setting a variable again overwrites it +- escape: replace Curl_isunreserved with ISUNRESERVED - Reported-by: Niall McGee - Bug: https://twitter.com/niallmcgee/status/1686523075423322113 - Closes #11571 + - Use the ALLCAPS version of the macro so that it is clear a macro is + being called that evaluates the variable multiple times. -Jay Satiro (2 Aug 2023) + - Also capitalize macro isurlpuntcs => ISURLPUNTCS since it evaluates + a variable multiple times. -- CURLOPT_PROXY_SSL_OPTIONS.3: sync formatting + 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. - - Re-wrap CURLSSLOPT_ALLOW_BEAST description. + For example, ISUNRESERVED(*foo++) is easily identifiable as wrong but + Curl_isunreserved(*foo++) is not even though they both are the same. -Daniel Stenberg (2 Aug 2023) + Closes https://github.com/curl/curl/pull/11846 -- RELEASE-NOTES: synced +Dan Fandrich (13 Sep 2023) -- resolve: use PF_INET6 family lookups when CURL_IPRESOLVE_V6 is set +- tests: increase the default server logs lock timeout - Previously it would always do PF_UNSPEC if CURL_IPRESOLVE_V4 is not - used, thus unnecessarily asking for addresses that will not be used. + 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. - Reported-by: Joseph Tharayil - Fixes #11564 - Closes #11565 + Ref: #11328 + Closes #11834 -- docs: link to the website versions instead of markdowns +- tests: increase TEST_HANG_TIMEOUT in two tests - ... to make the links work when the markdown is converted to webpages on - https://curl.se + 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. - Reported-by: Maurício Meneghini Fauth - Fixes https://github.com/curl/curl-www/issues/272 - Closes #11569 + Ref: #11328 -Viktor Szakats (1 Aug 2023) +- test1056: disable on Windows -- cmake: cache more config and delete unused ones + 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. - - cache more Windows config results for faster initialization. +- test587: add a slight delay after test - - delete unused config macros `HAVE_SYS_UTSNAME_H`, `HAVE_SSL_H`. + 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. - - delete dead references to `sys/utsname.h`. + Ref: #11328 - Closes #11551 +- tests: stop overriding the lock timeout -- egd: delete feature detection and related source code + 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. - EGD is Entropy Gathering Daemon, a socket-based entropy source supported - by pre-OpenSSL v1.1 versions and now deprecated. curl also deprecated it - a while ago. + Ref: #11328 - Its detection in CMake was broken all along because OpenSSL libs were - not linked at the point of feature check. +- tests: add some --expect100-timeout to reduce timing dependencies - Delete detection from both cmake and autotools, along with the related - source snippet, and the `--with-egd-socket=` `./configure` option. + 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. - Closes #11556 + Ref: #11328 -Stefan Eissing (1 Aug 2023) +- test661: return from test early in case of curl error -- tests: fix h3 server check and parallel instances +- tests: add the timing-dependent keyword on several tests - - fix check for availability of nghttpx server - - add `tcp` frontend config for same port as quic, as - without this, port 3000 is bound which clashes for parallel - testing + 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. - Closes #11553 +- test1592: greatly increase the maximum test timeout -Daniel Stenberg (1 Aug 2023) + 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. -- docs/cmdline-opts: spellfixes, typos and polish + Ref: #11328 - To make them accepted by the spell checker +- test: minor test cleanups - Closes #11562 + Remove an obsolete block of code in tests 2032 & 576. + Add a comment in test 1474. -- CI/spellcheck: build curl.1 and spellcheck it +- tests: quadruple the %FTPTIME2 and %FTPTIME3 timeouts - Added acceptable words + This gives more of a margin for error when running on overloaded CI + servers. - Closes #11562 + Ref: #11328 -Alexander Jaeger (1 Aug 2023) +- tests: improve SLOWDOWN test reliability by reducing sent data -- misc: fix various typos + 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. - Closes #11561 + Ref: #11328 -Daniel Stenberg (1 Aug 2023) +- test650: fix an end tag typo -- http2: avoid too early connection re-use/multiplexing +Jay Satiro (13 Sep 2023) - HTTP/1 connections that are upgraded to HTTP/2 should not be picked up - for reuse and multiplexing by other handles until the 101 switching - process is completed. +- tool_cb_wrt: fix debug assertion - Lots-of-debgging-by: Stefan Eissing - Reported-by: Richard W.M. Jones - Bug: https://curl.se/mail/lib-2023-07/0045.html - Closes #11557 + - Fix off-by-one out-of-bounds array index in Windows debug assertion. -- Revert "KNOWN_BUGS: build for iOS simulator on macOS 13.2 with Xcode 14" + Bug: https://github.com/curl/curl/commit/af3f4e41#r127212213 + Reported-by: Gisle Vanem - This reverts commit 2e8a3d7cb73c85a9aa151e263315f8a496dbb9d4. +Daniel Stenberg (13 Sep 2023) - It's a user error for supplying incomplete information to the build system. +- ctype: add ISUNRESERVED() - Reported-by: Ryan Schmidt - Ref: https://github.com/curl/curl/issues/11215#issuecomment-1658729367 + ... and make Curl_isunreserved() use that macro instead of providing a + separate funtion for the purpose. -Viktor Szakats (1 Aug 2023) + Closes #11840 -- cmake: add support for single libcurl compilation pass +Version 8.3.0 (13 Sep 2023) - Before this patch CMake builds used two separate compilation passes to - build the shared and static libcurl respectively. This patch allows to - reduce that to a single pass if the target platform and build settings - allow it. +Daniel Stenberg (13 Sep 2023) - This reduces CMake build times when building both static and shared - libcurl at the same time, making these dual builds an almost zero-cost - option. +- RELEASE-NOTES: syn ced - Enable this feature for Windows builds, where the difference between the - two passes was the use of `__declspec(dllexport)` attribute for exported - API functions for the shared builds. This patch replaces this method - with the use of `libcurl.def` at DLL link time. + curl 8.3.0 release - Also update `Makefile.mk` to use `libcurl.def` to export libcurl API - symbols on Windows. This simplifies (or fixes) this build method (e.g. - in curl-for-win, which generated a `libcurl.def` from `.h` files using - an elaborate set of transformations). +- THANKS: contributors from 8.3.0 - `libcurl.def` has the maintenance cost of keeping the list of public - libcurl API symbols up-to-date. This list seldom changes, so the cost - is low. +Thorsten Klein (12 Sep 2023) - Closes #11546 +- cmake: set SIZEOF_LONG_LONG in curl_config.h -- cmake: detect `SSL_set0_wbio` in OpenSSL + in order to support 32bit builds regarding wolfssl CTC_SETTINGS - Present in OpenSSL 1.1.0 and BoringSSL. - Missing from LibreSSL 3.8.0. + Closes #11839 - Follow-up to f39472ea9f4f4e12cfbc0500c4580a8d52ce4a59 +Jay Satiro (12 Sep 2023) - While here, also fix `RAND_egd()` detection which was broken, likely all - along. This feature is probably broken with CMake builds and also - requires a sufficiently obsolete OpenSSL version, so this part of the - update was not tested. +- curl_ngtcp2: fix error message - Closes #11555 +- http_aws_sigv4: handle no-value user header entries -- cmake: fixup H2 duplicate symbols for unity builds + - Handle user headers in format 'name:' and 'name;' with no value. - Closes #11550 + 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). -Pablo Busse (1 Aug 2023) + Prior to this change the AWS header import code did not special case + either of those and the generated AWS SignedHeaders would be incorrect. -- openssl: Support async cert verify callback + Reported-by: apparentorder@users.noreply.github.com - - Update the OpenSSL connect state machine to handle - SSL_ERROR_WANT_RETRY_VERIFY. + Ref: https://curl.se/docs/manpage.html#-H - This allows libcurl users that are using custom certificate validation - to suspend processing while waiting for external I/O during certificate - validation. + Fixes https://github.com/curl/curl/issues/11664 + Closes https://github.com/curl/curl/pull/11668 - Closes https://github.com/curl/curl/pull/11499 +Dan Fandrich (11 Sep 2023) -Jay Satiro (1 Aug 2023) +- CI: run pytest with the -v option -- tool_cb_wrt: fix invalid unicode for windows console + This lists of the test cases being run so it can be tracked over time. - - Suppress an incomplete UTF-8 sequence at the end of the buffer. + Closes #11824 - - Attempt to reconstruct incomplete UTF-8 sequence from prior call(s) - in current call. +Daniel Stenberg (11 Sep 2023) - Prior to this change, in Windows console UTF-8 sequences split between - two or more calls to the write callback would cause invalid "replacement - characters" U+FFFD to be printed instead of the actual Unicode - character. This is because in Windows only UTF-16 encoded characters are - printed to the console, therefore we convert the UTF-8 contents to - UTF-16, which cannot be done with partial UTF-8 sequences. +- HTTP3: the msquic backend is not functional - Reported-by: Maksim Arhipov + I ask that we do not submit bugs for this backend just yet as we know it + does not fully work. - Fixes https://github.com/curl/curl/issues/9841 - Closes https://github.com/curl/curl/pull/10890 + Closes #11831 + Closes #11819 -Daniel Stenberg (1 Aug 2023) +- aws_sigv4: the query canon code miscounted URL encoded input -- sectransp: prevent CFRelease() of NULL + Added some extra ampersands to test 439 to verify "blank" query parts - When SecCertificateCopyCommonName() returns NULL, the common_name - pointer remains set to NULL which apparently when calling CFRelease() on - (sometimes?) crashes. + Follow-up to fc76a24c53b08cdf - Reported-by: Guillaume Algis - Fixes #9194 - Closes #11554 + Closes #11829 -Jay Satiro (1 Aug 2023) +vvb2060 (11 Sep 2023) -- vtls: clarify "ALPN: offers" message +- quic: don't set SNI if hostname is an IP address - Before: - * ALPN: offers h2,http/1.1 + We already do this for TLS connections. - After: - * ALPN: curl offers h2,http/1.1 + RFC 6066 says: Literal IPv4 and IPv6 addresses are not permitted in + "HostName". - Bug: https://curl.se/mail/lib-2023-07/0041.html - Reported-by: Richard W.M. Jones - Closes #11544 + Ref: https://www.rfc-editor.org/rfc/rfc6066#section-3 -Daniel Stenberg (1 Aug 2023) + Fixes https://github.com/curl/curl/issues/11827 + Closes https://github.com/curl/curl/pull/11828 -- urlapi: make sure zoneid is also duplicated in curl_url_dup +Daniel Stenberg (10 Sep 2023) - Add several curl_url_dup() tests to the general lib1560 test. +- RELEASE-NOTES: synced - Reported-by: Rutger Broekhoff - Bug: https://curl.se/mail/lib-2023-07/0047.html - Closes #11549 +Benoit Pierre (10 Sep 2023) -Sergey (1 Aug 2023) +- configure: fix `HAVE_TIME_T_UNSIGNED` check -- urlapi: fix heap buffer overflow + The syntax was incorrect (need a proper main body), and the test + condition was wrong (resulting in a signed `time_t` detected as + unsigned). - `u->path = Curl_memdup(path, pathlen + 1);` accesses bytes after the null-ter - minator. + Closes #11825 - ``` - ==2676==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x04d48c75 a - t pc 0x0112708a bp 0x006fb7e0 sp 0x006fb3c4 - READ of size 78 at 0x04d48c75 thread T0 - #0 0x1127089 in __asan_wrap_memcpy D:\a\_work\1\s\src\vctools\asan\llvm\c - ompiler-rt\lib\sanitizer_common\sanitizer_common_interceptors.inc:840 - #1 0x1891a0e in Curl_memdup C:\actions-runner\_work\client\client\third_p - arty\curl\lib\strdup.c:97 - #2 0x18db4b0 in parseurl C:\actions-runner\_work\client\client\third_part - y\curl\lib\urlapi.c:1297 - #3 0x18db819 in parseurl_and_replace C:\actions-runner\_work\client\clien - t\third_party\curl\lib\urlapi.c:1342 - #4 0x18d6e39 in curl_url_set C:\actions-runner\_work\client\client\third_ - party\curl\lib\urlapi.c:1790 - #5 0x1877d3e in parseurlandfillconn C:\actions-runner\_work\client\client - \third_party\curl\lib\url.c:1768 - #6 0x1871acf in create_conn C:\actions-runner\_work\client\client\third_p - arty\curl\lib\url.c:3403 - #7 0x186d8dc in Curl_connect C:\actions-runner\_work\client\client\third_ - party\curl\lib\url.c:3888 - #8 0x1856b78 in multi_runsingle C:\actions-runner\_work\client\client\thi - rd_party\curl\lib\multi.c:1982 - #9 0x18531e3 in curl_multi_perform C:\actions-runner\_work\client\client\ - third_party\curl\lib\multi.c:2756 - ``` +Daniel Stenberg (9 Sep 2023) - Closes #11560 +- THANKS-filter: pszlazak on github -Daniel Stenberg (31 Jul 2023) +pszlazak (9 Sep 2023) -- curl: make %output{} in -w specify a file to write to +- include.d: explain headers not printed with --fail before 7.75.0 - It can be used multiple times. Use %output{>>name} to append. + Prior to 7.75.0 response headers were not printed if -f/--fail was used + and an error was reported by server. This was fixed in ab525c0 + (precedes 7.75.0). - Add docs. Test 990 and 991 verify. + Closes #11822 - Idea: #11400 - Suggested-by: ed0d2b2ce19451f2 - Closes #11416 +Daniel Stenberg (8 Sep 2023) -- RELEASE-NOTES: synced +- http_aws_sigv4: skip the op if the query pair is zero bytes -- tool: add "variable" support + Follow-up to fc76a24c53b08cdf - Add support for command line variables. Set variables with --variable - name=content or --variable name@file (where "file" can be stdin if set - to a single dash (-)). + Spotted by OSS-Fuzz - Variable content is expanded in option parameters using "{{name}}" - (without the quotes) if the option name is prefixed with - "--expand-". This gets the contents of the variable "name" inserted, or - a blank if the name does not exist as a variable. Insert "{{" verbatim - in the string by prefixing it with a backslash, like "\\{{". + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=62175 + Closes #11823 - Import an environment variable with --variable %name. It makes curl exit - with an error if the environment variable is not set. It can also rather - get a default value if the variable does not exist, using =content or - @file like shown above. +- cmdline-docs: use present tense, not future - Example: get the USER environment variable into the URL: + + some smaller cleanups - --variable %USER - --expand-url = "https://example.com/api/{{USER}}/method" + Closes #11821 - When expanding variables, curl supports a set of functions that can make - the variable contents more convenient to use. It can trim leading and - trailing white space with "trim", output the contents as a JSON quoted - string with "json", URL encode it with "url" and base 64 encode it with - "b64". To apply functions to a variable expansion, add them colon - separated to the right side of the variable. They are then performed in - a left to right order. +- cmdline-docs: make sure to phrase it as "added in ...." - Example: get the contents of a file called $HOME/.secret into a variable - called "fix". Make sure that the content is trimmed and percent-encoded - sent as POST data: + References to things that were added or changed in a specific version + should be specified as "(added in [version]) for two reasons: - --variable %HOME=/home/default - --expand-variable fix@{{HOME}}/.secret - --expand-data "{{fix:trim:url}}" - https://example.com/ + 1 - consistency - Documented. Many new test cases. + 2 - to allow gen.pl to strip them out if deemed referring to too old + versions - Co-brainstormed-by: Emanuele Torre - Assisted-by: Jat Satiro - Closes #11346 + Closes #11821 -- KNOWN_BUGS: cygwin: make install installs curl-config.1 twice +Jay Satiro (8 Sep 2023) - Closes #8839 +- docs: mark --ssl-revoke-best-effort as Schannel specific -- KNOWN_BUGS: build for iOS simulator on macOS 13.2 with Xcode 14 + Closes https://github.com/curl/curl/pull/11760 - Closes #11215 +Nathan Moinvaziri (8 Sep 2023) -- KNOWN_BUGS: cmake outputs: no version information available +- schannel: fix ordering of cert chain info - Closes #11158 + - Use CERT_CONTEXT's pbCertEncoded to determine chain order. -- KNOWN_BUGS: APOP authentication fails on POP3 + CERT_CONTEXT from SECPKG_ATTR_REMOTE_CERT_CONTEXT contains + end-entity/server certificate in pbCertEncoded. We can use this pointer + to determine the order of certificates when enumerating hCertStore using + CertEnumCertificatesInStore. - Closes #10073 + This change is to help ensure that the ordering of the certificate chain + requested by the user via CURLINFO_CERTINFO has the same ordering on all + versions of Windows. -- KNOWN_BUGS: hyper is slow + Prior to this change Schannel certificate order was reversed in 8986df80 + but that was later reverted in f540a39b when it was discovered that + Windows 11 22H2 does the reversal on its own. - Closes #11203 + Ref: https://github.com/curl/curl/issues/9706 -Patrick Monnerat (31 Jul 2023) + Closes https://github.com/curl/curl/pull/11632 -- configure, cmake, lib: more form api deprecation +Chris Talbot (8 Sep 2023) - Introduce a --enable-form-api configure option to control its inclusion - in builds. The condition name defined for it is CURL_DISABLE_FORM_API. +- digest: Use hostname to generate spn instead of realm - Form api code is dependent of MIME: configure and CMake handle this - dependency automatically: CMake by making it a dependent option - explicitly, configure by inheriting the MIME value by default and - rejecting explicit incompatible values. + In https://www.rfc-editor.org/rfc/rfc2831#section-2.1.2 - "form-api" is now a new hidden test feature. + digest-uri-value should be serv-type "/" host , where host is: - Update libcurl modules to respect this option and adjust tests - accordingly. + The DNS host name or IP address for the service requested. The + DNS host name must be the fully-qualified canonical name of the + host. The DNS host name is the preferred form; see notes on server + processing of the digest-uri. - Closes #9621 + Realm may not be the host, so we must specify the host explicitly. -Daniel Stenberg (31 Jul 2023) + Note this change only affects the non-SSPI digest code. The digest code + used by SSPI builds already uses the hostname to generate the spn. -- mailmap: add Derzsi Dániel + Ref: https://github.com/curl/curl/issues/11369 -Derzsi Dániel (31 Jul 2023) + Closes https://github.com/curl/curl/pull/11395 -- wolfssl: support loading system CA certificates +Daniel Stenberg (7 Sep 2023) - Closes #11452 +- docs: remove use of the word 'very' -Viktor Szakats (30 Jul 2023) + It is mostly superfluous. proselint would complain. -- nss: delete more NSS references + Closes #11818 - Fix the distcheck CI failure and delete more NSS references. +- curl_multi_remove_handle.3: clarify what happens with connection - Follow-up to 7c8bae0d9c9b2dfeeb008b9a316117d7b9675175 + Closes #11817 - Reviewed-by: Marcel Raad - Reviewed-by: Daniel Stenberg - Closes #11548 +- RELEASE-NOTES: synced -Daniel Stenberg (29 Jul 2023) +- test439: verify query canonization for aws-sigv4 -- nss: remove support for this TLS library +- tool_operate: make aws-sigv4 not require TLS to be used - Closes #11459 + Maybe not used too often, but we want it for testing and it should work. -Ryan Schmidt (29 Jul 2023) +- http_aws_sigv4: canonicalize the query -- macOS: fix target detection more + Percent encoding needs to be done using uppercase, and most + non-alphanumerical must be percent-encoded. - Now SCDynamicStoreCopyProxies is called (and the required frameworks are - linked in) on all versions of macOS and only on macOS. Fixes crash due - to undefined symbol when built with the macOS 10.11 SDK or earlier. + Fixes #11794 + Reported-by: John Walker + Closes #11806 - CURL_OSX_CALL_COPYPROXIES is renamed to CURL_MACOS_CALL_COPYPROXIES and - is now only defined when SCDynamicStoreCopyProxies will actually be - called. Previously, it was defined when ENABLE_IPV6 was not defined but - SCDynamicStoreCopyProxies is not called in that case. +Wyatt O'Day (7 Sep 2023) - TARGET_OS_OSX is only defined in the macOS 10.12 SDK and later and only - when dynamic targets are enabled. TARGET_OS_MAC is always defined but - means any Mac OS or derivative including macOS, iOS, tvOS, and watchOS. - TARGET_OS_IPHONE means any Darwin OS other than macOS. +- lib: add ability to disable auths individually - Follow-up to c73b2f82 + Both with configure and cmake - Fixes #11502 - Closes #11516 + Closes #11490 -Daniel Stenberg (29 Jul 2023) +Stefan Eissing (7 Sep 2023) -- tool_operate: allow SSL_CERT_FILE and SSL_CERT_DIR +- ngtcp2: fix handling of large requests - ... used at once. + - requests >64K are send in parts to the filter + - fix parsing of the request to assemble it correctly + from several sends + - open a QUIC stream only when the complete request has + been collected - Reported-by: Gabriel Corona - Fixes #11325 - Closes #11531 + Closes #11815 -Thomas M. DuBuisson (29 Jul 2023) +- openssl: when CURLOPT_SSL_CTX_FUNCTION is registered, init x509 store before -- CI: remove Lift's configuration + - we delay loading the x509 store to shorten the handshake time. + However an application callback installed via CURLOPT_SSL_CTX_FUNCTION + may need to have the store loaded and try to manipulate it. + - load the x509 store before invoking the app callback - The Lift tool is being retired. Their site reads: + Fixes #11800 + Reported-by: guoxinvmware on github + Cloes #11805 - "Sonatype Lift will be retiring on Sep 12, 2023, with its analysis - stopping on Aug 12, 2023." +Daniel Stenberg (7 Sep 2023) - Closes #11541 +- krb5: fix "implicit conversion loses integer precision" warnings -Nathan Moinvaziri (29 Jul 2023) + conversions to/from enum and unsigned chars -- Revert "schannel: reverse the order of certinfo insertions" + Closes #11814 - This reverts commit 8986df802db9b5338d9d50a54232ebae4dbcf6dd. +Stefan Eissing (7 Sep 2023) - Windows does not guarantee a particular certificate ordering, even - though TLS may have its own ordering/relationship guarantees. Recent - versions of Windows 11 reversed the ordering of ceritifcates returned by - CertEnumCertificatesInStore, therefore this commit no longer works as - initially intended. libcurl makes no guarantees about certificate - ordering if the operating system can't. +- pytest: improvements - Ref: https://github.com/curl/curl/issues/9706 + - set CURL_CI for pytest runs in CI environments + - exclude timing sensitive tests from CI runs + - for failed results, list only the log and stat of + the failed transfer - Closes https://github.com/curl/curl/pull/11536 + - fix type in http.c comment -wangzhikun (29 Jul 2023) + Closes #11812 -- winbuild: improve check for static zlib +- CI: move on to ngtcp2 v0.19.1 - - Check for zlib static library name zlibstatic.lib. + Closes #11809 - zlib's static library has a different name depending on how it was - built. zlibstatic.lib is output by cmake. zlibstat.lib is output by - their pre-generated Visual Studio project files (in the contrib - directory) and defines ZLIB_WINAPI (ie it's meant to use stdcall - instead of cdecl if you end up exporting the zlib functions). +Dan Fandrich (5 Sep 2023) - Prior to this change the makefile only checked for the latter. +- CI: run Circle macOS builds on x86 for now - Closes https://github.com/curl/curl/pull/11521 + The ARM machines aren't ready for us and requesting them now causes + warnings e-mails to be sent to some PR pushers. -Daniel Stenberg (29 Jul 2023) + Ref: #11771 -- configure: use the pkg-config --libs-only-l flag for libssh2 +Viktor Szakats (5 Sep 2023) - ... instead of --libs, as that one also returns -L flags. +- http3: adjust cast for ngtcp2 v0.19.0 - Reported-by: Wilhelm von Thiele - Fixes #11538 - Closes #11539 + ngtcp2 v0.19.0 made size of `ecn` member of `ngtcp2_pkt_info` + an `uint8_t` (was: `uint32_t`). Adjust our local cast accordingly. -Viktor Szakats (29 Jul 2023) + Fixes: + ``` + ./curl/lib/vquic/curl_ngtcp2.c:1912:12: warning: implicit conversion loses in + teger precision: 'uint32_t' (aka 'unsigned int') to 'uint8_t' (aka 'unsigned + char') [-Wimplicit-int-conversion] + pi.ecn = (uint32_t)ecn; + ~ ^~~~~~~~~~~~~ + ``` -- cmake: support building static and shared libcurl in one go + Also bump ngtcp2, nghttp3 and nghttp2 to their latest versions in our + docs and CI. - This patch adds the ability to build a static and shared libcurl library - in a single build session. It also adds an option to select which one to - use when building the curl executable. + Ref: https://github.com/ngtcp2/ngtcp2/commit/80447281bbc94af53f8aa7a4cfc19175 + 782894a3 + Ref: https://github.com/ngtcp2/ngtcp2/pull/877 + Closes #11798 - New build options: - - `BUILD_STATIC_LIBS`. Default: `OFF`. - Enabled automatically if `BUILD_SHARED_LIBS` is `OFF`. - - `BUILD_STATIC_CURL`. Default: `OFF`. - Requires `BUILD_STATIC_LIBS` enabled. - Enabled automatically if building static libcurl only. - - `STATIC_LIB_SUFFIX`. Default: empty. - - `IMPORT_LIB_SUFFIX`. Default: `_imp` if implib filename would collide - with static lib name (typically with MSVC) in Windows builds. - Otherwise empty. +Stefan Eissing (5 Sep 2023) - Also: +- http: fix sending of large requests - - Stop setting the `CURL_STATICLIB` macro via `curl_config.h`, and pass - it directly to the compiler. This also allows to delete a condition - from `tests/server/CMakeLists.txt`. + - refs #11342 where errors with git https interactions + were observed + - problem was caused by 1st sends of size larger than 64KB + which resulted in later retries of 64KB only + - limit sending of 1st block to 64KB + - adjust h2/h3 filters to cope with parsing the HTTP/1.1 + formatted request in chunks - - Complete a TODO by following the logic used in autotools (also for - `LIBCURL_NO_SHARED`), and set `-DCURL_STATICLIB` in `Cflags:` of - `libcurl.pc` for _static-only_ curl builds. + - introducing Curl_nwrite() as companion to Curl_write() + for the many cases where the sockindex is already known - - Convert an existing CI test to build both shared and static libcurl. + Fixes #11342 (again) + Closes #11803 - Closes #11505 +- pytest: fix check for slow_network skips to only apply when intended -Stefan Eissing (28 Jul 2023) + Closes #11801 -- CI/awslc: add cache for build awslc library +Daniel Stenberg (5 Sep 2023) - Closes #11535 +- curl_url_get/set.3: add missing semicolon in SYNOPSIS -- GHA/linux.yml: add caching +- CURLOPT_URL.3: explain curl_url_set() uses the same parser - Closes #11532 +- CURLOPT_URL.3: add two URL API calls in the see-also section -Daniel Stenberg (27 Jul 2023) +Dan Fandrich (4 Sep 2023) -- RELEASE-NOTES: synced +- CI: add a 32-bit i686 Linux build - Bump working version to 8.3.0 + This is done by cross-compiling under regular x86_64 Linux. Since the + kernel offers backwards compatibility, the binaries can be tested as + normal. -- url: remove infof() output for "still name resolving" + Closes #11799 - The message does not help and might get spewed a lot during times. +- tests: fix a type warning on 32-bit x86 - Reported-by: yushicheng7788 on github - Fixes #11394 - Closes #11529 +Viktor Szakats (4 Sep 2023) -- KNOWN_BUGS: cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!" +- tests: delete stray `.orig` file - Closes #11244 + Follow-up to 331b89a319d0067fa1e6441719307cfef9c7960f + Closes #11797 -Stefan Eissing (27 Jul 2023) +Daniel Stenberg (4 Sep 2023) -- CI: quiche updates +- RELEASE-NOTES: synced - - remove quiche from standard `linux` workflow - - add mod_h2 caching to quiche workflow - - rename quiche to quiche-linux - - move version definitions into env section +Viktor Szakats (4 Sep 2023) - Closes #11528 +- lib: silence compiler warning in inet_ntop6 -- http2: disable asssertion blocking OSSFuzz testing + ``` + ./curl/lib/inet_ntop.c:121:21: warning: possible misuse of comma operator her + e [-Wcomma] + cur.base = i, cur.len = 1; + ^ + ./curl/lib/inet_ntop.c:121:9: note: cast expression to void to silence warnin + g + cur.base = i, cur.len = 1; + ^~~~~~~~~~~~ + (void)( ) + ``` - - not clear how this triggers and it blocks OSSFuzz testing other - things. Since we handle the case with an error return, disabling the - assertion for now seems the best way forward. + Closes #11790 - Fixes #11500 - Closes #11519 +Daniel Stenberg (4 Sep 2023) -- http2: fix in h2 proxy tunnel: progress in ingress on sending +- transfer: also stop the sending on closed connection - - depending on what is tunneled, the proxy may never get invoked for - receiving data explicitly. Not progressing ingress may lead to stalls - due to missed WINDOW_UPDATEs. + Previously this cleared the receiving bit only but in some cases it is + also still sending (like a request-body) when disconnected and neither + direction can continue then. - CI: - - add a chache for building mod_h2 + Fixes #11769 + Reported-by: Oleg Jukovec + Closes #11795 - Closes #11527 +John Bampton (4 Sep 2023) -- CI ngtcp2+quictls: use nghttpx cache as in quiche build +- docs: change `sub-domain` to `subdomain` -Jay Satiro (27 Jul 2023) + https://en.wikipedia.org/wiki/Subdomain -- bearssl: don't load CA certs when peer verification is disabled + Closes #11793 - We already do this for other SSL backends. +Stefan Eissing (4 Sep 2023) - Bug: https://github.com/curl/curl/pull/11457#issuecomment-1644587473 - Reported-by: kyled-dell@users.noreply.github.com +- multi: more efficient pollfd count for poll - Closes https://github.com/curl/curl/pull/11497 + - do not use separate pollfds for sockets that have POLLIN+POLLOUT -Daniel Stenberg (26 Jul 2023) + Closes #11792 -- easy: remove #ifdefs to make code easier on the eye +- http2: polish things around POST - Closes #11525 + - added test cases for various code paths + - fixed handling of blocked write when stream had + been closed inbetween attempts + - re-enabled DEBUGASSERT on send with smaller data size -Stefan Eissing (26 Jul 2023) + - in debug builds, environment variables can be set to simulate a slow + network when sending data. cf-socket.c and vquic.c support + * CURL_DBG_SOCK_WBLOCK: percentage of send() calls that should be + answered with a EAGAIN. TCP/UNIX sockets. + This is chosen randomly. + * CURL_DBG_SOCK_WPARTIAL: percentage of data that shall be written + to the network. TCP/UNIX sockets. + Example: 80 means a send with 1000 bytes would only send 800 + This is applied to every send. + * CURL_DBG_QUIC_WBLOCK: percentage of send() calls that should be + answered with EAGAIN. QUIC only. + This is chosen randomly. -- GHA: adding quiche workflow + Closes #11756 - - adding separate quiche workflow to also build nghttpx server for testing +Daniel Stenberg (4 Sep 2023) - Closes #11517 +- docs: add curl_global_trace to some SEE ALSO sections -Version 8.2.1 (26 Jul 2023) + Closes #11791 -Daniel Stenberg (26 Jul 2023) +- os400: fix checksrc nits -- RELEASE-NOTES: synced + Closes #11789 - curl 8.2.1 release +Nicholas Nethercote (3 Sep 2023) -- THANKS: add contributors from 8.2.1 +- hyper: remove `hyptransfer->endtask` -- docs: provide more see also for cipher options + `Curl_hyper_stream` needs to distinguish between two kinds of + `HYPER_TASK_EMPTY` tasks: (a) the `foreach` tasks it creates itself, and + (b) background tasks that hyper produces. It does this by recording the + address of any `foreach` task in `hyptransfer->endtask` before pushing + it into the executor, and then comparing that against the address of + tasks later polled out of the executor. - More cross references. Hide nroff errors. + This works right now, but there is no guarantee from hyper that the + addresses are stable. `hyper_executor_push` says "The executor takes + ownership of the task, which should not be accessed again unless + returned back to the user with `hyper_executor_poll`". That wording is a + bit ambiguous but with my Rust programmer's hat on I read it as meaning + the task returned with `hyper_executor_poll` may be conceptually the + same as a task that was pushed, but that there are no other guarantees + and comparing addresses is a bad idea. - Closes #11513 + This commit instead uses `hyper_task_set_userdata` to mark the `foreach` + task with a `USERDATA_RESP_BODY` value which can then be checked for, + removing the need for `hyptransfer->endtask`. This makes the code look + more like that hyper C API examples, which use userdata for every task + and never look at task addresses. -- docs: mark two TLS options for TLS, not SSL + Closes #11779 - Closes #11514 +Dave Cottlehuber (3 Sep 2023) -Brad Harder (25 Jul 2023) +- ws: fix spelling mistakes in examples and tests -- curl_multi_wait.3: fix arg quoting to doc macro .BR + Closes #11784 - Closes #11511 +Daniel Stenberg (3 Sep 2023) -Daniel Stenberg (24 Jul 2023) +- tool_filetime: make -z work with file dates before 1970 -- RELEASE-NOTES: synced + Fixes #11785 + Reported-by: Harry Sintonen + Closes #11786 -Viktor Szakats (24 Jul 2023) +Dan Fandrich (1 Sep 2023) -- cmake: update ngtcp2 detection +- build: fix portability of mancheck and checksrc targets - Replace `OpenSSL` with `quictls` to follow the same change - in the v0.17.0 ngtcp2 release. + At least FreeBSD preserves cwd across makefile lines, so rules + consisting of more than one "cd X; do_something" must be explicitly run + in a subshell to avoid this. This problem caused the Cirrus FreeBSD + build to fail when parallel make jobs were enabled. - Follow-up to e0093b4b732f6495b0fb1cd6747cbfedcdcf63ed +- CI: adjust labeler match patterns for new & obsolete files - Closes #11508 +- configure: trust pkg-config when it's used for zlib -Stefan Eissing (24 Jul 2023) + The library flags retrieved from pkg-config were later thrown out and + harded-coded, which negates the whole reason to use pkg-config. + Also, previously, the assumption was made that --libs-only-l and + --libs-only-L are the full decomposition of --libs, which is untrue and + would not allow linking against a static zlib. The new approach is + better in that it uses --libs, although only if --libs-only-l returns + nothing. -- http: VLH, very large header test and fixes + Bug: https://curl.se/mail/lib-2023-08/0081.html + Reported-by: Randall + Closes #11778 - - adding tests using very large passwords in auth - - fixes general http sending to treat h3 like h2, and - not like http1.1 - - eliminate H2_HEADER max definitions and use the commmon - DYN_HTTP_REQUEST everywhere, different limits do not help - - fix http2 handling of requests denied by nghttp2 on send - to immediately report the refused stream +Stefan Eissing (1 Sep 2023) - Closes #11509 +- CI/ngtcp2: clear wolfssl for when cache is ignored -Andrei Rybak (23 Jul 2023) + Closes #11783 -- CONTRIBUTE: drop mention of copyright year ranges +Daniel Stenberg (1 Sep 2023) - Year ranges in copyrights were dropped in commits [1] and [2]. - Verification of year ranges in copyrights was dropped from script - 'scripts/copyright.pl' in commit [3]. However, the corresponding - passages in file 'docs/CONTRIBUTE.md' weren't updated. +- RELEASE-NOTES: synced - Drop mentions of copyright year ranges from 'docs/CONTRIBUTE.md'. +Nicholas Nethercote (1 Sep 2023) - [1] 2bc1d775f (copyright: update all copyright lines and remove year - ranges, 2023-01-02) - [2] c46761bd8 (tests/http: remove year ranges from copyrights, - 2023-03-14) - [3] 0e293bacb (copyright.pl: cease doing year verifications, 2023-01-28) +- hyper: fix a progress upload counter bug - Closes #11504 + `Curl_pgrsSetUploadCounter` should be a passed a total count, not an + increment. -- CONTRIBUTE: fix syntax in commit message description + This changes the failing diff for test 579 with hyper from this: + ``` + Progress callback called with UL 0 out of 0[LF] + -Progress callback called with UL 8 out of 0[LF] + -Progress callback called with UL 16 out of 0[LF] + -Progress callback called with UL 26 out of 0[LF] + -Progress callback called with UL 61 out of 0[LF] + -Progress callback called with UL 66 out of 0[LF] + +Progress callback called with UL 29 out of 0[LF] + ``` + to this: + ``` + Progress callback called with UL 0 out of 0[LF] + -Progress callback called with UL 8 out of 0[LF] + -Progress callback called with UL 16 out of 0[LF] + -Progress callback called with UL 26 out of 0[LF] + -Progress callback called with UL 61 out of 0[LF] + -Progress callback called with UL 66 out of 0[LF] + +Progress callback called with UL 40 out of 0[LF] + ``` + Presumably a step in the right direction. - File 'docs/CONTRIBUTE.md' includes a description of how one should write - commit messages in the curl project. Different possible parts of the - message are enclosed in square brackets. One exception is the section - describing how the curl project doesn't use "Signed-off-by" commit - trailers [1], which is enclosed in an opening curly brace paired with a - closing square bracket. + Closes #11780 - Fix the enclosing square brackets in description of "Signed-off-by" - trailers in commit messages in file 'docs/CONTRIBUTE.md'. +Daniel Stenberg (1 Sep 2023) - [1] See description of option '--signoff' in Git documentation: - https://git-scm.com/docs/git-commit +- awssiv4: avoid freeing the date pointer on error - Closes #11504 + Since it was not allocated, don't free it even if it was wrong syntax -Daniel Stenberg (23 Jul 2023) + Bug: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=61908 -- src/mkhelp: strip off escape sequences + Follow-up to b137634ba3adb - At some point the nroff command stopped stripping off escape sequences, - so then this script needs to do the job instead. + Closes #11782 - Reported-by: VictorVG on github - Fixes #11501 - Closes #11503 +Stefan Eissing (1 Sep 2023) -- KNOWN_BUGS: building for old macOS fails with gcc +- CI: ngtcp2-linux: use separate caches for tls libraries - Closes #11441 + allow ever changing master for wolfssl -Jacob Hoffman-Andrews (22 Jul 2023) + Closes #11766 -- rustls: update rustls-ffi 0.10.0 +- replace `master` as wolfssl-version with recent commit - This brings in version 0.21.0 of the upstream rustls implementation, - which notable includes support for IP address certificates. +- wolfssl, use master again in CI - Closes #10865 + - with the shared session update fix landed in master, it + is time to use that in our CI again -Brad Harder (22 Jul 2023) +Nicholas Nethercote (31 Aug 2023) -- websocket: rename arguments/variables to match docs +- tests: fix formatting errors in `FILEFORMAT.md`. - Pedantry/semantic-alignment between functions, docs, comments with - respect to websocket protocol code; No functional change intended. + Without the surrounding backticks, these tags get swallowed when the + markdown is rendered. - * "totalsize", "framesize" becomes "fragsize" (we deal in frame fragments). + Closes #11777 - * "sendflags" becomes "flags" +Viktor Szakats (31 Aug 2023) - * use canonical CURL *handle +- cmake: add support for `CURL_DEFAULT_SSL_BACKEND` - Closes #11493 + Allow overriding the default TLS backend via a CMake setting. -Jan Macku (21 Jul 2023) + E.g.: + `cmake [...] -DCURL_DEFAULT_SSL_BACKEND=mbedtls` -- bug_report: use issue forms instead of markdown template + Accepted values: bearssl, gnutls, mbedtls, openssl, rustls, + schannel, secure-transport, wolfssl - Issue forms allow you to define web-like input forms using YAML - syntax. It allows you to guide the reporter to get the required - information. + The passed string is baked into the curl/libcurl binaries. + The value is case-insensitive. - Signed-off-by: Jan Macku - Closes #11474 + We added a similar option to autotools in 2017 via + c7170e20d0a18ec8a514b4daa53bcdbb4dcb3a05. -Daniel Stenberg (21 Jul 2023) + TODO: Convert to lowercase to improve reproducibility. -- TODO: Obey Retry-After in redirects + Closes #11774 - (remove "Set custom client ip when using haproxy protocol" which was - shipped in 8.2.0) +- sectransp: fix compiler warnings - Mentioned-by: Yair Lenga - Closes #11447 + https://github.com/curl/curl-for-win/actions/runs/6037489221/job/16381860220# + step:3:11046 + ``` + /Users/runner/work/curl-for-win/curl-for-win/curl/lib/vtls/sectransp.c:2435:1 + 4: warning: unused variable 'success' [-Wunused-variable] + OSStatus success; + ^ + /Users/runner/work/curl-for-win/curl-for-win/curl/lib/vtls/sectransp.c:3300:4 + 4: warning: unused parameter 'sha256len' [-Wunused-parameter] + size_t sha256len) + ^ + ``` -- RELEASE-NOTES: synced + Closes #11773 -Oliver Roberts (21 Jul 2023) +- tidy-up: mostly whitespace nits -- amissl: fix AmiSSL v5 detection + - delete completed TODO from `./CMakeLists.txt`. + - convert a C++ comment to C89 in `./CMake/CurlTests.c`. + - delete duplicate EOLs from EOF. + - add missing EOL at EOF. + - delete whitespace at EOL (except from expected test results). + - convert tabs to spaces. + - convert CRLF EOLs to LF in GHA yaml. + - text casing fixes in `./CMakeLists.txt`. + - fix a codespell typo in `packages/OS400/initscript.sh`. - Due to changes in the AmiSSL SDK, the detection needed adjusting. + Closes #11772 - Closes #11477 +Dan Fandrich (31 Aug 2023) -Alois Klink (21 Jul 2023) +- CI: remove Windows builds from Cirrus, without replacement -- unittest/makefile: remove unneeded unit1621_LDADD + If we don't do this, all coverage on Cirrus will cease in a few days. By + removing the Windows builds, the FreeBSD one should still continue + as before. The Windows builds will need be moved to another service to + maintain test coverage. - The `unit1621_LDADD` variable has the exact same value as the `LDADD` - flag in `Makefile.am`, except without `@LDFLAGS@ @LIBCURL_LIBS@`. + Closes #11771 - This was originally added by [98e6629][], but I can't see any reason - why it exists, so we should remove it to clean things up. +- CI: switch macOS ARM build from Cirrus to Circle CI - [98e6629]: https://github.com/curl/curl/commit/98e6629154044e4ab1ee7cff8351c7 - ebcb131e88 + Cirrus is drastically reducing their free tier on Sept. 1, so they will + no longer perform all these builds for us. All but one build has been + moved, with the LibreSSL one being dropped because of linking problems + on Circle. - Closes #11494 + One important note about this change is that Circle CI is currently + directing all these builds to x86_64 hardware, despite them requesting + ARM. This is because ARM nodes are scheduled to be available on the + free tier only in December. This reduces our architectural diversity + until then but it should automatically come back once those machines are + enabled. -- unittest/makefile: remove unneeded unit1394_LDADD +- CI: use the right variable for BSD make - These custom `unit1394_LDADD` and similar automake overrides are no - longer neded. They were originally added by added by [8dac7be][] for - metalink support, but are no longer after [265b14d][] removed metalink. + BSD uses MAKEFLAGS instead of MAKE_FLAGS so it wasn't doing parallel + builds before. - [8dac7be]: https://github.com/curl/curl/commit/8dac7be438512a8725d3c71e9139bd - fdcac1ed8c - [265b14d]: https://github.com/curl/curl/commit/265b14d6b37c4298bd5556fabcbc37 - d36f911693 +- CI: drop the FreeBSD 12.X build - Closes #11494 + Cirrus' new free tier won't let us have many builds, so drop the + nonessential ones. The FreeBSD 13.X build will still give us the most + relevant FreeBSD coverage. -- cmake: add `libcurlu`/`libcurltool` for unit tests +- CI: move the Alpine build from Cirrus to GHA - Add a `libcurlu`/`libcurltool` static library that is compiled only for - unit tests. We use `EXCLUDE_FROM_ALL` to make sure that they're not - built by default, they're only built if unit tests are built. + Cirrus is reducing their free tier to next to nothing, so we must move + builds elsewhere. - These libraries allow us to compile every unit test with CMake. +Stefan Eissing (30 Aug 2023) - Closes #11446 +- test_07_upload.py: fix test_07_34 curl args -Daniel Stenberg (21 Jul 2023) + - Pass correct filename to --data-binary. -- test979: test -u with redirect to (the same) absolute host + Prior to this change --data-binary was passed an incorrect filename due + to a missing separator in the arguments list. Since aacbeae7 curl will + error on incorrect filenames for POST. - Verifies #11492 + Fixes https://github.com/curl/curl/issues/11761 + Closes https://github.com/curl/curl/pull/11763 -- transfer: do not clear the credentials on redirect to absolute URL +Nicholas Nethercote (30 Aug 2023) - Makes test 979 work. Regression shipped in 8.2.0 from commit - dd4d1a26959f63a2c +- tests: document which tests fail due to hyper's lack of trailer support. - Fixes #11486 - Reported-by: Cloudogu Siebels - Closes #11492 + Closes #11762 -Jon Rumsey (20 Jul 2023) +- docs: removing "pausing transfers" from HYPER.md. -- os400: correct EXPECTED_STRING_LASTZEROTERMINATED + It's a reference to #8600, which was fixed by #9070. - Correct EXPECTED_STRING_LASTZEROTERMINATED to account for - CURLOPT_HAPROXY_CLIENT_IP which requires EBCDIC to ASCII conversion when - passed into curl_easy_setopt(). + Closes #11764 - Closes #11476 +Patrick Monnerat (30 Aug 2023) -Oliver Roberts (20 Jul 2023) +- os400: handle CURL_TEMP_PRINTF() while building bind source -- amissl: add missing signal.h include + Closes #11547 - In some environments, signal.h is already included, but not in others - which cause compilation to fail, so explictly include it. +- os400: build test servers - Closes #11478 + Also fix a non-compliant main prototype in disabled.c. -- amigaos: fix sys/mbuf.h m_len macro clash + Closes #11547 - The updated Curl_http_req_make and Curl_http_req_make2 functions spawned - a parameter called m_len. The AmigaOS networking headers, derived from - NetBSD, contain "#define m_len m_hdr.mh_len" which clashes with - this. Since we do not actually use mbuf, force the include file to be - ignored, removing the clash. +- tests: fix compilation error for os400 - Closes #11479 + OS400 uses BSD 4.3 setsockopt() prototype by default: this does not + define parameter as const, resulting in an error if actual parameter is + const. Remove the const keyword from the actual parameter cast: this + works in all conditions, even if the formal parameter uses it. -Daniel Stenberg (20 Jul 2023) + Closes #11547 -- socks: print ipv6 address within brackets +- os400: make programs and command name configurable - Fixes #11483 - Closes #11484 + Closes #11547 -Christian Schmitz (20 Jul 2023) +- os400: move build configuration parameters to a separate script -- libcurl-errors.3: add CURLUE_OK + They can then easily be overriden in a script named "config400.override" + that is not part of the distribution. - Closes #11488 + Closes #11547 -Oliver Roberts (20 Jul 2023) +- os400: implement CLI tool -- cfilters: rename close/connect functions to avoid clashes + This is provided as a QADRT (ascii) program, a link to it in the IFS and + a minimal CL command. - Rename `close` and `connect` in `struct Curl_cftype` for - consistency and to avoid clashes with macros of the same name - (the standard AmigaOS networking connect() function is implemented - via a macro). + Closes #11547 - Closes #11491 +Matthias Gatto (30 Aug 2023) -Stefan Eissing (20 Jul 2023) +- lib: fix aws-sigv4 having date header twice in some cases -- http2: fix regression on upload EOF handling + When the user was providing the header X-XXX-Date, the header was + re-added during signature computation, and we had it twice in the + request. - - a regression introduced by c9ec85121110d7cbbbed2990024222c8f5b8afe5 - where optimization of small POST bodies leads to a new code path - for such uploads that did not trigger the "done sending" event - - add triggering this event for early "upload_done" situations + Reported-by: apparentorder@users.noreply.github.com - Fixes #11485 - Closes #11487 - Reported-by: Aleksander Mazur + Signed-off-by: Matthias Gatto -Daniel Stenberg (19 Jul 2023) + Fixes: https://github.com/curl/curl/issues/11738 + Closes: https://github.com/curl/curl/pull/11754 -- configure: check for nghttp2_session_get_stream_local_window_size +Jay Satiro (30 Aug 2023) - The http2 code uses it now. Introduced in nghttp2 1.15.0 (Sep 2016) +- multi: remove 'processing: ' debug message - Fixes #11470 - Reported-by: Paul Howarth - Closes #11473 + - Remove debug message added by e024d566. -Stefan Eissing (19 Jul 2023) + Closes https://github.com/curl/curl/pull/11759 -- quiche: fix segfault and other things +- ftp: fix temp write of ipv6 address - - refs #11449 where a segfault is reported when IP Eyeballing did - not immediately connect but made several attempts - - The transfer initiating the eyeballing was initialized too early, - leadding to references to the filter instance that was then - replaced in the subsequent eyeball attempts. That led to a use - after free in the buffer handling for the transfer - - transfers are initiated now more lazy (like in the ngtcp2 filter), - when the stream is actually opened - - suppress reporting on quiche event errors for "other" transfers - than the current one to not fail a transfer due to faults in - another one. - - revert recent return value handling for quiche_h3_recv_body() - to not indicate an error but an EAGAIN situation. We wish quiche - would document what functions return. + - During the check to differentiate between a port and IPv6 address + without brackets, write the binary IPv6 address to an in6_addr. - Fixes #11449 - Closes #11469 - Reported-by: ウさん + Prior to this change the binary IPv6 address was erroneously written to + a sockaddr_in6 'sa6' when it should have been written to its in6_addr + member 'sin6_addr'. There's no fallout because no members of 'sa6' are + accessed before it is later overwritten. -Daniel Stenberg (19 Jul 2023) + Closes https://github.com/curl/curl/pull/11747 -- hostip: return IPv6 first for localhost resolves +- tool: change some fopen failures from warnings to errors - Fixes #11465 - Reported-by: Chilledheart on github - Closes #11466 + - Error on missing input file for --data, --data-binary, + --data-urlencode, --header, --variable, --write-out. -Harry Sintonen (19 Jul 2023) + Prior to this change if a user of the curl tool specified an input file + for one of the above options and that file could not be opened then it + would be treated as zero length data instead of an error. For example, a + POST using `--data @filenametypo` would cause a zero length POST which + is probably not what the user intended. -- tool: fix tool_seek_cb build when SIZEOF_CURL_OFF_T > SIZEOF_OFF_T + Closes https://github.com/curl/curl/pull/11677 - - a variable was renamed, and some use of it wasn't. this fixes the - build. +- hostip: fix typo - Closes #11468 +Davide Masserut (29 Aug 2023) -Stefan Eissing (19 Jul 2023) +- tool: avoid including leading spaces in the Location hyperlink -- quiche: fix lookup of transfer at multi + Co-authored-by: Dan Fandrich - - refs #11449 where weirdness in quiche multi connection tranfers was - observed - - fixes lookup of transfer for a quiche event to take the connection - into account - - formerly, a transfer with the same stream_id, but on another connection - could be found + Closes #11735 - Closes #11462 +Daniel Stenberg (29 Aug 2023) -Daniel Stenberg (19 Jul 2023) +- SECURITY-PROCESS.md: not a sec issue: Tricking user to run a cmdline -- RELEASE-NOTES: synced + Closes #11757 - bump to 8.2.1 +- connect: stop halving the remaining timeout when less than 600 ms left -John Haugabook (19 Jul 2023) + When curl wants to connect to a host, it always has a TIMEOUT. The + maximum time it is allowed to spend until a connect is confirmed. -- ciphers.d: put URL in first column + curl will try to connect to each of the IP adresses returned for the + host. Two loops, one for each IP family. - This makes the URL turn into a link properly when "webified". + During the connect loop, while curl has more than one IP address left to + try within a single address family, curl has traditionally allowed (time + left/2) for *this* connect attempt. This, to not get stuck on the + initial addresses in case the timeout but still allow later addresses to + get attempted. - Fixes https://github.com/curl/curl-www/issues/270 - Closes #11464 + This has the downside that when users set a very short timeout and the + host has a large number of IP addresses, the effective result might be + that every attempt gets a little too short time. -Version 8.2.0 (19 Jul 2023) + This change stop doing the divided-by-two if the total time left is + below a threshold. This threshold is 600 milliseconds. -Daniel Stenberg (19 Jul 2023) + Closes #11693 -- RELEASE-NOTES: synced +- asyn-ares: reduce timeout to 2000ms - 8.2.0 release + When UDP packets get lost this makes for slightly faster retries. This + lower timeout is used by @c-ares itself by default starting next + release. -- THANKS-filter: strip out "GitHub" + Closes #11753 -- THANKS: add contributors from 8.2.0 +John Bampton (29 Aug 2023) -- RELEASE-PROCEDURE.md: adjust the release dates +- misc: remove duplicate words -Stefan Eissing (17 Jul 2023) + Closes #11740 -- quiche: fix defects found in latest coverity report +Daniel Stenberg (29 Aug 2023) - Closes #11455 +- RELEASE-NOTES: synced -Daniel Stenberg (17 Jul 2023) +- wolfSSL: avoid the OpenSSL compat API when not needed -- quiche: avoid NULL deref in debug logging + ... and instead call wolfSSL functions directly. - Coverity reported "Dereference after null check" + Closes #11752 - If stream is NULL and the function exits, the logging must not deref it. +Viktor Szakats (28 Aug 2023) - Closes #11454 +- lib: fix null ptr derefs and uninitialized vars (h2/h3) -Stefan Eissing (17 Jul 2023) + Fixing compiler warnings with gcc 13.2.0 in unity builds. -- http2: treat initial SETTINGS as a WINDOW_UPDATE + Assisted-by: Jay Satiro + Assisted-by: Stefan Eissing + Closes #11739 - - refs #11426 where spurious stalls on large POST requests - are reported - - the issue seems to involve the following - * first stream on connection adds up to 64KB of POST - data, which is the max default HTTP/2 stream window size - transfer is set to HOLD - * initial SETTINGS from server arrive, enlarging the stream - window. But no WINDOW_UPDATE is received. - * curl stalls - - the fix un-HOLDs a stream on receiving SETTINGS, not - relying on a WINDOW_UPDATE from lazy servers +Jay Satiro (28 Aug 2023) - Closes #11450 +- secureserver.pl: fix stunnel version parsing -Daniel Stenberg (17 Jul 2023) + - Allow the stunnel minor-version version part to be zero. -- ngtcp2: assigning timeout, but value is overwritten before used + Prior to this change with the stunnel version scheme of . + if either part was 0 then version parsing would fail, causing + secureserver.pl to fail with error "No stunnel", causing tests that use + the SSL protocol to be skipped. As a practical matter this bug can only + be caused by a minor-version part of 0, since the major-version part is + always greater than 0. - Reported by Coverity + Closes https://github.com/curl/curl/pull/11722 - Closes #11453 +- secureserver.pl: fix stunnel path quoting -- krb5: add typecast to please Coverity + - Store the stunnel path in the private variable $stunnel unquoted and + instead quote it in the command strings. -Derzsi Dániel (16 Jul 2023) + Prior to this change the quoted stunnel path was passed to perl's file + operators which cannot handle quoted paths. For example: -- wolfssl: support setting CA certificates as blob + $stunnel = "\"/C/Program Files (x86)/stunnel/bin/tstunnel\""; + if(-x $stunnel or -x "$stunnel") + # false even if path exists and is executable - Closes #11445 + Our other test scripts written in perl, unlike this one, use servers.pm + which has a global $stunnel variable with the path stored unquoted and + therefore those scripts don't have this problem. -- wolfssl: detect when TLS 1.2 support is not built into wolfssl + Closes https://github.com/curl/curl/pull/11721 - Closes #11444 +Daniel Stenberg (28 Aug 2023) -Graham Campbell (15 Jul 2023) +- altsvc: accept and parse IPv6 addresses in response headers -- CI: bump nghttp2 from 1.55.0 to 1.55.1 + Store numerical IPv6 addresses in the alt-svc file with the brackets + present. - Closes #11442 + Verify with test 437 and 438 -Daniel Stenberg (15 Jul 2023) + Fixes #11737 + Reported-by: oliverpool on github + Closes #11743 -- curl: return error when asked to use an unsupported HTTP version +- libtest: use curl_free() to free libcurl allocated data - When one of the following options are used but the libcurl in use does - not support it: + In several test programs. These mistakes are not detected or a problem + as long as memdebug.h is included, as that provides the debug wrappers + for all memory functions in the same style libcurl internals do it, + which makes curl_free and free effectively the same call. - --http2 - --http2-prior-knowledge - --proxy-http2 + Reported-by: Nicholas Nethercote + Closes #11746 - Closes #11440 +Jay Satiro (28 Aug 2023) -Chris Paulson-Ellis (14 Jul 2023) +- disable.d: explain --disable not implemented prior to 7.50.0 -- cf-socket: don't bypass fclosesocket callback if cancelled before connect + Option -q/--disable was added in 5.0 but only -q was actually + implemented. Later --disable was implemented in e200034 (precedes + 7.49.0), but incorrectly, and fixed in 6dbc23c (precedes 7.50.0). - After upgrading to 8.1.2 from 7.84.0, I found that sockets were being - closed without calling the fclosesocket callback if a request was - cancelled after the associated socket was created, but before the socket - was connected. This lead to an imbalance of fopensocket & fclosesocket - callbacks, causing problems with a custom event loop integration using - the multi-API. + Reported-by: pszlazak@users.noreply.github.com - This was caused by cf_socket_close() calling sclose() directly instead - of calling socket_close() if the socket was not active. For regular TCP - client connections, the socket is activated by cf_socket_active(), which - is only called when the socket completes the connect. + Fixes https://github.com/curl/curl/issues/11710 + Closes #11712 - As far as I can tell, this issue has existed since 7.88.0. That is, - since the code in question was introduced by: - commit 71b7e0161032927cdfb4e75ea40f65b8898b3956 - Author: Stefan Eissing - Date: Fri Dec 30 09:14:55 2022 +0100 +Nicholas Nethercote (28 Aug 2023) - lib: connect/h2/h3 refactor +- hyper: fix ownership problems - Closes #11439 + Some of these changes come from comparing `Curl_http` and + `start_CONNECT`, which are similar, and adding things to them that are + present in one and missing in another. -Daniel Stenberg (13 Jul 2023) + The most important changes: + - In `start_CONNECT`, add a missing `hyper_clientconn_free` call on the + happy path. + - In `start_CONNECT`, add a missing `hyper_request_free` on the error + path. + - In `bodysend`, add a missing `hyper_body_free` on an early-exit path. + - In `bodysend`, remove an unnecessary `hyper_body_free` on a different + error path that would cause a double-free. + https://docs.rs/hyper/latest/hyper/ffi/fn.hyper_request_set_body.html + says of `hyper_request_set_body`: "This takes ownership of the + hyper_body *, you must not use it or free it after setting it on the + request." This is true even if `hyper_request_set_body` returns an + error; I confirmed this by looking at the hyper source code. -- tool_parsecfg: accept line lengths up to 10M + Other changes are minor but make things slightly nicer. - Bumped from 100K set in 47dd957daff9 + Closes #11745 - Reported-by: Antoine du Hamel - Fixes #11431 - Closes #11435 +Daniel Stenberg (28 Aug 2023) -Stefan Eissing (13 Jul 2023) +- multi.h: the 'revents' field of curl_waitfd is supported -- CI: brew fix for openssl in default path + Since 6d30f8ebed34e7276 - If brew install/update links openssl into /usr/local, it will be found - before anything we add with `-isystem path` to CPP/LDLFAGS. Get rid of - that by unlinking the keg. + Reported-by: Nicolás Ojeda Bär + Ref: #11748 + Closes #11749 - Fixes #11413 - Closes #11436 +Gerome Fournier (27 Aug 2023) -Daniel Stenberg (13 Jul 2023) +- tool_paramhlp: improve str2num(): avoid unnecessary call to strlen() -- RELEASE-NOTES: synced + Closes #11742 -Ondřej Koláček (13 Jul 2023) +Daniel Stenberg (27 Aug 2023) -- sectransp: fix EOF handling +- docs: mention critical files in same directories as curl saves - Regression since the large refactor from 2022 + ... cannot be fully protected. Don't do it. - Closes #11427 + Co-authored-by: Jay Satiro + Reported-by: Harry Sintonen + Fixes #11530 + Closes #11701 -Daniel Stenberg (13 Jul 2023) +John Hawthorn (26 Aug 2023) -- checksrc: quote the file name to work with "funny" letters +- OpenSSL: clear error queue after SSL_shutdown - Closes #11437 + We've seen errors left in the OpenSSL error queue (specifically, + "shutdown while in init") by adding some logging it revealed that the + source was this file. -Karthikdasari0423 (13 Jul 2023) + Since we call SSL_read and SSL_shutdown here, but don't check the return + code for an error, we should clear the OpenSSL error queue in case one + was raised. -- HTTP3.md: ngtcp2 updated to v0.17.0 and nghttp3 to v0.13.0 + This didn't affect curl because we call ERR_clear_error before every + write operation (a0dd9df9ab35528eb9eb669e741a5df4b1fb833c), but when + libcurl is used in a process with other OpenSSL users, they may detect + an OpenSSL error pushed by libcurl's SSL_shutdown as if it was their + own. - Follow-up to e0093b4b732f6 + Co-authored-by: Satana de Sant'Ana - Closes #11433 + Closes #11736 -Daniel Stenberg (13 Jul 2023) +Alexander Kanavin (25 Aug 2023) -- CURLOPT_MIMEPOST.3: clarify what setting to NULL means +- tests: update cookie expiry dates to far in the future - Follow-up to e08382a208d4e480 + This allows testing Y2038 with system time set to after that, so that + actual Y2038 issues can be exposed, and not masked by expiry errors. - Closes #11430 + Fixes #11576 + Closes #11610 -Tatsuhiro Tsujikawa (12 Jul 2023) +John Bampton (25 Aug 2023) -- ngtcp2: build with 0.17.0 and nghttp3 0.13.0 +- misc: fix spelling - - ngtcp2_crypto_openssl was renamed to ngtcp2_crypto_quictls. + Closes #11733 - Closes #11428 +Daniel Stenberg (25 Aug 2023) -- CI: Bump ngtcp2, nghttp3, and nghttp2 +- cmdline-opts/page-header: clarify stronger that !opt == URL - Closes #11428 + Everything provided on the command line that is not an option (or an + argument to an option) is treated as a URL. -James Fuller (11 Jul 2023) + Closes #11734 -- example/maxconnects: set maxconnect example +- tests/runner: fix %else handling - Closes #11343 + Getting the show state proper for %else and %endif did not properly work + in nested cases. -Pontakorn Prasertsuk (11 Jul 2023) + Follow-up to 3d089c41ea9 -- http2: send HEADER & DATA together if possible + Closes #11731 - Closes #11420 +Nicholas Nethercote (25 Aug 2023) -Daniel Stenberg (11 Jul 2023) +- docs: Remove mention of #10803 from `KNOWN_BUGS`. -- CI: use wolfSSL 5.6.3 in builds + Because the leaks have been fixed. - No using master anymore +- c-hyper: fix another memory leak in `Curl_http`. - Closes #11424 + There is a `hyper_clientconn_free` call on the happy path, but not one + on the error path. This commit adds one. -SaltyMilk (11 Jul 2023) + Fixes the second memory leak reported by Valgrind in #10803. -- fopen: optimize + Fixes #10803 + Closes #11729 - Closes #11419 +- c-hyper: fix a memory leak in `Curl_http`. -Daniel Stenberg (11 Jul 2023) + A request created with `hyper_request_new` must be consumed by either + `hyper_clientconn_send` or `hyper_request_free`. -- cmake: make use of snprintf + This is not terrifically clear from the hyper docs -- + `hyper_request_free` is documented only with "Free an HTTP request if + not going to send it on a client" -- but a perusal of the hyper code + confirms it. - Follow-up to 935b1bd4544a23a91d68 + This commit adds a `hyper_request_free` to the `error:` path in + `Curl_http` so that the request is consumed when an error occurs after + the request is created but before it is sent. - Closes #11423 + Fixes the first memory leak reported by Valgrind in #10803. -Stefan Eissing (11 Jul 2023) + Closes #11729 -- macOS: fix taget detection +Daniel Stenberg (25 Aug 2023) - - TARGET_OS_OSX is not always defined on macOS - - this leads to missing symbol Curl_macos_init() - - TargetConditionals.h seems to define these only when - dynamic targets are enabled (somewhere?) - - this PR fixes that on my macOS 13.4.1 - - I have no clue why CI builds worked without it +- RELEASE-NOTES: synced - Follow-up to c7308592fb8ba213fc2c1 - Closes #11417 +John Bampton (25 Aug 2023) -Stan Hu (9 Jul 2023) +- misc: spellfixes -- hostip.c: Move macOS-specific calls into global init call + Closes #11730 - https://github.com/curl/curl/pull/7121 introduced a macOS system call - to `SCDynamicStoreCopyProxies`, which is invoked every time an IP - address needs to be resolved. +Daniel Stenberg (25 Aug 2023) - However, this system call is not thread-safe, and macOS will kill the - process if the system call is run first in a fork. To make it possible - for the parent process to call this once and prevent the crash, only - invoke this system call in the global initialization routine. +- tests: add support for nested %if conditions - In addition, this change is beneficial because it: + Provides more flexiblity to test cases. - 1. Avoids extra macOS system calls for every IP lookup. - 2. Consolidates macOS-specific initialization in a separate file. + Also warn and bail out if there is an '%else' or %endif' without a + preceeding '%if'. - Fixes #11252 - Closes #11254 + Ref: #11610 + Closes #11728 -Daniel Stenberg (9 Jul 2023) +- time-cond.d: mention what happens on a missing file -- docs: use a space after RFC when spelling out RFC numbers + Closes #11727 - Closes #11382 +Christian Hesse (24 Aug 2023) -Margu (9 Jul 2023) +- docs/cmdline-opts: match the current output -- imap-append.c: update to make it more likely to work + The release date has been added in output, reflect that in documentation. - Fixes #10300 - Closes #11397 + Closes #11723 -Emanuele Torre (9 Jul 2023) +Daniel Stenberg (24 Aug 2023) -- tool_writeout_json: fix encoding of control characters +- lib: minor comment corrections - Control characters without a special escape sequence e.g. %00 or %06 - were being encoded as "u0006" instead of "\u0006". +- docs: rewrite to present tense - Ref: https://github.com/curl/trurl/pull/214#discussion_r1257487858 - Closes #11414 + ... instead of using future tense. -Stefan Eissing (9 Jul 2023) + + numerous cleanups and improvements + + stick to "reuse" not "re-use" + + fewer contractions -- http3/ngtcp2: upload EAGAIN handling + Closes #11713 - - refs #11389 where IDLE timeouts on upload are reported - - reword ngtcp2 expiry handling to apply to both send+recv - calls into the filter - - EAGAIN uploads similar to the recent changes in HTTP/2, e.g. - report success only when send data was ACKed. - - HOLD sending of EAGAINed uploads to avoid cpu busy loops - - rename internal function for consistency with HTTP/2 - implementation +- urlapi: setting a blank URL ("") is not an ok URL - Fixes #11389 - Closes #11390 + Test it in 1560 + Fixes #11714 + Reported-by: ad0p on github + Closes #11715 -Brian Nixon (9 Jul 2023) +- spelling: use 'reuse' not 're-use' in code and elsewhere -- tool_easysrc.h: correct `easysrc_perform` for `CURL_DISABLE_LIBCURL_OPTION` + Unify the spelling as both versions were previously used intermittently - Closes #11398 + Closes #11717 -Daniel Stenberg (9 Jul 2023) +Michael Osipov (23 Aug 2023) -- RELEASE-NOTES: synced +- system.h: add CURL_OFF_T definitions on HP-UX with HP aCC -- transfer: clear credentials when redirecting to absolute URL + HP-UX on IA64 provides two modes: 32 and 64 bit while 32 bit being the + default one. Use "long long" in 32 bit mode and just "long" in 64 bit + mode. - Make sure the user and password for the second request is taken from the - redirected-to URL. + Closes #11718 - Add test case 899 to verify. +Dan Fandrich (22 Aug 2023) - Reported-by: James Lucas - Fixes #11410 - Closes #11412 +- tests: don't call HTTP errors OK in test cases -Stefan Eissing (8 Jul 2023) + Some HTTP errors codes were accompanied by the text OK, which causes + some cognitive dissonance when reading them. -- hyper: fix EOF handling on input +- http: close the connection after a late 417 is received - We ran out of disc space due to an infinite loop with debug logging + In this situation, only part of the data has been sent before aborting + so the connection is no longer usable. - Fixes #11377 - Closes #11385 - Reported-by: Dan Fandrich + Assisted-by: Jay Satiro + Fixes #11678 + Closes #11679 -- http2: raise header limitations above and beyond +- runtests: slightly increase the longest log file displayed - - not quite to infinity - - rewrote the implementation of our internal HTTP/1.x request - parsing to work with very large lines using dynbufs. - - new default limit is `DYN_HTTP_REQUEST`, aka 1MB, which - is also the limit of curl's general HTTP request processing. + The new limit provides enough space for a 64 KiB data block to be logged + in a trace file, plus a few lines at the start and end for context. This + happens to be the amount of data sent at a time in a PUT request. - Fixes #11405 - Closes #11407 +- tests: add delay command to the HTTP server -Juan Cruz Viotti (8 Jul 2023) + This adds a delay after client connect. -- curl_easy_nextheader.3: add missing open parenthesis examples +Daniel Stenberg (22 Aug 2023) - Closes #11409 - Signed-off-by: Juan Cruz Viotti +- cirrus: install everthing with pkg, avoid pip -Dan Fandrich (7 Jul 2023) + Assisted-by: Sevan Janiyan -- CI: enable verbose test output on pytest + Closes #11711 - This shows individual pass/fail status on tests and makes this output - consistent with other jobs' pytest invocations. +- curl_url*.3: update function descriptions -Stefan Eissing (28 Jun 2023) + - expand and clarify several descriptions + - avoid using future tense all over -- http2: fix crash in handling stream weights + Closes #11708 - - Delay the priority handling until the stream has been opened. +- RELEASE-NOTES: synced - - Add test2404 to reproduce and verify. +Stefan Eissing (21 Aug 2023) - Weights may change "on the run", which is why there are checks in - general egress handling. These must not trigger when the stream has not - been opened yet. +- CI/cirrus: disable python install on FreeBSD - Reported-by: jbgoog@users.noreply.github.com + - python cryptography package does not build build FreeBSD + - install just mentions "error" + - this gets the build and the main test suite going again - Fixes https://github.com/curl/curl/issues/11379 - Closes https://github.com/curl/curl/pull/11384 + Closes #11705 -- tests/http: Add mod_h2 directive `H2ProxyRequests` +- test2600: fix flakiness on low cpu - master of mod_h2 now requires H2ProxyRequests directives for forward - proxying with HTTP/2 to work. + - refs #11355 where failures to to low cpu resources in CI + are reported + - vastly extend CURLOPT_CONNECTTIMEOUT_MS and max durations + to test cases + - trigger Curl_expire() in test filter to allow re-checks before + the usual 1second interval - Ref: https://github.com/icing/mod_h2/commit/3897a7086 + Closes #11690 - Closes https://github.com/curl/curl/pull/11392 +Maksim Sciepanienka (20 Aug 2023) -Dan Fandrich (28 Jun 2023) +- tool_urlglob: use the correct format specifier for curl_off_t in msnprintf -- CI: make Appveyor job names unique + Closes #11698 - Two otherwise identical mingw-w64 jobs now have their differing compiler - versions mentioned in their names. +Daniel Stenberg (20 Aug 2023) -Sheshadri.V (25 Jun 2023) +- test687/688: two more basic --xattr tests -- curl.h: include for vxworks + Closes #11697 - Closes #11356 +- cmdline-opts/docs: mentioned the negative option part -Dan Fandrich (24 Jun 2023) + ... for --no-alpn and --no-buffer in the same style done for other --no- + options: -- CI: enable parallel make in more builds + "Note that this is the negated option name documented." - Most CI services provide at least two cores, so enable parallel make - jobs to take advantage of that for builds. Some dependencies aren't safe - to build in parallel so leave those as-is. Also, rename a few - workflows to eliminate duplicate names and provide a better idea what - they're about. + Closes #11695 -- CI: don't install impacket if tests are not run +Emanuele Torre (19 Aug 2023) - It just wastes time and bandwidth and isn't even used. +- tool/var: also error when expansion result starts with NUL -divinity76 (24 Jun 2023) + Expansions whose output starts with NUL were being expanded to the empty + string, and not being recognised as values that contain a NUL byte, and + should error. -- configure: the --without forms of the options are also gone + Closes #11694 - --without-darwin-ssl and --without-metalink +Daniel Stenberg (19 Aug 2023) - Closes #11378 +- tests: add 'large-time' as a testable feature -Daniel Stenberg (23 Jun 2023) + This allows test cases to require this feature to run and to be used in + %if conditions. -- configure: add check for ldap_init_fd + Large here means larger than 32 bits. Ie does not suffer from y2038. - ... as otherwise the configure script will say it is OpenLDAP in the - summary, but not set the USE_OPENLDAP define, therefor not using the - intended OpenLDAP code paths. + Closes #11696 - Regression since 4d7385446 (7.85.0) - Fixes #11372 - Closes #11374 - Reported-by: vlkl-sap on github +- tests/Makefile: add check-translatable-options.pl to tarball -Michał Petryka (23 Jun 2023) + Used in test 1544 -- cmake: stop CMake from quietly ignoring missing Brotli + Follow-up to ae806395abc8c - The CMake project was set to `QUIET` for Brotli instead of - `REQUIRED`. This makes builds unexpectedly ignore missing Brotli even - when `CURL_BROTLI` is enabled. +- gen.pl: fix a long version generation mistake - Closes #11376 + Too excessive escaping made the parsing not find the correct long names + later and instead add "wrong" links. -Emanuele Torre (22 Jun 2023) + Follow-up to 439ff2052e219 -- docs: add more .IP after .RE to fix indentation of generate paragraphs + Reported-by: Lukas Tribus + Fixes #11688 + Closes #11689 - follow-up from 099f41e097c030077b8ec078f2c2d4038d31353b +- lib: move mimepost data from ->req.p.http to ->state - I just thought of checking all the other files with .RE, and I found 6 - other files that were missing .IP at the end. + When the legacy CURLOPT_HTTPPOST option is used, it gets converted into + the modem mimpost struct at first use. This data is (now) kept for the + entire transfer and not only per single HTTP request. This re-enables + rewind in the beginning of the second request instead of in end of the + first, as brought by 1b39731. - Closes #11375 + The request struct is per-request data only. -Stefan Eissing (22 Jun 2023) + Extend test 650 to verify. -- http2: h2 and h2-PROXY connection alive check fixes + Fixes #11680 + Reported-by: yushicheng7788 on github + Closes #11682 - - fix HTTP/2 check to not declare a connection dead when - the read attempt results in EAGAIN - - add H2-PROXY alive check as for HTTP/2 that was missing - and is needed - - add attach/detach around Curl_conn_is_alive() and remove - these in filter methods - - add checks for number of connections used in some test_10 - proxy tunneling tests +Patrick Monnerat (17 Aug 2023) - Closes #11368 +- os400: do not check translatable options at build time -- http2: error stream resets with code CURLE_HTTP2_STREAM + Now that there is a test for this, the build time check is not needed + anymore. - - refs #11357, where it was reported that HTTP/1.1 downgrades - no longer works - - fixed with suggested change - - added test_05_03 and a new handler in the curltest module - to reproduce that downgrades work + Closes #11650 - Fixes #11357 - Closes #11362 - Reported-by: Jay Satiro +- test1554: check translatable string options in OS400 wrapper -Daniel Stenberg (22 Jun 2023) + This test runs a perl script that checks all string options are properly + translated by the OS400 character code conversion wrapper. It also + verifies these options are listed in alphanumeric order in the wrapper + switch statement. -- connect-timeout.d: mention that the DNS lookup is included + Closes #11650 - Closes #11370 +Daniel Stenberg (17 Aug 2023) -Emanuele Torre (22 Jun 2023) +- unit3200: skip testing if function is not present -- quote.d: fix indentation of generated paragraphs + Fake a successful run since we have no easy mechanism to skip this test + for this advanced condition. - quote.d was missing a .IP at the end which caused the paragraphs - generated for See-also, Multi, and Example to not be indented correctly. +- unit2600: fix build warning if built without verbose messages - I also remove a redundant "This option can be used multiple times.", and - replaced .IP "item" with .TP .B "item" to make more clear which lines - are part of the list of commands and which aren't. +- test1608: make it build and get skipped without shuffle DNS support - Closes #11371 +- lib: --disable-bindlocal builds curl without local binding support -Paul Wise (22 Jun 2023) +- test1304: build and skip without netrc support -- checksrc: modernise perl file open +- lib: build fixups when built with most things disabled - Use regular variables and separate file open modes from filenames. + Closes #11687 - Suggested by perlcritic +- workflows/macos.yml: disable zstd and alt-svc in the http-only build - Copied from https://github.com/curl/trurl/commit/f2784a9240f47ee28a845 + Closes #11683 - Closes #11358 +Stefan Eissing (17 Aug 2023) -Dan Fandrich (21 Jun 2023) +- bearssl: handshake fix, provide proper get_select_socks() implementation -- runtests: work around a perl without SIGUSR1 + - bring bearssl handshake times down from +200ms down to other TLS backends + - vtls: improve generic get_select_socks() implementation + - tests: provide Apache with a suitable ssl session cache - At least msys2 perl v5.32.1 doesn't seem to define this signal. Since - this signal is only used for debugging, just ignore if setting it fails. + Closes #11675 - Reported-by: Marcel Raad - Fixes #11350 - Closes #11366 +- tests: TLS session sharing test -- runtests: include missing valgrind package + - test TLS session sharing with special test client + - expect failure with wolfSSL + - disable flaky wolfSSL test_02_07b - use valgrind was missing which caused torture tests with valgrind - enabled to fail. + Closes #11675 - Reported-by: Daniel Stenberg - Fixes #11364 - Closes #11365 +Daniel Stenberg (17 Aug 2023) -- runtests: use more consistent failure lines +- CURLOPT_*TIMEOUT*: extend and clarify - After a test failure log a consistent log message to make it easier to - parse the log file. Also, log a consistent message with "ignored" for - failures that cause the test to be not considered at all. These should - perhaps be counted in the skipped category, but this commit does not - change that behaviour. + Closes #11686 -- runtests: consistently write the test check summary block +- urlapi: return CURLUE_BAD_HOSTNAME if puny2idn encoding fails - The memory check character was erroneously omitted if the memory - checking file was not available for some reason, making the block of - characters an inconsistent length. + And document it. Only return out of memory when it actually is a memory + problem. -- test2600: fix the description + Pointed-out-by: Jacob Mealey + Closes #11674 - It looks like it was cut-and-pasted. +Mathew Benson (17 Aug 2023) - Closes #11354 +- cmake: add GnuTLS option -Daniel Stenberg (21 Jun 2023) + - Option to use GNUTLS was missing. Hence was not able to use GNUTLS + with ngtcp2 for http3. -- TODO: "Support HTTP/2 for HTTP(S) proxies" *done* + Closes #11685 -humbleacolyte (21 Jun 2023) +Daniel Stenberg (16 Aug 2023) -- cf-socket: move ctx declaration under HAVE_GETPEERNAME +- RELEASE-NOTES: synced - Closes #11352 +- http: remove the p_pragma struct field -Daniel Stenberg (20 Jun 2023) + unused since 40e8b4e52 (2008) -- RELEASE-NOTES: synced + Closes #11681 -- example/connect-to: show CURLOPT_CONNECT_TO +Jay Satiro (16 Aug 2023) - Closes #11340 +- CURLINFO_CERTINFO.3: better explain curl_certinfo struct -Stefan Eissing (20 Jun 2023) + Closes https://github.com/curl/curl/pull/11666 -- hyper: unslow +- CURLINFO_TLS_SSL_PTR.3: clarify a recommendation - - refs #11203 where hyper was reported as being slow - - fixes hyper_executor_poll to loop until it is out of - tasks as advised by @seanmonstar in https://github.com/hyperium/hyper/issue - s/3237 - - added a fix in hyper io handling for detecting EAGAIN - - added some debug logs to see IO results - - pytest http/1.1 test cases pass - - pytest h2 test cases fail on connection reuse. HTTP/2 - connection reuse does not seem to work. Hyper submits - a request on a reused connection, curl's IO works and - thereafter hyper declares `Hyper: [1] operation was canceled: connection cl - osed` - on stderr without any error being logged before. + - Remove the out-of-date SSL backend list supported by + CURLOPT_SSL_CTX_FUNCTION. - Fixes #11203 - Reported-by: Gisle Vanem - Advised-by: Sean McArthur - Closes #11344 + It makes more sense to just refer to that document instead of having + a separate list that has to be kept in sync. -- HTTP/2: upload handling fixes + Closes https://github.com/curl/curl/pull/11665 - - fixes #11242 where 100% CPU on uploads was reported - - fixes possible stalls on last part of a request body when - that information could not be fully send on the connection - due to an EAGAIN - - applies the same EGAIN handling to HTTP/2 proxying +- write-out.d: clarify %{time_starttransfer} - Reported-by: Sergey Alirzaev - Fixed #11242 - Closes #11342 + sync it up with CURLINFO_STARTTRANSFER_TIME_T -Daniel Stenberg (20 Jun 2023) +Daniel Stenberg (15 Aug 2023) -- example/opensslthreadlock: remove +- transfer: don't set TIMER_STARTTRANSFER on first send - This shows how to setup OpenSSL mutex callbacks, but this is not - necessary since OpenSSL 1.1.0 - meaning that no currently supported - OpenSSL version requires this anymore + The time stamp is for measuring the first *received* byte - Closes #11341 + Fixes #11669 + Reported-by: JazJas on github + Closes #11670 -Dan Fandrich (19 Jun 2023) +trrui-huawei (15 Aug 2023) -- libtest: display the times after a test timeout error +- quiche: enable quiche to handle timeout events - This is to help with test failure debugging. + In parallel with ngtcp2, quiche also offers the `quiche_conn_on_timeout` + interface for the application to invoke upon timer + expiration. Therefore, invoking the `on_timeout` function of the + Connection is crucial to ensure seamless functionality of quiche with + timeout events. - Ref: #11328 - Closes #11329 + Closes #11654 -- test2600: bump a test timeout +- quiche: adjust quiche `QUIC_IDLE_TIMEOUT` to 60s - Case 1 failed at least once on GHA by going 30 msec too long. + Set the `QUIC_IDLE_TIMEOUT` parameter to match ngtcp2 for consistency. - Ref: #11328 +Daniel Stenberg (15 Aug 2023) -- runtests: better detect and handle pipe errors in the controller +- KNOWN_BUGS: LDAPS requests to ActiveDirectory server hang - Errors reading and writing to the pipes are now better detected and - propagated up to the main test loop so it can be cleanly shut down. Such - errors are usually due to a runner dying so it doesn't make much sense - to try to continue the test run. + Closes #9580 -- runtests: cleanly abort the runner if the controller dies +- imap: add a check for failing strdup() - If the controller dies unexpectedly, have the runner stop its servers - and exit cleanly. Otherwise, the orphaned servers will stay running in - the background. +- imap: remove the only sscanf() call in the IMAP code -- runtests: improve error logging + Avoids the use of a stack buffer. - Give more information about test harness error conditions to help figure - out what might be wrong. Print some internal test state when SIGUSR1 is - sent to runtests.pl. + Closes #11673 - Ref: #11328 +- imap: use a dynbuf in imap_atom -- runtests: better handle ^C during slow tests + Avoid a calculation + malloc. Build the output in a dynbuf. - Since the SIGINT handler now just sets a flag that must be checked in the - main controller loop, make sure that runs periodically. Rather than - blocking on a response from a test runner near the end of the test run, - add a short timeout to allow it. + Closes #11672 -- runtests: rename server command file +Marin Hannache (14 Aug 2023) - The name ftpserver.cmd was historical and has been used for more than - ftp for many years now. Rename it to plain server.cmd to reduce - confusion. +- http: do not require a user name when using CURLAUTH_NEGOTIATE -- tests: improve reliability of TFTP tests + In order to get Negotiate (SPNEGO) authentication to work in HTTP you + used to be required to provide a (fake) user name (this concerned both + curl and the lib) because the code wrongly only considered + authentication if there was a user name provided, as in: - Stop checking the timeout used by the client under test (for most - tests). The timeout will change if the TFTP test server is slow (such as - happens on an overprovisioned CI server) because the client will retry - and reduce its timeout, and the actual value is not important for most - tests. + curl -u : --negotiate https://example.com/ - test285 is changed a different way, by increasing the connect timeout. - This improves test coverage by allowing the changed timeout value to be - checked, but improves reliability with a carefully-chosen timeout that - not only allows twice the time to respond as before, but also allows - several retries before the client will change its timeout value. + This commit leverages the `struct auth` want member to figure out if the + user enabled CURLAUTH_NEGOTIATE, effectively removing the requirement of + setting a user name both in curl and the lib. - Ref: #11328 + Signed-off-by: Marin Hannache + Reported-by: Enrico Scholz + Fixes https://sourceforge.net/p/curl/bugs/440/ + Fixes #1161 + Closes #9047 -Daniel Stenberg (19 Jun 2023) +Viktor Szakats (13 Aug 2023) -- cf-socket: skip getpeername()/getsockname for TFTP +- build: streamline non-UWP wincrypt detections - Since the socket is not connected then the call fails. When the call - fails, failf() is called to write an error message that is then - surviving and is returned when the *real* error occurs later. The - earlier, incorrect, error therefore hides the actual error message. + - with CMake, use the variable `WINDOWS_STORE` to detect an UWP build + and disable our non-UWP-compatible use the Windows crypto API. This + allows to drop two dynamic feature checks. - This could be seen in stderr for test 1007 + `WINDOWS_STORE` is true when invoking CMake with + `CMAKE_SYSTEM_NAME` == `WindowsStore`. Introduced in CMake v3.1. - Test 1007 has now been extended to verify the stderr message. + Ref: https://cmake.org/cmake/help/latest/variable/WINDOWS_STORE.html - Closes #11332 + - with autotools, drop the separate feature check for `wincrypt.h`. On + one hand this header has been present for long (even Borland C 5.5 had + it from year 2000), on the other we used the check result solely to + enable another check for certain crypto functions. This fails anyway + with the header not present. We save one dynamic feature check at the + configure stage. -- example/crawler: make it use a few more options + Reviewed-by: Marcel Raad + Closes #11657 - For show, but reasonable +Nicholas Nethercote (13 Aug 2023) -- libcurl-ws.3: mention raw mode +- docs/HYPER.md: update hyper build instructions - Closes #11339 + Nightly Rust and `-Z unstable-options` are not needed. -- example/default-scheme: set the default scheme for schemeless URLs + The instructions here now match the hyper docs exactly: + https://github.com/hyperium/hyper/commit/bd7928f3dd6a8461f0f0fdf7ee0fd95c2f15 + 6f88 - Closes #11338 + Closes #11662 -- example/hsts-preload: show one way to HSTS preload +Daniel Stenberg (13 Aug 2023) - Closes #11337 +- RELEASE-NOTES: synced -- examples/http-options: show how to send "OPTIONS *" +- urlapi: CURLU_PUNY2IDN - convert from punycode to IDN name - With CURLOPT_REQUEST_TARGET. + Asssisted-by: Jay Satiro + Closes #11655 - Also add use of CURLOPT_QUICK_EXIT to show. +- spellcheck: adapt to backslashed minuses - Closes #11333 + As the curl.1 has more backslashed minus, the cleanup sed lines xneed to + adapt. -- examples: make use of CURLOPT_(REDIR_|)PROTOCOLS_STR + Adjusted some docs slighly. - To show how to use them + Follow-up to 439ff2052e - Closes #11334 + Closes #11663 -- examples/smtp-mime: use CURLOPT_MAIL_RCPT_ALLOWFAILS +- gen: escape more minus - For show + Detected since it was still hard to search for option names using dashes + in the middle in the man page. - Closes #11335 + Closes #11660 -- http: rectify the outgoing Cookie: header field size check +- cookie-jar.d: enphasize that this option is ONLY writing cookies - Previously it would count the size of the entire outgoing request and - not just the size of only the Cookie: header field - which was the - intention. + Reported-by: Dan Jacobson + Tweaked-by: Jay Satiro + Ref: #11642 + Closes #11661 - This could make the check be off by several hundred bytes in some cases. +Nicholas Nethercote (11 Aug 2023) - Closes #11331 +- docs/HYPER.md: document a workaround for a link error -Jay Satiro (17 Jun 2023) + Closes #11653 -- lib: fix some format specifiers +Jay Satiro (11 Aug 2023) - - Use CURL_FORMAT_CURL_OFF_T where %zd was erroneously used for some - curl_off_t variables. +- schannel: verify hostname independent of verify cert - - Use %zu where %zd was erroneously used for some size_t variables. + Prior to this change when CURLOPT_SSL_VERIFYPEER (verifypeer) was off + and CURLOPT_SSL_VERIFYHOST (verifyhost) was on we did not verify the + hostname in schannel code. - Prior to this change some of the Windows CI tests were failing because - in Windows 32-bit targets have a 32-bit size_t and a 64-bit curl_off_t. - When %zd was used for some curl_off_t variables then only the lower - 32-bits was read and the upper 32-bits would be read for part or all of - the next specifier. + This fixes KNOWN_BUG 2.8 "Schannel disable CURLOPT_SSL_VERIFYPEER and + verify hostname". We discussed a fix several years ago in #3285 but it + went stale. - Fixes https://github.com/curl/curl/issues/11327 - Closes https://github.com/curl/curl/pull/11321 + Assisted-by: Daniel Stenberg -Marcel Raad (16 Jun 2023) + Bug: https://curl.haxx.se/mail/lib-2018-10/0113.html + Reported-by: Martin Galvan -- test427: add `cookies` feature and keyword + Ref: https://github.com/curl/curl/pull/3285 - This test doesn't work with `--disable-cookies`. + Fixes https://github.com/curl/curl/issues/3284 + Closes https://github.com/curl/curl/pull/10056 - Closes https://github.com/curl/curl/pull/11320 +Daniel Stenberg (11 Aug 2023) -Chris Talbot (15 Jun 2023) +- curl_quiche: remove superfluous NULL check -- imap: Provide method to disable SASL if it is advertised + 'stream' is always non-NULL at this point - - Implement AUTH=+LOGIN for CURLOPT_LOGIN_OPTIONS to prefer plaintext - LOGIN over SASL auth. + Pointed out by Coverity - Prior to this change there was no method to be able to fall back to - LOGIN if an IMAP server advertises SASL capabilities. However, this may - be desirable for e.g. a misconfigured server. + Closes #11656 - Per: https://www.ietf.org/rfc/rfc5092.html#section-3.2 +- curl/urlapi.h: tiny typo - ";AUTH=" looks to be the correct way to specify what - authenication method to use, regardless of SASL or not. +- github/labeler: make HYPER.md set Hyper and not TLS - Closes https://github.com/curl/curl/pull/10041 +- docs/cmdline-opts/gen.pl: hide "added in" before 7.50.0 -Daniel Stenberg (15 Jun 2023) + 7.50.0 shipped on Jul 21 2016, over seven years ago. We no longer need + to specify version changes for earlier releases in the generated output. -- RELEASE-NOTES: synced + This ups the limit from the previous 7.30.0 (Apr 12 2013) -- examples/multi-debugcallback.c: avoid the bool typedef + This hides roughly 35 "added in" mentions. - Apparently this cannot be done in c23 + Closes #11651 - Reported-by: Cristian Rodríguez - Fixes #11299 - Closes #11319 +Jay Satiro (10 Aug 2023) -- docs/libcurl/libcurl.3: cleanups and improvements +- bug_report: require reporters to specify curl and os versions - Closes #11317 + - Change curl version and os sections from single-line input to + multi-line textarea. -- libcurl-ws.3: fix typo + - Require curl version and os sections to be filled out before report + can be submitted. -- curl_ws_*.3: enhance + Closes https://github.com/curl/curl/pull/11636 - - all: SEE ALSO the libcurl-ws man page - - send: add example and return value information - - meta: mention that the returned data is read-only +Daniel Stenberg (9 Aug 2023) - Closes #11318 +- gen.pl: replace all single quotes with aq -- docs/libcurl/libcurl-ws.3: see also CURLOPT_WS_OPTIONS + - this prevents man from using a unicode sequence for them + - which then allows search to work properly -- docs/libcurl/libcurl-ws.3: minor polish + Closes #11645 -- libcurl-ws.3. WebSocket API overview +Viktor Szakats (9 Aug 2023) - Closes #11314 +- cmake: fix to use variable for the curl namespace -- libcurl-url.3: also mention CURLUPART_ZONEID + Replace (wrong) literal with a variable to specify the curl + namespace. - ... and sort the two part-using lists alphabetically + Follow-up to 1199308dbc902c52be67fc805c72dd2582520d30 #11505 -Marcel Raad (14 Jun 2023) + Reported-by: balikalina on Github + Fixes https://github.com/curl/curl/commit/1199308dbc902c52be67fc805c72dd25825 + 20d30#r123923098 + Closes #11629 -- fopen: fix conversion warning on 32-bit Android +- cmake: allow `SHARE_LIB_OBJECT=ON` on all platforms - When building for 32-bit ARM or x86 Android, `st_mode` is defined as - `unsigned int` instead of `mode_t`, resulting in a - -Wimplicit-int-conversion clang warning because `mode_t` is - `unsigned short`. Add a cast to silence the warning. + 2ebc74c36a19a1700af394c16855ce144d9878e3 #11546 introduced sharing + libcurl objects for shared and static targets. - Ref: https://android.googlesource.com/platform/bionic/+/refs/tags/ndk-r25c/li - bc/include/sys/stat.h#86 - Closes https://github.com/curl/curl/pull/11313 + The above automatically enabled for Windows builds, with an option to + disable with `SHARE_LIB_OBJECT=OFF`. -- http2: fix variable type + This patch extend this feature to all platforms as a manual option. + You can enable it by setting `SHARE_LIB_OBJECT=ON`. Then shared objects + are built in PIC mode, meaning the static lib will also have PIC code. - `max_recv_speed` is `curl_off_t`, so using `size_t` might result in - -Wconversion GCC warnings for 32-bit `size_t`. Visible in the NetBSD - ARM autobuilds. + [EXPERIMENTAL] - Closes https://github.com/curl/curl/pull/11312 + Closes #11627 -Daniel Stenberg (13 Jun 2023) +- cmake: assume `wldap32` availability on Windows -- vtls: fix potentially uninitialized local variable warnings + This system library first shipped with Windows ME, available as an extra + install for some older releases (according to [1]). The import library + was present already in old MinGW 3.4.2 (year 2007). - Follow-up from a4a5e438ae533c + Drop the feature check and its associated `HAVE_WLDAP32` variable. - Closes #11310 + To manually disable `wldap32`, you can use the `USE_WIN32_LDAP=OFF` + CMake option, like before. -- timeval: use CLOCK_MONOTONIC_RAW if available + [1]: https://dlcdn.apache.org/httpd/binaries/win32/LEGACY.html - Reported-by: Harry Sintonen - Ref: #11288 - Closes #11291 + Reviewed-by: Jay Satiro + Closes #11624 -Stefan Eissing (12 Jun 2023) +Daniel Stenberg (9 Aug 2023) -- tool: add curl command line option `--trace-ids` +- page-header: move up a URL paragraph from GLOBBING to URL - - added and documented --trace-ids to prepend (after the timestamp) - the transfer and connection identifiers to each verbose log line - - format is [n-m] with `n` being the transfer id and `m` being the - connection id. In case there is not valid connection id, print 'x'. - - Log calls with a handle that has no transfer id yet, are written - without any ids. +- variable.d: output the function names table style - Closes #11185 + Also correct the url function name in the header -- lib: add CURLINFO_CONN_ID and CURLINFO_XFER_ID + Closes #11641 - - add an `id` long to Curl_easy, -1 on init - - once added to a multi (or its own multi), it gets - a non-negative number assigned by the connection cache - - `id` is unique among all transfers using the same - cache until reaching LONG_MAX where it will wrap - around. So, not unique eternally. - - CURLINFO_CONN_ID returns the connection id attached to - data or, if none present, data->state.lastconnect_id - - variables and type declared in tool for write out +- haproxy-clientip.d: remove backticks - Closes #11185 + This is not markdown -Daniel Stenberg (12 Jun 2023) + Follow-up to 0a75964d0d94a4 -- CURLOPT_INFILESIZE.3: mention -1 triggers chunked + Closes #11639 - Ref: #11300 - Closes #11304 +- RELEASE-NOTES: synced -Philip Heiduck (12 Jun 2023) +- gen.pl: escape all dashes (ascii minus) to avoid unicode hyphens -- CI: openssl-3.0.9+quic + Reported-by: FC Stegerman + Fixes #11635 + Closes #11637 - Closes #11296 +- cmdline-opts/page-header: reorder, clean up -Karthikdasari0423 (12 Jun 2023) + - removed some unnecessary blurb to focus + - moved up the more important URL details + - put "globbing" into its own subtitle and moved down a little + - mention the online man page in the version section -- HTTP3.md: update openssl version + Closes #11638 - Closes #11297 +- c-hyper: adjust the hyper to curlcode conversion -Daniel Stenberg (12 Jun 2023) + Closes #11621 -- vtls: avoid memory leak if sha256 call fails +- test2306: make it use a persistent connection - ... in the pinned public key handling function. + + enable verbose already from the start - Reported-by: lizhuang0630 on github - Fixes #11306 - Closes #11307 + Closes #11621 -- examples/ipv6: disable on win32 +eppesuig (8 Aug 2023) - I can't make if_nametoindex() work there +- list-only.d: mention SFTP as supported protocol - Follow-up to c23dc42f3997acf23 + Closes #11628 - Closes #11305 +Daniel Stenberg (8 Aug 2023) -- tool_operate: allow cookie lines up to 8200 bytes +- request.d: use .TP for protocol "labels" - Since this option might set multiple cookies in the same line, it does - not make total sense to cap this at 4096 bytes, which is the limit for a - single cookie name or value. + To render the section nicer in man page. - Closes #11303 + Closes #11630 -- test427: verify sending more cookies than fit in a 8190 bytes line +- cf-haproxy: make CURLOPT_HAPROXY_CLIENT_IP set the *source* IP - curl will then only populate the header with cookies that fit, dropping - ones that otherwise would have been sent + ... as documented. - Ref: https://curl.se/mail/lib-2023-06/0020.html + Update test 3201 and 3202 accordingly. - Closes #11303 + Reported-by: Markus Sommer + Fixes #11619 + Closes #11626 -- testutil: allow multiple %-operators on the same line +- page-footer: QLOGDIR works with ngtcp2 and quiche - Closes #11303 + It previously said "both" backends which is confusing as we currently + have three... -Oleg Jukovec (12 Jun 2023) + Closes #11631 -- docs: update CURLOPT_UPLOAD.3 +Stefan Eissing (8 Aug 2023) - The behavior of CURLOPT_UPLOAD differs from what is described in the - documentation. The option automatically adds the 'Transfer-Encoding: - chunked' header if the upload size is unknown. +- http3: quiche, handshake optimization, trace cleanup - Closes #11300 + - load x509 store after clienthello + - cleanup of tracing -Daniel Stenberg (12 Jun 2023) + Closes #11618 -- RELEASE-NOTES: synced +Daniel Stenberg (8 Aug 2023) -- CURLOPT_AWS_SIGV4.3: remove unused variable from example +- ngtcp2: remove dead code - Closes #11302 + 'result' is always zero (CURLE_OK) at this point -- examples/https.c: use CURLOPT_CA_CACHE_TIMEOUT + Detected by Coverity - for demonstration purposes + Closes #11622 - Closes #11290 +Viktor Szakats (8 Aug 2023) -- example/ipv6: feature CURLOPT_ADDRESS_SCOPE in use +- openssl: auto-detect `SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED` - Closes #11282 + OpenSSL 1.1.1 defines this macro, but no ealier version, or any of the + popular forks (yet). Use the macro itself to detect its presence, + replacing the hard-wired fork-specific conditions. -Karthikdasari0423 (10 Jun 2023) + This way the feature will enable automatically when forks implement it, + while also shorter and possibly requiring less future maintenance. -- docs: Update HTTP3.md for newer ngtcp2 and nghttp3 + Follow-up to 94241a9e78397a2aaf89a213e6ada61e7de7ee02 #6721 - Follow-up to fb9b9b58 + Reviewed-by: Jay Satiro + Closes #11617 - Ref: #11184 - Closes #11295 +- openssl: use `SSL_CTX_set_ciphersuites` with LibreSSL 3.4.1 -Dan Fandrich (10 Jun 2023) + LibreSSL 3.4.1 (2021-10-14) added support for + `SSL_CTX_set_ciphersuites`. -- docs: update the supported ngtcp2 and nghttp3 versions + Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.4.1-relnotes.txt - Follow-up to cae9d10b + Reviewed-by: Jay Satiro + Closes #11616 - Ref: #11184 - Closes #11294 +- openssl: use `SSL_CTX_set_keylog_callback` with LibreSSL 3.5.0 -- tests: fix error messages & handling around sockets + LibreSSL 3.5.0 (2022-02-24) added support for + `SSL_CTX_set_keylog_callback`. - The wrong error code was checked on Windows on UNIX socket failures, - which could have caused all UNIX sockets to be reported as having - errored and the tests therefore skipped. Also, a useless error message - was displayed on socket errors in many test servers on Windows because - strerror() doesn't work on WinSock error codes; perror() is overridden - there to work on all errors and is used instead. + Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0-relnotes.txt - Ref #11258 - Closes #11265 + Reviewed-by: Jay Satiro + Closes #11615 -Daniel Stenberg (9 Jun 2023) +- cmake: drop `HAVE_LIBWINMM` and `HAVE_LIBWS2_32` feature checks -- CURLOPT_SSH_PRIVATE_KEYFILE.3: expand on the file search + - `HAVE_LIBWINMM` was detected but unused. The `winmm` system library is + also not used by curl, but it is by its optional dependency `librtmp`. + Change the logic to always add `winmm` when `USE_LIBRTMP` is set. This + library has been available since the early days of Windows. - Reported-by: atjg on github - Ref: #11287 - Closes #11289 + - `HAVE_LIBWS2_32` detected `ws2_32` lib on Windows. This lib is present + since Windows 95 OSR2 (AFAIR). Winsock1 already wasn't supported and + other existing logic already assumed this lib being present, so delete + the check and replace the detection variable with `WIN32` and always + add `ws2_32` on Windows. -Stefan Eissing (9 Jun 2023) + Closes #11612 -- ngtcp2: use ever increasing timestamp in io +Daniel Gustafsson (8 Aug 2023) - - ngtcp2 v0.16.0 asserts that timestamps passed to its function - will only ever increase. - - Use a context shared between ingress/egress operations that - uses a shared timestamp, regularly updated during calls. +- crypto: ensure crypto initialization works - Closes #11288 + Make sure that context initialization during hash setup works to avoid + going forward with the risk of a null pointer dereference. -Daniel Stenberg (9 Jun 2023) + Reported-by: Philippe Antoine on HackerOne + Assisted-by: Jay Satiro + Assisted-by: Daniel Stenberg -- GHA: use nghttp2 1.54.0 for the ngtcp2 jobs + Closes #11614 -Philip Heiduck (9 Jun 2023) +Viktor Szakats (7 Aug 2023) -- GHA: ngtcp2: use 0.16.0 and nghttp3 0.12.0 +- openssl: switch to modern init for LibreSSL 2.7.0+ -Daniel Stenberg (9 Jun 2023) + LibreSSL 2.7.0 (2018-03-21) introduced automatic initialization, + `OPENSSL_init_ssl()` function and deprecated the old, manual init + method, as seen in OpenSSL 1.1.0. Switch to the modern method when + available. -- ngtcp2: build with 0.16.0 and nghttp3 0.12.0 + Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.7.0-relnotes.txt - - moved to qlog_write - - crypto => encryption - - CRYPTO => ENCRYPTION - - removed "_is_" - - ngtcp2_conn_shutdown_stream_read and - ngtcp2_conn_shutdown_stream_write got flag arguments - - the nghttp3_callbacks struct got a recv_settings callback + Reviewed-by: Daniel Stenberg + Closes #11611 - Closes #11184 +Daniel Stenberg (7 Aug 2023) -- example/http2-download: set CURLOPT_BUFFERSIZE +- gskit: remove - Primarily because no other example sets it, and remove the disabling of - the certificate check because we should not recommend that. + We remove support for building curl with gskit. - Closes #11284 + - This is a niche TLS library, only running on some IBM systems + - no regular curl contributors use this backend + - no CI builds use or verify this backend + - gskit, or the curl adaption for it, lacks many modern TLS features + making it an inferior solution + - build breakages in this code take weeks or more to get detected + - fixing gskit code is mostly done "flying blind" -- example/crawler: also set CURLOPT_AUTOREFERER + This removal has been advertized in DEPRECATED in Jan 2, 2023 and it has + been mentioned on the curl-library mailing list. - Could make sense, and it was not used in any example before. + It could be brought back, this is not a ban. Given proper effort and + will, gskit support is welcome back into the curl TLS backend family. - Closes #11283 + Closes #11460 -Wyatt OʼDay (9 Jun 2023) +- RELEASE-NOTES: synced -- tls13-ciphers.d: include Schannel +Dan Fandrich (7 Aug 2023) - Closes #11271 +- THANKS-filter: add a name typo -Daniel Stenberg (9 Jun 2023) +Stefan Eissing (7 Aug 2023) -- curl_pushheader_byname/bynum.3: document in their own man pages +- http3/ngtcp2: shorten handshake, trace cleanup - These two functions were added in 7.44.0 when CURLMOPT_PUSHFUNCTION was - introduced but always lived a life in the shadows, embedded in the - CURLMOPT_PUSHFUNCTION man page. Until now. + - shorten handshake timing by delayed x509 store load (OpenSSL) + as we do for HTTP/2 + - cleanup of trace output, align with HTTP/2 output - It makes better sense and gives more visibility to document them in - their own stand-alone man pages. + Closes #11609 - Closes #11286 +Daniel Stenberg (7 Aug 2023) -- curl_mprintf.3: minor fix of the example +- headers: accept leading whitespaces on first response header -- curl_url_set: enforce the max string length check for all parts + This is a bad header fold but since the popular browsers accept this + violation, so does curl now. Unless built with hyper. - Update the docs and test 1559 accordingly + Add test 1473 to verify and adjust test 2306. - Closes #11273 + Reported-by: junsik on github + Fixes #11605 + Closes #11607 -- examples/ftpuploadresume.c: add use of CURLOPT_ACCEPTTIMEOUT_MS +- include/curl/mprintf.h: add __attribute__ for the prototypes - For show + - if gcc or clang is used + - if __STDC_VERSION__ >= 199901L, which means greater than C90 + - if not using mingw + - if CURL_NO_FMT_CHECKS is not defined - Closes #11277 + Closes #11589 -- examples/unixsocket.c: example using CURLOPT_UNIX_SOCKET_PATH +- tests: fix bad printf format flags in test code - and alternatively CURLOPT_ABSTRACT_UNIX_SOCKET +- tests: fix header scan tools for attribute edits in mprintf.h - Closes #11276 +- cf-socket: log successful interface bind -Anssi Kolehmainen (8 Jun 2023) + When the setsockopt SO_BINDTODEVICE operation succeeds, output that in + the verbose output. -- docs: fix missing parameter names in examples + Ref: #11599 + Closes #11608 - Closes #11278 +- CURLOPT_SSL_VERIFYPEER.3: mention it does not load CA certs when disabled -Daniel Stenberg (8 Jun 2023) + Ref: #11457 + Closes #11606 -- urlapi: have *set(PATH) prepend a slash if one is missing +- CURLOPT_SSL_VERIFYPEER.3: add two more see also options - Previously the code would just do that for the path when extracting the - full URL, which made a subsequent curl_url_get() of the path to - (unexpectedly) still return it without the leading path. + CURLINFO_CAINFO and CURLINFO_CAPATH - Amend lib1560 to verify this. Clarify the curl_url_set() docs about it. + Closes #11603 - Bug: https://curl.se/mail/lib-2023-06/0015.html - Closes #11272 - Reported-by: Pedro Henrique +- KNOWN_BUGS: aws-sigv4 does not behave well with AWS VPC Lattice -Dan Fandrich (7 Jun 2023) + Closes #11007 -- runtests; give each server a unique log lock file +Graham Campbell (6 Aug 2023) - Logs are written by several servers and all of them must be finished - writing before the test results can be determined. This means each - server must have its own lock file rather than sharing a single one, - which is how it was done up to now. Previously, the first server to - complete a test would clear the lock before the other server was done, - which caused flaky tests. +- CI: use openssl 3.0.10+quic, nghttp3 0.14.0, ngtcp2 0.18.0 - Lock files are now all found in their own directory, so counting locks - equals counting the files in that directory. The result is that the - proxy logs are now reliably written which actually changes the expected - output for two tests. + Closes #11585 - Fixes #11231 - Closes #11259 +Daniel Stenberg (6 Aug 2023) -- runtests: make test file directories in log/N +- TODO: add *5* entries for aws-sigv4 - Test files in subdirectories were not created after parallel test log - directories were moved down a level due to a now-bad comparison. + Closes #7559 + Closes #8107 + Closes #8810 + Closes #9717 + Closes #10129 - Follow-up to 92d7dd39 +- TODO: LDAP Certificate-Based Authentication - Ref #11264 - Closes #11267 + Closes #9641 -Daniel Stenberg (7 Jun 2023) +Stefan Eissing (6 Aug 2023) -- ws: make the curl_ws_meta() return pointer a const +- http2: cleanup trace messages - The returned info is read-only for the user. + - more compact format with bracketed stream id + - all frames traced in and out - Closes #11261 + Closes #11592 -- RELEASE-NOTES: synced +Daniel Stenberg (6 Aug 2023) -- runtests: move parallel log dirs from logN to log/N +- tests/tftpd+mqttd: make variables static to silence picky warnings - Having several hundreds of them in there gets annoying. + Closes #11594 - Closes #11264 +- docs/cmdline: remove repeated working for negotiate + ntlm -Dan Fandrich (7 Jun 2023) + The extra wording is added automatically by the gen.pl tool -- test447: move the test file into %LOGDIR + Closes #11597 -Viktor Szakats (7 Jun 2023) +- docs/cmdline: add small "warning" to verbose options -- cmake: add support for "unity" builds + "Note that verbose output of curl activities and network traffic might + contain sensitive data, including user names, credentials or secret data + content. Be aware and be careful when sharing trace logs with others." - Aka "jumbo" or "amalgamation" builds. It means to compile all sources - per target as a single C source. This is experimental. + Closes #11596 - You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. - It requires CMake 3.16 or newer. +- RELEASE-NOTES: synced - It makes builds (much) faster, allows for better optimizations and tends - to promote less ambiguous code. +- pingpong: don't use *bump_headersize - Also add a new AppVeyor CI job and convert an existing one to use - "unity" mode (one MSVC, one MinGW), and enable it for one macOS CI job. + We use that for HTTP(S) only. - Fix related issues: - - add missing include guard to `easy_lock.h`. - - rename static variables and functions (and a macro) with names reused - across sources, or shadowed by local variables. - - add an `#undef` after use. - - add a missing `#undef` before use. - - move internal definitions from `ftp.h` to `ftp.c`. - - `curl_memory.h` fixes to make it work when included repeatedly. - - stop building/linking curlx bits twice for a static-mode curl tool. - These caused doubly defined symbols in unity builds. - - silence missing extern declarations compiler warning for ` _CRT_glob`. - - fix extern declarations for `tool_freq` and `tool_isVistaOrGreater`. - - fix colliding static symbols in debug mode: `debugtime()` and - `statename`. - - rename `ssl_backend_data` structure to unique names for each - TLS-backend, along with the `ssl_connect_data` struct member - referencing them. This required adding casts for each access. - - add workaround for missing `[P]UNICODE_STRING` types in certain Windows - builds when compiling `lib/ldap.c`. To support "unity" builds, we had - to enable `SCHANNEL_USE_BLACKLISTS` for Schannel (a Windows - `schannel.h` option) _globally_. This caused an indirect inclusion of - Windows `schannel.h` from `ldap.c` via `winldap.h` to have it enabled - as well. This requires `[P]UNICODE_STRING` types, which is apperantly - not defined automatically (as seen with both MSVS and mingw-w64). - This patch includes `` to fix it. - Ref: https://github.com/curl/curl/runs/13987772013 - Ref: https://dev.azure.com/daniel0244/curl/_build/results?buildId=15827&vie - w=logs&jobId=2c9f582d-e278-56b6-4354-f38a4d851906&j=2c9f582d-e278-56b6-4354-f - 38a4d851906&t=90509b00-34fa-5a81-35d7-5ed9569d331c - - tweak unity builds to compile `lib/memdebug.c` separately in memory - trace builds to avoid PP confusion. - - force-disable unity for test programs. - - do not compile and link libcurl sources to libtests _twice_ when libcurl - is built in static mode. + Follow-up to 3ee79c1674fd6 - KNOWN ISSUES: - - running tests with unity builds may fail in cases. - - some build configurations/env may not compile in unity mode. E.g.: - https://ci.appveyor.com/project/curlorg/curl/builds/47230972/job/51wfesgnfu - auwl8q#L250 + Closes #11590 - Ref: https://github.com/libssh2/libssh2/issues/1034 - Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html - Ref: https://en.wikipedia.org/wiki/Unity_build +- urldata: remove spurious parenthesis to unbreak no-proxy build - Closes #11095 + Follow-up to e12b39e13382 -Daniel Stenberg (7 Jun 2023) + Closes #11591 -- examples/websocket.c: websocket example using CONNECT_ONLY +- easy: don't call Curl_trc_opt() in disabled-verbose builds - Closes #11262 + Follow-up to e12b39e133822c6a0 -- websocket-cb: example doing WebSocket download using callback + Closes #11588 - Very basic +- http: use %u for printfing int - Closes #11260 + Follow-up to 3ee79c1674fd6f99e8efca5 -- test/.gitignore: ignore log* + Closes #11587 -Dan Fandrich (5 Jun 2023) +Goro FUJI (3 Aug 2023) -- runtests: document the -j parallel testing option +- vquic: show stringified messages for errno - Reported-by: Daniel Stenberg - Ref: #10818 - Closes #11255 + Closes #11584 -- runtests: create multiple test runners when requested +Stefan Eissing (3 Aug 2023) - Parallel testing is enabled by using a nonzero value for the -j option - to runtests.pl. Performant values seem to be about 7*num CPU cores, or - 1.3*num CPU cores if Valgrind is in use. +- trace: make tracing available in non-debug builds - Flaky tests due to improper log locking (bug #11231) are exacerbated - while parallel testing, so it is not enabled by default yet. + Add --trace-config to curl - Fixes #10818 - Closes #11246 + Add curl_global_trace() to libcurl -- runtests: handle repeating tests in multiprocess mode + Closes #11421 - Such as what happens with the --repeat option. Some functions are - changed to pass the runner ID instead of relying on the non-unique test - number. +Daniel Stenberg (3 Aug 2023) - Ref: #10818 +- TODO: remove "Support intermediate & root pinning for PINNEDPUBLICKEY" -- runtests: buffer logmsg while running singletest() + See also https://github.com/curl/curl/pull/7507 - This allows all messages relating to a single test case to be displayed - together at the end of the test. +- TODO: add "WebSocket read callback" - Ref: #10818 + remove "Upgrade to websockets" as we already have this -- runtests: call initserverconfig() in the runner + Closes #11402 - This must be done so variables pick up the runner's unique $LOGDIR. +- test497: verify rejecting too large incoming headers - Ref: #10818 +- http: return error when receiving too large header set -- runtests: use a per-runner random seed + To avoid abuse. The limit is set to 300 KB for the accumulated size of + all received HTTP headers for a single response. Incomplete research + suggests that Chrome uses a 256-300 KB limit, while Firefox allows up to + 1MB. - Each runner needs a unique random seed to reduce the chance of port - number collisions. The new scheme uses a consistent per-runner source of - randomness which results in deterministic behaviour, as it did before. + Closes #11582 - Ref: #10818 +Stefan Eissing (3 Aug 2023) -- runtests: complete main test loop refactor for multiple runners +- http2: upgrade tests and add fix for non-existing stream - The main test loop is now able to handle multiple runners, or no - additional runner processes at all. At most one process is still - created, however. + - check in h2 filter recv that stream actually exists + and return error if not + - add test for parallel, extreme h2 upgrades that fail if + connections get reused before fully switched + - add h2 upgrade upload test just for completeness - Ref: #10818 + Closes #11563 -- runtests: prepare main test loop for multiple runners +Viktor Szakats (3 Aug 2023) - Some variables are expanded to arrays and hashes so that multiple - runners can be used for running tests. +- tests: ensure `libcurl.def` contains all exports - Ref: #10818 + Add `test1279` to verify that `libcurl.def` lists all exported API + functions found in libcurl headers. -Stefan Eissing (5 Jun 2023) + Also: -- bufq: make write/pass methods more robust + - extend test suite XML `stdout` tag with the `loadfile` attribute. - - related to #11242 where curl enters busy loop when - sending http2 data to the server + - fix `tests/extern-scan.pl` and `test1135` to include websocket API. - Closes #11247 + - use all headers (sorted) in `test1135` instead of a manual list. -Boris Verkhovskiy (5 Jun 2023) + - add options `--sort`, `--heading=` to `tests/extern-scan.pl`. -- tool_getparam: fix comment + - add `libcurl.def` to the auto-labeler GHA task. - Closes #11253 + Follow-up to 2ebc74c36a19a1700af394c16855ce144d9878e3 -Raito Bezarius (5 Jun 2023) + Closes #11570 -- haproxy: add --haproxy-clientip flag to spoof client IPs +Daniel Stenberg (2 Aug 2023) - CURLOPT_HAPROXY_CLIENT_IP in the library +- url: change default value for CURLOPT_MAXREDIRS to 30 - Closes #10779 + It was previously unlimited by default, but that's not a sensible + default. While changing this has a remote risk of breaking an existing + use case, I figure it is more likely to actually save users from loops. -Daniel Stenberg (5 Jun 2023) + Closes #11581 -- curl: add --ca-native and --proxy-ca-native +- lib: fix a few *printf() flag mistakes - These are two boolean options to ask curl to use the native OS's CA - store when verifying TLS servers. For peers and for proxies - respectively. + Reported-by: Gisle Vanem + Ref: #11574 + Closes #11579 - They currently only have an effect for curl on Windows when built to use - OpenSSL for TLS. +Samuel Chiang (2 Aug 2023) - Closes #11049 +- openssl: make aws-lc version support OCSP -Viktor Szakats (5 Jun 2023) + And bump version in CI -- build: drop unused/redundant `HAVE_WINLDAP_H` + Closes #11568 - Sources did not use it. Autotools used it when checking for the - `winldap` library, which is redundant. +Daniel Stenberg (2 Aug 2023) - With CMake, detection was broken: - ``` - Run Build Command(s):/usr/local/Cellar/cmake/3.26.3/bin/cmake -E env VERBOSE= - 1 /usr/bin/make -f Makefile cmTC_2d8fe/fast && /Library/Developer/CommandLine - Tools/usr/bin/make -f CMakeFiles/cmTC_2d8fe.dir/build.make CMakeFiles/cmTC_2 - d8fe.dir/build - Building C object CMakeFiles/cmTC_2d8fe.dir/HAVE_WINLDAP_H.c.obj - /usr/local/opt/llvm/bin/clang --target=x86_64-w64-mingw32 --sysroot=/usr/loca - l/opt/mingw-w64/toolchain-x86_64 -D_WINSOCKAPI_="" -I/my/quictls/x64-ucrt/usr - /include -I/my/zlib/x64-ucrt/usr/include -I/my/brotli/x64-ucrt/usr/include -W - no-unused-command-line-argument -D_UCRT -DCURL_HIDDEN_SYMBOLS -DHAVE_SSL_SE - T0_WBIO -DHAS_ALPN -DNGHTTP2_STATICLIB -DNGHTTP3_STATICLIB -DNGTCP2_STATICLIB - -DUSE_MANUAL=1 -fuse-ld=lld -Wl,-s -static-libgcc -lucrt -Wextra -Wall -p - edantic -Wbad-function-cast -Wconversion -Winline -Wmissing-declarations -Wmi - ssing-prototypes -Wnested-externs -Wno-long-long -Wno-multichar -Wpointer-ari - th -Wshadow -Wsign-compare -Wundef -Wunused -Wwrite-strings -Wcast-align -Wde - claration-after-statement -Wempty-body -Wendif-labels -Wfloat-equal -Wignored - -qualifiers -Wno-format-nonliteral -Wno-sign-conversion -Wno-system-headers - - Wstrict-prototypes -Wtype-limits -Wvla -Wshift-sign-overflow -Wshorten-64-to- - 32 -Wdouble-promotion -Wenum-conversion -Wunused-const-variable -Wcomma -Wmis - sing-variable-declarations -Wassign-enum -Wextra-semi-stmt -MD -MT CMakeFile - s/cmTC_2d8fe.dir/HAVE_WINLDAP_H.c.obj -MF CMakeFiles/cmTC_2d8fe.dir/HAVE_WINL - DAP_H.c.obj.d -o CMakeFiles/cmTC_2d8fe.dir/HAVE_WINLDAP_H.c.obj -c /my/curl/b - ld-cmake-llvm-x64-shared/CMakeFiles/CMakeScratch/TryCompile-3JP6dR/HAVE_WINLD - AP_H.c - In file included from /my/curl/bld-cmake-llvm-x64-shared/CMakeFiles/CMakeScra - tch/TryCompile-3JP6dR/HAVE_WINLDAP_H.c:2: - In file included from /usr/local/opt/mingw-w64/toolchain-x86_64/x86_64-w64-mi - ngw32/include/winldap.h:17: - In file included from /usr/local/opt/mingw-w64/toolchain-x86_64/x86_64-w64-mi - ngw32/include/schnlsp.h:9: - In file included from /usr/local/opt/mingw-w64/toolchain-x86_64/x86_64-w64-mi - ngw32/include/schannel.h:10: - /usr/local/opt/mingw-w64/toolchain-x86_64/x86_64-w64-mingw32/include/wincrypt - .h:5041:254: error: unknown type name 'PSYSTEMTIME' - WINIMPM PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate (HCRYPTPROV_OR_ - NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey, PCERT_NAME_BLOB pSubjectIssuerBlob, - DWORD dwFlags, PCRYPT_KEY_PROV_INFO pKeyProvInfo, PCRYPT_ALGORITHM_IDENTIFIER - pSignatureAlgorithm, PSYSTEMTIME pStartTime, PSYSTEMTIME pEndTime, PCERT_EXT - ENSIONS pExtensions); - - - - ^ - /usr/local/opt/mingw-w64/toolchain-x86_64/x86_64-w64-mingw32/include/wincrypt - .h:5041:278: error: unknown type name 'PSYSTEMTIME' - WINIMPM PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate (HCRYPTPROV_OR_ - NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey, PCERT_NAME_BLOB pSubjectIssuerBlob, - DWORD dwFlags, PCRYPT_KEY_PROV_INFO pKeyProvInfo, PCRYPT_ALGORITHM_IDENTIFIER - pSignatureAlgorithm, PSYSTEMTIME pStartTime, PSYSTEMTIME pEndTime, PCERT_EXT - ENSIONS pExtensions); - - - - ^ - 2 errors generated. - make[1]: *** [CMakeFiles/cmTC_2d8fe.dir/HAVE_WINLDAP_H.c.obj] Error 1 - make: *** [cmTC_2d8fe/fast] Error 2 - exitCode: 2 - ``` +- tool: make the length argument an int for printf()-.* flags - Cherry-picked from #11095 88e4a21ff70ccef391cf99c8165281ff81374503 - Reviewed-by: Daniel Stenberg - Closes #11245 + Closes #11578 -Daniel Stenberg (5 Jun 2023) +- tool_operate: fix memory leak when SSL_CERT_DIR is used -- urlapi: scheme starts with alpha + Detected by Coverity - Add multiple tests to lib1560 to verify + Follow-up to 29bce9857a12b6cfa726a5 - Fixes #11249 - Reported-by: ad0p on github - Closes #11250 + Closes #11577 -- RELEASE-NOTES: synced +- tool/var: free memory on OOM -- CURLOPT_MAIL_RCPT_ALLOWFAILS: replace CURLOPT_MAIL_RCPT_ALLLOWFAILS + Coverity detected this memory leak in OOM situation - Deprecate the name using three Ls and prefer the name with two. + Follow-up to 2e160c9c652504e - Replaces #10047 - Closes #11218 + Closes #11575 -- tests/servers: generate temp names in /tmp for unix domain sockets +Viktor Szakats (2 Aug 2023) - ... instead of putting them in the regular pid directories because - systems generally have strict length requirements for the path name to - be shorter than 107 bytes and we easily hit that boundary otherwise. +- gha: bump libressl and mbedtls versions - The new concept generates two random names: one for the socks daemon and - one for http. + Closes #11573 - Reported-by: Andy Fiddaman - Fixes #11152 - Closes #11166 +Jay Satiro (2 Aug 2023) -Stefan Eissing (2 Jun 2023) +- schannel: fix user-set legacy algorithms in Windows 10 & 11 -- http2: better support for --limit-rate + - If the user set a legacy algorithm list (CURLOPT_SSL_CIPHER_LIST) then + use the SCHANNEL_CRED legacy structure to pass the list to Schannel. - - leave transfer loop when --limit-rate is in effect and has - been received - - adjust stream window size to --limit-rate plus some slack - to make the server observe the pacing we want - - add test case to confirm behaviour + - If the user set both a legacy algorithm list and a TLS 1.3 cipher list + then abort. - Closes #11115 + Although MS doesn't document it, Schannel will not negotiate TLS 1.3 + when SCHANNEL_CRED is used. That means setting a legacy algorithm list + limits the user to earlier versions of TLS. -- curl_log: evaluate log statement only when transfer is verbose + Prior to this change, since 8beff435 (precedes 7.85.0), libcurl would + ignore legacy algorithms in Windows 10 1809 and later. - Closes #11238 + Reported-by: zhihaoy@users.noreply.github.com -Daniel Stenberg (2 Jun 2023) + Fixes https://github.com/curl/curl/pull/10741 + Closes https://github.com/curl/curl/pull/10746 -- libssh2: provide error message when setting host key type fails +Daniel Stenberg (2 Aug 2023) - Ref: https://curl.se/mail/archive-2023-06/0001.html +- variable.d: setting a variable again overwrites it - Closes #11240 + Reported-by: Niall McGee + Bug: https://twitter.com/niallmcgee/status/1686523075423322113 + Closes #11571 -Igor Todorovski (2 Jun 2023) +Jay Satiro (2 Aug 2023) -- system.h: remove __IBMC__/__IBMCPP__ guards and apply to all z/OS compiles +- CURLOPT_PROXY_SSL_OPTIONS.3: sync formatting - Closes #11241 + - Re-wrap CURLSSLOPT_ALLOW_BEAST description. -Daniel Stenberg (2 Jun 2023) +Daniel Stenberg (2 Aug 2023) -- docs/SECURITY-PROCESS.md: link to example of previous critical flaw +- RELEASE-NOTES: synced -Mark Seuffert (2 Jun 2023) +- resolve: use PF_INET6 family lookups when CURL_IPRESOLVE_V6 is set -- README.md: updated link to opencollective + Previously it would always do PF_UNSPEC if CURL_IPRESOLVE_V4 is not + used, thus unnecessarily asking for addresses that will not be used. - Closes #11232 + Reported-by: Joseph Tharayil + Fixes #11564 + Closes #11565 -Daniel Stenberg (1 Jun 2023) +- docs: link to the website versions instead of markdowns -- libssh2: use custom memory functions + ... to make the links work when the markdown is converted to webpages on + https://curl.se - Because of how libssh2_userauth_keyboard_interactive_ex() works: the - libcurl callback allocates memory that is later free()d by libssh2, we - must set the custom memory functions. + Reported-by: Maurício Meneghini Fauth + Fixes https://github.com/curl/curl-www/issues/272 + Closes #11569 - Reverts 8b5f100db388ee60118c08aa28 +Viktor Szakats (1 Aug 2023) - Ref: https://github.com/libssh2/libssh2/issues/1078 - Closes #11235 +- cmake: cache more config and delete unused ones -- test447: test PUTting a file that grows + - cache more Windows config results for faster initialization. - ... and have curl trim the end when it reaches the expected total amount - of bytes instead of over-sending. + - delete unused config macros `HAVE_SYS_UTSNAME_H`, `HAVE_SSL_H`. - Reported-by: JustAnotherArchivist on github - Closes #11223 + - delete dead references to `sys/utsname.h`. -- curl: count uploaded data to stop at the originally given size + Closes #11551 - Closes #11223 - Fixes #11222 - Reported-by: JustAnotherArchivist on github +- egd: delete feature detection and related source code -- tool: remove exclamation marks from error/warning messages + EGD is Entropy Gathering Daemon, a socket-based entropy source supported + by pre-OpenSSL v1.1 versions and now deprecated. curl also deprecated it + a while ago. -- tool: use errorf() for error output + Its detection in CMake was broken all along because OpenSSL libs were + not linked at the point of feature check. - Convert a number of fprintf() calls. + Delete detection from both cmake and autotools, along with the related + source snippet, and the `--with-egd-socket=` `./configure` option. -- tool: remove newlines from all helpf/notef/warnf/errorf calls + Closes #11556 - Make voutf() always add one. +Stefan Eissing (1 Aug 2023) - Closes #11226 +- tests: fix h3 server check and parallel instances -- tests/servers.pm: pick unused port number with a server socket + - fix check for availability of nghttpx server + - add `tcp` frontend config for same port as quic, as + without this, port 3000 is bound which clashes for parallel + testing - This change replaces the previous method of picking a port number at - random to try to start servers on, then retrying up to ten times with - new random numbers each time, with a function that creates a server - socket on port zero, thereby getting a suitable random port set by the - kernel. That server socket is then closed and that port number is used - to setup the actual test server on. + Closes #11553 - There is a risk that *another* server can be started on the machine in - the time gap, but the server verification feature will detect that. +Daniel Stenberg (1 Aug 2023) - Closes #11220 +- docs/cmdline-opts: spellfixes, typos and polish -- RELEASE-NOTES: synced + To make them accepted by the spell checker - bump to 8.2.0 + Closes #11562 -Alejandro R. Sedeño (31 May 2023) +- CI/spellcheck: build curl.1 and spellcheck it -- configure: fix run-compiler for old /bin/sh + Added acceptable words - If you try to assign and export on the same line on some older /bin/sh - implementations, it complains: + Closes #11562 - ``` - $ export "NAME=value" - NAME=value: is not an identifier - ``` +Alexander Jaeger (1 Aug 2023) - This commit rewrites run-compiler's assignments and exports to work with - old /bin/sh, splitting assignment and export into two separate - statements, and only quote the value. So now we have: +- misc: fix various typos - ``` - NAME="value" - export NAME - ``` + Closes #11561 - While we're here, make the same change to the two supporting - assign+export lines preceeding the script to be consistent with how - exports work throughout the rest of configure.ac. +Daniel Stenberg (1 Aug 2023) - Closes #11228 +- http2: avoid too early connection re-use/multiplexing -Philip Heiduck (31 May 2023) + HTTP/1 connections that are upgraded to HTTP/2 should not be picked up + for reuse and multiplexing by other handles until the 101 switching + process is completed. -- circleci: install impacket & wolfssl 5.6.0 + Lots-of-debgging-by: Stefan Eissing + Reported-by: Richard W.M. Jones + Bug: https://curl.se/mail/lib-2023-07/0045.html + Closes #11557 - Closes #11221 +- Revert "KNOWN_BUGS: build for iOS simulator on macOS 13.2 with Xcode 14" -Daniel Stenberg (31 May 2023) + This reverts commit 2e8a3d7cb73c85a9aa151e263315f8a496dbb9d4. -- tool_urlglob: use curl_off_t instead of longs + It's a user error for supplying incomplete information to the build system. - To handle more globs better (especially on Windows) + Reported-by: Ryan Schmidt + Ref: https://github.com/curl/curl/issues/11215#issuecomment-1658729367 - Closes #11224 +Viktor Szakats (1 Aug 2023) -Dan Fandrich (30 May 2023) +- cmake: add support for single libcurl compilation pass -- scripts: Fix GHA matrix job detection in cijobs.pl + Before this patch CMake builds used two separate compilation passes to + build the shared and static libcurl respectively. This patch allows to + reduce that to a single pass if the target platform and build settings + allow it. - The parsing is pretty brittle and it broke detecting some jobs at some - point. Also, detect if Windows is used in GHA. + This reduces CMake build times when building both static and shared + libcurl at the same time, making these dual builds an almost zero-cost + option. -- runtests: abort test run after failure without -a + Enable this feature for Windows builds, where the difference between the + two passes was the use of `__declspec(dllexport)` attribute for exported + API functions for the shared builds. This patch replaces this method + with the use of `libcurl.def` at DLL link time. - This was broken in a recent refactor and test runs would not stop. + Also update `Makefile.mk` to use `libcurl.def` to export libcurl API + symbols on Windows. This simplifies (or fixes) this build method (e.g. + in curl-for-win, which generated a `libcurl.def` from `.h` files using + an elaborate set of transformations). - Follow-up to d4a1b5b6 + `libcurl.def` has the maintenance cost of keeping the list of public + libcurl API symbols up-to-date. This list seldom changes, so the cost + is low. - Reported-by: Daniel Stenberg - Fixes #11225 - Closes #11227 + Closes #11546 -Version 8.1.2 (30 May 2023) +- cmake: detect `SSL_set0_wbio` in OpenSSL -Daniel Stenberg (30 May 2023) + Present in OpenSSL 1.1.0 and BoringSSL. + Missing from LibreSSL 3.8.0. -- RELEASE-NOTES: synced + Follow-up to f39472ea9f4f4e12cfbc0500c4580a8d52ce4a59 - 8.1.2 release + While here, also fix `RAND_egd()` detection which was broken, likely all + along. This feature is probably broken with CMake builds and also + requires a sufficiently obsolete OpenSSL version, so this part of the + update was not tested. -- THANKS: contributors from 8.1.2 + Closes #11555 diff --git a/libs/libcurl/docs/COPYING b/libs/libcurl/docs/COPYING index 5cf733b096..5f6dc0aef2 100644 --- a/libs/libcurl/docs/COPYING +++ b/libs/libcurl/docs/COPYING @@ -1,6 +1,6 @@ COPYRIGHT AND PERMISSION NOTICE -Copyright (c) 1996 - 2023, Daniel Stenberg, , and many +Copyright (c) 1996 - 2024, Daniel Stenberg, , and many contributors, see the THANKS file. All rights reserved. diff --git a/libs/libcurl/docs/THANKS b/libs/libcurl/docs/THANKS index d7e05f07ef..0c1d0c7589 100644 --- a/libs/libcurl/docs/THANKS +++ b/libs/libcurl/docs/THANKS @@ -92,6 +92,7 @@ Alex Samorukov Alex Suykov Alex Vinnik Alex Xu +Alexander Bartel Alexander Beedie Alexander Chuykov Alexander Dyagilev @@ -206,6 +207,7 @@ Andy Stamp Andy Tsouladze Angus Mackay anio on github +annalee anon00000000 on github anshnd on github Anssi Kolehmainen @@ -290,6 +292,7 @@ Basuke Suzuki baumanj on github bdry on github beckenc on github +Ben Ben Boeckel Ben Darnell Ben Fritz @@ -373,6 +376,7 @@ Brandon Dong Brandon Wang BratSinot on github Brendan Jurd +Brennan Kinney Brent Beardsley Brian Akins Brian Bergeron @@ -404,11 +408,13 @@ Bryan Henderson Bryan Kemp bsammon on github bsergean on github +bubbleguuum on github Bubu on github buzo-ffm on github bxac on github Bylon2 on github Byrial Jensen +Cajus Pollmeier Caleb Raitto Calvin Buckley calvin2021y on github @@ -441,6 +447,7 @@ Cering on github Cesar Eduardo Barros Chad Monroe Chandrakant Bagul +Chara White Charles Cazabon Charles Kerr Charles Romestant @@ -465,6 +472,7 @@ Chris Maltby Chris Mumford Chris Paulson-Ellis Chris Roberts +Chris Sauer Chris Smowton Chris Talbot Chris Young @@ -681,6 +689,7 @@ Denis Laxalde Denis Ollier Dennis Clarke Dennis Felsing +dependabot[bot] Derek Higgins Derzsi Dániel Desmond O. Chang @@ -943,6 +952,7 @@ FuccDucc on github Fujii Hironori fullincome on github fundawang on github +Gabe Gabriel Corona Gabriel Kuri Gabriel Simmer @@ -1055,6 +1065,7 @@ Hannes Magnusson Hanno Böck Hanno Kranzhoff Hans Steegers +Hans-Christian Egtvedt Hans-Christian Noren Egtvedt Hans-Jurgen May Hao Wu @@ -1066,6 +1077,7 @@ Harry Sarson Harry Sintonen Harshal Pradhan Hauke Duden +Haydar Alaidrus Hayden Roche He Qin Heikki Korpela @@ -1084,6 +1096,7 @@ Henry Ludemann Henry Roeland Herve Amblard HexTheDragon +hgdagon on github Hide Ishikawa Hidemoto Nakada highmtworks on github @@ -1117,6 +1130,7 @@ Ian Lynagh Ian Spence Ian Turner Ian Wilkes +iAroc on github iconoclasthero icy17 on github Ignacio Vazquez-Abrams @@ -1155,6 +1169,7 @@ Ishan SinghLevett Ithubg on github Ivan Avdeev Ivan Tsybulin +ivanfywang IvanoG on github Ivo Bellin Salarin iz8mbw on github @@ -1214,6 +1229,7 @@ Jan Venekamp Jan Verbeek Jan-Piet Mens JanB on github +janko-js on github Janne Blomqvist Janne Johansson Jared Jennings @@ -1235,6 +1251,7 @@ Javier Navarro Javier Sixto Jay Austin Jay Dommaschk +Jay Wu Jayesh A Shah Jaz Fresh JazJas on github @@ -1289,6 +1306,7 @@ Jerry Krinock Jerry Wu Jes Badwal Jesper Jensen +Jess Lowe Jesse Chisholm Jesse Noller Jesse Tan @@ -1600,6 +1618,7 @@ Lawrence Gripper Lawrence Matthews Lawrence Wagerfield Leah Neukirchen +Lealem Amedie Leandro Coutinho Legoff Vincent Lehel Bernadt @@ -1623,6 +1642,7 @@ LigH-de on github lijian996 on github Lijo Antony lilongyan-huawei on github +Lin Sun Linas Vepstas Lindley French Ling Thio @@ -1739,6 +1759,7 @@ Mark Davies Mark Dodgson Mark Gaiser Mark Hamilton +Mark Huang Mark Incley Mark Itzcovitz Mark Karpeles @@ -1747,6 +1768,7 @@ Mark Nottingham Mark Roszko Mark Salisbury Mark Seuffert +Mark Sinkovics Mark Snelling Mark Swaanenburg Mark Tully @@ -1835,6 +1857,7 @@ Matthias Naegler Mattias Fornander Matus Uzak Maurice Barnum +Mauricio Scheffer Mauro Iorio Mauro Rappa Maurício Meneghini Fauth @@ -1958,6 +1981,7 @@ Mohamed Lrhazi Mohamed Osama Mohammad AlSaleh Mohammad Hasbini +Mohammadreza Hendiani Mohammed Naser Mohun Biswas momala454 on github @@ -2109,6 +2133,7 @@ Oskar Liljeblad Oskar Sigvardsson Oumph on github ovidiu-benea on github +Ozan Cansel P R Schaffner Pablo Busse Palo Markovic @@ -2261,6 +2286,7 @@ Prithvi MK privetryan on github Priyanka Shah ProceduralMan on github +promptfuzz_ on hackerone Pronyushkin Petr Przemysław Tomaszewski pszemus on github @@ -2330,6 +2356,7 @@ Renaud Lehoux Rene Bernhardt Rene Rebe Reuven Wachtfogel +RevaliQaQ on github Reza Arbab Rianov Viacheslav Ricardo Cadime @@ -2355,6 +2382,7 @@ Richard Gorton Richard Gray Richard Hosking Richard Hsu +Richard Levitte Richard Marion Richard Michael Richard Moore @@ -2511,6 +2539,7 @@ Saul good Saurav Babu sayrer on github SBKarr on github +Scarlett McAllister Scott Bailey Scott Barrett Scott Cantor @@ -2556,6 +2585,7 @@ SerusDev on github Seshubabu Pasam Seth Mos Sevan Janiyan +sfan5 on github Sgharat on github Sh Diao Shachaf Ben-Kiki @@ -2705,6 +2735,7 @@ Taneli Vähäkangas Tanguy Fautre Taras Kushnir tarek112 on github +Tatsuhiko Miyagawa Tatsuhiro Tsujikawa tawmoto on github tbugfinder on github @@ -2717,6 +2748,7 @@ thanhchungbtc on github The Infinnovation team TheAssassin on github TheKnarf on github +Theo Theodore Dubois therealhirudo on github Thiago Suchorski @@ -2724,6 +2756,7 @@ tholin on github Thomas Bouzerar Thomas Braun Thomas Danielsson +Thomas Ferguson Thomas Gamper Thomas Glanzmann Thomas Guillem @@ -2961,6 +2994,7 @@ x2018 on github Xavier Bouchoux XhmikosR on github XhstormR on github +Xi Ruoyao Xiang Xiao Xiangbin Li xianghongai on github @@ -2972,6 +3006,7 @@ xtonik on github xwxbug on github Xì Gà Yaakov Selkowitz +Yadhu Krishna M Yair Lenga Yang Tse Yaobin Wen @@ -2979,10 +3014,12 @@ Yarram Sunil Yasuharu Yamada Yasuhiro Matsumoto Yechiel Kalmenson +Yedaya Katsman Yehezkel Horowitz Yehoshua Hershberg ygthien on github Yi Huang +Yifei Kong Yiming Jing Yingwei Liu yiyuaner on github @@ -3010,6 +3047,8 @@ Zachary Seguin Zdenek Pavlas Zekun Ni zelinchen on github +zengwei +zengwei2000 Zenju on github Zero King Zespre Schmidt diff --git a/libs/libcurl/include/curl/curl.h b/libs/libcurl/include/curl/curl.h index 1f6c5764c6..e69cb4fc17 100644 --- a/libs/libcurl/include/curl/curl.h +++ b/libs/libcurl/include/curl/curl.h @@ -631,6 +631,7 @@ typedef enum { CURLE_PROXY, /* 97 - proxy handshake error */ 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 */ CURL_LAST /* never use! */ } CURLcode; @@ -1845,7 +1846,8 @@ typedef enum { /* allow GSSAPI credential delegation */ CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_VALUES, 210), - /* Set the name servers to use for DNS resolution */ + /* Set the name servers to use for DNS resolution. + * Only supported by the c-ares DNS backend */ CURLOPT(CURLOPT_DNS_SERVERS, CURLOPTTYPE_STRINGPOINT, 211), /* Time-out accept operations (currently for FTP only) after this amount @@ -2201,6 +2203,9 @@ typedef enum { /* set a specific client IP for HAProxy PROXY protocol header? */ CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323), + /* millisecond version */ + CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -2932,7 +2937,8 @@ typedef enum { CURLINFO_CAPATH = CURLINFO_STRING + 62, CURLINFO_XFER_ID = CURLINFO_OFF_T + 63, CURLINFO_CONN_ID = CURLINFO_OFF_T + 64, - CURLINFO_LASTONE = 64 + CURLINFO_QUEUE_TIME_T = CURLINFO_OFF_T + 65, + CURLINFO_LASTONE = 65 } CURLINFO; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as diff --git a/libs/libcurl/include/curl/curlver.h b/libs/libcurl/include/curl/curlver.h index e54a5e6138..8d3879a30a 100644 --- a/libs/libcurl/include/curl/curlver.h +++ b/libs/libcurl/include/curl/curlver.h @@ -32,12 +32,12 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "8.5.0" +#define LIBCURL_VERSION "8.6.0" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 8 -#define LIBCURL_VERSION_MINOR 5 +#define LIBCURL_VERSION_MINOR 6 #define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier @@ -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 0x080500 +#define LIBCURL_VERSION_NUM 0x080600 /* * This is the date and time when the full source package was created. The @@ -70,7 +70,7 @@ * * "2007-11-23" */ -#define LIBCURL_TIMESTAMP "2023-12-06" +#define LIBCURL_TIMESTAMP "2024-01-31" #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/mprintf.h b/libs/libcurl/include/curl/mprintf.h index b344c8c830..7880024983 100644 --- a/libs/libcurl/include/curl/mprintf.h +++ b/libs/libcurl/include/curl/mprintf.h @@ -34,19 +34,27 @@ extern "C" { #if (defined(__GNUC__) || defined(__clang__)) && \ defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !defined(__MINGW32__) && !defined(CURL_NO_FMT_CHECKS) -#define CURL_TEMP_PRINTF(a,b) __attribute__ ((format(printf, a, b))) + !defined(CURL_NO_FMT_CHECKS) +#if defined(__MINGW32__) && !defined(__clang__) +#define CURL_TEMP_PRINTF(fmt, arg) \ + __attribute__((format(gnu_printf, fmt, arg))) #else -#define CURL_TEMP_PRINTF(a,b) +#define CURL_TEMP_PRINTF(fmt, arg) \ + __attribute__((format(printf, fmt, arg))) +#endif +#else +#define CURL_TEMP_PRINTF(fmt, arg) #endif -CURL_EXTERN int curl_mprintf(const char *format, ...) CURL_TEMP_PRINTF(1, 2); +CURL_EXTERN int curl_mprintf(const char *format, ...) + CURL_TEMP_PRINTF(1, 2); CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...) CURL_TEMP_PRINTF(2, 3); CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...) CURL_TEMP_PRINTF(2, 3); CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, - const char *format, ...) CURL_TEMP_PRINTF(3, 4); + const char *format, ...) + CURL_TEMP_PRINTF(3, 4); CURL_EXTERN int curl_mvprintf(const char *format, va_list args) CURL_TEMP_PRINTF(1, 0); CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args) diff --git a/libs/libcurl/include/curl/system.h b/libs/libcurl/include/curl/system.h index 40044a4ee3..01ff338b15 100644 --- a/libs/libcurl/include/curl/system.h +++ b/libs/libcurl/include/curl/system.h @@ -184,9 +184,8 @@ # define CURL_FORMAT_CURL_OFF_TU PRIu64 # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL -# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_TYPEOF_CURL_SOCKLEN_T int # define CURL_PULL_SYS_TYPES_H 1 -# define CURL_PULL_WS2TCPIP_H 1 #elif defined(__VMS) # if defined(__VAX) @@ -417,15 +416,6 @@ #define CURL_PULL_SYS_POLL_H #endif - -/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */ -/* ws2tcpip.h is required here to properly make type definitions below. */ -#ifdef CURL_PULL_WS2TCPIP_H -# include -# include -# include -#endif - /* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ /* sys/types.h is required here to properly make type definitions below. */ #ifdef CURL_PULL_SYS_TYPES_H diff --git a/libs/libcurl/include/curl/urlapi.h b/libs/libcurl/include/curl/urlapi.h index 1c9b11fec5..f5f2a2b771 100644 --- a/libs/libcurl/include/curl/urlapi.h +++ b/libs/libcurl/include/curl/urlapi.h @@ -63,6 +63,7 @@ typedef enum { CURLUE_BAD_SLASHES, /* 28 */ CURLUE_BAD_USER, /* 29 */ CURLUE_LACKS_IDN, /* 30 */ + CURLUE_TOO_LARGE, /* 31 */ CURLUE_LAST } CURLUcode; diff --git a/libs/libcurl/src/Makefile.in b/libs/libcurl/src/Makefile.in index 3beb50dc1f..662f586563 100644 --- a/libs/libcurl/src/Makefile.in +++ b/libs/libcurl/src/Makefile.in @@ -244,40 +244,42 @@ am__libcurl_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.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_quiche.c vquic/vquic.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_range.h curl_rtmp.h curl_sasl.h \ - curl_setup.h curl_setup_once.h curl_sha256.h curl_sspi.h \ - curl_threads.h curl_trc.h curlx.h dict.h doh.h dynbuf.h \ - dynhds.h easy_lock.h easyif.h easyoptions.h escape.h file.h \ - fileinfo.h fopen.h formdata.h ftp.h ftplistparser.h \ - functypes.h getinfo.h gopher.h hash.h headers.h hostip.h \ - hsts.h http.h http1.h http2.h http_aws_sigv4.h http_chunks.h \ - http_digest.h http_negotiate.h http_ntlm.h http_proxy.h idn.h \ - if2ip.h imap.h inet_ntop.h inet_pton.h llist.h macos.h \ - memdebug.h mime.h mqtt.h multihandle.h multiif.h netrc.h \ - nonblock.h noproxy.h parsedate.h pingpong.h pop3.h progress.h \ - psl.h rand.h rename.h rtsp.h select.h sendf.h setopt.h \ - setup-vms.h share.h sigpipe.h slist.h smb.h smtp.h sockaddr.h \ - socketpair.h socks.h speedcheck.h splay.h strcase.h strdup.h \ - strerror.h strtok.h strtoofft.h system_win32.h telnet.h tftp.h \ - timediff.h timeval.h transfer.h url.h urlapi-int.h urldata.h \ + 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_range.h curl_rtmp.h curl_sasl.h curl_setup.h \ + curl_setup_once.h curl_sha256.h curl_sspi.h curl_threads.h \ + curl_trc.h curlx.h dict.h doh.h dynbuf.h dynhds.h easy_lock.h \ + easyif.h easyoptions.h escape.h file.h fileinfo.h fopen.h \ + formdata.h ftp.h ftplistparser.h functypes.h getinfo.h \ + gopher.h hash.h headers.h hostip.h hsts.h http.h http1.h \ + http2.h http_aws_sigv4.h http_chunks.h http_digest.h \ + http_negotiate.h http_ntlm.h http_proxy.h idn.h if2ip.h imap.h \ + inet_ntop.h inet_pton.h llist.h macos.h memdebug.h mime.h \ + mqtt.h multihandle.h multiif.h netrc.h nonblock.h noproxy.h \ + parsedate.h pingpong.h pop3.h progress.h psl.h rand.h rename.h \ + rtsp.h select.h sendf.h setopt.h setup-vms.h share.h sigpipe.h \ + slist.h smb.h smtp.h sockaddr.h socketpair.h socks.h \ + speedcheck.h splay.h strcase.h strdup.h strerror.h strtok.h \ + strtoofft.h system_win32.h 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_quiche.h \ - vquic/vquic.h vquic/vquic_int.h vssh/ssh.h libcurl.rc + 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 \ @@ -351,8 +353,9 @@ am__objects_3 = vtls/libcurl_la-bearssl.lo vtls/libcurl_la-gtls.lo \ vtls/libcurl_la-sectransp.lo vtls/libcurl_la-vtls.lo \ vtls/libcurl_la-wolfssl.lo vtls/libcurl_la-x509asn1.lo am__objects_4 = vquic/libcurl_la-curl_msh3.lo \ - vquic/libcurl_la-curl_ngtcp2.lo \ - vquic/libcurl_la-curl_quiche.lo vquic/libcurl_la-vquic.lo + vquic/libcurl_la-curl_ngtcp2.lo vquic/libcurl_la-curl_osslq.lo \ + vquic/libcurl_la-curl_quiche.lo vquic/libcurl_la-vquic.lo \ + vquic/libcurl_la-vquic-tls.lo am__objects_5 = vssh/libcurl_la-libssh.lo vssh/libcurl_la-libssh2.lo \ vssh/libcurl_la-wolfssh.lo am__objects_6 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ @@ -453,7 +456,9 @@ am__objects_13 = vtls/libcurlu_la-bearssl.lo vtls/libcurlu_la-gtls.lo \ vtls/libcurlu_la-wolfssl.lo vtls/libcurlu_la-x509asn1.lo am__objects_14 = vquic/libcurlu_la-curl_msh3.lo \ vquic/libcurlu_la-curl_ngtcp2.lo \ - vquic/libcurlu_la-curl_quiche.lo vquic/libcurlu_la-vquic.lo + vquic/libcurlu_la-curl_osslq.lo \ + vquic/libcurlu_la-curl_quiche.lo vquic/libcurlu_la-vquic.lo \ + vquic/libcurlu_la-vquic-tls.lo am__objects_15 = vssh/libcurlu_la-libssh.lo \ vssh/libcurlu_la-libssh2.lo vssh/libcurlu_la-wolfssh.lo am__objects_16 = $(am__objects_11) $(am__objects_12) $(am__objects_13) \ @@ -763,11 +768,15 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \ vauth/$(DEPDIR)/libcurlu_la-vauth.Plo \ vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo \ vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo \ + vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo \ vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo \ + vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo \ vquic/$(DEPDIR)/libcurl_la-vquic.Plo \ vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo \ vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo \ + vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo \ vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo \ + vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo \ vquic/$(DEPDIR)/libcurlu_la-vquic.Plo \ vssh/$(DEPDIR)/libcurl_la-libssh.Plo \ vssh/$(DEPDIR)/libcurl_la-libssh2.Plo \ @@ -926,6 +935,7 @@ HAVE_BROTLI = @HAVE_BROTLI@ HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@ HAVE_LDAP_SSL = @HAVE_LDAP_SSL@ HAVE_LIBZ = @HAVE_LIBZ@ +HAVE_OPENSSL_QUIC = @HAVE_OPENSSL_QUIC@ HAVE_OPENSSL_SRP = @HAVE_OPENSSL_SRP@ HAVE_PROTO_BSDSOCKET_H = @HAVE_PROTO_BSDSOCKET_H@ HAVE_ZSTD = @HAVE_ZSTD@ @@ -1003,10 +1013,14 @@ USE_MSH3 = @USE_MSH3@ USE_NGHTTP2 = @USE_NGHTTP2@ USE_NGHTTP3 = @USE_NGHTTP3@ USE_NGTCP2 = @USE_NGTCP2@ +USE_NGTCP2_CRYPTO_BORINGSSL = @USE_NGTCP2_CRYPTO_BORINGSSL@ USE_NGTCP2_CRYPTO_GNUTLS = @USE_NGTCP2_CRYPTO_GNUTLS@ USE_NGTCP2_CRYPTO_QUICTLS = @USE_NGTCP2_CRYPTO_QUICTLS@ USE_NGTCP2_CRYPTO_WOLFSSL = @USE_NGTCP2_CRYPTO_WOLFSSL@ +USE_NGTCP2_H3 = @USE_NGTCP2_H3@ USE_OPENLDAP = @USE_OPENLDAP@ +USE_OPENSSL_H3 = @USE_OPENSSL_H3@ +USE_OPENSSL_QUIC = @USE_OPENSSL_QUIC@ USE_QUICHE = @USE_QUICHE@ USE_RUSTLS = @USE_RUSTLS@ USE_SCHANNEL = @USE_SCHANNEL@ @@ -1186,15 +1200,19 @@ LIB_VTLS_HFILES = \ LIB_VQUIC_CFILES = \ vquic/curl_msh3.c \ vquic/curl_ngtcp2.c \ + vquic/curl_osslq.c \ vquic/curl_quiche.c \ - vquic/vquic.c + vquic/vquic.c \ + vquic/vquic-tls.c LIB_VQUIC_HFILES = \ 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_int.h \ + vquic/vquic-tls.h LIB_VSSH_CFILES = \ vssh/libssh.c \ @@ -1675,10 +1693,14 @@ vquic/libcurl_la-curl_msh3.lo: vquic/$(am__dirstamp) \ vquic/$(DEPDIR)/$(am__dirstamp) vquic/libcurl_la-curl_ngtcp2.lo: vquic/$(am__dirstamp) \ vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurl_la-curl_osslq.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) vquic/libcurl_la-curl_quiche.lo: vquic/$(am__dirstamp) \ vquic/$(DEPDIR)/$(am__dirstamp) vquic/libcurl_la-vquic.lo: vquic/$(am__dirstamp) \ vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurl_la-vquic-tls.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) vssh/$(am__dirstamp): @$(MKDIR_P) vssh @: > vssh/$(am__dirstamp) @@ -1752,10 +1774,14 @@ vquic/libcurlu_la-curl_msh3.lo: vquic/$(am__dirstamp) \ vquic/$(DEPDIR)/$(am__dirstamp) vquic/libcurlu_la-curl_ngtcp2.lo: vquic/$(am__dirstamp) \ vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurlu_la-curl_osslq.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) vquic/libcurlu_la-curl_quiche.lo: vquic/$(am__dirstamp) \ vquic/$(DEPDIR)/$(am__dirstamp) vquic/libcurlu_la-vquic.lo: vquic/$(am__dirstamp) \ vquic/$(DEPDIR)/$(am__dirstamp) +vquic/libcurlu_la-vquic-tls.lo: vquic/$(am__dirstamp) \ + vquic/$(DEPDIR)/$(am__dirstamp) vssh/libcurlu_la-libssh.lo: vssh/$(am__dirstamp) \ vssh/$(DEPDIR)/$(am__dirstamp) vssh/libcurlu_la-libssh2.lo: vssh/$(am__dirstamp) \ @@ -2068,11 +2094,15 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-vauth.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-vquic.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-vquic.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-libssh.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vssh/$(DEPDIR)/libcurl_la-libssh2.Plo@am__quote@ # am--include-marker @@ -3252,6 +3282,13 @@ vquic/libcurl_la-curl_ngtcp2.lo: vquic/curl_ngtcp2.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 vquic/libcurl_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c +vquic/libcurl_la-curl_osslq.lo: vquic/curl_osslq.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 vquic/libcurl_la-curl_osslq.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_osslq.Tpo -c -o vquic/libcurl_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_osslq.Tpo vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_osslq.c' object='vquic/libcurl_la-curl_osslq.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 vquic/libcurl_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c + vquic/libcurl_la-curl_quiche.lo: vquic/curl_quiche.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 vquic/libcurl_la-curl_quiche.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_quiche.Tpo -c -o vquic/libcurl_la-curl_quiche.lo `test -f 'vquic/curl_quiche.c' || echo '$(srcdir)/'`vquic/curl_quiche.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_quiche.Tpo vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo @@ -3266,6 +3303,13 @@ vquic/libcurl_la-vquic.lo: vquic/vquic.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 vquic/libcurl_la-vquic.lo `test -f 'vquic/vquic.c' || echo '$(srcdir)/'`vquic/vquic.c +vquic/libcurl_la-vquic-tls.lo: vquic/vquic-tls.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 vquic/libcurl_la-vquic-tls.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-vquic-tls.Tpo -c -o vquic/libcurl_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-vquic-tls.Tpo vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/vquic-tls.c' object='vquic/libcurl_la-vquic-tls.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 vquic/libcurl_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c + vssh/libcurl_la-libssh.lo: vssh/libssh.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 vssh/libcurl_la-libssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurl_la-libssh.Tpo -c -o vssh/libcurl_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurl_la-libssh.Tpo vssh/$(DEPDIR)/libcurl_la-libssh.Plo @@ -4400,6 +4444,13 @@ vquic/libcurlu_la-curl_ngtcp2.lo: vquic/curl_ngtcp2.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 vquic/libcurlu_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c +vquic/libcurlu_la-curl_osslq.lo: vquic/curl_osslq.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 vquic/libcurlu_la-curl_osslq.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Tpo -c -o vquic/libcurlu_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_osslq.c' object='vquic/libcurlu_la-curl_osslq.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 vquic/libcurlu_la-curl_osslq.lo `test -f 'vquic/curl_osslq.c' || echo '$(srcdir)/'`vquic/curl_osslq.c + vquic/libcurlu_la-curl_quiche.lo: vquic/curl_quiche.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 vquic/libcurlu_la-curl_quiche.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Tpo -c -o vquic/libcurlu_la-curl_quiche.lo `test -f 'vquic/curl_quiche.c' || echo '$(srcdir)/'`vquic/curl_quiche.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo @@ -4414,6 +4465,13 @@ vquic/libcurlu_la-vquic.lo: vquic/vquic.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 vquic/libcurlu_la-vquic.lo `test -f 'vquic/vquic.c' || echo '$(srcdir)/'`vquic/vquic.c +vquic/libcurlu_la-vquic-tls.lo: vquic/vquic-tls.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 vquic/libcurlu_la-vquic-tls.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Tpo -c -o vquic/libcurlu_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Tpo vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/vquic-tls.c' object='vquic/libcurlu_la-vquic-tls.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 vquic/libcurlu_la-vquic-tls.lo `test -f 'vquic/vquic-tls.c' || echo '$(srcdir)/'`vquic/vquic-tls.c + vssh/libcurlu_la-libssh.lo: vssh/libssh.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 vssh/libcurlu_la-libssh.lo -MD -MP -MF vssh/$(DEPDIR)/libcurlu_la-libssh.Tpo -c -o vssh/libcurlu_la-libssh.lo `test -f 'vssh/libssh.c' || echo '$(srcdir)/'`vssh/libssh.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vssh/$(DEPDIR)/libcurlu_la-libssh.Tpo vssh/$(DEPDIR)/libcurlu_la-libssh.Plo @@ -4869,11 +4927,15 @@ distclean: distclean-am -rm -f vauth/$(DEPDIR)/libcurlu_la-vauth.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-vquic.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-vquic.Plo -rm -f vssh/$(DEPDIR)/libcurl_la-libssh.Plo -rm -f vssh/$(DEPDIR)/libcurl_la-libssh2.Plo @@ -5242,11 +5304,15 @@ maintainer-clean: maintainer-clean-am -rm -f vauth/$(DEPDIR)/libcurlu_la-vauth.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo + -rm -f vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-vquic.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo + -rm -f vquic/$(DEPDIR)/libcurlu_la-vquic-tls.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-vquic.Plo -rm -f vssh/$(DEPDIR)/libcurl_la-libssh.Plo -rm -f vssh/$(DEPDIR)/libcurl_la-libssh2.Plo diff --git a/libs/libcurl/src/Makefile.inc b/libs/libcurl/src/Makefile.inc index efaf2f50db..a607bee30c 100644 --- a/libs/libcurl/src/Makefile.inc +++ b/libs/libcurl/src/Makefile.inc @@ -78,15 +78,19 @@ LIB_VTLS_HFILES = \ LIB_VQUIC_CFILES = \ vquic/curl_msh3.c \ vquic/curl_ngtcp2.c \ + vquic/curl_osslq.c \ vquic/curl_quiche.c \ - vquic/vquic.c + vquic/vquic.c \ + vquic/vquic-tls.c LIB_VQUIC_HFILES = \ 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_int.h \ + vquic/vquic-tls.h LIB_VSSH_CFILES = \ vssh/libssh.c \ diff --git a/libs/libcurl/src/altsvc.c b/libs/libcurl/src/altsvc.c index 13d4f11b71..f410c2e7b2 100644 --- a/libs/libcurl/src/altsvc.c +++ b/libs/libcurl/src/altsvc.c @@ -106,9 +106,11 @@ static struct altsvc *altsvc_createid(const char *srchost, dlen = strlen(dsthost); DEBUGASSERT(hlen); DEBUGASSERT(dlen); - if(!hlen || !dlen) + if(!hlen || !dlen) { /* bad input */ + free(as); return NULL; + } if((hlen > 2) && srchost[0] == '[') { /* IPv6 address, strip off brackets */ srchost++; @@ -123,11 +125,11 @@ static struct altsvc *altsvc_createid(const char *srchost, dlen -= 2; } - as->src.host = Curl_strndup(srchost, hlen); + as->src.host = Curl_memdup0(srchost, hlen); if(!as->src.host) goto error; - as->dst.host = Curl_strndup(dsthost, dlen); + as->dst.host = Curl_memdup0(dsthost, dlen); if(!as->dst.host) goto error; @@ -333,9 +335,6 @@ CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file) CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl) { DEBUGASSERT(asi); - if(!ctrl) - /* unexpected */ - return CURLE_BAD_FUNCTION_ARGUMENT; asi->flags = ctrl; return CURLE_OK; } diff --git a/libs/libcurl/src/asyn-ares.c b/libs/libcurl/src/asyn-ares.c index f13ccb36cb..69d22ea9fe 100644 --- a/libs/libcurl/src/asyn-ares.c +++ b/libs/libcurl/src/asyn-ares.c @@ -173,10 +173,26 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver) int status; struct ares_options options; int optmask = ARES_OPT_SOCK_STATE_CB; + static int ares_ver = 0; options.sock_state_cb = sock_state_cb; options.sock_state_cb_data = easy; - options.timeout = CARES_TIMEOUT_PER_ATTEMPT; - optmask |= ARES_OPT_TIMEOUTMS; + if(ares_ver == 0) + ares_version(&ares_ver); + + if(ares_ver < 0x011400) { /* c-ares included similar change since 1.20.0 */ + options.timeout = CARES_TIMEOUT_PER_ATTEMPT; + optmask |= ARES_OPT_TIMEOUTMS; + } + + /* + if c ares < 1.20.0: curl set timeout to CARES_TIMEOUT_PER_ATTEMPT (2s) + + if c-ares >= 1.20.0 it already has the timeout to 2s, curl does not need + to set the timeout value; + + if c-ares >= 1.24.0, user can set the timeout via /etc/resolv.conf to + overwrite c-ares' timeout. + */ status = ares_init_options((ares_channel*)resolver, &options, optmask); if(status != ARES_SUCCESS) { @@ -228,9 +244,9 @@ static void destroy_async_data(struct Curl_async *async); void Curl_resolver_cancel(struct Curl_easy *data) { DEBUGASSERT(data); - if(data->conn->resolve_async.resolver) - ares_cancel((ares_channel)data->conn->resolve_async.resolver); - destroy_async_data(&data->conn->resolve_async); + if(data->state.async.resolver) + ares_cancel((ares_channel)data->state.async.resolver); + destroy_async_data(&data->state.async); } /* @@ -278,14 +294,14 @@ int Curl_resolver_getsock(struct Curl_easy *data, struct timeval timebuf; struct timeval *timeout; long milli; - int max = ares_getsock((ares_channel)data->conn->resolve_async.resolver, + int max = ares_getsock((ares_channel)data->state.async.resolver, (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE); maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; maxtime.tv_usec = 0; - timeout = ares_timeout((ares_channel)data->conn->resolve_async.resolver, - &maxtime, &timebuf); + timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime, + &timebuf); milli = (long)curlx_tvtoms(timeout); if(milli == 0) milli += 10; @@ -313,8 +329,8 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms) int i; int num = 0; - bitmask = ares_getsock((ares_channel)data->conn->resolve_async.resolver, - socks, ARES_GETSOCK_MAXNUM); + bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks, + ARES_GETSOCK_MAXNUM); for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { pfd[i].events = 0; @@ -344,12 +360,12 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms) if(!nfds) /* Call ares_process() unconditionally here, even if we simply timed out above, as otherwise the ares name resolve won't timeout! */ - ares_process_fd((ares_channel)data->conn->resolve_async.resolver, - ARES_SOCKET_BAD, ARES_SOCKET_BAD); + ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD, + ARES_SOCKET_BAD); else { /* move through the descriptors and ask for processing on them */ for(i = 0; i < num; i++) - ares_process_fd((ares_channel)data->conn->resolve_async.resolver, + ares_process_fd((ares_channel)data->state.async.resolver, (pfd[i].revents & (POLLRDNORM|POLLIN))? pfd[i].fd:ARES_SOCKET_BAD, (pfd[i].revents & (POLLWRNORM|POLLOUT))? @@ -368,7 +384,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms) CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, struct Curl_dns_entry **dns) { - struct thread_data *res = data->conn->resolve_async.tdata; + struct thread_data *res = data->state.async.tdata; CURLcode result = CURLE_OK; DEBUGASSERT(dns); @@ -397,7 +413,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, ARES_ECANCELLED synchronously for all pending responses. This will leave us with res->num_pending == 0, which is perfect for the next block. */ - ares_cancel((ares_channel)data->conn->resolve_async.resolver); + ares_cancel((ares_channel)data->state.async.resolver); DEBUGASSERT(res->num_pending == 0); } #endif @@ -408,12 +424,12 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, them */ res->temp_ai = NULL; - if(!data->conn->resolve_async.dns) + if(!data->state.async.dns) result = Curl_resolver_error(data); else - *dns = data->conn->resolve_async.dns; + *dns = data->state.async.dns; - destroy_async_data(&data->conn->resolve_async); + destroy_async_data(&data->state.async); } return result; @@ -464,8 +480,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, store.tv_sec = itimeout/1000; store.tv_usec = (itimeout%1000)*1000; - tvp = ares_timeout((ares_channel)data->conn->resolve_async.resolver, - &store, &tv); + tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv); /* use the timeout period ares returned to us above if less than one second is left, otherwise just use 1000ms to make sure the progress @@ -479,7 +494,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, return CURLE_UNRECOVERABLE_POLL; result = Curl_resolver_is_resolved(data, entry); - if(result || data->conn->resolve_async.done) + if(result || data->state.async.done) break; if(Curl_pgrsUpdate(data)) @@ -500,12 +515,12 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, } if(result) /* failure, so we cancel the ares operation */ - ares_cancel((ares_channel)data->conn->resolve_async.resolver); + ares_cancel((ares_channel)data->state.async.resolver); /* Operation complete, if the lookup was successful we now have the entry in the cache. */ if(entry) - *entry = data->conn->resolve_async.dns; + *entry = data->state.async.dns; if(result) /* close the connection, since we can't return failure here without @@ -572,13 +587,12 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */ be valid so only defer it when we know the 'status' says its fine! */ return; - res = data->conn->resolve_async.tdata; + res = data->state.async.tdata; if(res) { res->num_pending--; if(CURL_ASYNC_SUCCESS == status) { - struct Curl_addrinfo *ai = Curl_he2ai(hostent, - data->conn->resolve_async.port); + struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port); if(ai) { compound_results(res, ai); } @@ -729,16 +743,14 @@ static void addrinfo_cb(void *arg, int status, int timeouts, struct ares_addrinfo *result) { struct Curl_easy *data = (struct Curl_easy *)arg; - if(data->conn) { - struct thread_data *res = data->conn->resolve_async.tdata; - (void)timeouts; - if(ARES_SUCCESS == status) { - res->temp_ai = ares2addr(result->nodes); - res->last_status = CURL_ASYNC_SUCCESS; - ares_freeaddrinfo(result); - } - res->num_pending--; + struct thread_data *res = data->state.async.tdata; + (void)timeouts; + if(ARES_SUCCESS == status) { + res->temp_ai = ares2addr(result->nodes); + res->last_status = CURL_ASYNC_SUCCESS; + ares_freeaddrinfo(result); } + res->num_pending--; } #endif @@ -762,12 +774,12 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, res = calloc(1, sizeof(struct thread_data) + namelen); if(res) { strcpy(res->hostname, hostname); - data->conn->resolve_async.hostname = res->hostname; - data->conn->resolve_async.port = port; - data->conn->resolve_async.done = FALSE; /* not done */ - data->conn->resolve_async.status = 0; /* clear */ - data->conn->resolve_async.dns = NULL; /* clear */ - data->conn->resolve_async.tdata = res; + data->state.async.hostname = res->hostname; + data->state.async.port = port; + data->state.async.done = FALSE; /* not done */ + data->state.async.status = 0; /* clear */ + data->state.async.dns = NULL; /* clear */ + data->state.async.tdata = res; /* initial status - failed */ res->last_status = ARES_ENOTFOUND; @@ -797,8 +809,8 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, hints.ai_flags = ARES_AI_NUMERICSERV; msnprintf(service, sizeof(service), "%d", port); res->num_pending = 1; - ares_getaddrinfo((ares_channel)data->conn->resolve_async.resolver, - hostname, service, &hints, addrinfo_cb, data); + ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname, + service, &hints, addrinfo_cb, data); } #else @@ -808,10 +820,10 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, res->num_pending = 2; /* areschannel is already setup in the Curl_open() function */ - ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver, - hostname, PF_INET, query_completed_cb, data); - ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver, - hostname, PF_INET6, query_completed_cb, data); + ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, + PF_INET, query_completed_cb, data); + ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, + PF_INET6, query_completed_cb, data); } else #endif @@ -819,7 +831,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, res->num_pending = 1; /* areschannel is already setup in the Curl_open() function */ - ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver, + ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, PF_INET, query_completed_cb, data); } @@ -833,7 +845,6 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers) { CURLcode result = CURLE_NOT_BUILT_IN; - ares_channel channel, lchannel = NULL; int ares_result; /* If server is NULL or empty, this would purge all DNS servers @@ -846,23 +857,11 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data, return CURLE_OK; #ifdef HAVE_CARES_SERVERS_CSV - if(data->conn) - channel = data->conn->resolve_async.resolver; - else { - /* we are called by setopt on a data without a connection (yet). In that - * case we set the value on a local instance for checking. - * The configured data options are set when the connection for this - * transfer is created. */ - result = Curl_resolver_init(data, (void **)&lchannel); - if(result) - goto out; - channel = lchannel; - } - #ifdef HAVE_CARES_PORTS_CSV - ares_result = ares_set_servers_ports_csv(channel, servers); + ares_result = ares_set_servers_ports_csv(data->state.async.resolver, + servers); #else - ares_result = ares_set_servers_csv(channel, servers); + ares_result = ares_set_servers_csv(data->state.async.resolver, servers); #endif switch(ares_result) { case ARES_SUCCESS: @@ -875,12 +874,10 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data, case ARES_ENODATA: case ARES_EBADSTR: default: + DEBUGF(infof(data, "bad servers set")); result = CURLE_BAD_FUNCTION_ARGUMENT; break; } -out: - if(lchannel) - Curl_resolver_cleanup(lchannel); #else /* too old c-ares version! */ (void)data; (void)(ares_result); @@ -892,14 +889,11 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { #ifdef HAVE_CARES_LOCAL_DEV - if(data->conn) { - /* not a setopt test run, set the value */ - if(!interf) - interf = ""; + if(!interf) + interf = ""; + + ares_set_local_dev((ares_channel)data->state.async.resolver, interf); - ares_set_local_dev((ares_channel)data->conn->resolve_async.resolver, - interf); - } return CURLE_OK; #else /* c-ares version too old! */ (void)data; @@ -919,15 +913,13 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, } else { if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) { + DEBUGF(infof(data, "bad DNS IPv4 address")); return CURLE_BAD_FUNCTION_ARGUMENT; } } - if(data->conn) { - /* not a setopt test run, set the value */ - ares_set_local_ip4((ares_channel)data->conn->resolve_async.resolver, - ntohl(a4.s_addr)); - } + ares_set_local_ip4((ares_channel)data->state.async.resolver, + ntohl(a4.s_addr)); return CURLE_OK; #else /* c-ares version too old! */ @@ -949,14 +941,12 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, } else { if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) { + DEBUGF(infof(data, "bad DNS IPv6 address")); return CURLE_BAD_FUNCTION_ARGUMENT; } } - if(data->conn) { - /* not a setopt test run, set the value */ - ares_set_local_ip6((ares_channel)data->conn->resolve_async.resolver, a6); - } + ares_set_local_ip6((ares_channel)data->state.async.resolver, a6); return CURLE_OK; #else /* c-ares version too old! */ diff --git a/libs/libcurl/src/asyn-thread.c b/libs/libcurl/src/asyn-thread.c index 493f009e34..c0ee113098 100644 --- a/libs/libcurl/src/asyn-thread.c +++ b/libs/libcurl/src/asyn-thread.c @@ -54,6 +54,7 @@ # define RESOLVER_ENOMEM ENOMEM #endif +#include "system_win32.h" #include "urldata.h" #include "sendf.h" #include "hostip.h" @@ -136,7 +137,7 @@ static void destroy_async_data(struct Curl_async *); */ void Curl_resolver_cancel(struct Curl_easy *data) { - destroy_async_data(&data->conn->resolve_async); + destroy_async_data(&data->state.async); } /* This function is used to init a threaded resolve */ @@ -144,9 +145,22 @@ static bool init_resolve_thread(struct Curl_easy *data, const char *hostname, int port, const struct addrinfo *hints); +#ifdef _WIN32 +/* Thread sync data used by GetAddrInfoExW for win8+ */ +struct thread_sync_data_w8 +{ + OVERLAPPED overlapped; + ADDRINFOEXW_ *res; + HANDLE cancel_ev; + ADDRINFOEXW_ hints; +}; +#endif /* Data for synchronization between resolver thread and its parent */ struct thread_sync_data { +#ifdef _WIN32 + struct thread_sync_data_w8 w8; +#endif curl_mutex_t *mtx; int done; int port; @@ -165,6 +179,9 @@ struct thread_sync_data { }; struct thread_data { +#ifdef _WIN32 + HANDLE complete_ev; +#endif curl_thread_t thread_hnd; unsigned int poll_interval; timediff_t interval_end; @@ -173,7 +190,7 @@ struct thread_data { static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data) { - return &(data->conn->resolve_async.tdata->tsd); + return &(data->state.async.tdata->tsd); } /* Destroy resolver thread synchronization data */ @@ -276,6 +293,151 @@ static CURLcode getaddrinfo_complete(struct Curl_easy *data) return result; } +#ifdef _WIN32 +static VOID WINAPI +query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped) +{ + size_t ss_size; + const ADDRINFOEXW_ *ai; + struct Curl_addrinfo *ca; + struct Curl_addrinfo *cafirst = NULL; + struct Curl_addrinfo *calast = NULL; +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-align" +#endif + struct thread_sync_data *tsd = + CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlapped); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + struct thread_data *td = tsd->td; + const ADDRINFOEXW_ *res = tsd->w8.res; + int error = (int)err; + (void)bytes; + + if(error == ERROR_SUCCESS) { + /* traverse the addrinfo list */ + + for(ai = res; ai != NULL; ai = ai->ai_next) { + size_t namelen = ai->ai_canonname ? wcslen(ai->ai_canonname) + 1 : 0; + /* ignore elements with unsupported address family, */ + /* settle family-specific sockaddr structure size. */ + if(ai->ai_family == AF_INET) + ss_size = sizeof(struct sockaddr_in); +#ifdef ENABLE_IPV6 + else if(ai->ai_family == AF_INET6) + ss_size = sizeof(struct sockaddr_in6); +#endif + else + continue; + + /* ignore elements without required address info */ + if(!ai->ai_addr || !(ai->ai_addrlen > 0)) + continue; + + /* ignore elements with bogus address size */ + if((size_t)ai->ai_addrlen < ss_size) + continue; + + ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen); + if(!ca) { + error = EAI_MEMORY; + break; + } + + /* copy each structure member individually, member ordering, */ + /* size, or padding might be different for each platform. */ + ca->ai_flags = ai->ai_flags; + ca->ai_family = ai->ai_family; + ca->ai_socktype = ai->ai_socktype; + ca->ai_protocol = ai->ai_protocol; + ca->ai_addrlen = (curl_socklen_t)ss_size; + ca->ai_addr = NULL; + ca->ai_canonname = NULL; + ca->ai_next = NULL; + + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); + memcpy(ca->ai_addr, ai->ai_addr, ss_size); + + if(namelen) { + size_t i; + ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size); + for(i = 0; i < namelen; ++i) /* convert wide string to ascii */ + ca->ai_canonname[i] = (char)ai->ai_canonname[i]; + ca->ai_canonname[namelen] = '\0'; + } + + /* if the return list is empty, this becomes the first element */ + if(!cafirst) + cafirst = ca; + + /* add this element last in the return list */ + if(calast) + calast->ai_next = ca; + calast = ca; + } + + /* if we failed, also destroy the Curl_addrinfo list */ + if(error) { + Curl_freeaddrinfo(cafirst); + cafirst = NULL; + } + else if(!cafirst) { +#ifdef EAI_NONAME + /* rfc3493 conformant */ + error = EAI_NONAME; +#else + /* rfc3493 obsoleted */ + error = EAI_NODATA; +#endif +#ifdef USE_WINSOCK + SET_SOCKERRNO(error); +#endif + } + tsd->res = cafirst; + } + + if(tsd->w8.res) { + Curl_FreeAddrInfoExW(tsd->w8.res); + tsd->w8.res = NULL; + } + + if(error) { + tsd->sock_error = SOCKERRNO?SOCKERRNO:error; + if(tsd->sock_error == 0) + tsd->sock_error = RESOLVER_ENOMEM; + } + else { + Curl_addrinfo_set_port(tsd->res, tsd->port); + } + + Curl_mutex_acquire(tsd->mtx); + if(tsd->done) { + /* too late, gotta clean up the mess */ + Curl_mutex_release(tsd->mtx); + destroy_thread_sync_data(tsd); + free(td); + } + else { +#ifndef CURL_DISABLE_SOCKETPAIR + char buf[1]; + if(tsd->sock_pair[1] != CURL_SOCKET_BAD) { + /* DNS has been resolved, signal client task */ + buf[0] = 1; + if(swrite(tsd->sock_pair[1], buf, sizeof(buf)) < 0) { + /* update sock_erro to errno */ + tsd->sock_error = SOCKERRNO; + } + } +#endif + tsd->done = 1; + Curl_mutex_release(tsd->mtx); + if(td->complete_ev) + SetEvent(td->complete_ev); /* Notify caller that the query completed */ + } +} +#endif #ifdef HAVE_GETADDRINFO @@ -391,9 +553,21 @@ static void destroy_async_data(struct Curl_async *async) Curl_mutex_release(td->tsd.mtx); if(!done) { +#ifdef _WIN32 + if(td->complete_ev) + CloseHandle(td->complete_ev); + else +#endif Curl_thread_destroy(td->thread_hnd); } else { +#ifdef _WIN32 + if(td->complete_ev) { + Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev); + WaitForSingleObject(td->complete_ev, INFINITE); + CloseHandle(td->complete_ev); + } +#endif if(td->thread_hnd != curl_thread_t_null) Curl_thread_join(&td->thread_hnd); @@ -428,9 +602,9 @@ static bool init_resolve_thread(struct Curl_easy *data, { struct thread_data *td = calloc(1, sizeof(struct thread_data)); int err = ENOMEM; - struct Curl_async *asp = &data->conn->resolve_async; + struct Curl_async *asp = &data->state.async; - data->conn->resolve_async.tdata = td; + data->state.async.tdata = td; if(!td) goto errno_exit; @@ -439,6 +613,9 @@ static bool init_resolve_thread(struct Curl_easy *data, asp->status = 0; asp->dns = NULL; td->thread_hnd = curl_thread_t_null; +#ifdef _WIN32 + td->complete_ev = NULL; +#endif if(!init_thread_sync_data(td, hostname, port, hints)) { asp->tdata = NULL; @@ -454,6 +631,41 @@ static bool init_resolve_thread(struct Curl_easy *data, /* The thread will set this to 1 when complete. */ td->tsd.done = 0; +#ifdef _WIN32 + if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW && + Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW) { +#define MAX_NAME_LEN 256 /* max domain name is 253 chars */ +#define MAX_PORT_LEN 8 + WCHAR namebuf[MAX_NAME_LEN]; + WCHAR portbuf[MAX_PORT_LEN]; + /* calculate required length */ + int w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname, + -1, NULL, 0); + if((w_len > 0) && (w_len < MAX_NAME_LEN)) { + /* do utf8 conversion */ + w_len = MultiByteToWideChar(CP_UTF8, 0, hostname, -1, namebuf, w_len); + if((w_len > 0) && (w_len < MAX_NAME_LEN)) { + swprintf(portbuf, MAX_PORT_LEN, L"%d", port); + td->tsd.w8.hints.ai_family = hints->ai_family; + td->tsd.w8.hints.ai_socktype = hints->ai_socktype; + td->complete_ev = CreateEvent(NULL, TRUE, FALSE, NULL); + if(!td->complete_ev) { + /* failed to start, mark it as done here for proper cleanup. */ + td->tsd.done = 1; + goto err_exit; + } + err = Curl_GetAddrInfoExW(namebuf, portbuf, NS_DNS, + NULL, &td->tsd.w8.hints, &td->tsd.w8.res, + NULL, &td->tsd.w8.overlapped, + &query_complete, &td->tsd.w8.cancel_ev); + if(err != WSA_IO_PENDING) + query_complete(err, 0, &td->tsd.w8.overlapped); + return TRUE; + } + } + } +#endif + #ifdef HAVE_GETADDRINFO td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd); #else @@ -488,11 +700,24 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data, CURLcode result = CURLE_OK; DEBUGASSERT(data); - td = data->conn->resolve_async.tdata; + td = data->state.async.tdata; DEBUGASSERT(td); +#ifdef _WIN32 + DEBUGASSERT(td->complete_ev || td->thread_hnd != curl_thread_t_null); +#else DEBUGASSERT(td->thread_hnd != curl_thread_t_null); +#endif /* wait for the thread to resolve the name */ +#ifdef _WIN32 + if(td->complete_ev) { + WaitForSingleObject(td->complete_ev, INFINITE); + CloseHandle(td->complete_ev); + if(entry) + result = getaddrinfo_complete(data); + } + else +#endif if(Curl_thread_join(&td->thread_hnd)) { if(entry) result = getaddrinfo_complete(data); @@ -500,18 +725,18 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data, else DEBUGASSERT(0); - data->conn->resolve_async.done = TRUE; + data->state.async.done = TRUE; if(entry) - *entry = data->conn->resolve_async.dns; + *entry = data->state.async.dns; - if(!data->conn->resolve_async.dns && report) + if(!data->state.async.dns && report) /* a name was not resolved, report error */ result = Curl_resolver_error(data); - destroy_async_data(&data->conn->resolve_async); + destroy_async_data(&data->state.async); - if(!data->conn->resolve_async.dns && report) + if(!data->state.async.dns && report) connclose(data->conn, "asynch resolve failed"); return result; @@ -524,7 +749,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data, */ void Curl_resolver_kill(struct Curl_easy *data) { - struct thread_data *td = data->conn->resolve_async.tdata; + struct thread_data *td = data->state.async.tdata; /* 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 @@ -563,7 +788,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, struct Curl_dns_entry **entry) { - struct thread_data *td = data->conn->resolve_async.tdata; + struct thread_data *td = data->state.async.tdata; int done = 0; DEBUGASSERT(entry); @@ -581,13 +806,13 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, if(done) { getaddrinfo_complete(data); - if(!data->conn->resolve_async.dns) { + if(!data->state.async.dns) { CURLcode result = Curl_resolver_error(data); - destroy_async_data(&data->conn->resolve_async); + destroy_async_data(&data->state.async); return result; } - destroy_async_data(&data->conn->resolve_async); - *entry = data->conn->resolve_async.dns; + destroy_async_data(&data->state.async); + *entry = data->state.async.dns; } else { /* poll for name lookup done with exponential backoff up to 250ms */ @@ -619,9 +844,9 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks) int ret_val = 0; timediff_t milli; timediff_t ms; - struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver; + struct resdata *reslv = (struct resdata *)data->state.async.resolver; #ifndef CURL_DISABLE_SOCKETPAIR - struct thread_data *td = data->conn->resolve_async.tdata; + struct thread_data *td = data->state.async.tdata; #else (void)socks; #endif @@ -662,7 +887,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, int port, int *waitp) { - struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver; + struct resdata *reslv = (struct resdata *)data->state.async.resolver; *waitp = 0; /* default to synchronous response */ @@ -691,7 +916,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, { struct addrinfo hints; int pf = PF_INET; - struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver; + struct resdata *reslv = (struct resdata *)data->state.async.resolver; *waitp = 0; /* default to synchronous response */ diff --git a/libs/libcurl/src/bufref.c b/libs/libcurl/src/bufref.c index 3b69e5958e..644aebf188 100644 --- a/libs/libcurl/src/bufref.c +++ b/libs/libcurl/src/bufref.c @@ -25,6 +25,7 @@ #include "curl_setup.h" #include "urldata.h" #include "bufref.h" +#include "strdup.h" #include "curl_memory.h" #include "memdebug.h" @@ -116,12 +117,9 @@ CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len) DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH); if(ptr) { - cpy = malloc(len + 1); + cpy = Curl_memdup0(ptr, len); if(!cpy) return CURLE_OUT_OF_MEMORY; - if(len) - memcpy(cpy, ptr, len); - cpy[len] = '\0'; } Curl_bufref_set(br, cpy, len, curl_free); diff --git a/libs/libcurl/src/c-hyper.c b/libs/libcurl/src/c-hyper.c index efb534ccad..4b479733ab 100644 --- a/libs/libcurl/src/c-hyper.c +++ b/libs/libcurl/src/c-hyper.c @@ -148,7 +148,7 @@ static int hyper_each_header(void *userdata, if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) { failf(data, "Too long response header"); - data->state.hresult = CURLE_OUT_OF_MEMORY; + data->state.hresult = CURLE_TOO_LARGE; return HYPER_ITER_BREAK; } @@ -325,6 +325,9 @@ static CURLcode empty_header(struct Curl_easy *data) CURLE_WRITE_ERROR : CURLE_OK; if(result) failf(data, "hyperstream: couldn't pass blank header"); + /* Hyper does chunked decoding itself. If it was added during + * response header processing, remove it again. */ + Curl_cwriter_remove_by_name(data, "chunked"); } return result; } diff --git a/libs/libcurl/src/cf-h1-proxy.c b/libs/libcurl/src/cf-h1-proxy.c index a49d6869a6..1725c0e509 100644 --- a/libs/libcurl/src/cf-h1-proxy.c +++ b/libs/libcurl/src/cf-h1-proxy.c @@ -70,6 +70,7 @@ struct h1_tunnel_state { struct dynbuf request_data; size_t nsent; size_t headerlines; + struct Curl_chunker ch; enum keeponval { KEEPON_DONE, KEEPON_CONNECT, @@ -133,6 +134,7 @@ static CURLcode tunnel_init(struct Curl_cfilter *cf, Curl_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS); Curl_dyn_init(&ts->request_data, DYN_HTTP_REQUEST); + Curl_httpchunk_init(data, &ts->ch, TRUE); *pts = ts; connkeep(cf->conn, "HTTP proxy CONNECT"); @@ -146,14 +148,6 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf, { if(ts->tunnel_state == new_state) return; - /* leaving this one */ - switch(ts->tunnel_state) { - case H1_TUNNEL_CONNECT: - data->req.ignorebody = FALSE; - break; - default: - break; - } /* entering this one */ switch(new_state) { case H1_TUNNEL_INIT: @@ -183,7 +177,7 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf, infof(data, "CONNECT phase completed"); data->state.authproxy.done = TRUE; data->state.authproxy.multipass = FALSE; - /* FALLTHROUGH */ + FALLTHROUGH(); case H1_TUNNEL_FAILED: if(new_state == H1_TUNNEL_FAILED) CURL_TRC_CF(data, cf, "new tunnel state 'failed'"); @@ -212,6 +206,7 @@ static void tunnel_free(struct Curl_cfilter *cf, 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; } @@ -344,8 +339,8 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf, STRCONST("chunked"))) { infof(data, "CONNECT responded chunked"); ts->chunked_encoding = TRUE; - /* init our chunky engine */ - Curl_httpchunk_init(data); + /* reset our chunky engine */ + Curl_httpchunk_reset(data, &ts->ch, TRUE); } } else if(Curl_compareheader(header, @@ -373,7 +368,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, struct SingleRequest *k = &data->req; curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data); char *linep; - size_t perline; + size_t line_len; int error, writetype; #define SELECT_OK 0 @@ -432,17 +427,17 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, break; } } - else { + else if(ts->chunked_encoding) { /* chunked-encoded body, so we need to do the chunked dance properly to know when the end of the body is reached */ - CHUNKcode r; - CURLcode extra; size_t consumed = 0; /* now parse the chunked piece of data so that we can properly tell when the stream ends */ - r = Curl_httpchunk_read(data, &byte, 1, &consumed, &extra); - if(r == CHUNKE_STOP) { + result = Curl_httpchunk_read(data, &ts->ch, &byte, 1, &consumed); + if(result) + return result; + if(Curl_httpchunk_is_done(data, &ts->ch)) { /* we're done reading chunks! */ infof(data, "chunk reading DONE"); ts->keepon = KEEPON_DONE; @@ -462,19 +457,19 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, ts->headerlines++; linep = Curl_dyn_ptr(&ts->rcvbuf); - perline = Curl_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */ + line_len = Curl_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */ /* output debug if that is requested */ - Curl_debug(data, CURLINFO_HEADER_IN, linep, perline); + Curl_debug(data, CURLINFO_HEADER_IN, linep, line_len); /* send the header to the callback */ writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT | (ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0); - result = Curl_client_write(data, writetype, linep, perline); + result = Curl_client_write(data, writetype, linep, line_len); if(result) return result; - result = Curl_bump_headersize(data, perline, TRUE); + result = Curl_bump_headersize(data, line_len, TRUE); if(result) return result; @@ -497,29 +492,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, " bytes of response-body", ts->cl); } else if(ts->chunked_encoding) { - CHUNKcode r; - CURLcode extra; - size_t consumed = 0; - infof(data, "Ignore chunked response-body"); - - /* We set ignorebody true here since the chunked decoder - function will acknowledge that. Pay attention so that this is - cleared again when this function returns! */ - k->ignorebody = TRUE; - - if(linep[1] == '\n') - /* this can only be a LF if the letter at index 0 was a CR */ - linep++; - - /* now parse the chunked piece of data so that we can properly - tell when the stream ends */ - r = Curl_httpchunk_read(data, linep + 1, 1, &consumed, &extra); - if(r == CHUNKE_STOP) { - /* we're done reading chunks! */ - infof(data, "chunk reading DONE"); - ts->keepon = KEEPON_DONE; - } } else { /* without content-length or chunked encoding, we @@ -752,7 +725,7 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf, } if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent")) && - data->set.str[STRING_USERAGENT]) { + data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) { struct dynbuf ua; Curl_dyn_init(&ua, DYN_HTTP_REQUEST); result = Curl_dyn_addf(&ua, "User-Agent: %s\r\n", @@ -912,7 +885,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf, if(result) goto out; h1_tunnel_go_state(cf, ts, H1_TUNNEL_CONNECT, data); - /* FALLTHROUGH */ + FALLTHROUGH(); case H1_TUNNEL_CONNECT: /* see that the request is completely sent */ @@ -921,7 +894,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf, if(result || !done) goto out; h1_tunnel_go_state(cf, ts, H1_TUNNEL_RECEIVE, data); - /* FALLTHROUGH */ + FALLTHROUGH(); case H1_TUNNEL_RECEIVE: /* read what is there */ @@ -936,7 +909,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf, goto out; /* got it */ h1_tunnel_go_state(cf, ts, H1_TUNNEL_RESPONSE, data); - /* FALLTHROUGH */ + FALLTHROUGH(); case H1_TUNNEL_RESPONSE: CURL_TRC_CF(data, cf, "CONNECT response"); @@ -1030,6 +1003,14 @@ out: *done = (result == CURLE_OK) && tunnel_is_established(cf->ctx); if(*done) { cf->connected = TRUE; + /* Restore `data->req` fields that may habe been touched */ + data->req.header = TRUE; /* assume header */ + data->req.bytecount = 0; + data->req.ignorebody = FALSE; + Curl_client_cleanup(data); + Curl_pgrsSetUploadCounter(data, 0); + Curl_pgrsSetDownloadCounter(data, 0); + tunnel_free(cf, data); } return result; diff --git a/libs/libcurl/src/cf-h2-proxy.c b/libs/libcurl/src/cf-h2-proxy.c index f69098b704..83915a6e26 100644 --- a/libs/libcurl/src/cf-h2-proxy.c +++ b/libs/libcurl/src/cf-h2-proxy.c @@ -155,7 +155,7 @@ static void h2_tunnel_go_state(struct Curl_cfilter *cf, infof(data, "CONNECT phase completed"); data->state.authproxy.done = TRUE; data->state.authproxy.multipass = FALSE; - /* FALLTHROUGH */ + FALLTHROUGH(); case H2_TUNNEL_FAILED: if(new_state == H2_TUNNEL_FAILED) CURL_TRC_CF(data, cf, "[%d] new tunnel state 'failed'", ts->stream_id); @@ -221,10 +221,10 @@ static void drain_tunnel(struct Curl_cfilter *cf, bits = CURL_CSELECT_IN; if(!tunnel->closed && !tunnel->reset && tunnel->upload_blocked_len) bits |= CURL_CSELECT_OUT; - if(data->state.dselect_bits != bits) { - CURL_TRC_CF(data, cf, "[%d] DRAIN dselect_bits=%x", + if(data->state.select_bits != bits) { + CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x", tunnel->stream_id, bits); - data->state.dselect_bits = bits; + data->state.select_bits = bits; Curl_expire(data, 0, EXPIRE_RUN_NOW); } } @@ -1033,7 +1033,7 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf, if(result) goto out; h2_tunnel_go_state(cf, ts, H2_TUNNEL_CONNECT, data); - /* FALLTHROUGH */ + FALLTHROUGH(); case H2_TUNNEL_CONNECT: /* see that the request is completely sent */ @@ -1052,7 +1052,7 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf, result = CURLE_OK; goto out; } - /* FALLTHROUGH */ + FALLTHROUGH(); case H2_TUNNEL_RESPONSE: DEBUGASSERT(ts->has_final_response); diff --git a/libs/libcurl/src/cf-haproxy.c b/libs/libcurl/src/cf-haproxy.c index 6036e028a5..902de36345 100644 --- a/libs/libcurl/src/cf-haproxy.c +++ b/libs/libcurl/src/cf-haproxy.c @@ -125,7 +125,7 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf, if(result) goto out; ctx->state = HAPROXY_SEND; - /* FALLTHROUGH */ + FALLTHROUGH(); case HAPROXY_SEND: len = Curl_dyn_len(&ctx->data_out); if(len > 0) { @@ -141,7 +141,7 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf, } } ctx->state = HAPROXY_DONE; - /* FALLTHROUGH */ + FALLTHROUGH(); default: Curl_dyn_free(&ctx->data_out); break; diff --git a/libs/libcurl/src/cf-https-connect.c b/libs/libcurl/src/cf-https-connect.c index f2ae2cbee6..05e6bdf044 100644 --- a/libs/libcurl/src/cf-https-connect.c +++ b/libs/libcurl/src/cf-https-connect.c @@ -266,7 +266,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf, cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", cf->conn->transport); ctx->state = CF_HC_CONNECT; - /* FALLTHROUGH */ + FALLTHROUGH(); case CF_HC_CONNECT: if(cf_hc_baller_is_active(&ctx->h3_baller)) { diff --git a/libs/libcurl/src/cf-socket.c b/libs/libcurl/src/cf-socket.c index 8582fdff64..31b0291579 100644 --- a/libs/libcurl/src/cf-socket.c +++ b/libs/libcurl/src/cf-socket.c @@ -137,14 +137,14 @@ static void nosigpipe(struct Curl_easy *data, #define nosigpipe(x,y) Curl_nop_stmt #endif -#if defined(__DragonFly__) || defined(HAVE_WINSOCK2_H) +#if defined(__DragonFly__) || defined(USE_WINSOCK) /* DragonFlyBSD and Windows use millisecond units */ #define KEEPALIVE_FACTOR(x) (x *= 1000) #else #define KEEPALIVE_FACTOR(x) #endif -#if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS) +#if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS) #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) struct tcp_keepalive { @@ -163,7 +163,9 @@ tcpkeepalive(struct Curl_easy *data, /* only set IDLE and INTVL if setting KEEPALIVE is successful */ if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval, sizeof(optval)) < 0) { - infof(data, "Failed to set SO_KEEPALIVE on fd %d", sockfd); + infof(data, "Failed to set SO_KEEPALIVE on fd " + "%" CURL_FORMAT_SOCKET_T ": errno %d", + sockfd, SOCKERRNO); } else { #if defined(SIO_KEEPALIVE_VALS) @@ -178,8 +180,9 @@ tcpkeepalive(struct Curl_easy *data, vals.keepaliveinterval = optval; if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals), NULL, 0, &dummy, NULL, NULL) != 0) { - infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d", - (int)sockfd, WSAGetLastError()); + infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd " + "%" CURL_FORMAT_SOCKET_T ": errno %d", + sockfd, SOCKERRNO); } #else #ifdef TCP_KEEPIDLE @@ -187,7 +190,9 @@ tcpkeepalive(struct Curl_easy *data, KEEPALIVE_FACTOR(optval); if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&optval, sizeof(optval)) < 0) { - infof(data, "Failed to set TCP_KEEPIDLE on fd %d", sockfd); + infof(data, "Failed to set TCP_KEEPIDLE on fd " + "%" CURL_FORMAT_SOCKET_T ": errno %d", + sockfd, SOCKERRNO); } #elif defined(TCP_KEEPALIVE) /* Mac OS X style */ @@ -195,7 +200,9 @@ tcpkeepalive(struct Curl_easy *data, KEEPALIVE_FACTOR(optval); if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, (void *)&optval, sizeof(optval)) < 0) { - infof(data, "Failed to set TCP_KEEPALIVE on fd %d", sockfd); + infof(data, "Failed to set TCP_KEEPALIVE on fd " + "%" CURL_FORMAT_SOCKET_T ": errno %d", + sockfd, SOCKERRNO); } #endif #ifdef TCP_KEEPINTVL @@ -203,7 +210,9 @@ tcpkeepalive(struct Curl_easy *data, KEEPALIVE_FACTOR(optval); if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&optval, sizeof(optval)) < 0) { - infof(data, "Failed to set TCP_KEEPINTVL on fd %d", sockfd); + infof(data, "Failed to set TCP_KEEPINTVL on fd " + "%" CURL_FORMAT_SOCKET_T ": errno %d", + sockfd, SOCKERRNO); } #endif #endif @@ -783,6 +792,7 @@ struct cf_socket_ctx { #endif BIT(got_first_byte); /* if first byte was received */ BIT(accepted); /* socket was accepted, not connected */ + BIT(sock_connected); /* socket is "connected", e.g. in UDP */ BIT(active); BIT(buffer_recv); }; @@ -983,20 +993,14 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf, if(result) goto out; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - { - const char *ipmsg; #ifdef ENABLE_IPV6 - if(ctx->addr.family == AF_INET6) { - set_ipv6_v6only(ctx->sock, 0); - ipmsg = " Trying [%s]:%d..."; - } - else -#endif - ipmsg = " Trying %s:%d..."; - infof(data, ipmsg, ctx->r_ip, ctx->r_port); + if(ctx->addr.family == AF_INET6) { + set_ipv6_v6only(ctx->sock, 0); + infof(data, " Trying [%s]:%d...", ctx->r_ip, ctx->r_port); } + else #endif + infof(data, " Trying %s:%d...", ctx->r_ip, ctx->r_port); #ifdef ENABLE_IPV6 is_tcp = (ctx->addr.family == AF_INET @@ -1054,7 +1058,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf, /* set socket non-blocking */ (void)curlx_nonblock(ctx->sock, TRUE); - + ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM); out: if(result) { if(ctx->sock != CURL_SOCKET_BAD) { @@ -1242,11 +1246,14 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf, struct cf_socket_ctx *ctx = cf->ctx; if(ctx->sock != CURL_SOCKET_BAD) { - if(!cf->connected) + if(!cf->connected) { Curl_pollset_set_out_only(data, ps, ctx->sock); - else + CURL_TRC_CF(data, cf, "adjust_pollset(!connected) -> %d socks", ps->num); + } + else if(!ctx->active) { Curl_pollset_add_in(data, ps, ctx->sock); - CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num); + CURL_TRC_CF(data, cf, "adjust_pollset(!active) -> %d socks", ps->num); + } } } @@ -1429,36 +1436,11 @@ out: static void conn_set_primary_ip(struct Curl_cfilter *cf, struct Curl_easy *data) { -#ifdef HAVE_GETPEERNAME struct cf_socket_ctx *ctx = cf->ctx; - if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) { - /* TFTP does not connect the endpoint: getpeername() failed with errno - 107: Transport endpoint is not connected */ - - char buffer[STRERROR_LEN]; - struct Curl_sockaddr_storage ssrem; - curl_socklen_t plen; - int port; - plen = sizeof(ssrem); - memset(&ssrem, 0, plen); - if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) { - int error = SOCKERRNO; - failf(data, "getpeername() failed with errno %d: %s", - error, Curl_strerror(error, buffer, sizeof(buffer))); - return; - } - if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, - cf->conn->primary_ip, &port)) { - failf(data, "ssrem inet_ntop() failed with errno %d: %s", - errno, Curl_strerror(errno, buffer, sizeof(buffer))); - return; - } - } -#else - cf->conn->primary_ip[0] = 0; (void)data; -#endif + DEBUGASSERT(sizeof(ctx->r_ip) == sizeof(cf->conn->primary_ip)); + memcpy(cf->conn->primary_ip, ctx->r_ip, sizeof(cf->conn->primary_ip)); } static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data) @@ -1574,7 +1556,7 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf, *when = ctx->first_byte_at; break; } - /* FALLTHROUGH */ + FALLTHROUGH(); default: *when = ctx->connected_at; break; @@ -1648,10 +1630,17 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf, /* QUIC needs a connected socket, nonblocking */ DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD); +#if defined(__APPLE__) && defined(USE_OPENSSL_QUIC) + (void)rc; + /* On macOS OpenSSL QUIC fails on connected sockets. + * see: */ +#else rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen); if(-1 == rc) { return socket_connect_result(data, ctx->r_ip, SOCKERRNO); } + ctx->sock_connected = TRUE; +#endif set_local_ip(cf, data); CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T " connected: [%s:%d] -> [%s:%d]", diff --git a/libs/libcurl/src/cf-socket.h b/libs/libcurl/src/cf-socket.h index 805e612bd4..6031506526 100644 --- a/libs/libcurl/src/cf-socket.h +++ b/libs/libcurl/src/cf-socket.h @@ -34,23 +34,6 @@ struct Curl_easy; struct connectdata; struct Curl_sockaddr_ex; -#ifndef SIZEOF_CURL_SOCKET_T -/* configure and cmake check and set the define */ -# ifdef _WIN64 -# define SIZEOF_CURL_SOCKET_T 8 -# else -/* default guess */ -# define SIZEOF_CURL_SOCKET_T 4 -# endif -#endif - -#if SIZEOF_CURL_SOCKET_T < 8 -# define CURL_FORMAT_SOCKET_T "d" -#else -# define CURL_FORMAT_SOCKET_T "qd" -#endif - - /* * The Curl_sockaddr_ex structure is basically libcurl's external API * curl_sockaddr structure with enough space available to directly hold any diff --git a/libs/libcurl/src/cfilters.c b/libs/libcurl/src/cfilters.c index 72783eb53d..653220ddb7 100644 --- a/libs/libcurl/src/cfilters.c +++ b/libs/libcurl/src/cfilters.c @@ -760,25 +760,11 @@ static void ps_add(struct Curl_easy *data, struct easy_pollset *ps, void Curl_pollset_add_socks(struct Curl_easy *data, struct easy_pollset *ps, int (*get_socks_cb)(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks)) { curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; int bitmap; - DEBUGASSERT(data->conn); - bitmap = get_socks_cb(data, data->conn, socks); - ps_add(data, ps, bitmap, socks); -} - -void Curl_pollset_add_socks2(struct Curl_easy *data, - struct easy_pollset *ps, - int (*get_socks_cb)(struct Curl_easy *data, - curl_socket_t *socks)) -{ - curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; - int bitmap; - bitmap = get_socks_cb(data, socks); ps_add(data, ps, bitmap, socks); } diff --git a/libs/libcurl/src/cfilters.h b/libs/libcurl/src/cfilters.h index a343ea5fb6..5fc11be79c 100644 --- a/libs/libcurl/src/cfilters.h +++ b/libs/libcurl/src/cfilters.h @@ -530,12 +530,7 @@ void Curl_pollset_set(struct Curl_easy *data, void Curl_pollset_add_socks(struct Curl_easy *data, struct easy_pollset *ps, int (*get_socks_cb)(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks)); -void Curl_pollset_add_socks2(struct Curl_easy *data, - struct easy_pollset *ps, - int (*get_socks_cb)(struct Curl_easy *data, - curl_socket_t *socks)); /** * Check if the pollset, as is, wants to read and/or write regarding diff --git a/libs/libcurl/src/config-os400.h b/libs/libcurl/src/config-os400.h index 355399a1bc..af97f64947 100644 --- a/libs/libcurl/src/config-os400.h +++ b/libs/libcurl/src/config-os400.h @@ -116,12 +116,6 @@ /* Define if you have the GNU gssapi libraries */ #undef HAVE_GSSGNU -/* Define if you have the Heimdal gssapi libraries */ -#define HAVE_GSSHEIMDAL - -/* Define if you have the MIT gssapi libraries */ -#undef HAVE_GSSMIT - /* Define if you need the malloc.h header file even with stdlib.h */ /* #define NEED_MALLOC_H 1 */ diff --git a/libs/libcurl/src/config-win32.h b/libs/libcurl/src/config-win32.h index 388871d84a..2514a09c33 100644 --- a/libs/libcurl/src/config-win32.h +++ b/libs/libcurl/src/config-win32.h @@ -97,15 +97,6 @@ #define HAVE_UNISTD_H 1 #endif -/* Define if you have the header file. */ -#define HAVE_WINDOWS_H 1 - -/* Define if you have the header file. */ -#define HAVE_WINSOCK2_H 1 - -/* Define if you have the header file. */ -#define HAVE_WS2TCPIP_H 1 - /* Define to 1 if you have the header file. */ #if defined(__MINGW32__) #define HAVE_LIBGEN_H 1 @@ -167,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 @@ -296,52 +283,6 @@ /* Define to the size of `curl_off_t', as computed by sizeof. */ #define SIZEOF_CURL_OFF_T 8 -/* ---------------------------------------------------------------- */ -/* BSD-style lwIP TCP/IP stack SPECIFIC */ -/* ---------------------------------------------------------------- */ - -/* Define to use BSD-style lwIP TCP/IP stack. */ -/* #define USE_LWIPSOCK 1 */ - -#ifdef USE_LWIPSOCK -# undef USE_WINSOCK -# undef HAVE_WINSOCK2_H -# undef HAVE_WS2TCPIP_H -# undef HAVE_GETHOSTNAME -# undef LWIP_POSIX_SOCKETS_IO_NAMES -# undef RECV_TYPE_ARG1 -# undef RECV_TYPE_ARG3 -# undef SEND_TYPE_ARG1 -# undef SEND_TYPE_ARG3 -# define HAVE_GETHOSTBYNAME_R -# define HAVE_GETHOSTBYNAME_R_6 -# define LWIP_POSIX_SOCKETS_IO_NAMES 0 -# define RECV_TYPE_ARG1 int -# define RECV_TYPE_ARG3 size_t -# define SEND_TYPE_ARG1 int -# define SEND_TYPE_ARG3 size_t -#endif - -/* ---------------------------------------------------------------- */ -/* Watt-32 tcp/ip SPECIFIC */ -/* ---------------------------------------------------------------- */ - -#ifdef USE_WATT32 - #include - #undef byte - #undef word - #undef USE_WINSOCK - #undef HAVE_WINSOCK2_H - #undef HAVE_WS2TCPIP_H - #define HAVE_SYS_IOCTL_H - #define HAVE_SYS_SOCKET_H - #define HAVE_NETINET_IN_H - #define HAVE_NETDB_H - #define HAVE_ARPA_INET_H - #define SOCKET int -#endif - - /* ---------------------------------------------------------------- */ /* COMPILER SPECIFIC */ /* ---------------------------------------------------------------- */ @@ -533,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 diff --git a/libs/libcurl/src/config-win32ce.h b/libs/libcurl/src/config-win32ce.h index 70a95d0411..7e913dffbe 100644 --- a/libs/libcurl/src/config-win32ce.h +++ b/libs/libcurl/src/config-win32ce.h @@ -85,15 +85,6 @@ #define HAVE_UNISTD_H 1 #endif -/* Define if you have the header file. */ -#define HAVE_WINDOWS_H 1 - -/* Define if you have the header file. */ -#define HAVE_WINSOCK2_H 1 - -/* Define if you have the header file. */ -#define HAVE_WS2TCPIP_H 1 - /* ---------------------------------------------------------------- */ /* OTHER HEADER INFO */ /* ---------------------------------------------------------------- */ diff --git a/libs/libcurl/src/connect.c b/libs/libcurl/src/connect.c index 4e77d275e5..eccdc4a7db 100644 --- a/libs/libcurl/src/connect.c +++ b/libs/libcurl/src/connect.c @@ -93,25 +93,17 @@ * transfer/connection. If the value is 0, there's no timeout (ie there's * infinite time left). If the value is negative, the timeout time has already * elapsed. - * - * If 'nowp' is non-NULL, it points to the current time. - * 'duringconnect' is FALSE if not during a connect, as then of course the - * connect timeout is not taken into account! - * + * @param data the transfer to check on + * @param nowp timestamp to use for calculdation, NULL to use Curl_now() + * @param duringconnect TRUE iff connect timeout is also taken into account. * @unittest: 1303 */ - -#define TIMEOUT_CONNECT 1 -#define TIMEOUT_MAXTIME 2 - timediff_t Curl_timeleft(struct Curl_easy *data, struct curltime *nowp, bool duringconnect) { - unsigned int timeout_set = 0; - timediff_t connect_timeout_ms = 0; - timediff_t maxtime_timeout_ms = 0; - timediff_t timeout_ms = 0; + timediff_t timeleft_ms = 0; + timediff_t ctimeleft_ms = 0; struct curltime now; /* The duration of a connect and the total transfer are calculated from two @@ -119,43 +111,35 @@ timediff_t Curl_timeleft(struct Curl_easy *data, before the connect timeout expires and we must acknowledge whichever timeout that is reached first. The total timeout is set per entire operation, while the connect timeout is set per connect. */ - - if(data->set.timeout > 0) { - timeout_set = TIMEOUT_MAXTIME; - maxtime_timeout_ms = data->set.timeout; - } - if(duringconnect) { - timeout_set |= TIMEOUT_CONNECT; - connect_timeout_ms = (data->set.connecttimeout > 0) ? - data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT; - } - if(!timeout_set) - /* no timeout */ - return 0; + if(data->set.timeout <= 0 && !duringconnect) + return 0; /* no timeout in place or checked, return "no limit" */ if(!nowp) { now = Curl_now(); nowp = &now; } - if(timeout_set & TIMEOUT_MAXTIME) { - maxtime_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop); - timeout_ms = maxtime_timeout_ms; + if(data->set.timeout > 0) { + timeleft_ms = data->set.timeout - + Curl_timediff(*nowp, data->progress.t_startop); + if(!timeleft_ms) + timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */ + if(!duringconnect) + return timeleft_ms; /* no connect check, this is it */ } - if(timeout_set & TIMEOUT_CONNECT) { - connect_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle); - - if(!(timeout_set & TIMEOUT_MAXTIME) || - (connect_timeout_ms < maxtime_timeout_ms)) - timeout_ms = connect_timeout_ms; + if(duringconnect) { + timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ? + data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT; + ctimeleft_ms = ctimeout_ms - + Curl_timediff(*nowp, data->progress.t_startsingle); + if(!ctimeleft_ms) + ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */ + if(!timeleft_ms) + return ctimeleft_ms; /* no general timeout, this is it */ } - - if(!timeout_ms) - /* avoid returning 0 as that means no timeout! */ - return -1; - - return timeout_ms; + /* return minimal time left or max amount already expired */ + return (ctimeleft_ms < timeleft_ms)? ctimeleft_ms : timeleft_ms; } /* Copies connection info into the transfer handle to make it available when @@ -405,7 +389,7 @@ static CURLcode eyeballer_new(struct eyeballer **pballer, struct eyeballer *baller; *pballer = NULL; - baller = calloc(1, sizeof(*baller) + 1000); + baller = calloc(1, sizeof(*baller)); if(!baller) return CURLE_OUT_OF_MEMORY; @@ -908,7 +892,7 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf, if(result) return result; ctx->state = SCFST_WAITING; - /* FALLTHROUGH */ + FALLTHROUGH(); case SCFST_WAITING: result = is_connected(cf, data, done); if(!result && *done) { diff --git a/libs/libcurl/src/content_encoding.c b/libs/libcurl/src/content_encoding.c index 2ea5e140be..cccf027489 100644 --- a/libs/libcurl/src/content_encoding.c +++ b/libs/libcurl/src/content_encoding.c @@ -365,11 +365,14 @@ static CURLcode gzip_do_init(struct Curl_easy *data, #ifdef OLD_ZLIB_SUPPORT /* Skip over the gzip header */ -static enum { +typedef enum { GZIP_OK, GZIP_BAD, GZIP_UNDERFLOW -} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen) +} gzip_status; + +static gzip_status check_gzip_header(unsigned char const *data, ssize_t len, + ssize_t *headerlen) { int method, flags; const ssize_t totallen = len; @@ -832,8 +835,8 @@ static const struct Curl_cwtype identity_encoding = { }; -/* supported content encodings table. */ -static const struct Curl_cwtype * const encodings[] = { +/* supported general content decoders. */ +static const struct Curl_cwtype * const general_unencoders[] = { &identity_encoding, #ifdef HAVE_LIBZ &deflate_encoding, @@ -848,6 +851,13 @@ static const struct Curl_cwtype * const encodings[] = { NULL }; +/* supported content decoders only for transfer encodings */ +static const struct Curl_cwtype * const transfer_unencoders[] = { +#ifndef CURL_DISABLE_HTTP + &Curl_httpchunk_unencoder, +#endif + NULL +}; /* Provide a list of comma-separated names of supported encodings. */ @@ -861,7 +871,7 @@ void Curl_all_content_encodings(char *buf, size_t blen) DEBUGASSERT(blen); buf[0] = 0; - for(cep = encodings; *cep; cep++) { + for(cep = general_unencoders; *cep; cep++) { ce = *cep; if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) len += strlen(ce->name) + 2; @@ -873,7 +883,7 @@ void Curl_all_content_encodings(char *buf, size_t blen) } else if(blen > len) { char *p = buf; - for(cep = encodings; *cep; cep++) { + for(cep = general_unencoders; *cep; cep++) { ce = *cep; if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) { strcpy(p, ce->name); @@ -931,12 +941,23 @@ static const struct Curl_cwtype error_writer = { }; /* Find the content encoding by name. */ -static const struct Curl_cwtype *find_encoding(const char *name, - size_t len) +static const struct Curl_cwtype *find_unencode_writer(const char *name, + size_t len, + Curl_cwriter_phase phase) { const struct Curl_cwtype * const *cep; - for(cep = encodings; *cep; cep++) { + if(phase == CURL_CW_TRANSFER_DECODE) { + for(cep = transfer_unencoders; *cep; cep++) { + const struct Curl_cwtype *ce = *cep; + if((strncasecompare(name, ce->name, len) && !ce->name[len]) || + (ce->alias && strncasecompare(name, ce->alias, len) + && !ce->alias[len])) + return ce; + } + } + /* look among the general decoders */ + for(cep = general_unencoders; *cep; cep++) { const struct Curl_cwtype *ce = *cep; if((strncasecompare(name, ce->name, len) && !ce->name[len]) || (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len])) @@ -950,7 +971,6 @@ static const struct Curl_cwtype *find_encoding(const char *name, CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, const char *enclist, int is_transfer) { - struct SingleRequest *k = &data->req; Curl_cwriter_phase phase = is_transfer? CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE; CURLcode result; @@ -969,16 +989,14 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, if(!ISSPACE(*enclist)) namelen = enclist - name + 1; - /* Special case: chunked encoding is handled at the reader level. */ - if(is_transfer && namelen == 7 && strncasecompare(name, "chunked", 7)) { - k->chunk = TRUE; /* chunks coming our way. */ - Curl_httpchunk_init(data); /* init our chunky engine. */ - } - else if(namelen) { + if(namelen) { const struct Curl_cwtype *cwt; struct Curl_cwriter *writer; - if((is_transfer && !data->set.http_transfer_encoding) || + /* 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))) || (!is_transfer && data->set.http_ce_skip)) { /* not requested, ignore */ return CURLE_OK; @@ -990,7 +1008,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, return CURLE_BAD_CONTENT_ENCODING; } - cwt = find_encoding(name, namelen); + cwt = find_unencode_writer(name, namelen, phase); if(!cwt) cwt = &error_writer; /* Defer error at use. */ diff --git a/libs/libcurl/src/cookie.c b/libs/libcurl/src/cookie.c index 03f9699bd4..73ca6282d5 100644 --- a/libs/libcurl/src/cookie.c +++ b/libs/libcurl/src/cookie.c @@ -365,7 +365,7 @@ static void strstore(char **str, const char *newstr, size_t len) DEBUGASSERT(newstr); DEBUGASSERT(str); free(*str); - *str = Curl_strndup(newstr, len); + *str = Curl_memdup0(newstr, len); } /* @@ -821,10 +821,8 @@ Curl_cookie_add(struct Curl_easy *data, endslash = memrchr(path, '/', (queryp - path)); if(endslash) { size_t pathlen = (endslash-path + 1); /* include end slash */ - co->path = malloc(pathlen + 1); /* one extra for the zero byte */ + co->path = Curl_memdup0(path, pathlen); if(co->path) { - memcpy(co->path, path, pathlen); - co->path[pathlen] = 0; /* null-terminate */ co->spath = sanitize_cookie_path(co->path); if(!co->spath) badcookie = TRUE; /* out of memory bad */ @@ -927,7 +925,7 @@ Curl_cookie_add(struct Curl_easy *data, if(!co->spath) badcookie = TRUE; fields++; /* add a field and fall down to secure */ - /* FALLTHROUGH */ + FALLTHROUGH(); case 3: co->secure = FALSE; if(strcasecompare(ptr, "TRUE")) { @@ -1229,7 +1227,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, if(data) { FILE *fp = NULL; - if(file) { + if(file && *file) { if(!strcmp(file, "-")) fp = stdin; else { diff --git a/libs/libcurl/src/curl_config.h.cmake b/libs/libcurl/src/curl_config.h.cmake index 11fa806dd1..f0f6b95c98 100644 --- a/libs/libcurl/src/curl_config.h.cmake +++ b/libs/libcurl/src/curl_config.h.cmake @@ -298,12 +298,6 @@ /* if you have the GNU gssapi libraries */ #cmakedefine HAVE_GSSGNU 1 -/* if you have the Heimdal gssapi libraries */ -#cmakedefine HAVE_GSSHEIMDAL 1 - -/* if you have the MIT gssapi libraries */ -#cmakedefine HAVE_GSSMIT 1 - /* Define to 1 if you have the `idna_strerror' function. */ #cmakedefine HAVE_IDNA_STRERROR 1 @@ -599,18 +593,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UTIME_H 1 -/* Define to 1 if you have the windows.h header file. */ -#cmakedefine HAVE_WINDOWS_H 1 - -/* Define to 1 if you have the winsock2.h header file. */ -#cmakedefine HAVE_WINSOCK2_H 1 - /* Define this symbol if your OS supports changing the contents of argv */ #cmakedefine HAVE_WRITABLE_ARGV 1 -/* Define to 1 if you have the ws2tcpip.h header file. */ -#cmakedefine HAVE_WS2TCPIP_H 1 - /* Define to 1 if you need the lber.h header file even with ldap.h */ #cmakedefine NEED_LBER_H 1 @@ -713,9 +698,6 @@ ${SIZEOF_TIME_T_CODE} /* if libPSL is in use */ #cmakedefine USE_LIBPSL 1 -/* If you want to build curl with the built-in manual */ -#cmakedefine USE_MANUAL 1 - /* if you want to use OpenLDAP code instead of legacy ldap implementation */ #cmakedefine USE_OPENLDAP 1 diff --git a/libs/libcurl/src/curl_config.h.in b/libs/libcurl/src/curl_config.h.in index ee2c680f6d..d41e70b937 100644 --- a/libs/libcurl/src/curl_config.h.in +++ b/libs/libcurl/src/curl_config.h.in @@ -323,12 +323,6 @@ /* if you have GNU GSS */ #undef HAVE_GSSGNU -/* if you have Heimdal */ -#undef HAVE_GSSHEIMDAL - -/* if you have MIT Kerberos */ -#undef HAVE_GSSMIT - /* Define to 1 if you have the header file. */ #undef HAVE_HYPER_H @@ -493,6 +487,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_PEM_H +/* if you have the functions OSSL_QUIC_client_method */ +#undef HAVE_OPENSSL_QUIC + /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_RSA_H @@ -602,6 +599,10 @@ /* Define to 1 if you have the `SSL_set0_wbio' function. */ #undef HAVE_SSL_SET0_WBIO +/* Define to 1 if you have the `SSL_set_quic_use_legacy_codepoint' function. + */ +#undef HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT + /* Define to 1 if you have the header file. */ #undef HAVE_STDATOMIC_H @@ -722,12 +723,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UTIME_H -/* Define to 1 if you have the windows.h header file. */ -#undef HAVE_WINDOWS_H - -/* Define to 1 if you have the winsock2.h header file. */ -#undef HAVE_WINSOCK2_H - /* Define to 1 if you have the header file. */ #undef HAVE_WOLFSSH_SSH_H @@ -746,9 +741,6 @@ /* Define this symbol if your OS supports changing the contents of argv */ #undef HAVE_WRITABLE_ARGV -/* Define to 1 if you have the ws2tcpip.h header file. */ -#undef HAVE_WS2TCPIP_H - /* Define to 1 if you have the header file. */ #undef HAVE_X509_H @@ -886,6 +878,9 @@ /* if ngtcp2 is in use */ #undef USE_NGTCP2 +/* if ngtcp2_crypto_boringssl is in use */ +#undef USE_NGTCP2_CRYPTO_BORINGSSL + /* if ngtcp2_crypto_gnutls is in use */ #undef USE_NGTCP2_CRYPTO_GNUTLS @@ -895,12 +890,21 @@ /* if ngtcp2_crypto_wolfssl is in use */ #undef USE_NGTCP2_CRYPTO_WOLFSSL +/* if ngtcp2 + nghttp3 is in use */ +#undef USE_NGTCP2_H3 + /* Use OpenLDAP-specific code */ #undef USE_OPENLDAP /* if OpenSSL is in use */ #undef USE_OPENSSL +/* if openssl quic + nghttp3 is in use */ +#undef USE_OPENSSL_H3 + +/* if openssl QUIC is in use */ +#undef USE_OPENSSL_QUIC + /* if quiche is in use */ #undef USE_QUICHE diff --git a/libs/libcurl/src/curl_ntlm_wb.c b/libs/libcurl/src/curl_ntlm_wb.c index 3103b9e3f4..68d2994154 100644 --- a/libs/libcurl/src/curl_ntlm_wb.c +++ b/libs/libcurl/src/curl_ntlm_wb.c @@ -266,7 +266,7 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, size_t len_in = strlen(input), len_out = 0; struct dynbuf b; char *ptr = NULL; - unsigned char *buf = (unsigned char *)data->state.buffer; + usigned char buf[1024] Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE); while(len_in > 0) { @@ -284,7 +284,7 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm, /* Read one line */ while(1) { ssize_t size = - wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, data->set.buffer_size); + wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, sizeof(buf)); if(size == -1) { if(errno == EINTR) continue; @@ -481,7 +481,7 @@ CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn, /* connection is already authenticated, * don't send a header in future requests */ *state = NTLMSTATE_LAST; - /* FALLTHROUGH */ + FALLTHROUGH(); case NTLMSTATE_LAST: Curl_safefree(*allocuserpwd); authp->done = TRUE; diff --git a/libs/libcurl/src/curl_printf.h b/libs/libcurl/src/curl_printf.h index a3c3ce773f..35a3bf81fc 100644 --- a/libs/libcurl/src/curl_printf.h +++ b/libs/libcurl/src/curl_printf.h @@ -31,6 +31,10 @@ #include +#define MERR_OK 0 +#define MERR_MEM 1 +#define MERR_TOO_LARGE 2 + # undef printf # undef fprintf # undef msnprintf diff --git a/libs/libcurl/src/curl_rtmp.c b/libs/libcurl/src/curl_rtmp.c index 0af8cdeb1a..a4b60175e7 100644 --- a/libs/libcurl/src/curl_rtmp.c +++ b/libs/libcurl/src/curl_rtmp.c @@ -79,7 +79,7 @@ const struct Curl_handler Curl_handler_rtmp = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_RTMP, /* defport */ @@ -102,7 +102,7 @@ const struct Curl_handler Curl_handler_rtmpt = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_RTMPT, /* defport */ @@ -125,7 +125,7 @@ const struct Curl_handler Curl_handler_rtmpe = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_RTMP, /* defport */ @@ -148,7 +148,7 @@ const struct Curl_handler Curl_handler_rtmpte = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_RTMPT, /* defport */ @@ -171,7 +171,7 @@ const struct Curl_handler Curl_handler_rtmps = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_RTMPS, /* defport */ @@ -194,7 +194,7 @@ const struct Curl_handler Curl_handler_rtmpts = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_RTMPS, /* defport */ diff --git a/libs/libcurl/src/curl_sasl.c b/libs/libcurl/src/curl_sasl.c index 8d78d49129..8ec942cd1c 100644 --- a/libs/libcurl/src/curl_sasl.c +++ b/libs/libcurl/src/curl_sasl.c @@ -205,18 +205,23 @@ void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data, sasl->force_ir = FALSE; /* Respect external option */ if(auth != CURLAUTH_BASIC) { - sasl->resetprefs = FALSE; - sasl->prefmech = SASL_AUTH_NONE; + unsigned short mechs = SASL_AUTH_NONE; + + /* If some usable http authentication options have been set, determine + new defaults from them. */ if(auth & CURLAUTH_BASIC) - sasl->prefmech |= SASL_MECH_PLAIN | SASL_MECH_LOGIN; + mechs |= SASL_MECH_PLAIN | SASL_MECH_LOGIN; if(auth & CURLAUTH_DIGEST) - sasl->prefmech |= SASL_MECH_DIGEST_MD5; + mechs |= SASL_MECH_DIGEST_MD5; if(auth & CURLAUTH_NTLM) - sasl->prefmech |= SASL_MECH_NTLM; + mechs |= SASL_MECH_NTLM; if(auth & CURLAUTH_BEARER) - sasl->prefmech |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2; + mechs |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2; if(auth & CURLAUTH_GSSAPI) - sasl->prefmech |= SASL_MECH_GSSAPI; + mechs |= SASL_MECH_GSSAPI; + + if(mechs != SASL_AUTH_NONE) + sasl->prefmech = mechs; } } diff --git a/libs/libcurl/src/curl_setup.h b/libs/libcurl/src/curl_setup.h index 98e0853cb0..f907684b2d 100644 --- a/libs/libcurl/src/curl_setup.h +++ b/libs/libcurl/src/curl_setup.h @@ -28,6 +28,13 @@ #define CURL_NO_OLDIES #endif +/* FIXME: Delete this once the warnings have been fixed. */ +#if !defined(CURL_WARN_SIGN_CONVERSION) +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif +#endif + /* Set default _WIN32_WINNT */ #ifdef __MINGW32__ #include <_mingw.h> @@ -53,6 +60,16 @@ # 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 +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ + !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define CURL_WINDOWS_APP +# endif +# endif #endif /* @@ -243,12 +260,39 @@ * Windows setup file includes some system headers. */ -#ifdef HAVE_WINDOWS_H +#ifdef _WIN32 # include "setup-win32.h" #endif #include +/* curl uses its own printf() function internally. It understands the GNU + * format. Use this format, so that is matches the GNU format attribute we + * use with the mingw compiler, allowing it to verify them at compile-time. + */ +#ifdef __MINGW32__ +# undef CURL_FORMAT_CURL_OFF_T +# undef CURL_FORMAT_CURL_OFF_TU +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +#endif + +/* based on logic in "curl/mprintf.h" */ + +#if (defined(__GNUC__) || defined(__clang__)) && \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(CURL_NO_FMT_CHECKS) +#if defined(__MINGW32__) && !defined(__clang__) +#define CURL_PRINTF(fmt, arg) \ + __attribute__((format(gnu_printf, fmt, arg))) +#else +#define CURL_PRINTF(fmt, arg) \ + __attribute__((format(__printf__, fmt, arg))) +#endif +#else +#define CURL_PRINTF(fmt, arg) +#endif + /* * Use getaddrinfo to resolve the IPv4 address literal. If the current network * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64, @@ -398,6 +442,24 @@ #define SIZEOF_TIME_T 4 #endif +#ifndef SIZEOF_CURL_SOCKET_T +/* configure and cmake check and set the define */ +# ifdef _WIN64 +# define SIZEOF_CURL_SOCKET_T 8 +# else +/* default guess */ +# define SIZEOF_CURL_SOCKET_T 4 +# endif +#endif + +#if SIZEOF_CURL_SOCKET_T < 8 +# define CURL_FORMAT_SOCKET_T "d" +#elif defined(__MINGW32__) +# define CURL_FORMAT_SOCKET_T "zd" +#else +# define CURL_FORMAT_SOCKET_T "qd" +#endif + /* * Default sizeof(off_t) in case it hasn't been defined in config file. */ @@ -638,6 +700,17 @@ #endif #endif +/* fallthrough attribute */ + +#if !defined(FALLTHROUGH) +#if (defined(__GNUC__) && __GNUC__ >= 7) || \ + (defined(__clang__) && __clang_major__ >= 10) +# define FALLTHROUGH() __attribute__((fallthrough)) +#else +# define FALLTHROUGH() do {} while (0) +#endif +#endif + /* * Include macros and defines that should only be processed once. */ @@ -659,10 +732,7 @@ */ #if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H) -# if defined(SOCKET) || \ - defined(USE_WINSOCK) || \ - defined(HAVE_WINSOCK2_H) || \ - defined(HAVE_WS2TCPIP_H) +# if defined(SOCKET) || defined(USE_WINSOCK) # error "WinSock and lwIP TCP/IP stack definitions shall not coexist!" # endif #endif @@ -757,7 +827,13 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, #endif #if (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \ + (defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)) || \ defined(USE_QUICHE) || defined(USE_MSH3) + +#ifdef CURL_WITH_MULTI_SSL +#error "Multi-SSL combined with QUIC is not supported" +#endif + #define ENABLE_QUIC #define USE_HTTP3 #endif diff --git a/libs/libcurl/src/curl_trc.c b/libs/libcurl/src/curl_trc.c index 9913ceaf9a..4e9b099f16 100644 --- a/libs/libcurl/src/curl_trc.c +++ b/libs/libcurl/src/curl_trc.c @@ -157,8 +157,10 @@ static struct Curl_cftype *cf_types[] = { #endif #ifdef USE_SSL &Curl_cft_ssl, +#ifndef CURL_DISABLE_PROXY &Curl_cft_ssl_proxy, #endif +#endif #if !defined(CURL_DISABLE_PROXY) #if !defined(CURL_DISABLE_HTTP) &Curl_cft_h1_proxy, diff --git a/libs/libcurl/src/curl_trc.h b/libs/libcurl/src/curl_trc.h index 27fc8fc769..3da00690e2 100644 --- a/libs/libcurl/src/curl_trc.h +++ b/libs/libcurl/src/curl_trc.h @@ -58,14 +58,7 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type, * Output a failure message on registered callbacks for transfer. */ void Curl_failf(struct Curl_easy *data, -#if defined(__GNUC__) && !defined(printf) && \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !defined(__MINGW32__) - const char *fmt, ...) - __attribute__((format(printf, 2, 3))); -#else - const char *fmt, ...); -#endif + const char *fmt, ...) CURL_PRINTF(2, 3); #define failf Curl_failf @@ -102,26 +95,14 @@ void Curl_failf(struct Curl_easy *data, * Output an informational message when transfer's verbose logging is enabled. */ void Curl_infof(struct Curl_easy *data, -#if defined(__GNUC__) && !defined(printf) && defined(CURL_HAVE_C99) && \ - !defined(__MINGW32__) - const char *fmt, ...) - __attribute__((format(printf, 2, 3))); -#else - const char *fmt, ...); -#endif + const char *fmt, ...) CURL_PRINTF(2, 3); /** * Output an informational message when both transfer's verbose logging * and connection filters verbose logging are enabled. */ void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf, -#if defined(__GNUC__) && !defined(printf) && defined(CURL_HAVE_C99) && \ - !defined(__MINGW32__) - const char *fmt, ...) - __attribute__((format(printf, 3, 4))); -#else - const char *fmt, ...); -#endif + const char *fmt, ...) CURL_PRINTF(3, 4); #else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */ /* All informational messages are not compiled in for size savings */ diff --git a/libs/libcurl/src/dict.c b/libs/libcurl/src/dict.c index 0d1208bc58..71549ccbb5 100644 --- a/libs/libcurl/src/dict.c +++ b/libs/libcurl/src/dict.c @@ -89,7 +89,7 @@ const struct Curl_handler Curl_handler_dict = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_DICT, /* defport */ @@ -122,6 +122,9 @@ static char *unescape_word(const char *input) } /* sendf() sends formatted data to the server */ +static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data, + const char *fmt, ...) CURL_PRINTF(3, 4); + static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data, const char *fmt, ...) { diff --git a/libs/libcurl/src/doh.c b/libs/libcurl/src/doh.c index 0abeb965cd..6bc2c43b10 100644 --- a/libs/libcurl/src/doh.c +++ b/libs/libcurl/src/doh.c @@ -218,7 +218,6 @@ static CURLcode dohprobe(struct Curl_easy *data, struct curl_slist *headers) { struct Curl_easy *doh = NULL; - char *nurl = NULL; CURLcode result = CURLE_OK; timediff_t timeout_ms; DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer), @@ -351,11 +350,9 @@ static CURLcode dohprobe(struct Curl_easy *data, } else goto error; - free(nurl); return CURLE_OK; error: - free(nurl); Curl_close(&doh); return result; } @@ -447,7 +444,7 @@ static DOHcode skipqname(const unsigned char *doh, size_t dohlen, return DOH_DNS_BAD_LABEL; if(dohlen < (*indexp + 1 + length)) return DOH_DNS_OUT_OF_RANGE; - *indexp += 1 + length; + *indexp += (unsigned int)(1 + length); } while(length); return DOH_OK; } @@ -459,14 +456,15 @@ static unsigned short get16bit(const unsigned char *doh, int index) static unsigned int get32bit(const unsigned char *doh, int index) { - /* make clang and gcc optimize this to bswap by incrementing - the pointer first. */ - doh += index; - - /* avoid undefined behavior by casting to unsigned before shifting - 24 bits, possibly into the sign bit. codegen is same, but - ub sanitizer won't be upset */ - return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3]; + /* make clang and gcc optimize this to bswap by incrementing + the pointer first. */ + doh += index; + + /* avoid undefined behavior by casting to unsigned before shifting + 24 bits, possibly into the sign bit. codegen is same, but + ub sanitizer won't be upset */ + return ((unsigned)doh[0] << 24) | ((unsigned)doh[1] << 16) | + ((unsigned)doh[2] << 8) | doh[3]; } static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d) @@ -904,7 +902,6 @@ UNITTEST void de_cleanup(struct dohentry *d) CURLcode Curl_doh_is_resolved(struct Curl_easy *data, struct Curl_dns_entry **dnsp) { - struct connectdata *conn = data->conn; CURLcode result; struct dohdata *dohp = data->req.doh; *dnsp = NULL; /* defaults to no response */ @@ -913,7 +910,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data, if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy && !dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) { - failf(data, "Could not DoH-resolve: %s", conn->resolve_async.hostname); + failf(data, "Could not DoH-resolve: %s", data->state.async.hostname); return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY: CURLE_COULDNT_RESOLVE_HOST; } @@ -976,7 +973,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data, Curl_freeaddrinfo(ai); } else { - conn->resolve_async.dns = dns; + data->state.async.dns = dns; *dnsp = dns; result = CURLE_OK; /* address resolution OK */ } diff --git a/libs/libcurl/src/dynbuf.c b/libs/libcurl/src/dynbuf.c index dcf3da23ac..16a47108ca 100644 --- a/libs/libcurl/src/dynbuf.c +++ b/libs/libcurl/src/dynbuf.c @@ -81,7 +81,7 @@ static CURLcode dyn_nappend(struct dynbuf *s, if(fit > s->toobig) { Curl_dyn_free(s); - return CURLE_OUT_OF_MEMORY; + return CURLE_TOO_LARGE; } else if(!a) { DEBUGASSERT(!indx); @@ -199,6 +199,9 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap) if(!rc) return CURLE_OK; + else if(rc == MERR_TOO_LARGE) + return CURLE_TOO_LARGE; + return CURLE_OUT_OF_MEMORY; #else char *str; str = vaprintf(fmt, ap); /* this allocs a new string to append */ @@ -210,8 +213,8 @@ 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; #endif - return CURLE_OUT_OF_MEMORY; } /* diff --git a/libs/libcurl/src/dynbuf.h b/libs/libcurl/src/dynbuf.h index 76b551d93b..2fd7d7e0ae 100644 --- a/libs/libcurl/src/dynbuf.h +++ b/libs/libcurl/src/dynbuf.h @@ -61,9 +61,9 @@ CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len) CURLcode Curl_dyn_add(struct dynbuf *s, const char *str) WARN_UNUSED_RESULT; CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...) - WARN_UNUSED_RESULT; + WARN_UNUSED_RESULT CURL_PRINTF(2, 3); CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap) - WARN_UNUSED_RESULT; + WARN_UNUSED_RESULT CURL_PRINTF(2, 0); void Curl_dyn_reset(struct dynbuf *s); CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail); CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set); diff --git a/libs/libcurl/src/easy.c b/libs/libcurl/src/easy.c index f5ffe259de..5aa564c808 100644 --- a/libs/libcurl/src/easy.c +++ b/libs/libcurl/src/easy.c @@ -480,13 +480,15 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */ ev->list = nxt; free(m); m = nxt; - infof(easy, "socket cb: socket %d REMOVED", s); + infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T + " REMOVED", s); } else { /* The socket 's' is already being monitored, update the activity mask. Convert from libcurl bitmask to the poll one. */ m->socket.events = socketcb2poll(what); - infof(easy, "socket cb: socket %d UPDATED as %s%s", s, + infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T + " UPDATED as %s%s", s, (what&CURL_POLL_IN)?"IN":"", (what&CURL_POLL_OUT)?"OUT":""); } @@ -510,7 +512,8 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */ m->socket.events = socketcb2poll(what); m->socket.revents = 0; ev->list = m; - infof(easy, "socket cb: socket %d ADDED as %s%s", s, + infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T + " ADDED as %s%s", s, (what&CURL_POLL_IN)?"IN":"", (what&CURL_POLL_OUT)?"OUT":""); } @@ -599,8 +602,9 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) if(fds[i].revents) { /* socket activity, tell libcurl */ int act = poll2cselect(fds[i].revents); /* convert */ - infof(multi->easyp, "call curl_multi_socket_action(socket %d)", - fds[i].fd); + infof(multi->easyp, + "call curl_multi_socket_action(socket " + "%" CURL_FORMAT_SOCKET_T ")", fds[i].fd); mcode = curl_multi_socket_action(multi, fds[i].fd, act, &ev->running_handles); } @@ -684,9 +688,9 @@ static CURLcode easy_transfer(struct Curl_multi *multi) /* Make sure to return some kind of error if there was a multi problem */ if(mcode) { result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : - /* The other multi errors should never happen, so return - something suitably generic */ - CURLE_BAD_FUNCTION_ARGUMENT; + /* The other multi errors should never happen, so return + something suitably generic */ + CURLE_BAD_FUNCTION_ARGUMENT; } return result; @@ -973,6 +977,36 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) } #endif +#ifdef CURLRES_ASYNCH + /* Clone the resolver handle, if present, for the new handle */ + if(Curl_resolver_duphandle(outcurl, + &outcurl->state.async.resolver, + data->state.async.resolver)) + goto fail; +#endif + +#ifdef USE_ARES + { + CURLcode rc; + + rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + + rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]); + if(rc && rc != CURLE_NOT_BUILT_IN) + goto fail; + } +#endif /* USE_ARES */ + Curl_initinfo(outcurl); outcurl->magic = CURLEASY_MAGIC_NUMBER; @@ -1111,7 +1145,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) if(!data->state.tempcount) /* if not pausing again, force a recv/send check of this connection as the data might've been read off the socket already */ - data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT; + data->state.select_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT; if(data->multi) { if(Curl_update_timer(data->multi)) return CURLE_ABORTED_BY_CALLBACK; diff --git a/libs/libcurl/src/easyoptions.c b/libs/libcurl/src/easyoptions.c index deade8ed71..be6073a90c 100644 --- a/libs/libcurl/src/easyoptions.c +++ b/libs/libcurl/src/easyoptions.c @@ -274,6 +274,8 @@ struct curl_easyoption Curl_easyopts[] = { {"SEEKFUNCTION", CURLOPT_SEEKFUNCTION, CURLOT_FUNCTION, 0}, {"SERVER_RESPONSE_TIMEOUT", CURLOPT_SERVER_RESPONSE_TIMEOUT, CURLOT_LONG, 0}, + {"SERVER_RESPONSE_TIMEOUT_MS", CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, + CURLOT_LONG, 0}, {"SERVICE_NAME", CURLOPT_SERVICE_NAME, CURLOT_STRING, 0}, {"SHARE", CURLOPT_SHARE, CURLOT_OBJECT, 0}, {"SOCKOPTDATA", CURLOPT_SOCKOPTDATA, CURLOT_CBPTR, 0}, @@ -373,6 +375,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return ((CURLOPT_LASTENTRY%10000) != (323 + 1)); + return ((CURLOPT_LASTENTRY%10000) != (324 + 1)); } #endif diff --git a/libs/libcurl/src/file.c b/libs/libcurl/src/file.c index 7e0570d9f9..b15b6ab408 100644 --- a/libs/libcurl/src/file.c +++ b/libs/libcurl/src/file.c @@ -113,7 +113,7 @@ const struct Curl_handler Curl_handler_file = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ file_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ 0, /* defport */ @@ -290,16 +290,15 @@ static CURLcode file_upload(struct Curl_easy *data) int fd; int mode; CURLcode result = CURLE_OK; - char *buf = data->state.buffer; + char buffer[8*1024], *uphere_save; curl_off_t bytecount = 0; struct_stat file_stat; - const char *buf2; + const char *sendbuf; /* * Since FILE: doesn't do the full init, we need to provide some extra * assignments here. */ - data->req.upload_fromhere = buf; if(!dir) return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ @@ -338,11 +337,15 @@ static CURLcode file_upload(struct Curl_easy *data) data->state.resume_from = (curl_off_t)file_stat.st_size; } + /* Yikes! Curl_fillreadbuffer uses data->req.upload_fromhere to READ + * client data to! Please, someone fix... */ + uphere_save = data->req.upload_fromhere; while(!result) { size_t nread; ssize_t nwrite; size_t readcount; - result = Curl_fillreadbuffer(data, data->set.buffer_size, &readcount); + data->req.upload_fromhere = buffer; + result = Curl_fillreadbuffer(data, sizeof(buffer), &readcount); if(result) break; @@ -356,19 +359,19 @@ static CURLcode file_upload(struct Curl_easy *data) if((curl_off_t)nread <= data->state.resume_from) { data->state.resume_from -= nread; nread = 0; - buf2 = buf; + sendbuf = buffer; } else { - buf2 = buf + data->state.resume_from; + sendbuf = buffer + data->state.resume_from; nread -= (size_t)data->state.resume_from; data->state.resume_from = 0; } } else - buf2 = buf; + sendbuf = buffer; /* write the data to the target */ - nwrite = write(fd, buf2, nread); + nwrite = write(fd, sendbuf, nread); if((size_t)nwrite != nread) { result = CURLE_SEND_ERROR; break; @@ -387,6 +390,7 @@ static CURLcode file_upload(struct Curl_easy *data) result = CURLE_ABORTED_BY_CALLBACK; close(fd); + data->req.upload_fromhere = uphere_save; return result; } @@ -413,14 +417,11 @@ static CURLcode file_do(struct Curl_easy *data, bool *done) curl_off_t expected_size = -1; bool size_known; bool fstated = FALSE; - char *buf = data->state.buffer; int fd; struct FILEPROTO *file; *done = TRUE; /* unconditionally */ - Curl_pgrsStartNow(data); - if(data->state.upload) return file_upload(data); @@ -543,21 +544,22 @@ static CURLcode file_do(struct Curl_easy *data, bool *done) Curl_pgrsTime(data, TIMER_STARTTRANSFER); while(!result) { + char tmpbuf[8*1024]; 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 < data->set.buffer_size) ? - curlx_sotouz(expected_size) : (size_t)data->set.buffer_size; + bytestoread = (expected_size < (curl_off_t)(sizeof(tmpbuf)-1)) ? + curlx_sotouz(expected_size) : (sizeof(tmpbuf)-1); } else - bytestoread = data->set.buffer_size-1; + bytestoread = sizeof(tmpbuf)-1; - nread = read(fd, buf, bytestoread); + nread = read(fd, tmpbuf, bytestoread); if(nread > 0) - buf[nread] = 0; + tmpbuf[nread] = 0; if(nread <= 0 || (size_known && (expected_size == 0))) break; @@ -565,7 +567,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done) if(size_known) expected_size -= nread; - result = Curl_client_write(data, CLIENTWRITE_BODY, buf, nread); + result = Curl_client_write(data, CLIENTWRITE_BODY, tmpbuf, nread); if(result) return result; diff --git a/libs/libcurl/src/formdata.c b/libs/libcurl/src/formdata.c index 88901c6bdd..1fd05fe186 100644 --- a/libs/libcurl/src/formdata.c +++ b/libs/libcurl/src/formdata.c @@ -277,7 +277,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, case CURLFORM_PTRNAME: current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ - /* FALLTHROUGH */ + FALLTHROUGH(); case CURLFORM_COPYNAME: if(current_form->name) return_value = CURL_FORMADD_OPTION_TWICE; @@ -303,7 +303,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, */ case CURLFORM_PTRCONTENTS: current_form->flags |= HTTPPOST_PTRCONTENTS; - /* FALLTHROUGH */ + FALLTHROUGH(); case CURLFORM_COPYCONTENTS: if(current_form->value) return_value = CURL_FORMADD_OPTION_TWICE; @@ -603,7 +603,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, app passed in a bad combo, so we better check for that first. */ if(form->name) { /* copy name (without strdup; possibly not null-terminated) */ - form->name = Curl_strndup(form->name, form->namelength? + form->name = Curl_memdup0(form->name, form->namelength? form->namelength: strlen(form->name)); } @@ -779,11 +779,9 @@ static CURLcode setname(curl_mimepart *part, const char *name, size_t len) if(!name || !len) return curl_mime_name(part, name); - zname = malloc(len + 1); + zname = Curl_memdup0(name, len); if(!zname) return CURLE_OUT_OF_MEMORY; - memcpy(zname, name, len); - zname[len] = '\0'; res = curl_mime_name(part, zname); free(zname); return res; diff --git a/libs/libcurl/src/ftp.c b/libs/libcurl/src/ftp.c index cee0d97c59..03678ac20c 100644 --- a/libs/libcurl/src/ftp.c +++ b/libs/libcurl/src/ftp.c @@ -72,6 +72,7 @@ #include "warnless.h" #include "http_proxy.h" #include "socks.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -167,7 +168,7 @@ const struct Curl_handler Curl_handler_ftp = { ftp_domore_getsock, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_FTP, /* defport */ @@ -198,7 +199,7 @@ const struct Curl_handler Curl_handler_ftps = { ftp_domore_getsock, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_FTPS, /* defport */ @@ -362,10 +363,11 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received) curl_socket_t data_sock = conn->sock[SECONDARYSOCKET]; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; - int result; + int socketstate = 0; timediff_t timeout_ms; ssize_t nread; int ftpcode; + bool response = FALSE; *received = FALSE; @@ -378,17 +380,21 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received) } /* First check whether there is a cached response from server */ - if(pp->cache_size && pp->cache && pp->cache[0] > '3') { + if(Curl_dyn_len(&pp->recvbuf) && (*Curl_dyn_ptr(&pp->recvbuf) > '3')) { /* Data connection could not be established, let's return */ infof(data, "There is negative response in cache while serv connect"); (void)Curl_GetFTPResponse(data, &nread, &ftpcode); return CURLE_FTP_ACCEPT_FAILED; } - result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0); + if(pp->overflow) + /* there is pending control data still in the buffer to read */ + response = TRUE; + else + socketstate = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0); /* see if the connection request is already here */ - switch(result) { + switch(socketstate) { case -1: /* error */ /* let's die here */ failf(data, "Error while waiting for server connect"); @@ -396,23 +402,23 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received) case 0: /* Server connect is not received yet */ break; /* loop */ default: - - if(result & CURL_CSELECT_IN2) { + if(socketstate & CURL_CSELECT_IN2) { infof(data, "Ready to accept data connection from server"); *received = TRUE; } - else if(result & CURL_CSELECT_IN) { - infof(data, "Ctrl conn has data while waiting for data conn"); - (void)Curl_GetFTPResponse(data, &nread, &ftpcode); - - if(ftpcode/100 > 3) - return CURLE_FTP_ACCEPT_FAILED; + else if(socketstate & CURL_CSELECT_IN) + response = TRUE; + break; + } + if(response) { + infof(data, "Ctrl conn has data while waiting for data conn"); + (void)Curl_GetFTPResponse(data, &nread, &ftpcode); - return CURLE_WEIRD_SERVER_REPLY; - } + if(ftpcode/100 > 3) + return CURLE_FTP_ACCEPT_FAILED; - break; - } /* switch() */ + return CURLE_WEIRD_SERVER_REPLY; + } return CURLE_OK; } @@ -553,7 +559,7 @@ static CURLcode ftp_readresp(struct Curl_easy *data, #ifdef HAVE_GSSAPI { struct connectdata *conn = data->conn; - char * const buf = data->state.buffer; + char * const buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf); /* handle the security-oriented responses 6xx ***/ switch(code) { @@ -659,7 +665,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data, * */ - if(pp->cache && (cache_skip < 2)) { + if(Curl_dyn_len(&pp->recvbuf) && (cache_skip < 2)) { /* * There's a cache left since before. We then skipping the wait for * socket action, unless this is the same cache like the previous round @@ -687,7 +693,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data, if(result) break; - if(!nread && pp->cache) + if(!nread && Curl_dyn_len(&pp->recvbuf)) /* bump cache skip counter as on repeated skips we must wait for more data */ cache_skip++; @@ -926,6 +932,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, bool possibly_non_local = TRUE; char buffer[STRERROR_LEN]; char *addr = NULL; + size_t addrlen = 0; + char ipstr[50]; /* Step 1, figure out what is requested, * accepted format : @@ -934,32 +942,17 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, if(data->set.str[STRING_FTPPORT] && (strlen(data->set.str[STRING_FTPPORT]) > 1)) { - -#ifdef ENABLE_IPV6 - size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ? - INET6_ADDRSTRLEN : strlen(string_ftpport); -#else - size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ? - INET_ADDRSTRLEN : strlen(string_ftpport); -#endif - char *ip_start = string_ftpport; char *ip_end = NULL; - char *port_start = NULL; - char *port_sep = NULL; - - addr = calloc(1, addrlen + 1); - if(!addr) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } #ifdef ENABLE_IPV6 if(*string_ftpport == '[') { /* [ipv6]:port(-range) */ - ip_start = string_ftpport + 1; - ip_end = strchr(string_ftpport, ']'); - if(ip_end) - strncpy(addr, ip_start, ip_end - ip_start); + char *ip_start = string_ftpport + 1; + ip_end = strchr(ip_start, ']'); + if(ip_end) { + addrlen = ip_end - ip_start; + addr = ip_start; + } } else #endif @@ -969,28 +962,27 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, } else { ip_end = strchr(string_ftpport, ':'); + addr = string_ftpport; if(ip_end) { /* either ipv6 or (ipv4|domain|interface):port(-range) */ + addrlen = ip_end - string_ftpport; #ifdef ENABLE_IPV6 if(Curl_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) { /* ipv6 */ port_min = port_max = 0; - strcpy(addr, string_ftpport); ip_end = NULL; /* this got no port ! */ } - else #endif - /* (ipv4|domain|interface):port(-range) */ - strncpy(addr, string_ftpport, ip_end - ip_start); } else /* ipv4|interface */ - strcpy(addr, string_ftpport); + addrlen = strlen(string_ftpport); } /* parse the port */ if(ip_end) { - port_start = strchr(ip_end, ':'); + char *port_sep = NULL; + char *port_start = strchr(ip_end, ':'); if(port_start) { port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10)); port_sep = strchr(port_start, '-'); @@ -1011,22 +1003,29 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, if(port_min > port_max) port_min = port_max = 0; - if(*addr != '\0') { + if(addrlen) { + DEBUGASSERT(addr); + if(addrlen >= sizeof(ipstr)) + goto out; + memcpy(ipstr, addr, addrlen); + ipstr[addrlen] = 0; + /* attempt to get the address of the given interface name */ switch(Curl_if2ip(conn->remote_addr->family, #ifdef ENABLE_IPV6 Curl_ipv6_scope(&conn->remote_addr->sa_addr), conn->scope_id, #endif - addr, hbuf, sizeof(hbuf))) { + ipstr, hbuf, sizeof(hbuf))) { case IF2IP_NOT_FOUND: /* not an interface, use the given string as host name instead */ - host = addr; + host = ipstr; break; case IF2IP_AF_NOT_SUPPORTED: goto out; case IF2IP_FOUND: host = hbuf; /* use the hbuf for host name */ + break; } } else @@ -1266,7 +1265,6 @@ out: } if(portsock != CURL_SOCKET_BAD) Curl_socket_close(data, conn, portsock); - free(addr); return result; } @@ -1589,13 +1587,14 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data, } /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ do { + char scratch[4*1024]; size_t readthisamountnow = - (data->state.resume_from - passed > data->set.buffer_size) ? - (size_t)data->set.buffer_size : + (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - data->state.fread_func(data->state.buffer, 1, readthisamountnow, + data->state.fread_func(scratch, 1, readthisamountnow, data->state.in); passed += actuallyread; @@ -1828,7 +1827,9 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, struct Curl_dns_entry *addr = NULL; enum resolve_t rc; unsigned short connectport; /* the local port connect() should use! */ - char *str = &data->state.buffer[4]; /* start on the first letter */ + struct pingpong *pp = &ftpc->pp; + char *str = + Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first letter */ /* if we come here again, make sure the former name is cleared */ Curl_safefree(ftpc->newhost); @@ -2106,8 +2107,9 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the last .sss part is optional and means fractions of a second */ int year, month, day, hour, minute, second; - if(ftp_213_date(&data->state.buffer[4], - &year, &month, &day, &hour, &minute, &second)) { + struct pingpong *pp = &ftpc->pp; + char *resp = Curl_dyn_ptr(&pp->recvbuf) + 4; + if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) { /* we have a time, reformat it */ char timebuf[24]; msnprintf(timebuf, sizeof(timebuf), @@ -2318,7 +2320,8 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data, { CURLcode result = CURLE_OK; curl_off_t filesize = -1; - char *buf = data->state.buffer; + char *buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf); + size_t len = data->conn->proto.ftpc.pp.nfinal; /* get the size from the ascii string: */ if(ftpcode == 213) { @@ -2326,13 +2329,13 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data, for all the digits at the end of the response and parse only those as a number. */ char *start = &buf[4]; - char *fdigit = strchr(start, '\r'); + char *fdigit = memchr(start, '\r', len); if(fdigit) { - do + fdigit--; + if(*fdigit == '\n') + fdigit--; + while(ISDIGIT(fdigit[-1]) && (fdigit > start)) fdigit--; - while(ISDIGIT(*fdigit) && (fdigit > start)); - if(!ISDIGIT(*fdigit)) - fdigit++; } else fdigit = start; @@ -2501,7 +2504,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data, * * Example D above makes this parsing a little tricky */ char *bytes; - char *buf = data->state.buffer; + char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf); bytes = strstr(buf, " bytes"); if(bytes) { long in = (long)(--bytes-buf); @@ -2770,7 +2773,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, case FTP_AUTH: /* we have gotten the response to a previous AUTH command */ - if(pp->cache_size) + if(pp->overflow) return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */ /* RFC2228 (page 5) says: @@ -2868,14 +2871,11 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, case FTP_PWD: if(ftpcode == 257) { - char *ptr = &data->state.buffer[4]; /* start on the first letter */ - const size_t buf_size = data->set.buffer_size; - char *dir; + char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first + letter */ bool entry_extracted = FALSE; - - dir = malloc(nread + 1); - if(!dir) - return CURLE_OUT_OF_MEMORY; + struct dynbuf out; + Curl_dyn_init(&out, 1000); /* Reply format is like 257[rubbish]"" and the @@ -2887,33 +2887,30 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, */ /* scan for the first double-quote for non-standard responses */ - while(ptr < &data->state.buffer[buf_size] - && *ptr != '\n' && *ptr != '\0' && *ptr != '"') + while(*ptr != '\n' && *ptr != '\0' && *ptr != '"') ptr++; if('\"' == *ptr) { /* it started good */ - char *store; - ptr++; - for(store = dir; *ptr;) { + for(ptr++; *ptr; ptr++) { if('\"' == *ptr) { if('\"' == ptr[1]) { /* "quote-doubling" */ - *store = ptr[1]; + result = Curl_dyn_addn(&out, &ptr[1], 1); ptr++; } else { /* end of path */ - entry_extracted = TRUE; + if(Curl_dyn_len(&out)) + entry_extracted = TRUE; break; /* get out of this loop */ } } else - *store = *ptr; - store++; - ptr++; + result = Curl_dyn_addn(&out, ptr, 1); + if(result) + return result; } - *store = '\0'; /* null-terminate */ } if(entry_extracted) { /* If the path name does not look like an absolute path (i.e.: it @@ -2927,6 +2924,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, The method used here is to check the server OS: we do it only if the path name looks strange to minimize overhead on other systems. */ + char *dir = Curl_dyn_ptr(&out); if(!ftpc->server_os && dir[0] != '/') { result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); @@ -2951,7 +2949,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, } else { /* couldn't get the path */ - free(dir); + Curl_dyn_free(&out); infof(data, "Failed to figure out path"); } } @@ -2961,25 +2959,23 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, case FTP_SYST: if(ftpcode == 215) { - char *ptr = &data->state.buffer[4]; /* start on the first letter */ + char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first + letter */ char *os; - char *store; - - os = malloc(nread + 1); - if(!os) - return CURLE_OUT_OF_MEMORY; + char *start; /* Reply format is like 215 */ while(*ptr == ' ') ptr++; - for(store = os; *ptr && *ptr != ' ';) - *store++ = *ptr++; - *store = '\0'; /* null-terminate */ + for(start = ptr; *ptr && *ptr != ' '; ptr++) + ; + os = Curl_memdup0(start, ptr - start); + if(!os) + return CURLE_OUT_OF_MEMORY; /* Check for special servers here. */ - if(strcasecompare(os, "OS/400")) { /* Force OS400 name format 1. */ result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); @@ -3131,7 +3127,6 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, break; case FTP_QUIT: - /* fallthrough, just stop! */ default: /* internal error */ ftp_state(data, FTP_STOP); @@ -3206,8 +3201,7 @@ static CURLcode ftp_connect(struct Curl_easy *data, conn->bits.ftp_use_control_ssl = TRUE; } - Curl_pp_setup(pp); /* once per transfer */ - Curl_pp_init(data, pp); /* init the generic pingpong data */ + Curl_pp_init(pp); /* once per transfer */ /* When we connect, we start in the state where we await the 220 response */ @@ -3258,14 +3252,13 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, case CURLE_REMOTE_FILE_NOT_FOUND: case CURLE_WRITE_ERROR: /* the connection stays alive fine even though this happened */ - /* fall-through */ case CURLE_OK: /* doesn't affect the control connection's status */ if(!premature) break; /* until we cope better with prematurely ended requests, let them * fallback as if in complete failure */ - /* FALLTHROUGH */ + FALLTHROUGH(); default: /* by default, an error means the control connection is wedged and should not be used anymore */ ftpc->ctl_valid = FALSE; @@ -4177,13 +4170,12 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data) return CURLE_OUT_OF_MEMORY; } - ftpc->dirs[0] = calloc(1, dirlen + 1); + ftpc->dirs[0] = Curl_memdup0(rawPath, dirlen); if(!ftpc->dirs[0]) { free(rawPath); return CURLE_OUT_OF_MEMORY; } - strncpy(ftpc->dirs[0], rawPath, dirlen); ftpc->dirdepth = 1; /* we consider it to be a single dir */ fileName = slashPos + 1; /* rest is file name */ } @@ -4222,12 +4214,11 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data) CWD requires a parameter and a non-existent parameter a) doesn't work on many servers and b) has no effect on the others. */ if(compLen > 0) { - char *comp = calloc(1, compLen + 1); + char *comp = Curl_memdup0(curPos, compLen); if(!comp) { free(rawPath); return CURLE_OUT_OF_MEMORY; } - strncpy(comp, curPos, compLen); ftpc->dirs[ftpc->dirdepth++] = comp; } curPos = slashPos + 1; diff --git a/libs/libcurl/src/getinfo.c b/libs/libcurl/src/getinfo.c index 28e9c06c1d..0d72f1bdf2 100644 --- a/libs/libcurl/src/getinfo.c +++ b/libs/libcurl/src/getinfo.c @@ -409,6 +409,9 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, case CURLINFO_STARTTRANSFER_TIME_T: *param_offt = data->progress.t_starttransfer; break; + case CURLINFO_QUEUE_TIME_T: + *param_offt = data->progress.t_postqueue; + break; case CURLINFO_REDIRECT_TIME_T: *param_offt = data->progress.t_redirect; break; @@ -420,7 +423,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info, break; case CURLINFO_CONN_ID: *param_offt = data->conn? - data->conn->connection_id : data->state.recent_conn_id; + data->conn->connection_id : data->state.recent_conn_id; break; default: return CURLE_UNKNOWN_OPTION; diff --git a/libs/libcurl/src/gopher.c b/libs/libcurl/src/gopher.c index f2f016a332..8adf741532 100644 --- a/libs/libcurl/src/gopher.c +++ b/libs/libcurl/src/gopher.c @@ -75,7 +75,7 @@ const struct Curl_handler Curl_handler_gopher = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_GOPHER, /* defport */ @@ -99,7 +99,7 @@ const struct Curl_handler Curl_handler_gophers = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_GOPHER, /* defport */ diff --git a/libs/libcurl/src/headers.c b/libs/libcurl/src/headers.c index bcd65be503..7999ca911d 100644 --- a/libs/libcurl/src/headers.c +++ b/libs/libcurl/src/headers.c @@ -185,7 +185,7 @@ struct curl_header *curl_easy_nextheader(CURL *easy, } static CURLcode namevalue(char *header, size_t hlen, unsigned int type, - char **name, char **value) + char **name, char **value) { char *end = header + hlen - 1; /* point to the last byte */ DEBUGASSERT(hlen); @@ -292,9 +292,10 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header, if(!end) { end = strchr(header, '\n'); if(!end) - return CURLE_BAD_FUNCTION_ARGUMENT; + /* neither CR nor LF as terminator is not a valid header */ + return CURLE_WEIRD_SERVER_REPLY; } - hlen = end - header + 1; + hlen = end - header; if((header[0] == ' ') || (header[0] == '\t')) { if(data->state.prevhead) @@ -319,21 +320,19 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header, hs->buffer[hlen] = 0; /* nul terminate */ result = namevalue(hs->buffer, hlen, type, &name, &value); - if(result) - goto fail; - - hs->name = name; - hs->value = value; - hs->type = type; - 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); - data->state.prevhead = hs; - return CURLE_OK; -fail: - free(hs); + if(!result) { + hs->name = name; + hs->value = value; + hs->type = type; + 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); + data->state.prevhead = hs; + } + else + free(hs); return result; } diff --git a/libs/libcurl/src/hostasyn.c b/libs/libcurl/src/hostasyn.c index 326aa29983..59a009ce33 100644 --- a/libs/libcurl/src/hostasyn.c +++ b/libs/libcurl/src/hostasyn.c @@ -67,11 +67,10 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data, int status, struct Curl_addrinfo *ai) { - struct connectdata *conn = data->conn; struct Curl_dns_entry *dns = NULL; CURLcode result = CURLE_OK; - conn->resolve_async.status = status; + data->state.async.status = status; if(CURL_ASYNC_SUCCESS == status) { if(ai) { @@ -79,8 +78,8 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data, Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); dns = Curl_cache_addr(data, ai, - conn->resolve_async.hostname, 0, - conn->resolve_async.port); + data->state.async.hostname, 0, + data->state.async.port); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -95,12 +94,12 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data, } } - conn->resolve_async.dns = dns; + data->state.async.dns = dns; /* Set async.done TRUE last in this function since it may be used multi- threaded and once this is TRUE the other thread may read fields from the async struct */ - conn->resolve_async.done = TRUE; + data->state.async.done = TRUE; /* IPv4: The input hostent struct will be freed by ares when we return from this function */ diff --git a/libs/libcurl/src/hostip.c b/libs/libcurl/src/hostip.c index 8d84708a26..70297ad60b 100644 --- a/libs/libcurl/src/hostip.c +++ b/libs/libcurl/src/hostip.c @@ -741,7 +741,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, Curl_set_in_callback(data, true); st = data->set.resolver_start( #ifdef USE_CURL_ASYNC - conn->resolve_async.resolver, + data->state.async.resolver, #else NULL, #endif @@ -754,16 +754,22 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, #ifndef USE_RESOLVE_ON_IPS /* First check if this is an IPv4 address string */ - if(Curl_inet_pton(AF_INET, hostname, &in) > 0) + if(Curl_inet_pton(AF_INET, hostname, &in) > 0) { /* This is a dotted IP address 123.123.123.123-style */ addr = Curl_ip2addr(AF_INET, &in, hostname, port); + if(!addr) + return CURLRESOLV_ERROR; + } #ifdef ENABLE_IPV6 - if(!addr) { + else { struct in6_addr in6; /* check if this is an IPv6 address string */ - if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) + if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) { /* This is an IPv6 address literal */ addr = Curl_ip2addr(AF_INET6, &in6, hostname, port); + if(!addr) + return CURLRESOLV_ERROR; + } } #endif /* ENABLE_IPV6 */ @@ -1415,9 +1421,9 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done) struct connectdata *conn = data->conn; #ifdef USE_CURL_ASYNC - if(conn->resolve_async.dns) { - conn->dns_entry = conn->resolve_async.dns; - conn->resolve_async.dns = NULL; + if(data->state.async.dns) { + conn->dns_entry = data->state.async.dns; + data->state.async.dns = NULL; } #endif @@ -1439,11 +1445,11 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done) #ifdef USE_CURL_ASYNC CURLcode Curl_resolver_error(struct Curl_easy *data) { - struct connectdata *conn = data->conn; const char *host_or_proxy; CURLcode result; #ifndef CURL_DISABLE_PROXY + struct connectdata *conn = data->conn; if(conn->bits.httpproxy) { host_or_proxy = "proxy"; result = CURLE_COULDNT_RESOLVE_PROXY; @@ -1456,7 +1462,7 @@ CURLcode Curl_resolver_error(struct Curl_easy *data) } failf(data, "Could not resolve %s: %s", host_or_proxy, - conn->resolve_async.hostname); + data->state.async.hostname); return result; } diff --git a/libs/libcurl/src/hsts.c b/libs/libcurl/src/hsts.c index 9ccfa14905..96af618bde 100644 --- a/libs/libcurl/src/hsts.c +++ b/libs/libcurl/src/hsts.c @@ -117,8 +117,6 @@ static CURLcode hsts_create(struct hsts *h, bool subdomains, curl_off_t expires) { - struct stsentry *sts; - char *duphost; size_t hlen; DEBUGASSERT(h); DEBUGASSERT(hostname); @@ -127,24 +125,23 @@ static CURLcode hsts_create(struct hsts *h, if(hlen && (hostname[hlen - 1] == '.')) /* strip off any trailing dot */ --hlen; - if(!hlen) - /* no host name left */ - return CURLE_BAD_FUNCTION_ARGUMENT; - - sts = hsts_entry(); - if(!sts) - return CURLE_OUT_OF_MEMORY; + if(hlen) { + char *duphost; + struct stsentry *sts = hsts_entry(); + if(!sts) + return CURLE_OUT_OF_MEMORY; + + duphost = Curl_memdup0(hostname, hlen); + if(!duphost) { + free(sts); + return CURLE_OUT_OF_MEMORY; + } - duphost = Curl_strndup(hostname, hlen); - if(!duphost) { - free(sts); - return CURLE_OUT_OF_MEMORY; + sts->host = duphost; + sts->expires = expires; + sts->includeSubDomains = subdomains; + Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node); } - - sts->host = duphost; - sts->expires = expires; - sts->includeSubDomains = subdomains; - Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node); return CURLE_OK; } @@ -481,6 +478,7 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h) if(sc == CURLSTS_OK) { time_t expires; CURLcode result; + DEBUGASSERT(e.name[0]); if(!e.name[0]) /* bail out if no name was stored */ return CURLE_BAD_FUNCTION_ARGUMENT; diff --git a/libs/libcurl/src/http.c b/libs/libcurl/src/http.c index d27c300bd3..6741425ae5 100644 --- a/libs/libcurl/src/http.c +++ b/libs/libcurl/src/http.c @@ -100,24 +100,14 @@ * Forward declarations. */ -static int http_getsock_do(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *socks); static bool http_should_fail(struct Curl_easy *data); -static CURLcode http_setup_conn(struct Curl_easy *data, - struct connectdata *conn); -#ifdef USE_WEBSOCKETS -static CURLcode ws_setup_conn(struct Curl_easy *data, - struct connectdata *conn); -#endif - /* * HTTP handler interface. */ const struct Curl_handler Curl_handler_http = { "HTTP", /* scheme */ - http_setup_conn, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -125,11 +115,11 @@ const struct Curl_handler Curl_handler_http = { ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ - http_getsock_do, /* doing_getsock */ + Curl_http_getsock_do, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ + Curl_http_write_resp, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_HTTP, /* defport */ @@ -139,39 +129,13 @@ const struct Curl_handler Curl_handler_http = { PROTOPT_USERPWDCTRL }; -#ifdef USE_WEBSOCKETS -const struct Curl_handler Curl_handler_ws = { - "WS", /* scheme */ - ws_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - Curl_http_connect, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - http_getsock_do, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - Curl_ws_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - ZERO_NULL, /* attach connection */ - PORT_HTTP, /* defport */ - CURLPROTO_WS, /* protocol */ - CURLPROTO_HTTP, /* family */ - PROTOPT_CREDSPERREQUEST | /* flags */ - PROTOPT_USERPWDCTRL -}; -#endif - #ifdef USE_SSL /* * HTTPS handler interface. */ const struct Curl_handler Curl_handler_https = { "HTTPS", /* scheme */ - http_setup_conn, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -179,11 +143,11 @@ const struct Curl_handler Curl_handler_https = { NULL, /* connecting */ ZERO_NULL, /* doing */ NULL, /* proto_getsock */ - http_getsock_do, /* doing_getsock */ + Curl_http_getsock_do, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ + Curl_http_write_resp, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_HTTPS, /* defport */ @@ -193,36 +157,10 @@ const struct Curl_handler Curl_handler_https = { PROTOPT_USERPWDCTRL }; -#ifdef USE_WEBSOCKETS -const struct Curl_handler Curl_handler_wss = { - "WSS", /* scheme */ - ws_setup_conn, /* setup_connection */ - Curl_http, /* do_it */ - Curl_http_done, /* done */ - ZERO_NULL, /* do_more */ - Curl_http_connect, /* connect_it */ - NULL, /* connecting */ - ZERO_NULL, /* doing */ - NULL, /* proto_getsock */ - http_getsock_do, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - Curl_ws_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - ZERO_NULL, /* attach connection */ - PORT_HTTPS, /* defport */ - CURLPROTO_WSS, /* protocol */ - CURLPROTO_HTTP, /* family */ - PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | /* flags */ - PROTOPT_USERPWDCTRL -}; -#endif - #endif -static CURLcode http_setup_conn(struct Curl_easy *data, - struct connectdata *conn) +CURLcode Curl_http_setup_conn(struct Curl_easy *data, + struct connectdata *conn) { /* allocate the HTTP-specific struct for the Curl_easy, only to survive during this request */ @@ -245,16 +183,6 @@ static CURLcode http_setup_conn(struct Curl_easy *data, return CURLE_OK; } -#ifdef USE_WEBSOCKETS -static CURLcode ws_setup_conn(struct Curl_easy *data, - struct connectdata *conn) -{ - /* websockets is 1.1 only (for now) */ - data->state.httpwant = CURL_HTTP_VERSION_1_1; - return http_setup_conn(data, conn); -} -#endif - #ifndef CURL_DISABLE_PROXY /* * checkProxyHeaders() checks the linked list of custom proxy headers @@ -297,7 +225,6 @@ char *Curl_copy_header_value(const char *header) { const char *start; const char *end; - char *value; size_t len; /* Find the end of the header name */ @@ -330,14 +257,7 @@ char *Curl_copy_header_value(const char *header) /* get length of the type */ len = end - start + 1; - value = malloc(len + 1); - if(!value) - return NULL; - - memcpy(value, start, len); - value[len] = 0; /* null-terminate */ - - return value; + return Curl_memdup0(start, len); } #ifndef CURL_DISABLE_HTTP_AUTH @@ -1597,9 +1517,9 @@ CURLcode Curl_http_connect(struct Curl_easy *data, bool *done) /* this returns the socket to wait for in the DO and DOING state for the multi interface and then we're always _sending_ a request and thus we wait for the single socket to become writable only */ -static int http_getsock_do(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *socks) +int Curl_http_getsock_do(struct Curl_easy *data, + struct connectdata *conn, + curl_socket_t *socks) { /* write mode */ (void)conn; @@ -2103,6 +2023,7 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data, switch(data->set.timecondition) { default: + DEBUGF(infof(data, "invalid time condition")); return CURLE_BAD_FUNCTION_ARGUMENT; case CURL_TIMECOND_IFMODSINCE: @@ -2271,7 +2192,7 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn) } #endif - if(strcmp("Host:", ptr)) { + if(!strcasecompare("Host:", ptr)) { aptr->host = aprintf("Host:%s\r\n", &ptr[5]); if(!aptr->host) return CURLE_OUT_OF_MEMORY; @@ -2359,9 +2280,7 @@ CURLcode Curl_http_target(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } } - /* Extract the URL to use in the request. Store in STRING_TEMP_URL for - clean-up reasons if the function returns before the free() further - down. */ + /* Extract the URL to use in the request. */ uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT); if(uc) { curl_url_cleanup(h); @@ -3021,13 +2940,14 @@ CURLcode Curl_http_resume(struct Curl_easy *data, } /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ do { + char scratch[4*1024]; size_t readthisamountnow = - (data->state.resume_from - passed > data->set.buffer_size) ? - (size_t)data->set.buffer_size : + (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - data->state.fread_func(data->state.buffer, 1, readthisamountnow, + data->state.fread_func(scratch, 1, readthisamountnow, data->state.in); passed += actuallyread; @@ -3062,6 +2982,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data, { struct SingleRequest *k = &data->req; + *done = FALSE; if(data->req.newurl) { if(conn->bits.close) { /* Abort after the headers if "follow Location" is set @@ -3187,7 +3108,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) ) { result = Curl_http2_switch(data, conn, FIRSTSOCKET); if(result) - return result; + goto fail; } else #endif @@ -3202,7 +3123,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) DEBUGF(infof(data, "HTTP/2 over clean TCP")); result = Curl_http2_switch(data, conn, FIRSTSOCKET); if(result) - return result; + goto fail; } break; } @@ -3212,11 +3133,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) result = Curl_http_host(data, conn); if(result) - return result; + goto fail; result = Curl_http_useragent(data); if(result) - return result; + goto fail; Curl_http_method(data, conn, &request, &httpreq); @@ -3232,7 +3153,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) (pq ? pq : data->state.up.path), FALSE); free(pq); if(result) - return result; + goto fail; } Curl_safefree(data->state.aptr.ref); @@ -3257,23 +3178,23 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) /* we only consider transfer-encoding magic if libz support is built-in */ result = Curl_transferencode(data); if(result) - return result; + goto fail; #endif result = Curl_http_body(data, conn, httpreq, &te); if(result) - return result; + goto fail; p_accept = Curl_checkheaders(data, STRCONST("Accept"))?NULL:"Accept: */*\r\n"; result = Curl_http_resume(data, conn, httpreq); if(result) - return result; + goto fail; result = Curl_http_range(data, httpreq); if(result) - return result; + goto fail; httpstring = get_http_string(data, conn); @@ -3291,7 +3212,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) result = Curl_http_target(data, conn, &req); if(result) { Curl_dyn_free(&req); - return result; + goto fail; } #ifndef CURL_DISABLE_ALTSVC @@ -3362,7 +3283,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(result) { Curl_dyn_free(&req); - return result; + goto fail; } if(!(conn->handler->flags&PROTOPT_SSL) && @@ -3398,7 +3319,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) } if(result) { Curl_dyn_free(&req); - return result; + goto fail; } if((http->postsize > -1) && @@ -3434,6 +3355,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) but is disabled here again to avoid that the chunked encoded version is actually used when sending the request body over h2 */ data->req.upload_chunky = FALSE; +fail: + if(CURLE_TOO_LARGE == result) + failf(data, "HTTP request too large"); return result; } @@ -3896,7 +3820,7 @@ CURLcode Curl_http_statusline(struct Curl_easy *data, * fields. */ if(data->set.timecondition) data->info.timecond = TRUE; - /* FALLTHROUGH */ + FALLTHROUGH(); case 204: /* (quote from RFC2616, section 10.2.5): The server has * fulfilled the request but does not need to return an @@ -3995,15 +3919,16 @@ CURLcode Curl_bump_headersize(struct Curl_easy *data, /* * Read any HTTP header lines from the server and pass them to the client app. */ -CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, - struct connectdata *conn, - const char *buf, size_t blen, - size_t *pconsumed) +static CURLcode http_rw_headers(struct Curl_easy *data, + const char *buf, size_t blen, + size_t *pconsumed) { - CURLcode result; + struct connectdata *conn = data->conn; + CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; char *headp; char *end_ptr; + bool leftover_body = FALSE; /* header line within buffer loop */ *pconsumed = 0; @@ -4032,12 +3957,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if(st == STATUS_BAD) { /* this is not the beginning of a protocol first header line */ k->header = FALSE; - k->badheader = TRUE; streamclose(conn, "bad HTTP: No end-of-message indicator"); if(!data->set.http09_allowed) { failf(data, "Received HTTP/0.9 when not allowed"); return CURLE_UNSUPPORTED_PROTOCOL; } + leftover_body = TRUE; goto out; } } @@ -4071,15 +3996,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, return CURLE_UNSUPPORTED_PROTOCOL; } k->header = FALSE; - if(blen) - /* since there's more, this is a partial bad header */ - k->badheader = TRUE; - else { - /* this was all we read so it's all a bad header */ - k->badheader = TRUE; - return CURLE_OK; - } - break; + leftover_body = TRUE; + goto out; } } @@ -4088,6 +4006,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, headp = Curl_dyn_ptr(&data->state.headerb); if((0x0a == *headp) || (0x0d == *headp)) { size_t headerlen; + bool switch_to_h2 = FALSE; /* Zero-length header line means end of headers! */ if('\r' == *headp) @@ -4117,42 +4036,40 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } break; case 101: - /* Switching Protocols */ - if(k->upgr101 == UPGR101_H2) { - /* Switching to HTTP/2 */ - DEBUGASSERT(conn->httpversion < 20); - 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 http2 now. The bytes after response headers - are also processed here, otherwise they are lost. */ - result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen); - if(result) - return result; - *pconsumed += blen; - blen = 0; - } + 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! */ - if(data->set.connect_only) { - k->keepon &= ~KEEP_RECV; /* read no more content */ - *pconsumed += blen; + 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 { - /* Not switching to another protocol */ - k->header = FALSE; /* no more header to parse! */ + /* invalid for other HTTP versions */ + failf(data, "unexpected 101 response code"); + return CURLE_WEIRD_SERVER_REPLY; } break; default: @@ -4359,16 +4276,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, */ if(data->req.no_body) k->download_done = TRUE; -#ifndef CURL_DISABLE_RTSP - else if((conn->handler->protocol & CURLPROTO_RTSP) && - (data->set.rtspreq == RTSPREQ_DESCRIBE) && - (k->size <= -1)) - /* Respect section 4.4 of rfc2326: If the Content-Length header is - absent, a length 0 must be assumed. It will prevent libcurl from - hanging on DESCRIBE request that got refused for whatever - reason */ - k->download_done = TRUE; -#endif /* If max download size is *zero* (nothing) we already have nothing and can safely return ok now! But for HTTP/2, we'd @@ -4388,6 +4295,17 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* We continue reading headers, reset the line-based header */ Curl_dyn_reset(&data->state.headerb); + 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); + if(result) + return result; + *pconsumed += blen; + blen = 0; + } + continue; } @@ -4578,9 +4496,78 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, there might be a non-header part left in the end of the read buffer. */ out: + if(!k->header && !leftover_body) { + Curl_dyn_free(&data->state.headerb); + } return CURLE_OK; } +/* + * HTTP protocol `write_resp` implementation. Will parse headers + * when not done yet and otherwise return without consuming data. + */ +CURLcode Curl_http_write_resp_hds(struct Curl_easy *data, + const char *buf, size_t blen, + size_t *pconsumed, + bool *done) +{ + *done = FALSE; + if(!data->req.header) { + *pconsumed = 0; + return CURLE_OK; + } + else { + CURLcode result; + + result = http_rw_headers(data, buf, blen, pconsumed); + if(!result && !data->req.header) { + /* we have successfully finished parsing the HEADERs */ + result = Curl_http_firstwrite(data, data->conn, done); + + 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 + * HTTP/0.9 like responses */ + result = Curl_client_write(data, CLIENTWRITE_BODY, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + } + Curl_dyn_free(&data->state.headerb); + } + return result; + } +} + +CURLcode Curl_http_write_resp(struct Curl_easy *data, + const char *buf, size_t blen, + bool is_eos, + bool *done) +{ + CURLcode result; + size_t consumed; + int flags; + + *done = FALSE; + result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done); + if(result || *done) + goto out; + + DEBUGASSERT(consumed <= blen); + blen -= consumed; + buf += consumed; + /* either all was consumed in header parsing, or we have data left + * and are done with heders, e.g. it is BODY data */ + DEBUGASSERT(!blen || !data->req.header); + if(!data->req.header && (blen || is_eos)) { + /* BODY data after header been parsed, write and consume */ + flags = CLIENTWRITE_BODY; + if(is_eos) + flags |= CLIENTWRITE_EOS; + result = Curl_client_write(data, flags, (char *)buf, blen); + } +out: + return result; +} /* Decode HTTP status code string. */ CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len) @@ -4617,7 +4604,7 @@ CURLcode Curl_http_req_make(struct httpreq **preq, CURLcode result = CURLE_OUT_OF_MEMORY; DEBUGASSERT(method); - if(m_len + 1 >= sizeof(req->method)) + if(m_len + 1 > sizeof(req->method)) return CURLE_BAD_FUNCTION_ARGUMENT; req = calloc(1, sizeof(*req)); @@ -4625,17 +4612,17 @@ CURLcode Curl_http_req_make(struct httpreq **preq, goto out; memcpy(req->method, method, m_len); if(scheme) { - req->scheme = Curl_strndup(scheme, s_len); + req->scheme = Curl_memdup0(scheme, s_len); if(!req->scheme) goto out; } if(authority) { - req->authority = Curl_strndup(authority, a_len); + req->authority = Curl_memdup0(authority, a_len); if(!req->authority) goto out; } if(path) { - req->path = Curl_strndup(path, p_len); + req->path = Curl_memdup0(path, p_len); if(!req->path) goto out; } @@ -4773,7 +4760,7 @@ CURLcode Curl_http_req_make2(struct httpreq **preq, CURLUcode uc; DEBUGASSERT(method); - if(m_len + 1 >= sizeof(req->method)) + if(m_len + 1 > sizeof(req->method)) return CURLE_BAD_FUNCTION_ARGUMENT; req = calloc(1, sizeof(*req)); diff --git a/libs/libcurl/src/http.h b/libs/libcurl/src/http.h index f7571ebdb0..3ceb049693 100644 --- a/libs/libcurl/src/http.h +++ b/libs/libcurl/src/http.h @@ -54,14 +54,6 @@ extern const struct Curl_handler Curl_handler_http; extern const struct Curl_handler Curl_handler_https; #endif -#ifdef USE_WEBSOCKETS -extern const struct Curl_handler Curl_handler_ws; - -#ifdef USE_SSL -extern const struct Curl_handler Curl_handler_wss; -#endif -#endif /* websockets */ - struct dynhds; CURLcode Curl_bump_headersize(struct Curl_easy *data, @@ -147,9 +139,17 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data, bool *done); /* protocol-specific functions set up to be called by the main engine */ +CURLcode Curl_http_setup_conn(struct Curl_easy *data, + struct connectdata *conn); CURLcode Curl_http(struct Curl_easy *data, bool *done); CURLcode Curl_http_done(struct Curl_easy *data, CURLcode, bool premature); CURLcode Curl_http_connect(struct Curl_easy *data, bool *done); +int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t *socks); +CURLcode Curl_http_write_resp(struct Curl_easy *data, + const char *buf, size_t blen, + bool is_eos, + bool *done); /* These functions are in http.c */ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, @@ -225,10 +225,10 @@ struct HTTP { CURLcode Curl_http_size(struct Curl_easy *data); -CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, - struct connectdata *conn, - const char *buf, size_t blen, - size_t *pconsumed); +CURLcode Curl_http_write_resp_hds(struct Curl_easy *data, + const char *buf, size_t blen, + size_t *pconsumed, + bool *done); /** * Curl_http_output_auth() setups the authentication headers for the diff --git a/libs/libcurl/src/http2.c b/libs/libcurl/src/http2.c index 6a7d18379d..fbec0a7927 100644 --- a/libs/libcurl/src/http2.c +++ b/libs/libcurl/src/http2.c @@ -219,10 +219,10 @@ static void drain_stream(struct Curl_cfilter *cf, if(!stream->send_closed && (stream->upload_left || stream->upload_blocked_len)) bits |= CURL_CSELECT_OUT; - if(data->state.dselect_bits != bits) { - CURL_TRC_CF(data, cf, "[%d] DRAIN dselect_bits=%x", + if(data->state.select_bits != bits) { + CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x", stream->id, bits); - data->state.dselect_bits = bits; + data->state.select_bits = bits; Curl_expire(data, 0, EXPIRE_RUN_NOW); } } @@ -283,13 +283,20 @@ static void http2_data_done(struct Curl_cfilter *cf, return; if(ctx->h2) { + bool flush_egress = FALSE; + /* returns error if stream not known, which is fine here */ + (void)nghttp2_session_set_stream_user_data(ctx->h2, stream->id, NULL); + if(!stream->closed && stream->id > 0) { /* RST_STREAM */ CURL_TRC_CF(data, cf, "[%d] premature DATA_DONE, RST stream", stream->id); - if(!nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, - stream->id, NGHTTP2_STREAM_CLOSED)) - (void)nghttp2_session_send(ctx->h2); + stream->closed = TRUE; + stream->reset = TRUE; + stream->send_closed = TRUE; + nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, + stream->id, NGHTTP2_STREAM_CLOSED); + flush_egress = TRUE; } if(!Curl_bufq_is_empty(&stream->recvbuf)) { /* Anything in the recvbuf is still being counted @@ -299,19 +306,11 @@ static void http2_data_done(struct Curl_cfilter *cf, nghttp2_session_consume(ctx->h2, stream->id, Curl_bufq_len(&stream->recvbuf)); /* give WINDOW_UPATE a chance to be sent, but ignore any error */ - (void)h2_progress_egress(cf, data); + flush_egress = TRUE; } - /* -1 means unassigned and 0 means cleared */ - if(nghttp2_session_get_stream_user_data(ctx->h2, stream->id)) { - int rv = nghttp2_session_set_stream_user_data(ctx->h2, - stream->id, 0); - if(rv) { - infof(data, "http/2: failed to clear user_data for stream %u", - stream->id); - DEBUGASSERT(0); - } - } + if(flush_egress) + nghttp2_session_send(ctx->h2); } Curl_bufq_free(&stream->sendbuf); @@ -1316,26 +1315,43 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, uint32_t error_code, void *userp) { struct Curl_cfilter *cf = userp; - struct Curl_easy *data_s; + struct Curl_easy *data_s, *call_data = CF_DATA_CURRENT(cf); struct stream_ctx *stream; int rv; (void)session; + DEBUGASSERT(call_data); /* get the stream from the hash based on Stream ID, stream ID zero is for connection-oriented stuff */ data_s = stream_id? nghttp2_session_get_stream_user_data(session, stream_id) : NULL; if(!data_s) { + CURL_TRC_CF(call_data, cf, + "[%d] on_stream_close, no easy set on stream", stream_id); return 0; } + if(!GOOD_EASY_HANDLE(data_s)) { + /* nghttp2 still has an easy registered for the stream which has + * been freed be libcurl. This points to a code path that does not + * trigger DONE or DETACH events as it must. */ + CURL_TRC_CF(call_data, cf, + "[%d] on_stream_close, not a GOOD easy on stream", stream_id); + (void)nghttp2_session_set_stream_user_data(session, stream_id, 0); + return NGHTTP2_ERR_CALLBACK_FAILURE; + } stream = H2_STREAM_CTX(data_s); - if(!stream) + if(!stream) { + CURL_TRC_CF(data_s, cf, + "[%d] on_stream_close, GOOD easy but no stream", stream_id); return NGHTTP2_ERR_CALLBACK_FAILURE; + } stream->closed = TRUE; stream->error = error_code; - if(stream->error) + if(stream->error) { stream->reset = TRUE; + stream->send_closed = TRUE; + } if(stream->error) CURL_TRC_CF(data_s, cf, "[%d] RESET: %s (err %d)", @@ -2315,18 +2331,22 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf, struct easy_pollset *ps) { struct cf_h2_ctx *ctx = cf->ctx; - bool want_recv = CURL_WANT_RECV(data); - bool want_send = CURL_WANT_SEND(data); + curl_socket_t sock; + bool want_recv, want_send; + + if(!ctx->h2) + return; - if(ctx->h2 && (want_recv || want_send)) { + sock = Curl_conn_cf_get_socket(cf, data); + Curl_pollset_check(data, ps, sock, &want_recv, &want_send); + if(want_recv || want_send) { struct stream_ctx *stream = H2_STREAM_CTX(data); - curl_socket_t sock = Curl_conn_cf_get_socket(cf, data); struct cf_call_data save; bool c_exhaust, s_exhaust; CF_DATA_SAVE(save, cf, data); - c_exhaust = !nghttp2_session_get_remote_window_size(ctx->h2); - s_exhaust = stream && stream->id >= 0 && + c_exhaust = want_send && !nghttp2_session_get_remote_window_size(ctx->h2); + s_exhaust = want_send && stream && stream->id >= 0 && !nghttp2_session_get_stream_remote_window_size(ctx->h2, stream->id); want_recv = (want_recv || c_exhaust || s_exhaust); diff --git a/libs/libcurl/src/http_aws_sigv4.c b/libs/libcurl/src/http_aws_sigv4.c index 0313026562..deea1d4b00 100644 --- a/libs/libcurl/src/http_aws_sigv4.c +++ b/libs/libcurl/src/http_aws_sigv4.c @@ -247,7 +247,7 @@ static CURLcode make_headers(struct Curl_easy *data, } else { char *value; - + char *endp; value = strchr(*date_header, ':'); if(!value) { *date_header = NULL; @@ -256,8 +256,17 @@ static CURLcode make_headers(struct Curl_easy *data, ++value; while(ISBLANK(*value)) ++value; - strncpy(timestamp, value, TIMESTAMP_SIZE - 1); - timestamp[TIMESTAMP_SIZE - 1] = 0; + endp = value; + while(*endp && ISALNUM(*endp)) + ++endp; + /* 16 bytes => "19700101T000000Z" */ + if((endp - value) == TIMESTAMP_SIZE - 1) { + memcpy(timestamp, value, TIMESTAMP_SIZE - 1); + timestamp[TIMESTAMP_SIZE - 1] = 0; + } + else + /* bad timestamp length */ + timestamp[0] = 0; *date_header = NULL; } @@ -605,7 +614,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) result = CURLE_URL_MALFORMAT; goto fail; } - strncpy(service, hostname, len); + memcpy(service, hostname, len); service[len] = '\0'; infof(data, "aws_sigv4: picked service %s from host", service); @@ -624,7 +633,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) result = CURLE_URL_MALFORMAT; goto fail; } - strncpy(region, reg, len); + memcpy(region, reg, len); region[len] = '\0'; infof(data, "aws_sigv4: picked region %s from host", region); } diff --git a/libs/libcurl/src/http_chunks.c b/libs/libcurl/src/http_chunks.c index 0d6d6302a4..8f8098e015 100644 --- a/libs/libcurl/src/http_chunks.c +++ b/libs/libcurl/src/http_chunks.c @@ -75,47 +75,67 @@ */ -void Curl_httpchunk_init(struct Curl_easy *data) +void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch, + bool ignore_body) { - struct connectdata *conn = data->conn; - struct Curl_chunker *chunk = &conn->chunk; - chunk->hexindex = 0; /* start at 0 */ - chunk->state = CHUNK_HEX; /* we get hex first! */ - Curl_dyn_init(&conn->trailer, DYN_H1_TRAILER); + (void)data; + ch->hexindex = 0; /* start at 0 */ + ch->state = CHUNK_HEX; /* we get hex first! */ + ch->last_code = CHUNKE_OK; + Curl_dyn_init(&ch->trailer, DYN_H1_TRAILER); + ch->ignore_body = ignore_body; } -/* - * chunk_read() returns a OK for normal operations, or a positive return code - * for errors. STOP means this sequence of chunks is complete. The 'wrote' - * argument is set to tell the caller how many bytes we actually passed to the - * client (for byte-counting and whatever). - * - * The states and the state-machine is further explained in the header file. - * - * This function always uses ASCII hex values to accommodate non-ASCII hosts. - * For example, 0x0d and 0x0a are used instead of '\r' and '\n'. - */ -CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, - char *buf, - size_t blen, - size_t *pconsumed, - CURLcode *extrap) +void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch, + bool ignore_body) +{ + (void)data; + ch->hexindex = 0; /* start at 0 */ + ch->state = CHUNK_HEX; /* we get hex first! */ + ch->last_code = CHUNKE_OK; + Curl_dyn_reset(&ch->trailer); + ch->ignore_body = ignore_body; +} + +void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch) +{ + (void)data; + Curl_dyn_free(&ch->trailer); +} + +bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch) +{ + (void)data; + return ch->state == CHUNK_DONE; +} + +static CURLcode httpchunk_readwrite(struct Curl_easy *data, + struct Curl_chunker *ch, + struct Curl_cwriter *cw_next, + const char *buf, size_t blen, + size_t *pconsumed) { CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - struct Curl_chunker *ch = &conn->chunk; - struct SingleRequest *k = &data->req; size_t piece; *pconsumed = 0; /* nothing's written yet */ + /* first check terminal states that will not progress anywhere */ + if(ch->state == CHUNK_DONE) + return CURLE_OK; + if(ch->state == CHUNK_FAILED) + return CURLE_RECV_ERROR; /* the original data is written to the client, but we go on with the chunk read process, to properly calculate the content length */ - if(data->set.http_te_skip && !k->ignorebody) { - result = Curl_client_write(data, CLIENTWRITE_BODY, buf, blen); + if(data->set.http_te_skip && !ch->ignore_body) { + if(cw_next) + result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY, buf, blen); + else + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen); if(result) { - *extrap = result; - return CHUNKE_PASSTHRU_ERROR; + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_PASSTHRU_ERROR; + return result; } } @@ -123,28 +143,35 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, switch(ch->state) { case CHUNK_HEX: if(ISXDIGIT(*buf)) { - if(ch->hexindex < CHUNK_MAXNUM_LEN) { - ch->hexbuffer[ch->hexindex] = *buf; - buf++; - blen--; - ch->hexindex++; - } - else { - return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */ + if(ch->hexindex >= CHUNK_MAXNUM_LEN) { + failf(data, "chunk hex-length longer than %d", CHUNK_MAXNUM_LEN); + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_TOO_LONG_HEX; /* longer than we support */ + return CURLE_RECV_ERROR; } + ch->hexbuffer[ch->hexindex++] = *buf; + buf++; + blen--; } else { char *endptr; - if(0 == ch->hexindex) + if(0 == ch->hexindex) { /* This is illegal data, we received junk where we expected a hexadecimal digit. */ - return CHUNKE_ILLEGAL_HEX; + failf(data, "chunk hex-length char not a hex digit: 0x%x", *buf); + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_ILLEGAL_HEX; + return CURLE_RECV_ERROR; + } /* blen and buf are unmodified */ ch->hexbuffer[ch->hexindex] = 0; - - if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize)) - return CHUNKE_ILLEGAL_HEX; + if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize)) { + failf(data, "chunk hex-length not valid: '%s'", ch->hexbuffer); + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_ILLEGAL_HEX; + return CURLE_RECV_ERROR; + } ch->state = CHUNK_LF; /* now wait for the CRLF */ } break; @@ -173,12 +200,17 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, piece = curlx_sotouz(ch->datasize); /* Write the data portion available */ - if(!data->set.http_te_skip && !k->ignorebody) { - result = Curl_client_write(data, CLIENTWRITE_BODY, buf, piece); - + if(!data->set.http_te_skip && !ch->ignore_body) { + if(cw_next) + result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY, + buf, piece); + else + result = Curl_client_write(data, CLIENTWRITE_BODY, + (char *)buf, piece); if(result) { - *extrap = result; - return CHUNKE_PASSTHRU_ERROR; + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_PASSTHRU_ERROR; + return result; } } @@ -195,38 +227,51 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, case CHUNK_POSTLF: if(*buf == 0x0a) { /* The last one before we go back to hex state and start all over. */ - Curl_httpchunk_init(data); /* sets state back to CHUNK_HEX */ + Curl_httpchunk_reset(data, ch, ch->ignore_body); + } + else if(*buf != 0x0d) { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_BAD_CHUNK; + return CURLE_RECV_ERROR; } - else if(*buf != 0x0d) - return CHUNKE_BAD_CHUNK; buf++; blen--; break; case CHUNK_TRAILER: if((*buf == 0x0d) || (*buf == 0x0a)) { - char *tr = Curl_dyn_ptr(&conn->trailer); + char *tr = Curl_dyn_ptr(&ch->trailer); /* this is the end of a trailer, but if the trailer was zero bytes there was no trailer and we move on */ if(tr) { size_t trlen; - result = Curl_dyn_addn(&conn->trailer, (char *)STRCONST("\x0d\x0a")); - if(result) - return CHUNKE_OUT_OF_MEMORY; - - tr = Curl_dyn_ptr(&conn->trailer); - trlen = Curl_dyn_len(&conn->trailer); + result = Curl_dyn_addn(&ch->trailer, (char *)STRCONST("\x0d\x0a")); + if(result) { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_OUT_OF_MEMORY; + return result; + } + tr = Curl_dyn_ptr(&ch->trailer); + trlen = Curl_dyn_len(&ch->trailer); if(!data->set.http_te_skip) { - result = Curl_client_write(data, - CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER, - tr, trlen); + if(cw_next) + result = Curl_cwriter_write(data, cw_next, + CLIENTWRITE_HEADER| + CLIENTWRITE_TRAILER, + tr, trlen); + else + result = Curl_client_write(data, + CLIENTWRITE_HEADER| + CLIENTWRITE_TRAILER, + tr, trlen); if(result) { - *extrap = result; - return CHUNKE_PASSTHRU_ERROR; + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_PASSTHRU_ERROR; + return result; } } - Curl_dyn_reset(&conn->trailer); + Curl_dyn_reset(&ch->trailer); ch->state = CHUNK_TRAILER_CR; if(*buf == 0x0a) /* already on the LF */ @@ -239,9 +284,12 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, } } else { - result = Curl_dyn_addn(&conn->trailer, buf, 1); - if(result) - return CHUNKE_OUT_OF_MEMORY; + result = Curl_dyn_addn(&ch->trailer, buf, 1); + if(result) { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_OUT_OF_MEMORY; + return result; + } } buf++; blen--; @@ -253,8 +301,11 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, buf++; blen--; } - else - return CHUNKE_BAD_CHUNK; + else { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_BAD_CHUNK; + return CURLE_RECV_ERROR; + } break; case CHUNK_TRAILER_POSTCR: @@ -277,21 +328,29 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, case CHUNK_STOP: if(*buf == 0x0a) { blen--; - /* Record the length of any data left in the end of the buffer even if there's no more chunks to read */ ch->datasize = blen; - - return CHUNKE_STOP; /* return stop */ + ch->state = CHUNK_DONE; + return CURLE_OK; } - else - return CHUNKE_BAD_CHUNK; + else { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_BAD_CHUNK; + return CURLE_RECV_ERROR; + } + case CHUNK_DONE: + return CURLE_OK; + + case CHUNK_FAILED: + return CURLE_RECV_ERROR; } + } - return CHUNKE_OK; + return CURLE_OK; } -const char *Curl_chunked_strerror(CHUNKcode code) +static const char *Curl_chunked_strerror(CHUNKcode code) { switch(code) { default: @@ -303,8 +362,7 @@ const char *Curl_chunked_strerror(CHUNKcode code) case CHUNKE_BAD_CHUNK: return "Malformed encoding found"; case CHUNKE_PASSTHRU_ERROR: - DEBUGASSERT(0); /* never used */ - return ""; + return "Error writing data to client"; case CHUNKE_BAD_ENCODING: return "Bad content-encoding found"; case CHUNKE_OUT_OF_MEMORY: @@ -312,4 +370,86 @@ const char *Curl_chunked_strerror(CHUNKcode code) } } +CURLcode Curl_httpchunk_read(struct Curl_easy *data, + struct Curl_chunker *ch, + char *buf, size_t blen, + size_t *pconsumed) +{ + return httpchunk_readwrite(data, ch, NULL, buf, blen, pconsumed); +} + +struct chunked_writer { + struct Curl_cwriter super; + struct Curl_chunker ch; +}; + +static CURLcode cw_chunked_init(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct chunked_writer *ctx = (struct chunked_writer *)writer; + + data->req.chunk = TRUE; /* chunks coming our way. */ + Curl_httpchunk_init(data, &ctx->ch, FALSE); + return CURLE_OK; +} + +static void cw_chunked_close(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct chunked_writer *ctx = (struct chunked_writer *)writer; + Curl_httpchunk_free(data, &ctx->ch); +} + +static CURLcode cw_chunked_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t blen) +{ + struct chunked_writer *ctx = (struct chunked_writer *)writer; + CURLcode result; + size_t consumed; + + if(!(type & CLIENTWRITE_BODY)) + return Curl_cwriter_write(data, writer->next, type, buf, blen); + + consumed = 0; + result = httpchunk_readwrite(data, &ctx->ch, writer->next, buf, blen, + &consumed); + + if(result) { + if(CHUNKE_PASSTHRU_ERROR == ctx->ch.last_code) { + failf(data, "Failed reading the chunked-encoded stream"); + } + else { + failf(data, "%s in chunked-encoding", + Curl_chunked_strerror(ctx->ch.last_code)); + } + return result; + } + + blen -= consumed; + if(CHUNK_DONE == ctx->ch.state) { + /* chunks read successfully, download is complete */ + data->req.download_done = TRUE; + if(blen) { + infof(data, "Leftovers after chunking: %zu bytes", blen); + } + } + else if((type & CLIENTWRITE_EOS) && !data->req.no_body) { + failf(data, "transfer closed with outstanding read data remaining"); + return CURLE_PARTIAL_FILE; + } + + return CURLE_OK; +} + +/* HTTP chunked Transfer-Encoding decoder */ +const struct Curl_cwtype Curl_httpchunk_unencoder = { + "chunked", + NULL, + cw_chunked_init, + cw_chunked_write, + cw_chunked_close, + sizeof(struct chunked_writer) +}; + #endif /* CURL_DISABLE_HTTP */ diff --git a/libs/libcurl/src/http_chunks.h b/libs/libcurl/src/http_chunks.h index 3c228f84eb..ea89949d7f 100644 --- a/libs/libcurl/src/http_chunks.h +++ b/libs/libcurl/src/http_chunks.h @@ -24,6 +24,10 @@ * ***************************************************************************/ +#ifndef CURL_DISABLE_HTTP + +#include "dynbuf.h" + struct connectdata; /* @@ -67,34 +71,68 @@ typedef enum { signalled If this is an empty trailer CHUNKE_STOP will be signalled. Otherwise the trailer will be broadcasted via Curl_client_write() and the next state will be CHUNK_TRAILER */ - CHUNK_TRAILER_POSTCR + CHUNK_TRAILER_POSTCR, + + /* Successfully de-chunked everything */ + CHUNK_DONE, + + /* Failed on seeing a bad or not correctly terminated chunk */ + CHUNK_FAILED } ChunkyState; typedef enum { - CHUNKE_STOP = -1, CHUNKE_OK = 0, CHUNKE_TOO_LONG_HEX = 1, CHUNKE_ILLEGAL_HEX, CHUNKE_BAD_CHUNK, CHUNKE_BAD_ENCODING, CHUNKE_OUT_OF_MEMORY, - CHUNKE_PASSTHRU_ERROR, /* Curl_httpchunk_read() returns a CURLcode to use */ - CHUNKE_LAST + CHUNKE_PASSTHRU_ERROR /* Curl_httpchunk_read() returns a CURLcode to use */ } CHUNKcode; -const char *Curl_chunked_strerror(CHUNKcode code); - struct Curl_chunker { curl_off_t datasize; ChunkyState state; + CHUNKcode last_code; + struct dynbuf trailer; /* for chunked-encoded trailer */ unsigned char hexindex; - char hexbuffer[ CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */ + char hexbuffer[CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */ + BIT(ignore_body); /* never write response body data */ }; /* The following functions are defined in http_chunks.c */ -void Curl_httpchunk_init(struct Curl_easy *data); -CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, char *buf, - size_t blen, size_t *pconsumed, - CURLcode *passthru); +void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch, + bool ignore_body); +void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch); +void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch, + bool ignore_body); + +/* + * Read BODY bytes in HTTP/1.1 chunked encoding from `buf` and return + * the amount of bytes consumed. The actual response bytes and trailer + * headers are written out to the client. + * On success, this will consume all bytes up to the end of the response, + * e.g. the last chunk, has been processed. + * @param data the transfer involved + * @param ch the chunker instance keeping state across calls + * @param buf the response data + * @param blen amount of bytes in `buf` + * @param pconsumed on successful return, the number of bytes in `buf` + * consumed + * + * This function always uses ASCII hex values to accommodate non-ASCII hosts. + * For example, 0x0d and 0x0a are used instead of '\r' and '\n'. + */ +CURLcode Curl_httpchunk_read(struct Curl_easy *data, struct Curl_chunker *ch, + char *buf, size_t blen, size_t *pconsumed); + +/** + * @return TRUE iff chunked decoded has finished successfully. + */ +bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch); + +extern const struct Curl_cwtype Curl_httpchunk_unencoder; + +#endif /* !CURL_DISABLE_HTTP */ #endif /* HEADER_CURL_HTTP_CHUNKS_H */ diff --git a/libs/libcurl/src/http_proxy.c b/libs/libcurl/src/http_proxy.c index 56bf385e70..bf0f3ff87d 100644 --- a/libs/libcurl/src/http_proxy.c +++ b/libs/libcurl/src/http_proxy.c @@ -131,8 +131,8 @@ CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq, goto out; } - if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent")) - && data->set.str[STRING_USERAGENT]) { + if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent")) && + data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) { result = Curl_dynhds_cadd(&req->headers, "User-Agent", data->set.str[STRING_USERAGENT]); if(result) diff --git a/libs/libcurl/src/imap.c b/libs/libcurl/src/imap.c index d4abe3568c..0cec828c46 100644 --- a/libs/libcurl/src/imap.c +++ b/libs/libcurl/src/imap.c @@ -97,7 +97,8 @@ static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done); static CURLcode imap_setup_connection(struct Curl_easy *data, struct connectdata *conn); static char *imap_atom(const char *str, bool escape_only); -static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...); +static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...) + CURL_PRINTF(2, 3); static CURLcode imap_parse_url_options(struct connectdata *conn); static CURLcode imap_parse_url_path(struct Curl_easy *data); static CURLcode imap_parse_custom_request(struct Curl_easy *data); @@ -129,7 +130,7 @@ const struct Curl_handler Curl_handler_imap = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_IMAP, /* defport */ @@ -158,7 +159,7 @@ const struct Curl_handler Curl_handler_imaps = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_IMAPS, /* defport */ @@ -354,8 +355,8 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn, */ static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out) { - char *message = data->state.buffer; - size_t len = strlen(message); + char *message = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf); + size_t len = data->conn->proto.imapc.pp.nfinal; if(len > 2) { /* Find the start of the message */ @@ -895,7 +896,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data, CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; struct imap_conn *imapc = &conn->proto.imapc; - const char *line = data->state.buffer; + const char *line = Curl_dyn_ptr(&imapc->pp.recvbuf); (void)instate; /* no use for this yet */ @@ -981,7 +982,7 @@ static CURLcode imap_state_starttls_resp(struct Curl_easy *data, (void)instate; /* no use for this yet */ /* Pipelining in response is forbidden. */ - if(data->conn->proto.imapc.pp.cache_size) + if(data->conn->proto.imapc.pp.overflow) return CURLE_WEIRD_SERVER_REPLY; if(imapcode != IMAP_RESP_OK) { @@ -1057,17 +1058,13 @@ static CURLcode imap_state_listsearch_resp(struct Curl_easy *data, imapstate instate) { CURLcode result = CURLE_OK; - char *line = data->state.buffer; - size_t len = strlen(line); + char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf); + size_t len = data->conn->proto.imapc.pp.nfinal; (void)instate; /* No use for this yet */ - if(imapcode == '*') { - /* Temporarily add the LF character back and send as body to the client */ - line[len] = '\n'; - result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1); - line[len] = '\0'; - } + if(imapcode == '*') + result = Curl_client_write(data, CLIENTWRITE_BODY, line, len); else if(imapcode != IMAP_RESP_OK) result = CURLE_QUOTE_ERROR; else @@ -1085,7 +1082,7 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode, struct connectdata *conn = data->conn; struct IMAP *imap = data->req.p.imap; struct imap_conn *imapc = &conn->proto.imapc; - const char *line = data->state.buffer; + const char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf); (void)instate; /* no use for this yet */ @@ -1144,7 +1141,8 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, CURLcode result = CURLE_OK; struct imap_conn *imapc = &conn->proto.imapc; struct pingpong *pp = &imapc->pp; - const char *ptr = data->state.buffer; + const char *ptr = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf); + size_t len = data->conn->proto.imapc.pp.nfinal; bool parsed = FALSE; curl_off_t size = 0; @@ -1158,16 +1156,12 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse the continuation data contained within the curly brackets */ - while(*ptr && (*ptr != '{')) - ptr++; - - if(*ptr == '{') { + ptr = memchr(ptr, '{', len); + if(ptr) { char *endptr; - if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) { - if(endptr - ptr > 1 && endptr[0] == '}' && - endptr[1] == '\r' && endptr[2] == '\0') - parsed = TRUE; - } + if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) && + (endptr - ptr > 1 && *endptr == '}')) + parsed = TRUE; } if(parsed) { @@ -1175,11 +1169,15 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, size); Curl_pgrsSetDownloadSize(data, size); - if(pp->cache) { - /* At this point there is a bunch of data in the header "cache" that is - actually body content, send it as body and then skip it. Do note - that there may even be additional "headers" after the body. */ - size_t chunk = pp->cache_size; + if(pp->overflow) { + /* At this point there is a data in the receive buffer that is body + content, send it as body and then skip it. Do note that there may + even be additional "headers" after the body. */ + size_t chunk = pp->overflow; + + /* keep only the overflow */ + Curl_dyn_tail(&pp->recvbuf, chunk); + pp->nfinal = 0; /* done */ if(chunk > (size_t)size) /* The conversion from curl_off_t to size_t is always fine here */ @@ -1190,25 +1188,24 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, imap_state(data, IMAP_STOP); return CURLE_OK; } - result = Curl_client_write(data, CLIENTWRITE_BODY, pp->cache, chunk); + result = Curl_client_write(data, CLIENTWRITE_BODY, + Curl_dyn_ptr(&pp->recvbuf), chunk); if(result) return result; infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU " bytes are left for transfer", chunk, size - chunk); - /* Have we used the entire cache or just part of it?*/ - if(pp->cache_size > chunk) { - /* Only part of it so shrink the cache to fit the trailing data */ - memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk); - pp->cache_size -= chunk; + /* Have we used the entire overflow or just part of it?*/ + if(pp->overflow > chunk) { + /* remember the remaining trailing overflow data */ + pp->overflow -= chunk; + Curl_dyn_tail(&pp->recvbuf, pp->overflow); } else { + pp->overflow = 0; /* handled */ /* Free the cache */ - Curl_safefree(pp->cache); - - /* Reset the cache size */ - pp->cache_size = 0; + Curl_dyn_reset(&pp->recvbuf); } } @@ -1220,7 +1217,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, data->req.maxdownload = size; /* force a recv/send check of this connection, as the data might've been read off the socket already */ - data->conn->cselect_bits = CURL_CSELECT_IN; + data->state.select_bits = CURL_CSELECT_IN; Curl_setup_transfer(data, FIRSTSOCKET, size, FALSE, -1); } } @@ -1376,7 +1373,6 @@ static CURLcode imap_statemachine(struct Curl_easy *data, break; case IMAP_LOGOUT: - /* fallthrough, just stop! */ default: /* internal error */ imap_state(data, IMAP_STOP); @@ -1472,9 +1468,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done) Curl_sasl_init(&imapc->sasl, data, &saslimap); Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD); - /* Initialise the pingpong layer */ - Curl_pp_setup(pp); - Curl_pp_init(data, pp); + Curl_pp_init(pp); /* Parse the URL options */ result = imap_parse_url_options(conn); @@ -1795,7 +1789,14 @@ static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...) if(!result) { va_list ap; va_start(ap, fmt); +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif result = Curl_pp_vsendf(data, &imapc->pp, Curl_dyn_ptr(&imapc->dyn), ap); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif va_end(ap); } return result; diff --git a/libs/libcurl/src/inet_pton.c b/libs/libcurl/src/inet_pton.c index a21679297f..04ccd2e97d 100644 --- a/libs/libcurl/src/inet_pton.c +++ b/libs/libcurl/src/inet_pton.c @@ -112,7 +112,8 @@ inet_pton4(const char *src, unsigned char *dst) pch = strchr(digits, ch); if(pch) { - unsigned int val = *tp * 10 + (unsigned int)(pch - digits); + unsigned int val = (unsigned int)(*tp * 10) + + (unsigned int)(pch - digits); if(saw_digit && *tp == 0) return (0); diff --git a/libs/libcurl/src/inet_pton.h b/libs/libcurl/src/inet_pton.h index 2d23c77a30..c3dc5d0415 100644 --- a/libs/libcurl/src/inet_pton.h +++ b/libs/libcurl/src/inet_pton.h @@ -31,9 +31,6 @@ int Curl_inet_pton(int, const char *, void *); #ifdef HAVE_INET_PTON #ifdef HAVE_ARPA_INET_H #include -#elif defined(HAVE_WS2TCPIP_H) -/* inet_pton() exists in Vista or later */ -#include #endif #define Curl_inet_pton(x,y,z) inet_pton(x,y,z) #endif diff --git a/libs/libcurl/src/krb5.c b/libs/libcurl/src/krb5.c index d69be2c17a..6c245c575d 100644 --- a/libs/libcurl/src/krb5.c +++ b/libs/libcurl/src/krb5.c @@ -75,8 +75,7 @@ static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn, unsigned char data_sec = conn->data_prot; #endif - if(!cmd) - return CURLE_BAD_FUNCTION_ARGUMENT; + DEBUGASSERT(cmd); write_len = strlen(cmd); if(!write_len || write_len > (sizeof(s) -3)) @@ -236,9 +235,12 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn) if(Curl_GetFTPResponse(data, &nread, NULL)) return -1; - - if(data->state.buffer[0] != '3') - return -1; + else { + struct pingpong *pp = &conn->proto.ftpc.pp; + char *line = Curl_dyn_ptr(&pp->recvbuf); + if(line[0] != '3') + return -1; + } } stringp = aprintf("%s@%s", service, host); @@ -322,15 +324,19 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn) ret = -1; break; } - - if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') { - infof(data, "Server didn't accept auth data"); - ret = AUTH_ERROR; - break; + else { + struct pingpong *pp = &conn->proto.ftpc.pp; + size_t len = Curl_dyn_len(&pp->recvbuf); + p = Curl_dyn_ptr(&pp->recvbuf); + if((len < 4) || (p[0] != '2' && p[0] != '3')) { + infof(data, "Server didn't accept auth data"); + ret = AUTH_ERROR; + break; + } } _gssresp.value = NULL; /* make sure it is initialized */ - p = data->state.buffer + 4; + p += 4; /* over '789 ' */ p = strstr(p, "ADAT="); if(p) { result = Curl_base64_decode(p + 5, @@ -417,7 +423,6 @@ static char level_to_char(int level) case PROT_PRIVATE: return 'P'; case PROT_CMD: - /* Fall through */ default: /* Those 2 cases should not be reached! */ break; @@ -429,6 +434,9 @@ static char level_to_char(int level) /* Send an FTP command defined by |message| and the optional arguments. The function returns the ftp_code. If an error occurs, -1 is returned. */ +static int ftp_send_command(struct Curl_easy *data, const char *message, ...) + CURL_PRINTF(2, 3); + static int ftp_send_command(struct Curl_easy *data, const char *message, ...) { int ftp_code; @@ -750,6 +758,8 @@ static int sec_set_protection_level(struct Curl_easy *data) if(level) { char *pbsz; unsigned int buffer_size = 1 << 20; /* 1048576 */ + struct pingpong *pp = &conn->proto.ftpc.pp; + char *line; code = ftp_send_command(data, "PBSZ %u", buffer_size); if(code < 0) @@ -761,10 +771,11 @@ static int sec_set_protection_level(struct Curl_easy *data) } conn->buffer_size = buffer_size; - pbsz = strstr(data->state.buffer, "PBSZ="); + line = Curl_dyn_ptr(&pp->recvbuf); + pbsz = strstr(line, "PBSZ="); if(pbsz) { /* stick to default value if the check fails */ - if(!strncmp(pbsz, "PBSZ=", 5) && ISDIGIT(pbsz[5])) + if(ISDIGIT(pbsz[5])) buffer_size = atoi(&pbsz[5]); if(buffer_size < conn->buffer_size) conn->buffer_size = buffer_size; diff --git a/libs/libcurl/src/ldap.c b/libs/libcurl/src/ldap.c index 16e851dcec..9d8bee81a0 100644 --- a/libs/libcurl/src/ldap.c +++ b/libs/libcurl/src/ldap.c @@ -137,7 +137,7 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp); _ldap_trace x; \ } while(0) - static void _ldap_trace(const char *fmt, ...); + static void _ldap_trace(const char *fmt, ...) CURL_PRINTF(1, 2); #else #define LDAP_TRACE(x) Curl_nop_stmt #endif @@ -177,7 +177,7 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_LDAP, /* defport */ @@ -205,7 +205,7 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_LDAPS, /* defport */ diff --git a/libs/libcurl/src/libcurl.plist b/libs/libcurl/src/libcurl.plist index 7c4364f8d8..f9df74ffe0 100644 --- a/libs/libcurl/src/libcurl.plist +++ b/libs/libcurl/src/libcurl.plist @@ -15,7 +15,7 @@ se.curl.libcurl CFBundleVersion - 8.5.0 + 8.6.0 CFBundleName libcurl @@ -27,9 +27,9 @@ ???? CFBundleShortVersionString - libcurl 8.5.0 + libcurl 8.6.0 CFBundleGetInfoString - libcurl.plist 8.5.0 + libcurl.plist 8.6.0 diff --git a/libs/libcurl/src/md4.c b/libs/libcurl/src/md4.c index 7aae719266..f48ea9987c 100644 --- a/libs/libcurl/src/md4.c +++ b/libs/libcurl/src/md4.c @@ -194,11 +194,9 @@ static int MD4_Init(MD4_CTX *ctx) static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) { if(!ctx->data) { - ctx->data = malloc(size); - if(ctx->data) { - memcpy(ctx->data, data, size); + ctx->data = Curl_memdup(data, size); + if(ctx->data) ctx->size = size; - } } } diff --git a/libs/libcurl/src/memdebug.c b/libs/libcurl/src/memdebug.c index 869d9ca54d..5d1bb4ad55 100644 --- a/libs/libcurl/src/memdebug.c +++ b/libs/libcurl/src/memdebug.c @@ -304,12 +304,6 @@ void curl_dbg_free(void *ptr, int line, const char *source) curl_socket_t curl_dbg_socket(int domain, int type, int protocol, int line, const char *source) { - const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d socket() = %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d socket() = %ld\n" : - "FD %s:%d socket() = %zd\n"; - curl_socket_t sockfd; if(countcheck("socket", line, source)) @@ -318,7 +312,8 @@ curl_socket_t curl_dbg_socket(int domain, int type, int protocol, sockfd = socket(domain, type, protocol); if(source && (sockfd != CURL_SOCKET_BAD)) - curl_dbg_log(fmt, source, line, sockfd); + curl_dbg_log("FD %s:%d socket() = %" CURL_FORMAT_SOCKET_T "\n", + source, line, sockfd); return sockfd; } @@ -357,16 +352,12 @@ int curl_dbg_socketpair(int domain, int type, int protocol, curl_socket_t socket_vector[2], int line, const char *source) { - const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d socketpair() = %d %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d socketpair() = %ld %ld\n" : - "FD %s:%d socketpair() = %zd %zd\n"; - int res = socketpair(domain, type, protocol, socket_vector); if(source && (0 == res)) - curl_dbg_log(fmt, source, line, socket_vector[0], socket_vector[1]); + curl_dbg_log("FD %s:%d socketpair() = " + "%" CURL_FORMAT_SOCKET_T " %" CURL_FORMAT_SOCKET_T "\n", + source, line, socket_vector[0], socket_vector[1]); return res; } @@ -375,19 +366,14 @@ int curl_dbg_socketpair(int domain, int type, int protocol, curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen, int line, const char *source) { - const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d accept() = %d\n" : - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d accept() = %ld\n" : - "FD %s:%d accept() = %zd\n"; - struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; curl_socket_t sockfd = accept(s, addr, addrlen); if(source && (sockfd != CURL_SOCKET_BAD)) - curl_dbg_log(fmt, source, line, sockfd); + curl_dbg_log("FD %s:%d accept() = %" CURL_FORMAT_SOCKET_T "\n", + source, line, sockfd); return sockfd; } @@ -395,14 +381,9 @@ curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen, /* separate function to allow libcurl to mark a "faked" close */ void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source) { - const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? - "FD %s:%d sclose(%d)\n": - (sizeof(curl_socket_t) == sizeof(long)) ? - "FD %s:%d sclose(%ld)\n": - "FD %s:%d sclose(%zd)\n"; - if(source) - curl_dbg_log(fmt, source, line, sockfd); + curl_dbg_log("FD %s:%d sclose(%" CURL_FORMAT_SOCKET_T ")\n", + source, line, sockfd); } /* this is our own defined way to close sockets on *ALL* platforms */ diff --git a/libs/libcurl/src/memdebug.h b/libs/libcurl/src/memdebug.h index a3a701011e..c3c81bad2c 100644 --- a/libs/libcurl/src/memdebug.h +++ b/libs/libcurl/src/memdebug.h @@ -72,7 +72,7 @@ CURL_EXTERN ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str, CURL_EXTERN void curl_dbg_memdebug(const char *logname); CURL_EXTERN void curl_dbg_memlimit(long limit); -CURL_EXTERN void curl_dbg_log(const char *format, ...); +CURL_EXTERN void curl_dbg_log(const char *format, ...) CURL_PRINTF(1, 2); /* file descriptor manipulators */ CURL_EXTERN curl_socket_t curl_dbg_socket(int domain, int type, int protocol, diff --git a/libs/libcurl/src/mime.c b/libs/libcurl/src/mime.c index 007a187bf5..167c8bab2d 100644 --- a/libs/libcurl/src/mime.c +++ b/libs/libcurl/src/mime.c @@ -30,6 +30,7 @@ #include "warnless.h" #include "urldata.h" #include "sendf.h" +#include "strdup.h" #if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \ !defined(CURL_DISABLE_SMTP) || \ @@ -817,7 +818,7 @@ static size_t read_part_content(curl_mimepart *part, case MIMEKIND_FILE: if(part->fp && feof(part->fp)) break; /* At EOF. */ - /* FALLTHROUGH */ + FALLTHROUGH(); default: if(part->readfunc) { if(!(part->flags & MIME_FAST_READ)) { @@ -936,7 +937,7 @@ static size_t readback_part(curl_mimepart *part, mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next); break; } - /* FALLTHROUGH */ + FALLTHROUGH(); case MIMESTATE_CURLHEADERS: if(!hdr) mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders); @@ -970,7 +971,7 @@ static size_t readback_part(curl_mimepart *part, fclose(part->fp); part->fp = NULL; } - /* FALLTHROUGH */ + FALLTHROUGH(); case CURL_READFUNC_ABORT: case CURL_READFUNC_PAUSE: case READ_ERROR: @@ -1235,6 +1236,7 @@ CURLcode Curl_mime_duppart(struct Curl_easy *data, } break; default: /* Invalid kind: should not occur. */ + DEBUGF(infof(data, "invalid MIMEKIND* attempt")); res = CURLE_BAD_FUNCTION_ARGUMENT; /* Internal error? */ break; } @@ -1370,27 +1372,22 @@ CURLcode curl_mime_filename(curl_mimepart *part, const char *filename) /* Set mime part content from memory data. */ CURLcode curl_mime_data(curl_mimepart *part, - const char *data, size_t datasize) + const char *ptr, size_t datasize) { if(!part) return CURLE_BAD_FUNCTION_ARGUMENT; cleanup_part_content(part); - if(data) { + if(ptr) { if(datasize == CURL_ZERO_TERMINATED) - datasize = strlen(data); + datasize = strlen(ptr); - part->data = malloc(datasize + 1); + part->data = Curl_memdup0(ptr, datasize); if(!part->data) return CURLE_OUT_OF_MEMORY; part->datasize = datasize; - - if(datasize) - memcpy(part->data, data, datasize); - part->data[datasize] = '\0'; /* Set a null terminator as sentinel. */ - part->readfunc = mime_mem_read; part->seekfunc = mime_mem_seek; part->freefunc = mime_mem_free; diff --git a/libs/libcurl/src/mime.h b/libs/libcurl/src/mime.h index 359fceea04..627689178b 100644 --- a/libs/libcurl/src/mime.h +++ b/libs/libcurl/src/mime.h @@ -130,7 +130,8 @@ struct curl_mimepart { size_t lastreadstatus; /* Last read callback returned status. */ }; -CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...); +CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...) + CURL_PRINTF(2, 3); #if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \ !defined(CURL_DISABLE_SMTP) || \ diff --git a/libs/libcurl/src/mprintf.c b/libs/libcurl/src/mprintf.c index cb91b6429a..72cf27edd3 100644 --- a/libs/libcurl/src/mprintf.c +++ b/libs/libcurl/src/mprintf.c @@ -20,25 +20,11 @@ * * SPDX-License-Identifier: curl * - * - * Purpose: - * A merge of Bjorn Reese's format() function and Daniel's dsprintf() - * 1.0. A full blooded printf() clone with full support for $ - * everywhere (parameters, widths and precisions) including variabled - * sized parameters (like doubles, long longs, long doubles and even - * void * in 64-bit architectures). - * - * Current restrictions: - * - Max 128 parameters - * - No 'long double' support. - * - * If you ever want truly portable and good *printf() clones, the project that - * took on from here is named 'Trio' and you find more details on the trio web - * page at https://daniel.haxx.se/projects/trio/ */ #include "curl_setup.h" #include "dynbuf.h" +#include "curl_printf.h" #include #include "curl_memory.h" @@ -86,7 +72,8 @@ #define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should fit negative DBL_MAX (317 letters) */ -#define MAX_PARAMETERS 128 /* lame static limit */ +#define MAX_PARAMETERS 128 /* number of input arguments */ +#define MAX_SEGMENTS 128 /* number of output segments */ #ifdef __AMIGA__ # undef FORMAT_INT @@ -98,31 +85,33 @@ static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; /* Upper-case digits. */ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; -#define OUTCHAR(x) \ - do { \ - if(stream((unsigned char)(x), (FILE *)data) != -1) \ - done++; \ - else \ - return done; /* return immediately on failure */ \ +#define OUTCHAR(x) \ + do { \ + if(!stream(x, userp)) \ + done++; \ + else \ + return done; /* return on failure */ \ } while(0) /* Data type to read from the arglist */ typedef enum { - FORMAT_UNKNOWN = 0, FORMAT_STRING, FORMAT_PTR, - FORMAT_INT, FORMAT_INTPTR, + FORMAT_INT, FORMAT_LONG, FORMAT_LONGLONG, + FORMAT_INTU, + FORMAT_LONGU, + FORMAT_LONGLONGU, FORMAT_DOUBLE, FORMAT_LONGDOUBLE, - FORMAT_WIDTH /* For internal use */ + FORMAT_WIDTH, + FORMAT_PRECISION } FormatType; /* conversion and display flags */ enum { - FLAGS_NEW = 0, FLAGS_SPACE = 1<<0, FLAGS_SHOWSIGN = 1<<1, FLAGS_LEFT = 1<<2, @@ -142,23 +131,40 @@ enum { FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */ FLAGS_CHAR = 1<<17, /* %c story */ FLAGS_FLOATE = 1<<18, /* %e or %E */ - FLAGS_FLOATG = 1<<19 /* %g or %G */ + FLAGS_FLOATG = 1<<19, /* %g or %G */ + FLAGS_SUBSTR = 1<<20 /* no input, only substring */ }; -struct va_stack { - FormatType type; - int flags; - long width; /* width OR width parameter number */ - long precision; /* precision OR precision parameter number */ +enum { + DOLLAR_UNKNOWN, + DOLLAR_NOPE, + DOLLAR_USE +}; + +/* + * Describes an input va_arg type and hold its value. + */ +struct va_input { + FormatType type; /* FormatType */ union { char *str; void *ptr; - union { - mp_intmax_t as_signed; - mp_uintmax_t as_unsigned; - } num; + mp_intmax_t nums; /* signed */ + mp_uintmax_t numu; /* unsigned */ double dnum; - } data; + } val; +}; + +/* + * Describes an output segment. + */ +struct outsegment { + int width; /* width OR width parameter number */ + int precision; /* precision OR precision parameter number */ + unsigned int flags; + unsigned int input; /* input argument array index */ + char *start; /* format string start to output */ + size_t outlen; /* number of bytes from the format string to output */ }; struct nsprintf { @@ -169,118 +175,123 @@ struct nsprintf { struct asprintf { struct dynbuf *b; - bool fail; /* if an alloc has failed and thus the output is not the complete - data */ + char merr; }; -static long dprintf_DollarString(char *input, char **end) -{ - int number = 0; - while(ISDIGIT(*input)) { - if(number < MAX_PARAMETERS) { - number *= 10; - number += *input - '0'; - } - input++; - } - if(number <= MAX_PARAMETERS && ('$' == *input)) { - *end = ++input; - return number; - } - return 0; -} +/* the provided input number is 1-based but this returns the number 0-based. -static bool dprintf_IsQualifierNoDollar(const char *fmt) + returns -1 if no valid number was provided. +*/ +static int dollarstring(char *input, char **end) { -#if defined(MP_HAVE_INT_EXTENSIONS) - if(!strncmp(fmt, "I32", 3) || !strncmp(fmt, "I64", 3)) { - return TRUE; - } -#endif - - switch(*fmt) { - case '-': case '+': case ' ': case '#': case '.': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case 'h': case 'l': case 'L': case 'z': case 'q': - case '*': case 'O': -#if defined(MP_HAVE_INT_EXTENSIONS) - case 'I': -#endif - return TRUE; + if(ISDIGIT(*input)) { + int number = 0; + do { + if(number < MAX_PARAMETERS) { + number *= 10; + number += *input - '0'; + } + input++; + } while(ISDIGIT(*input)); - default: - return FALSE; + if(number && (number <= MAX_PARAMETERS) && ('$' == *input)) { + *end = ++input; + return number - 1; + } } + return -1; } -/****************************************************************** +/* + * Parse the format string. * - * Pass 1: - * Create an index with the type of each parameter entry and its - * value (may vary in size) + * Create two arrays. One describes the inputs, one describes the outputs. * * Returns zero on success. - * - ******************************************************************/ + */ -static int dprintf_Pass1(const char *format, struct va_stack *vto, - char **endpos, va_list arglist) +#define PFMT_OK 0 +#define PFMT_DOLLAR 1 /* bad dollar for main param */ +#define PFMT_DOLLARWIDTH 2 /* bad dollar use for width */ +#define PFMT_DOLLARPREC 3 /* bad dollar use for precision */ +#define PFMT_MANYARGS 4 /* too many input arguments used */ +#define PFMT_PREC 5 /* precision overflow */ +#define PFMT_PRECMIX 6 /* bad mix of precision specifiers */ +#define PFMT_WIDTH 7 /* width overflow */ +#define PFMT_INPUTGAP 8 /* gap in arguments */ +#define PFMT_WIDTHARG 9 /* attempted to use same arg twice, for width */ +#define PFMT_PRECARG 10 /* attempted to use same arg twice, for prec */ +#define PFMT_MANYSEGS 11 /* maxed out output segments */ + +static int parsefmt(const char *format, + struct outsegment *out, + struct va_input *in, + int *opieces, + int *ipieces, va_list arglist) { char *fmt = (char *)format; int param_num = 0; - long this_param; - long width; - long precision; - int flags; - long max_param = 0; - long i; + int param; + int width; + int precision; + unsigned int flags; + FormatType type; + int max_param = -1; + int i; + int ocount = 0; + unsigned char usedinput[MAX_PARAMETERS/8]; + size_t outlen = 0; + struct outsegment *optr; + int use_dollar = DOLLAR_UNKNOWN; + char *start = fmt; + + /* clear, set a bit for each used input */ + memset(usedinput, 0, sizeof(usedinput)); while(*fmt) { - if(*fmt++ == '%') { + if(*fmt == '%') { + struct va_input *iptr; + bool loopit = TRUE; + fmt++; + outlen = fmt - start - 1; if(*fmt == '%') { + /* this means a %% that should be output only as %. Create an output + segment. */ + if(outlen) { + optr = &out[ocount++]; + if(ocount > MAX_SEGMENTS) + return PFMT_MANYSEGS; + optr->input = 0; + optr->flags = FLAGS_SUBSTR; + optr->start = start; + optr->outlen = outlen; + } + start = fmt; fmt++; continue; /* while */ } - flags = FLAGS_NEW; - - /* Handle the positional case (N$) */ - - param_num++; - - this_param = dprintf_DollarString(fmt, &fmt); - if(0 == this_param) - /* we got no positional, get the next counter */ - this_param = param_num; - - if(this_param > max_param) - max_param = this_param; + flags = width = precision = 0; - /* - * The parameter with number 'i' should be used. Next, we need - * to get SIZE and TYPE of the parameter. Add the information - * to our array. - */ + if(use_dollar != DOLLAR_NOPE) { + param = dollarstring(fmt, &fmt); + if(param < 0) { + if(use_dollar == DOLLAR_USE) + /* illegal combo */ + return PFMT_DOLLAR; - width = 0; - precision = 0; - - /* Handle the flags */ - - while(dprintf_IsQualifierNoDollar(fmt)) { -#if defined(MP_HAVE_INT_EXTENSIONS) - if(!strncmp(fmt, "I32", 3)) { - flags |= FLAGS_LONG; - fmt += 3; - } - else if(!strncmp(fmt, "I64", 3)) { - flags |= FLAGS_LONGLONG; - fmt += 3; + /* we got no positional, just get the next arg */ + param = -1; + use_dollar = DOLLAR_NOPE; } else -#endif + use_dollar = DOLLAR_USE; + } + else + param = -1; + /* Handle the flags */ + while(loopit) { switch(*fmt++) { case ' ': flags |= FLAGS_SPACE; @@ -298,40 +309,63 @@ static int dprintf_Pass1(const char *format, struct va_stack *vto, case '.': if('*' == *fmt) { /* The precision is picked from a specified parameter */ - flags |= FLAGS_PRECPARAM; fmt++; - param_num++; - i = dprintf_DollarString(fmt, &fmt); - if(i) - precision = i; + if(use_dollar == DOLLAR_USE) { + precision = dollarstring(fmt, &fmt); + if(precision < 0) + /* illegal combo */ + return PFMT_DOLLARPREC; + } else - precision = param_num; - - if(precision > max_param) - max_param = precision; + /* get it from the next argument */ + precision = -1; } else { + bool is_neg = FALSE; flags |= FLAGS_PREC; - precision = strtol(fmt, &fmt, 10); + precision = 0; + if('-' == *fmt) { + is_neg = TRUE; + fmt++; + } + while(ISDIGIT(*fmt)) { + if(precision > INT_MAX/10) + return PFMT_PREC; + precision *= 10; + precision += *fmt - '0'; + fmt++; + } + if(is_neg) + precision = -precision; } if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) == (FLAGS_PREC | FLAGS_PRECPARAM)) /* it is not permitted to use both kinds of precision for the same argument */ - return 1; + return PFMT_PRECMIX; break; case 'h': flags |= FLAGS_SHORT; break; #if defined(MP_HAVE_INT_EXTENSIONS) case 'I': + if((fmt[0] == '3') && (fmt[1] == '2')) { + flags |= FLAGS_LONG; + fmt += 2; + } + else if((fmt[0] == '6') && (fmt[1] == '4')) { + flags |= FLAGS_LONGLONG; + fmt += 2; + } + else { #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) - flags |= FLAGS_LONGLONG; + flags |= FLAGS_LONGLONG; #else - flags |= FLAGS_LONG; + flags |= FLAGS_LONG; #endif + } break; #endif case 'l': @@ -365,401 +399,421 @@ static int dprintf_Pass1(const char *format, struct va_stack *vto, case '0': if(!(flags & FLAGS_LEFT)) flags |= FLAGS_PAD_NIL; - /* FALLTHROUGH */ + FALLTHROUGH(); case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': flags |= FLAGS_WIDTH; - width = strtol(fmt-1, &fmt, 10); + width = 0; + fmt--; + do { + if(width > INT_MAX/10) + return PFMT_WIDTH; + width *= 10; + width += *fmt - '0'; + fmt++; + } while(ISDIGIT(*fmt)); break; - case '*': /* Special case */ + case '*': /* read width from argument list */ flags |= FLAGS_WIDTHPARAM; - param_num++; - - i = dprintf_DollarString(fmt, &fmt); - if(i) - width = i; + if(use_dollar == DOLLAR_USE) { + width = dollarstring(fmt, &fmt); + if(width < 0) + /* illegal combo */ + return PFMT_DOLLARWIDTH; + } else - width = param_num; - if(width > max_param) - max_param = width; + /* pick from the next argument */ + width = -1; break; - case '\0': - fmt--; default: + loopit = FALSE; + fmt--; break; - } - } /* switch */ - - /* Handle the specifier */ - - i = this_param - 1; - - if((i < 0) || (i >= MAX_PARAMETERS)) - /* out of allowed range */ - return 1; + } /* switch */ + } /* while */ switch(*fmt) { case 'S': flags |= FLAGS_ALT; - /* FALLTHROUGH */ + FALLTHROUGH(); case 's': - vto[i].type = FORMAT_STRING; + type = FORMAT_STRING; break; case 'n': - vto[i].type = FORMAT_INTPTR; + type = FORMAT_INTPTR; break; case 'p': - vto[i].type = FORMAT_PTR; + type = FORMAT_PTR; break; - case 'd': case 'i': - vto[i].type = FORMAT_INT; + case 'd': + case 'i': + if(flags & FLAGS_LONGLONG) + type = FORMAT_LONGLONG; + else if(flags & FLAGS_LONG) + type = FORMAT_LONG; + else + type = FORMAT_INT; break; case 'u': - vto[i].type = FORMAT_INT; + if(flags & FLAGS_LONGLONG) + type = FORMAT_LONGLONGU; + else if(flags & FLAGS_LONG) + type = FORMAT_LONGU; + else + type = FORMAT_INTU; flags |= FLAGS_UNSIGNED; break; case 'o': - vto[i].type = FORMAT_INT; + type = FORMAT_INT; flags |= FLAGS_OCTAL; break; case 'x': - vto[i].type = FORMAT_INT; + type = FORMAT_INTU; flags |= FLAGS_HEX|FLAGS_UNSIGNED; break; case 'X': - vto[i].type = FORMAT_INT; + type = FORMAT_INTU; flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED; break; case 'c': - vto[i].type = FORMAT_INT; + type = FORMAT_INT; flags |= FLAGS_CHAR; break; case 'f': - vto[i].type = FORMAT_DOUBLE; + type = FORMAT_DOUBLE; break; case 'e': - vto[i].type = FORMAT_DOUBLE; + type = FORMAT_DOUBLE; flags |= FLAGS_FLOATE; break; case 'E': - vto[i].type = FORMAT_DOUBLE; + type = FORMAT_DOUBLE; flags |= FLAGS_FLOATE|FLAGS_UPPER; break; case 'g': - vto[i].type = FORMAT_DOUBLE; + type = FORMAT_DOUBLE; flags |= FLAGS_FLOATG; break; case 'G': - vto[i].type = FORMAT_DOUBLE; + type = FORMAT_DOUBLE; flags |= FLAGS_FLOATG|FLAGS_UPPER; break; default: - vto[i].type = FORMAT_UNKNOWN; - break; + /* invalid instruction, disregard and continue */ + continue; } /* switch */ - vto[i].flags = flags; - vto[i].width = width; - vto[i].precision = precision; - if(flags & FLAGS_WIDTHPARAM) { - /* we have the width specified from a parameter, so we make that - parameter's info setup properly */ - long k = width - 1; - if((k < 0) || (k >= MAX_PARAMETERS)) - /* out of allowed range */ - return 1; - vto[i].width = k; - vto[k].type = FORMAT_WIDTH; - vto[k].flags = FLAGS_NEW; - /* can't use width or precision of width! */ - vto[k].width = 0; - vto[k].precision = 0; + if(width < 0) + width = param_num++; + else { + /* if this identifies a parameter already used, this + is illegal */ + if(usedinput[width/8] & (1 << (width&7))) + return PFMT_WIDTHARG; + } + if(width >= MAX_PARAMETERS) + return PFMT_MANYARGS; + if(width >= max_param) + max_param = width; + + in[width].type = FORMAT_WIDTH; + /* mark as used */ + usedinput[width/8] |= (unsigned char)(1 << (width&7)); } + if(flags & FLAGS_PRECPARAM) { - /* we have the precision specified from a parameter, so we make that - parameter's info setup properly */ - long k = precision - 1; - if((k < 0) || (k >= MAX_PARAMETERS)) - /* out of allowed range */ - return 1; - vto[i].precision = k; - vto[k].type = FORMAT_WIDTH; - vto[k].flags = FLAGS_NEW; - /* can't use width or precision of width! */ - vto[k].width = 0; - vto[k].precision = 0; + if(precision < 0) + precision = param_num++; + else { + /* if this identifies a parameter already used, this + is illegal */ + if(usedinput[precision/8] & (1 << (precision&7))) + return PFMT_PRECARG; + } + if(precision >= MAX_PARAMETERS) + return PFMT_MANYARGS; + if(precision >= max_param) + max_param = precision; + + in[precision].type = FORMAT_PRECISION; + usedinput[precision/8] |= (unsigned char)(1 << (precision&7)); } - *endpos++ = fmt + ((*fmt == '\0') ? 0 : 1); /* end of this sequence */ + + /* Handle the specifier */ + if(param < 0) + param = param_num++; + if(param >= MAX_PARAMETERS) + return PFMT_MANYARGS; + if(param >= max_param) + max_param = param; + + iptr = &in[param]; + iptr->type = type; + + /* mark this input as used */ + usedinput[param/8] |= (unsigned char)(1 << (param&7)); + + fmt++; + optr = &out[ocount++]; + if(ocount > MAX_SEGMENTS) + return PFMT_MANYSEGS; + optr->input = param; + optr->flags = flags; + optr->width = width; + optr->precision = precision; + optr->start = start; + optr->outlen = outlen; + start = fmt; } + else + fmt++; } - /* Read the arg list parameters into our data list */ - for(i = 0; i MAX_SEGMENTS) + return PFMT_MANYSEGS; + optr->input = 0; + optr->flags = FLAGS_SUBSTR; + optr->start = start; + optr->outlen = outlen; + } - switch(vto[i].type) { + /* Read the arg list parameters into our data list */ + for(i = 0; i < max_param + 1; i++) { + struct va_input *iptr = &in[i]; + if(!(usedinput[i/8] & (1 << (i&7)))) + /* bad input */ + return PFMT_INPUTGAP; + + /* based on the type, read the correct argument */ + switch(iptr->type) { case FORMAT_STRING: - vto[i].data.str = va_arg(arglist, char *); + iptr->val.str = va_arg(arglist, char *); break; case FORMAT_INTPTR: - case FORMAT_UNKNOWN: case FORMAT_PTR: - vto[i].data.ptr = va_arg(arglist, void *); + iptr->val.ptr = va_arg(arglist, void *); break; - case FORMAT_INT: -#ifdef HAVE_LONG_LONG_TYPE - if((vto[i].flags & FLAGS_LONGLONG) && (vto[i].flags & FLAGS_UNSIGNED)) - vto[i].data.num.as_unsigned = - (mp_uintmax_t)va_arg(arglist, mp_uintmax_t); - else if(vto[i].flags & FLAGS_LONGLONG) - vto[i].data.num.as_signed = - (mp_intmax_t)va_arg(arglist, mp_intmax_t); - else -#endif - { - if((vto[i].flags & FLAGS_LONG) && (vto[i].flags & FLAGS_UNSIGNED)) - vto[i].data.num.as_unsigned = - (mp_uintmax_t)va_arg(arglist, unsigned long); - else if(vto[i].flags & FLAGS_LONG) - vto[i].data.num.as_signed = - (mp_intmax_t)va_arg(arglist, long); - else if(vto[i].flags & FLAGS_UNSIGNED) - vto[i].data.num.as_unsigned = - (mp_uintmax_t)va_arg(arglist, unsigned int); - else - vto[i].data.num.as_signed = - (mp_intmax_t)va_arg(arglist, int); - } + case FORMAT_LONGLONGU: + iptr->val.numu = (mp_uintmax_t)va_arg(arglist, mp_uintmax_t); break; - case FORMAT_DOUBLE: - vto[i].data.dnum = va_arg(arglist, double); + case FORMAT_LONGLONG: + iptr->val.nums = (mp_intmax_t)va_arg(arglist, mp_intmax_t); + break; + + case FORMAT_LONGU: + iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned long); + break; + + case FORMAT_LONG: + iptr->val.nums = (mp_intmax_t)va_arg(arglist, long); + break; + + case FORMAT_INTU: + iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned int); break; + case FORMAT_INT: case FORMAT_WIDTH: - /* Argument has been read. Silently convert it into an integer - * for later use - */ - vto[i].type = FORMAT_INT; + case FORMAT_PRECISION: + iptr->val.nums = (mp_intmax_t)va_arg(arglist, int); + break; + + case FORMAT_DOUBLE: + iptr->val.dnum = va_arg(arglist, double); break; default: + DEBUGASSERT(NULL); /* unexpected */ break; } } + *ipieces = max_param + 1; + *opieces = ocount; - return 0; - + return PFMT_OK; } -static int dprintf_formatf( - void *data, /* untouched by format(), just sent to the stream() function in - the second argument */ +/* + * formatf() - the general printf function. + * + * It calls parsefmt() to parse the format string. It populates two arrays; + * one that describes the input arguments and one that describes a number of + * output segments. + * + * On success, the input array describes the type of all arguments and their + * values. + * + * The function then iterates over the output sengments and outputs them one + * by one until done. Using the appropriate input arguments (if any). + * + * All output is sent to the 'stream()' callback, one byte at a time. + */ + +static int formatf( + void *userp, /* untouched by format(), just sent to the stream() function in + the second argument */ /* function pointer called for each output character */ - int (*stream)(int, FILE *), + int (*stream)(unsigned char, void *), const char *format, /* %-formatted string */ va_list ap_save) /* list of parameters */ { - /* Base-36 digits for numbers. */ - const char *digits = lower_digits; - - /* Pointer into the format string. */ - char *f; - - /* Number of characters written. */ - int done = 0; - - long param; /* current parameter to read */ - long param_num = 0; /* parameter counter */ - - struct va_stack vto[MAX_PARAMETERS]; - char *endpos[MAX_PARAMETERS]; - char **end; + static const char nilstr[] = "(nil)"; + const char *digits = lower_digits; /* Base-36 digits for numbers. */ + int done = 0; /* number of characters written */ + int i; + int ocount = 0; /* number of output segments */ + int icount = 0; /* number of input arguments */ + + struct outsegment output[MAX_SEGMENTS]; + struct va_input input[MAX_PARAMETERS]; char work[BUFFSIZE]; - struct va_stack *p; /* 'workend' points to the final buffer byte position, but with an extra byte as margin to avoid the (false?) warning Coverity gives us otherwise */ char *workend = &work[sizeof(work) - 2]; - /* Do the actual %-code parsing */ - if(dprintf_Pass1(format, vto, endpos, ap_save)) + /* Parse the format string */ + if(parsefmt(format, output, input, &ocount, &icount, ap_save)) return 0; - end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1() - created for us */ - - f = (char *)format; - while(*f != '\0') { - /* Format spec modifiers. */ - int is_alt; - - /* Width of a field. */ - long width; - - /* Precision of a field. */ - long prec; - - /* Decimal integer is negative. */ - int is_neg; - - /* Base of a number to be written. */ - unsigned long base; - - /* Integral values to be written. */ - mp_uintmax_t num; - - /* Used to convert negative in positive. */ - mp_intmax_t signed_num; - + for(i = 0; i < ocount; i++) { + struct outsegment *optr = &output[i]; + struct va_input *iptr; + bool is_alt; /* Format spec modifiers. */ + int width; /* Width of a field. */ + int prec; /* Precision of a field. */ + bool is_neg; /* Decimal integer is negative. */ + unsigned long base; /* Base of a number to be written. */ + mp_uintmax_t num; /* Integral values to be written. */ + mp_intmax_t signed_num; /* Used to convert negative in positive. */ char *w; - - if(*f != '%') { - /* This isn't a format spec, so write everything out until the next one - OR end of string is reached. */ - do { - OUTCHAR(*f); - } while(*++f && ('%' != *f)); - continue; + size_t outlen = optr->outlen; + int flags = optr->flags; + + if(outlen) { + char *str = optr->start; + for(; outlen && *str; outlen--) + OUTCHAR(*str++); + if(optr->flags & FLAGS_SUBSTR) + /* this is just a substring */ + continue; } - ++f; - - /* Check for "%%". Note that although the ANSI standard lists - '%' as a conversion specifier, it says "The complete format - specification shall be `%%'," so we can avoid all the width - and precision processing. */ - if(*f == '%') { - ++f; - OUTCHAR('%'); - continue; - } - - /* If this is a positional parameter, the position must follow immediately - after the %, thus create a %$ sequence */ - param = dprintf_DollarString(f, &f); - - if(!param) - param = param_num; - else - --param; - - param_num++; /* increase this always to allow "%2$s %1$s %s" and then the - third %s will pick the 3rd argument */ - - p = &vto[param]; - /* pick up the specified width */ - if(p->flags & FLAGS_WIDTHPARAM) { - width = (long)vto[p->width].data.num.as_signed; - param_num++; /* since the width is extracted from a parameter, we - must skip that to get to the next one properly */ + if(flags & FLAGS_WIDTHPARAM) { + width = (int)input[optr->width].val.nums; if(width < 0) { /* "A negative field width is taken as a '-' flag followed by a positive field width." */ - width = -width; - p->flags |= FLAGS_LEFT; - p->flags &= ~FLAGS_PAD_NIL; + if(width == INT_MIN) + width = INT_MAX; + else + width = -width; + flags |= FLAGS_LEFT; + flags &= ~FLAGS_PAD_NIL; } } else - width = p->width; + width = optr->width; /* pick up the specified precision */ - if(p->flags & FLAGS_PRECPARAM) { - prec = (long)vto[p->precision].data.num.as_signed; - param_num++; /* since the precision is extracted from a parameter, we - must skip that to get to the next one properly */ + if(flags & FLAGS_PRECPARAM) { + prec = (int)input[optr->precision].val.nums; if(prec < 0) /* "A negative precision is taken as if the precision were omitted." */ prec = -1; } - else if(p->flags & FLAGS_PREC) - prec = p->precision; + else if(flags & FLAGS_PREC) + prec = optr->precision; else prec = -1; - is_alt = (p->flags & FLAGS_ALT) ? 1 : 0; + is_alt = (flags & FLAGS_ALT) ? 1 : 0; + iptr = &input[optr->input]; - switch(p->type) { + switch(iptr->type) { + case FORMAT_INTU: + case FORMAT_LONGU: + case FORMAT_LONGLONGU: + flags |= FLAGS_UNSIGNED; + FALLTHROUGH(); case FORMAT_INT: - num = p->data.num.as_unsigned; - if(p->flags & FLAGS_CHAR) { + case FORMAT_LONG: + case FORMAT_LONGLONG: + num = iptr->val.numu; + if(flags & FLAGS_CHAR) { /* Character. */ - if(!(p->flags & FLAGS_LEFT)) + if(!(flags & FLAGS_LEFT)) while(--width > 0) OUTCHAR(' '); OUTCHAR((char) num); - if(p->flags & FLAGS_LEFT) + if(flags & FLAGS_LEFT) while(--width > 0) OUTCHAR(' '); break; } - if(p->flags & FLAGS_OCTAL) { - /* Octal unsigned integer. */ + if(flags & FLAGS_OCTAL) { + /* Octal unsigned integer */ base = 8; - goto unsigned_number; + is_neg = FALSE; } - else if(p->flags & FLAGS_HEX) { - /* Hexadecimal unsigned integer. */ - - digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; + else if(flags & FLAGS_HEX) { + /* Hexadecimal unsigned integer */ + digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits; base = 16; - goto unsigned_number; + is_neg = FALSE; } - else if(p->flags & FLAGS_UNSIGNED) { - /* Decimal unsigned integer. */ + else if(flags & FLAGS_UNSIGNED) { + /* Decimal unsigned integer */ base = 10; - goto unsigned_number; + is_neg = FALSE; } + else { + /* Decimal integer. */ + base = 10; - /* Decimal integer. */ - base = 10; - - is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0; - if(is_neg) { - /* signed_num might fail to hold absolute negative minimum by 1 */ - signed_num = p->data.num.as_signed + (mp_intmax_t)1; - signed_num = -signed_num; - num = (mp_uintmax_t)signed_num; - num += (mp_uintmax_t)1; + is_neg = (iptr->val.nums < (mp_intmax_t)0); + if(is_neg) { + /* signed_num might fail to hold absolute negative minimum by 1 */ + signed_num = iptr->val.nums + (mp_intmax_t)1; + signed_num = -signed_num; + num = (mp_uintmax_t)signed_num; + num += (mp_uintmax_t)1; + } } - - goto number; - -unsigned_number: - /* Unsigned number of base BASE. */ - is_neg = 0; - number: - /* Number of base BASE. */ - /* Supply a default precision if none was given. */ if(prec == -1) prec = 1; /* Put the number in WORK. */ w = workend; - while(num > 0) { - *w-- = digits[num % base]; - num /= base; + switch(base) { + case 10: + while(num > 0) { + *w-- = (char)('0' + (num % 10)); + num /= 10; + } + break; + default: + while(num > 0) { + *w-- = digits[num % base]; + num /= base; + } + break; } - width -= (long)(workend - w); - prec -= (long)(workend - w); + width -= (int)(workend - w); + prec -= (int)(workend - w); if(is_alt && base == 8 && prec <= 0) { *w-- = '0'; @@ -775,29 +829,29 @@ number: if(is_alt && base == 16) width -= 2; - if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) + if(is_neg || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE)) --width; - if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) + if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_PAD_NIL)) while(width-- > 0) OUTCHAR(' '); if(is_neg) OUTCHAR('-'); - else if(p->flags & FLAGS_SHOWSIGN) + else if(flags & FLAGS_SHOWSIGN) OUTCHAR('+'); - else if(p->flags & FLAGS_SPACE) + else if(flags & FLAGS_SPACE) OUTCHAR(' '); if(is_alt && base == 16) { OUTCHAR('0'); - if(p->flags & FLAGS_UPPER) + if(flags & FLAGS_UPPER) OUTCHAR('X'); else OUTCHAR('x'); } - if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) + if(!(flags & FLAGS_LEFT) && (flags & FLAGS_PAD_NIL)) while(width-- > 0) OUTCHAR('0'); @@ -806,219 +860,199 @@ number: OUTCHAR(*w); } - if(p->flags & FLAGS_LEFT) + if(flags & FLAGS_LEFT) while(width-- > 0) OUTCHAR(' '); break; - case FORMAT_STRING: - /* String. */ - { - static const char null[] = "(nil)"; - const char *str; - size_t len; - - str = (char *) p->data.str; - if(!str) { - /* Write null[] if there's space. */ - if(prec == -1 || prec >= (long) sizeof(null) - 1) { - str = null; - len = sizeof(null) - 1; - /* Disable quotes around (nil) */ - p->flags &= (~FLAGS_ALT); - } - else { - str = ""; - len = 0; - } + case FORMAT_STRING: { + const char *str; + size_t len; + + str = (char *)iptr->val.str; + if(!str) { + /* Write null string if there's space. */ + if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) { + str = nilstr; + len = sizeof(nilstr) - 1; + /* Disable quotes around (nil) */ + flags &= (~FLAGS_ALT); } - else if(prec != -1) - len = (size_t)prec; - else if(*str == '\0') + else { + str = ""; len = 0; - else - len = strlen(str); + } + } + else if(prec != -1) + len = (size_t)prec; + else if(*str == '\0') + len = 0; + else + len = strlen(str); - width -= (len > LONG_MAX) ? LONG_MAX : (long)len; + width -= (len > INT_MAX) ? INT_MAX : (int)len; - if(p->flags & FLAGS_ALT) - OUTCHAR('"'); + if(flags & FLAGS_ALT) + OUTCHAR('"'); - if(!(p->flags&FLAGS_LEFT)) - while(width-- > 0) - OUTCHAR(' '); + if(!(flags&FLAGS_LEFT)) + while(width-- > 0) + OUTCHAR(' '); - for(; len && *str; len--) - OUTCHAR(*str++); - if(p->flags&FLAGS_LEFT) - while(width-- > 0) - OUTCHAR(' '); + for(; len && *str; len--) + OUTCHAR(*str++); + if(flags&FLAGS_LEFT) + while(width-- > 0) + OUTCHAR(' '); - if(p->flags & FLAGS_ALT) - OUTCHAR('"'); - } + if(flags & FLAGS_ALT) + OUTCHAR('"'); break; + } case FORMAT_PTR: /* Generic pointer. */ - { - void *ptr; - ptr = (void *) p->data.ptr; - if(ptr) { - /* If the pointer is not NULL, write it as a %#x spec. */ - base = 16; - digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; - is_alt = 1; - num = (size_t) ptr; - is_neg = 0; - goto number; - } - else { - /* Write "(nil)" for a nil pointer. */ - static const char strnil[] = "(nil)"; - const char *point; - - width -= (long)(sizeof(strnil) - 1); - if(p->flags & FLAGS_LEFT) - while(width-- > 0) - OUTCHAR(' '); - for(point = strnil; *point != '\0'; ++point) - OUTCHAR(*point); - if(!(p->flags & FLAGS_LEFT)) - while(width-- > 0) - OUTCHAR(' '); - } + if(iptr->val.ptr) { + /* If the pointer is not NULL, write it as a %#x spec. */ + base = 16; + digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits; + is_alt = TRUE; + num = (size_t) iptr->val.ptr; + is_neg = FALSE; + goto number; } - break; + else { + /* Write "(nil)" for a nil pointer. */ + const char *point; - case FORMAT_DOUBLE: - { - char formatbuf[32]="%"; - char *fptr = &formatbuf[1]; - size_t left = sizeof(formatbuf)-strlen(formatbuf); - int len; - - width = -1; - if(p->flags & FLAGS_WIDTH) - width = p->width; - else if(p->flags & FLAGS_WIDTHPARAM) - width = (long)vto[p->width].data.num.as_signed; + width -= (int)(sizeof(nilstr) - 1); + if(flags & FLAGS_LEFT) + while(width-- > 0) + OUTCHAR(' '); + for(point = nilstr; *point != '\0'; ++point) + OUTCHAR(*point); + if(!(flags & FLAGS_LEFT)) + while(width-- > 0) + OUTCHAR(' '); + } + break; - prec = -1; - if(p->flags & FLAGS_PREC) - prec = p->precision; - else if(p->flags & FLAGS_PRECPARAM) - prec = (long)vto[p->precision].data.num.as_signed; - - if(p->flags & FLAGS_LEFT) - *fptr++ = '-'; - if(p->flags & FLAGS_SHOWSIGN) - *fptr++ = '+'; - if(p->flags & FLAGS_SPACE) - *fptr++ = ' '; - if(p->flags & FLAGS_ALT) - *fptr++ = '#'; - - *fptr = 0; - - if(width >= 0) { - if(width >= (long)sizeof(work)) - width = sizeof(work)-1; - /* RECURSIVE USAGE */ - len = curl_msnprintf(fptr, left, "%ld", width); - fptr += len; - left -= len; + case FORMAT_DOUBLE: { + char formatbuf[32]="%"; + char *fptr = &formatbuf[1]; + size_t left = sizeof(formatbuf)-strlen(formatbuf); + int len; + + if(flags & FLAGS_WIDTH) + width = optr->width; + + if(flags & FLAGS_PREC) + prec = optr->precision; + + if(flags & FLAGS_LEFT) + *fptr++ = '-'; + if(flags & FLAGS_SHOWSIGN) + *fptr++ = '+'; + if(flags & FLAGS_SPACE) + *fptr++ = ' '; + if(flags & FLAGS_ALT) + *fptr++ = '#'; + + *fptr = 0; + + if(width >= 0) { + if(width >= (int)sizeof(work)) + width = sizeof(work)-1; + /* RECURSIVE USAGE */ + len = curl_msnprintf(fptr, left, "%d", width); + fptr += len; + left -= len; + } + if(prec >= 0) { + /* for each digit in the integer part, we can have one less + precision */ + size_t maxprec = sizeof(work) - 2; + double val = iptr->val.dnum; + if(width > 0 && prec <= width) + maxprec -= width; + while(val >= 10.0) { + val /= 10; + maxprec--; } - if(prec >= 0) { - /* for each digit in the integer part, we can have one less - precision */ - size_t maxprec = sizeof(work) - 2; - double val = p->data.dnum; - if(width > 0 && prec <= width) - maxprec -= width; - while(val >= 10.0) { - val /= 10; - maxprec--; - } - if(prec > (long)maxprec) - prec = (long)maxprec-1; - if(prec < 0) - prec = 0; - /* RECURSIVE USAGE */ - len = curl_msnprintf(fptr, left, ".%ld", prec); - fptr += len; - } - if(p->flags & FLAGS_LONG) - *fptr++ = 'l'; + if(prec > (int)maxprec) + prec = (int)maxprec-1; + if(prec < 0) + prec = 0; + /* RECURSIVE USAGE */ + len = curl_msnprintf(fptr, left, ".%d", prec); + fptr += len; + } + if(flags & FLAGS_LONG) + *fptr++ = 'l'; - if(p->flags & FLAGS_FLOATE) - *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e'); - else if(p->flags & FLAGS_FLOATG) - *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g'); - else - *fptr++ = 'f'; + if(flags & FLAGS_FLOATE) + *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E':'e'); + else if(flags & FLAGS_FLOATG) + *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g'); + else + *fptr++ = 'f'; - *fptr = 0; /* and a final null-termination */ + *fptr = 0; /* and a final null-termination */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wformat-nonliteral" #endif - /* NOTE NOTE NOTE!! Not all sprintf implementations return number of - output characters */ + /* NOTE NOTE NOTE!! Not all sprintf implementations return number of + output characters */ #ifdef HAVE_SNPRINTF - (snprintf)(work, sizeof(work), formatbuf, p->data.dnum); + (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum); #else - (sprintf)(work, formatbuf, p->data.dnum); + (sprintf)(work, formatbuf, iptr->val.dnum); #endif #ifdef __clang__ #pragma clang diagnostic pop #endif - DEBUGASSERT(strlen(work) <= sizeof(work)); - for(fptr = work; *fptr; fptr++) - OUTCHAR(*fptr); - } + DEBUGASSERT(strlen(work) <= sizeof(work)); + for(fptr = work; *fptr; fptr++) + OUTCHAR(*fptr); break; + } case FORMAT_INTPTR: /* Answer the count of characters written. */ #ifdef HAVE_LONG_LONG_TYPE - if(p->flags & FLAGS_LONGLONG) - *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done; + if(flags & FLAGS_LONGLONG) + *(LONG_LONG_TYPE *) iptr->val.ptr = (LONG_LONG_TYPE)done; else #endif - if(p->flags & FLAGS_LONG) - *(long *) p->data.ptr = (long)done; - else if(!(p->flags & FLAGS_SHORT)) - *(int *) p->data.ptr = (int)done; + if(flags & FLAGS_LONG) + *(long *) iptr->val.ptr = (long)done; + else if(!(flags & FLAGS_SHORT)) + *(int *) iptr->val.ptr = (int)done; else - *(short *) p->data.ptr = (short)done; + *(short *) iptr->val.ptr = (short)done; break; default: break; } - f = *end++; /* goto end of %-code */ - } return done; } /* fputc() look-alike */ -static int addbyter(int output, FILE *data) +static int addbyter(unsigned char outc, void *f) { - struct nsprintf *infop = (struct nsprintf *)data; - unsigned char outc = (unsigned char)output; - + struct nsprintf *infop = f; if(infop->length < infop->max) { /* only do this if we haven't reached max length yet */ - infop->buffer[0] = outc; /* store */ - infop->buffer++; /* increase pointer */ + *infop->buffer++ = outc; /* store */ infop->length++; /* we are now one byte larger */ - return outc; /* fputc() returns like this on success */ + return 0; /* fputc() returns like this on success */ } - return -1; + return 1; } int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, @@ -1031,7 +1065,7 @@ int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, info.length = 0; info.max = maxlength; - retcode = dprintf_formatf(&info, addbyter, format, ap_save); + retcode = formatf(&info, addbyter, format, ap_save); if(info.max) { /* we terminate this with a zero byte */ if(info.max == info.length) { @@ -1057,29 +1091,28 @@ int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) } /* fputc() look-alike */ -static int alloc_addbyter(int output, FILE *data) +static int alloc_addbyter(unsigned char outc, void *f) { - struct asprintf *infop = (struct asprintf *)data; - unsigned char outc = (unsigned char)output; - - if(Curl_dyn_addn(infop->b, &outc, 1)) { - infop->fail = 1; - return -1; /* fail */ + struct asprintf *infop = f; + CURLcode result = Curl_dyn_addn(infop->b, &outc, 1); + if(result) { + infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM; + return 1 ; /* fail */ } - return outc; /* fputc() returns like this on success */ + return 0; } -/* appends the formatted string, returns 0 on success, 1 on error */ +/* appends the formatted string, returns MERR error code */ int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save) { struct asprintf info; info.b = dyn; - info.fail = 0; + info.merr = MERR_OK; - (void)dprintf_formatf(&info, alloc_addbyter, format, ap_save); - if(info.fail) { + (void)formatf(&info, alloc_addbyter, format, ap_save); + if(info.merr) { Curl_dyn_free(info.b); - return 1; + return info.merr; } return 0; } @@ -1090,10 +1123,10 @@ char *curl_mvaprintf(const char *format, va_list ap_save) struct dynbuf dyn; info.b = &dyn; Curl_dyn_init(info.b, DYN_APRINTF); - info.fail = 0; + info.merr = MERR_OK; - (void)dprintf_formatf(&info, alloc_addbyter, format, ap_save); - if(info.fail) { + (void)formatf(&info, alloc_addbyter, format, ap_save); + if(info.merr) { Curl_dyn_free(info.b); return NULL; } @@ -1112,13 +1145,12 @@ char *curl_maprintf(const char *format, ...) return s; } -static int storebuffer(int output, FILE *data) +static int storebuffer(unsigned char outc, void *f) { - char **buffer = (char **)data; - unsigned char outc = (unsigned char)output; + char **buffer = f; **buffer = outc; (*buffer)++; - return outc; /* act like fputc() ! */ + return 0; } int curl_msprintf(char *buffer, const char *format, ...) @@ -1126,19 +1158,29 @@ int curl_msprintf(char *buffer, const char *format, ...) va_list ap_save; /* argument pointer */ int retcode; va_start(ap_save, format); - retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); + retcode = formatf(&buffer, storebuffer, format, ap_save); va_end(ap_save); *buffer = 0; /* we terminate this with a zero byte */ return retcode; } +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; +} + int curl_mprintf(const char *format, ...) { int retcode; va_list ap_save; /* argument pointer */ va_start(ap_save, format); - retcode = dprintf_formatf(stdout, fputc, format, ap_save); + retcode = formatf(stdout, fputc_wrapper, format, ap_save); va_end(ap_save); return retcode; } @@ -1148,25 +1190,24 @@ int curl_mfprintf(FILE *whereto, const char *format, ...) int retcode; va_list ap_save; /* argument pointer */ va_start(ap_save, format); - retcode = dprintf_formatf(whereto, fputc, format, ap_save); + retcode = formatf(whereto, fputc_wrapper, format, ap_save); va_end(ap_save); return retcode; } int curl_mvsprintf(char *buffer, const char *format, va_list ap_save) { - int retcode; - retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save); + int retcode = formatf(&buffer, storebuffer, format, ap_save); *buffer = 0; /* we terminate this with a zero byte */ return retcode; } int curl_mvprintf(const char *format, va_list ap_save) { - return dprintf_formatf(stdout, fputc, format, ap_save); + return formatf(stdout, fputc_wrapper, format, ap_save); } int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save) { - return dprintf_formatf(whereto, fputc, format, ap_save); + return formatf(whereto, fputc_wrapper, format, ap_save); } diff --git a/libs/libcurl/src/mqtt.c b/libs/libcurl/src/mqtt.c index 530d929e5e..20b839159b 100644 --- a/libs/libcurl/src/mqtt.c +++ b/libs/libcurl/src/mqtt.c @@ -88,7 +88,7 @@ const struct Curl_handler Curl_handler_mqtt = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_MQTT, /* defport */ @@ -524,8 +524,10 @@ static CURLcode mqtt_publish(struct Curl_easy *data) char encodedbytes[4]; curl_off_t postfieldsize = data->set.postfieldsize; - if(!payload) + if(!payload) { + DEBUGF(infof(data, "mqtt_publish without payload, return bad arg")); return CURLE_BAD_FUNCTION_ARGUMENT; + } if(postfieldsize < 0) payloadlen = strlen(payload); else @@ -622,7 +624,6 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done) struct connectdata *conn = data->conn; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; ssize_t nread; - unsigned char *pkt = (unsigned char *)data->state.buffer; size_t remlen; struct mqtt_conn *mqtt = &conn->proto.mqtt; struct MQTT *mq = data->req.p.mqtt; @@ -671,13 +672,14 @@ MQTT_SUBACK_COMING: data->req.bytecount = 0; data->req.size = remlen; mq->npacket = remlen; /* get this many bytes */ - /* FALLTHROUGH */ + FALLTHROUGH(); case MQTT_PUB_REMAIN: { /* read rest of packet, but no more. Cap to buffer size */ + char buffer[4*1024]; size_t rest = mq->npacket; - if(rest > (size_t)data->set.buffer_size) - rest = (size_t)data->set.buffer_size; - result = Curl_read(data, sockfd, (char *)pkt, rest, &nread); + if(rest > sizeof(buffer)) + rest = sizeof(buffer); + result = Curl_read(data, sockfd, buffer, rest, &nread); if(result) { if(CURLE_AGAIN == result) { infof(data, "EEEE AAAAGAIN"); @@ -690,14 +692,12 @@ MQTT_SUBACK_COMING: goto end; } - mq->npacket -= nread; - /* if QoS is set, message contains packet id */ - - result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)pkt, nread); + result = Curl_client_write(data, CLIENTWRITE_BODY, buffer, nread); if(result) goto end; + mq->npacket -= nread; if(!mq->npacket) /* no more PUBLISH payload, back to subscribe wait state */ mqstate(data, MQTT_FIRST, MQTT_PUBWAIT); @@ -745,7 +745,6 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done) struct MQTT *mq = data->req.p.mqtt; ssize_t nread; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; - unsigned char *pkt = (unsigned char *)data->state.buffer; unsigned char byte; *done = FALSE; @@ -776,14 +775,14 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done) /* remember the first byte */ mq->npacket = 0; mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE); - /* FALLTHROUGH */ + FALLTHROUGH(); case MQTT_REMAINING_LENGTH: do { result = Curl_read(data, sockfd, (char *)&byte, 1, &nread); if(!nread) break; Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1); - pkt[mq->npacket++] = byte; + mq->pkt_hd[mq->npacket++] = byte; } while((byte & 0x80) && (mq->npacket < 4)); if(nread && (byte & 0x80)) /* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 + @@ -791,7 +790,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done) result = CURLE_WEIRD_SERVER_REPLY; if(result) break; - mq->remaining_length = mqtt_decode_len(&pkt[0], mq->npacket, NULL); + mq->remaining_length = mqtt_decode_len(mq->pkt_hd, mq->npacket, NULL); mq->npacket = 0; if(mq->remaining_length) { mqstate(data, mqtt->nextstate, MQTT_NOSTATE); diff --git a/libs/libcurl/src/mqtt.h b/libs/libcurl/src/mqtt.h index bb768268f1..ea81f40448 100644 --- a/libs/libcurl/src/mqtt.h +++ b/libs/libcurl/src/mqtt.h @@ -57,6 +57,7 @@ struct MQTT { unsigned char firstbyte; size_t remaining_length; struct dynbuf recvbuf; + unsigned char pkt_hd[4]; /* for decoding the arriving packet length */ }; #endif /* HEADER_CURL_MQTT_H */ diff --git a/libs/libcurl/src/multi.c b/libs/libcurl/src/multi.c index 8e6f2c739d..1ff096b625 100644 --- a/libs/libcurl/src/multi.c +++ b/libs/libcurl/src/multi.c @@ -672,6 +672,7 @@ static CURLcode multi_done(struct Curl_easy *data, many callbacks and protocols work differently, we could potentially do this more fine-grained in the future. */ premature = TRUE; + FALLTHROUGH(); default: break; } @@ -993,31 +994,92 @@ void Curl_attach_connection(struct Curl_easy *data, Curl_conn_ev_data_attach(conn, data); } -static int domore_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *socks) +static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks) { + struct connectdata *conn = data->conn; + (void)socks; + /* Not using `conn->sockfd` as `Curl_setup_transfer()` initializes + * that *after* the connect. */ + if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) { + /* Default is to wait to something from the server */ + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(0); + } + return GETSOCK_BLANK; +} + +static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks) +{ + struct connectdata *conn = data->conn; + if(conn && conn->handler->proto_getsock) + return conn->handler->proto_getsock(data, conn, socks); + else if(conn && conn->sockfd != CURL_SOCKET_BAD) { + /* Default is to wait to something from the server */ + socks[0] = conn->sockfd; + return GETSOCK_READSOCK(0); + } + return GETSOCK_BLANK; +} + +static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks) +{ + struct connectdata *conn = data->conn; if(conn && conn->handler->domore_getsock) return conn->handler->domore_getsock(data, conn, socks); + else if(conn && conn->sockfd != CURL_SOCKET_BAD) { + /* Default is that we want to send something to the server */ + socks[0] = conn->sockfd; + return GETSOCK_WRITESOCK(0); + } return GETSOCK_BLANK; } -static int doing_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *socks) +static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks) { + struct connectdata *conn = data->conn; if(conn && conn->handler->doing_getsock) return conn->handler->doing_getsock(data, conn, socks); + else if(conn && conn->sockfd != CURL_SOCKET_BAD) { + /* Default is that we want to send something to the server */ + socks[0] = conn->sockfd; + return GETSOCK_WRITESOCK(0); + } return GETSOCK_BLANK; } -static int protocol_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *socks) +static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock) { - if(conn->handler->proto_getsock) - return conn->handler->proto_getsock(data, conn, socks); - return GETSOCK_BLANK; + struct connectdata *conn = data->conn; + + if(!conn) + return GETSOCK_BLANK; + else if(conn->handler->perform_getsock) + return conn->handler->perform_getsock(data, conn, sock); + else { + /* Default is to obey the data->req.keepon flags for send/recv */ + int bitmap = GETSOCK_BLANK; + unsigned sockindex = 0; + if(CURL_WANT_RECV(data)) { + DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD); + bitmap |= GETSOCK_READSOCK(sockindex); + sock[sockindex] = conn->sockfd; + } + + if(CURL_WANT_SEND(data)) { + if((conn->sockfd != conn->writesockfd) || + bitmap == GETSOCK_BLANK) { + /* only if they are not the same socket and we have a readable + one, we increase index */ + if(bitmap != GETSOCK_BLANK) + sockindex++; /* increase index if we need two entries */ + + DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD); + sock[sockindex] = conn->writesockfd; + } + bitmap |= GETSOCK_WRITESOCK(sockindex); + } + return bitmap; + } } /* Initializes `poll_set` with the current socket poll actions needed @@ -1033,45 +1095,61 @@ static void multi_getsock(struct Curl_easy *data, return; switch(data->mstate) { - default: + case MSTATE_INIT: + case MSTATE_PENDING: + case MSTATE_CONNECT: + /* nothing to poll for yet */ break; case MSTATE_RESOLVING: - Curl_pollset_add_socks2(data, ps, Curl_resolv_getsock); + Curl_pollset_add_socks(data, ps, Curl_resolv_getsock); /* connection filters are not involved in this phase */ - return; + break; + + case MSTATE_CONNECTING: + case MSTATE_TUNNELING: + Curl_pollset_add_socks(data, ps, connecting_getsock); + Curl_conn_adjust_pollset(data, ps); + break; - case MSTATE_PROTOCONNECTING: case MSTATE_PROTOCONNECT: + case MSTATE_PROTOCONNECTING: Curl_pollset_add_socks(data, ps, protocol_getsock); + Curl_conn_adjust_pollset(data, ps); break; case MSTATE_DO: case MSTATE_DOING: Curl_pollset_add_socks(data, ps, doing_getsock); - break; - - case MSTATE_TUNNELING: - case MSTATE_CONNECTING: + Curl_conn_adjust_pollset(data, ps); break; case MSTATE_DOING_MORE: Curl_pollset_add_socks(data, ps, domore_getsock); + Curl_conn_adjust_pollset(data, ps); break; - case MSTATE_DID: /* since is set after DO is completed, we switch to - waiting for the same as the PERFORMING state */ + case MSTATE_DID: /* same as PERFORMING in regard to polling */ case MSTATE_PERFORMING: - Curl_pollset_add_socks(data, ps, Curl_single_getsock); + Curl_pollset_add_socks(data, ps, perform_getsock); + Curl_conn_adjust_pollset(data, ps); break; case MSTATE_RATELIMITING: - /* nothing to wait for */ - return; - } + /* we need to let time pass, ignore socket(s) */ + break; + + case MSTATE_DONE: + case MSTATE_COMPLETED: + case MSTATE_MSGSENT: + /* nothing more to poll for */ + break; - /* Let connection filters add/remove as needed */ - Curl_conn_adjust_pollset(data, ps); + default: + failf(data, "multi_getsock: unexpected multi state %d", data->mstate); + DEBUGASSERT(0); + break; + } } CURLMcode curl_multi_fdset(struct Curl_multi *multi, @@ -1942,6 +2020,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } if(!result) { + *nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE); if(async) /* We're now waiting for an asynchronous name lookup */ multistate(data, MSTATE_RESOLVING); @@ -1983,8 +2062,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(dns) { #ifdef CURLRES_ASYNCH - conn->resolve_async.dns = dns; - conn->resolve_async.done = TRUE; + data->state.async.dns = dns; + data->state.async.done = TRUE; #endif result = CURLE_OK; infof(data, "Hostname '%s' was found in DNS cache", hostname); @@ -2371,7 +2450,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, { char *newurl = NULL; bool retry = FALSE; - bool comeback = FALSE; DEBUGASSERT(data->state.buffer); /* check if over send speed */ send_timeout_ms = 0; @@ -2402,7 +2480,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } /* read/write data if it is ready to do so */ - result = Curl_readwrite(data->conn, data, &done, &comeback); + result = Curl_readwrite(data, &done); if(done || (result == CURLE_RECV_ERROR)) { /* If CURLE_RECV_ERROR happens early enough, we assume it was a race @@ -2512,7 +2590,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } } } - else if(comeback) { + else if(data->state.select_bits) { /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer won't get stuck on this transfer at the expense of other concurrent transfers */ @@ -3164,7 +3242,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK)) /* set socket event bitmask if they're not locked */ - data->conn->cselect_bits = (unsigned char)ev_bitmask; + data->state.select_bits = (unsigned char)ev_bitmask; Curl_expire(data, 0, EXPIRE_RUN_NOW); } diff --git a/libs/libcurl/src/noproxy.c b/libs/libcurl/src/noproxy.c index 8517cbf343..db372732f5 100644 --- a/libs/libcurl/src/noproxy.c +++ b/libs/libcurl/src/noproxy.c @@ -216,7 +216,6 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy, /* case C passes through, not a match */ break; case TYPE_IPV4: - /* FALLTHROUGH */ case TYPE_IPV6: { const char *check = token; char *slash; diff --git a/libs/libcurl/src/openldap.c b/libs/libcurl/src/openldap.c index bd5a5f88c8..7452981562 100644 --- a/libs/libcurl/src/openldap.c +++ b/libs/libcurl/src/openldap.c @@ -130,7 +130,7 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ oldap_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_LDAP, /* defport */ @@ -158,7 +158,7 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ oldap_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_LDAPS, /* defport */ @@ -645,7 +645,7 @@ static CURLcode oldap_state_mechs_resp(struct Curl_easy *data, switch(code) { case LDAP_SIZELIMIT_EXCEEDED: infof(data, "Too many authentication mechanisms\n"); - /* FALLTHROUGH */ + FALLTHROUGH(); case LDAP_SUCCESS: case LDAP_NO_RESULTS_RETURNED: if(Curl_sasl_can_authenticate(&li->sasl, data)) @@ -793,10 +793,13 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) result = oldap_perform_bind(data, OLDAP_BIND); break; } - /* FALLTHROUGH */ + result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET); + if(result) + break; + FALLTHROUGH(); case OLDAP_TLS: result = oldap_ssl_connect(data, OLDAP_TLS); - if(result && data->set.use_ssl != CURLUSESSL_TRY) + if(result) result = oldap_map_error(code, CURLE_USE_SSL_FAILED); else if(ssl_installed(conn)) { conn->bits.tls_upgraded = TRUE; @@ -887,10 +890,14 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done) result = oldap_url_parse(data, &lud); if(!result) { - Sockbuf *sb; - /* re-install the libcurl SSL handlers into the sockbuf. */ - ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); - ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); +#ifdef USE_SSL + if(ssl_installed(conn)) { + Sockbuf *sb; + /* re-install the libcurl SSL handlers into the sockbuf. */ + ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); + ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data); + } +#endif rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope, lud->lud_filter, lud->lud_attrs, 0, @@ -1014,7 +1021,7 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf, switch(code) { case LDAP_SIZELIMIT_EXCEEDED: infof(data, "There are more than %d entries", lr->nument); - /* FALLTHROUGH */ + FALLTHROUGH(); case LDAP_SUCCESS: data->req.size = data->req.bytecount; break; diff --git a/libs/libcurl/src/pingpong.c b/libs/libcurl/src/pingpong.c index be892a866d..71116c8a9c 100644 --- a/libs/libcurl/src/pingpong.c +++ b/libs/libcurl/src/pingpong.c @@ -36,6 +36,7 @@ #include "pingpong.h" #include "multiif.h" #include "vtls/vtls.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -105,7 +106,7 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, if(Curl_conn_data_pending(data, FIRSTSOCKET)) rc = 1; - else if(Curl_pp_moredata(pp)) + else if(pp->overflow) /* We are receiving and there is data in the cache so just read it */ rc = 1; else if(!pp->sendleft && Curl_conn_data_pending(data, FIRSTSOCKET)) @@ -139,19 +140,13 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, } /* initialize stuff to prepare for reading a fresh new response */ -void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp) +void Curl_pp_init(struct pingpong *pp) { - DEBUGASSERT(data); pp->nread_resp = 0; - pp->linestart_resp = data->state.buffer; - pp->pending_resp = TRUE; pp->response = Curl_now(); /* start response time-out now! */ -} - -/* setup for the coming transfer */ -void Curl_pp_setup(struct pingpong *pp) -{ + pp->pending_resp = TRUE; Curl_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD); + Curl_dyn_init(&pp->recvbuf, DYN_PINGPPONG_CMD); } /*********************************************************************** @@ -197,9 +192,9 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data, if(result) return result; + pp->pending_resp = TRUE; write_len = Curl_dyn_len(&pp->sendbuf); s = Curl_dyn_ptr(&pp->sendbuf); - Curl_pp_init(data, pp); #ifdef HAVE_GSSAPI conn->data_prot = PROT_CMD; @@ -255,6 +250,25 @@ CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp, return result; } +static CURLcode pingpong_read(struct Curl_easy *data, + curl_socket_t sockfd, + char *buffer, + size_t buflen, + ssize_t *nread) +{ + CURLcode result; +#ifdef HAVE_GSSAPI + enum protection_level prot = data->conn->data_prot; + data->conn->data_prot = PROT_CLEAR; +#endif + result = Curl_read(data, sockfd, buffer, buflen, nread); +#ifdef HAVE_GSSAPI + DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST); + data->conn->data_prot = (unsigned char)prot; +#endif + return result; +} + /* * Curl_pp_readresp() * @@ -266,181 +280,96 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data, int *code, /* return the server code if done */ size_t *size) /* size of the response */ { - ssize_t perline; /* count bytes per line */ - bool keepon = TRUE; - ssize_t gotbytes; - char *ptr; struct connectdata *conn = data->conn; - char * const buf = data->state.buffer; CURLcode result = CURLE_OK; *code = 0; /* 0 for errors or not done */ *size = 0; - ptr = buf + pp->nread_resp; + if(pp->nfinal) { + /* a previous call left this many bytes in the beginning of the buffer as + that was the final line; now ditch that */ + size_t full = Curl_dyn_len(&pp->recvbuf); - /* number of bytes in the current line, so far */ - perline = (ssize_t)(ptr-pp->linestart_resp); + /* trim off the "final" leading part */ + Curl_dyn_tail(&pp->recvbuf, full - pp->nfinal); - while((pp->nread_resp < (size_t)data->set.buffer_size) && - (keepon && !result)) { + pp->nfinal = 0; /* now gone */ + } + if(!pp->overflow) { + ssize_t gotbytes = 0; + char buffer[900]; - if(pp->cache) { - /* we had data in the "cache", copy that instead of doing an actual - * read - * - * pp->cache_size is cast to ssize_t here. This should be safe, because - * it would have been populated with something of size int to begin - * with, even though its datatype may be larger than an int. - */ - if((ptr + pp->cache_size) > (buf + data->set.buffer_size + 1)) { - failf(data, "cached response data too big to handle"); - return CURLE_WEIRD_SERVER_REPLY; - } - memcpy(ptr, pp->cache, pp->cache_size); - gotbytes = (ssize_t)pp->cache_size; - free(pp->cache); /* free the cache */ - pp->cache = NULL; /* clear the pointer */ - pp->cache_size = 0; /* zero the size just in case */ - } - else { -#ifdef HAVE_GSSAPI - enum protection_level prot = conn->data_prot; - conn->data_prot = PROT_CLEAR; -#endif - DEBUGASSERT((ptr + data->set.buffer_size - pp->nread_resp) <= - (buf + data->set.buffer_size + 1)); - result = Curl_read(data, sockfd, ptr, - data->set.buffer_size - pp->nread_resp, - &gotbytes); -#ifdef HAVE_GSSAPI - DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST); - conn->data_prot = (unsigned char)prot; -#endif - if(result == CURLE_AGAIN) - return CURLE_OK; /* return */ + result = pingpong_read(data, sockfd, buffer, sizeof(buffer), &gotbytes); + if(result == CURLE_AGAIN) + return CURLE_OK; - if(result) - /* Set outer result variable to this error. */ - keepon = FALSE; - } + if(result) + return result; - if(!keepon) - ; - else if(gotbytes <= 0) { - keepon = FALSE; - result = CURLE_RECV_ERROR; + if(gotbytes <= 0) { failf(data, "response reading failed (errno: %d)", SOCKERRNO); + return CURLE_RECV_ERROR; } - else { - /* we got a whole chunk of data, which can be anything from one - * byte to a set of lines and possible just a piece of the last - * line */ - ssize_t i; - ssize_t clipamount = 0; - bool restart = FALSE; - - data->req.headerbytecount += (unsigned int)gotbytes; - - pp->nread_resp += gotbytes; - for(i = 0; i < gotbytes; ptr++, i++) { - perline++; - if(*ptr == '\n') { - /* a newline is CRLF in pp-talk, so the CR is ignored as - the line isn't really terminated until the LF comes */ - - /* output debug output if that is requested */ + + result = Curl_dyn_addn(&pp->recvbuf, buffer, gotbytes); + if(result) + return result; + + data->req.headerbytecount += (unsigned int)gotbytes; + + pp->nread_resp += gotbytes; + } + + do { + char *line = Curl_dyn_ptr(&pp->recvbuf); + char *nl = memchr(line, '\n', Curl_dyn_len(&pp->recvbuf)); + if(nl) { + /* a newline is CRLF in pp-talk, so the CR is ignored as + the line isn't really terminated until the LF comes */ + size_t length = nl - line + 1; + + /* output debug output if that is requested */ #ifdef HAVE_GSSAPI - if(!conn->sec_complete) + if(!conn->sec_complete) #endif - Curl_debug(data, CURLINFO_HEADER_IN, - pp->linestart_resp, (size_t)perline); - - /* - * We pass all response-lines to the callback function registered - * for "headers". The response lines can be seen as a kind of - * headers. - */ - result = Curl_client_write(data, CLIENTWRITE_INFO, - pp->linestart_resp, perline); - if(result) - return result; - - if(pp->endofresp(data, conn, pp->linestart_resp, perline, code)) { - /* This is the end of the last line, copy the last line to the - start of the buffer and null-terminate, for old times sake */ - size_t n = ptr - pp->linestart_resp; - memmove(buf, pp->linestart_resp, n); - buf[n] = 0; /* null-terminate */ - keepon = FALSE; - pp->linestart_resp = ptr + 1; /* advance pointer */ - i++; /* skip this before getting out */ - - *size = pp->nread_resp; /* size of the response */ - pp->nread_resp = 0; /* restart */ - break; - } - perline = 0; /* line starts over here */ - pp->linestart_resp = ptr + 1; - } - } + Curl_debug(data, CURLINFO_HEADER_IN, line, length); - if(!keepon && (i != gotbytes)) { - /* We found the end of the response lines, but we didn't parse the - full chunk of data we have read from the server. We therefore need - to store the rest of the data to be checked on the next invoke as - it may actually contain another end of response already! */ - clipamount = gotbytes - i; - restart = TRUE; - DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing " - "server response left", - (int)clipamount)); - } - else if(keepon) { - - if((perline == gotbytes) && - (gotbytes > (ssize_t)data->set.buffer_size/2)) { - /* We got an excessive line without newlines and we need to deal - with it. We keep the first bytes of the line then we throw - away the rest. */ - infof(data, "Excessive server response line length received, " - "%zd bytes. Stripping", gotbytes); - restart = TRUE; - - /* we keep 40 bytes since all our pingpong protocols are only - interested in the first piece */ - clipamount = 40; - } - else if(pp->nread_resp > (size_t)data->set.buffer_size/2) { - /* We got a large chunk of data and there's potentially still - trailing data to take care of, so we put any such part in the - "cache", clear the buffer to make space and restart. */ - clipamount = perline; - restart = TRUE; - } - } - else if(i == gotbytes) - restart = TRUE; - - if(clipamount) { - pp->cache_size = clipamount; - pp->cache = malloc(pp->cache_size); - if(pp->cache) - memcpy(pp->cache, pp->linestart_resp, pp->cache_size); + /* + * Pass all response-lines to the callback function registered for + * "headers". The response lines can be seen as a kind of headers. + */ + result = Curl_client_write(data, CLIENTWRITE_INFO, line, length); + if(result) + return result; + + if(pp->endofresp(data, conn, line, length, code)) { + /* When at "end of response", keep the endofresp line first in the + buffer since it will be accessed outside (by pingpong + parsers). Store the overflow counter to inform about additional + data in this buffer after the endofresp line. */ + pp->nfinal = length; + if(Curl_dyn_len(&pp->recvbuf) > length) + pp->overflow = Curl_dyn_len(&pp->recvbuf) - length; else - return CURLE_OUT_OF_MEMORY; + pp->overflow = 0; + *size = pp->nread_resp; /* size of the response */ + pp->nread_resp = 0; /* restart */ + break; } - if(restart) { - /* now reset a few variables to start over nicely from the start of - the big buffer */ - pp->nread_resp = 0; /* start over from scratch in the buffer */ - ptr = pp->linestart_resp = buf; - perline = 0; - } - - } /* there was data */ + if(Curl_dyn_len(&pp->recvbuf) > length) + /* keep the remaining piece */ + Curl_dyn_tail((&pp->recvbuf), Curl_dyn_len(&pp->recvbuf) - length); + else + Curl_dyn_reset(&pp->recvbuf); + } + else { + /* without a newline, there is no overflow */ + pp->overflow = 0; + break; + } - } /* while there's buffer left and loop is requested */ + } while(1); /* while there's buffer left to scan */ pp->pending_resp = FALSE; @@ -488,14 +417,13 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data, CURLcode Curl_pp_disconnect(struct pingpong *pp) { Curl_dyn_free(&pp->sendbuf); - Curl_safefree(pp->cache); + Curl_dyn_free(&pp->recvbuf); return CURLE_OK; } bool Curl_pp_moredata(struct pingpong *pp) { - return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ? - TRUE : FALSE; + return (!pp->sendleft && Curl_dyn_len(&pp->recvbuf)); } #endif diff --git a/libs/libcurl/src/pingpong.h b/libs/libcurl/src/pingpong.h index ae2dbad325..a74071675c 100644 --- a/libs/libcurl/src/pingpong.h +++ b/libs/libcurl/src/pingpong.h @@ -47,16 +47,11 @@ typedef enum { * It holds response cache and non-blocking sending data. */ struct pingpong { - char *cache; /* data cache between getresponse()-calls */ - size_t cache_size; /* size of cache in bytes */ size_t nread_resp; /* number of bytes currently read of a server response */ - char *linestart_resp; /* line start pointer for the server response - reader function */ bool pending_resp; /* set TRUE when a server response is pending or in progress, and is cleared once the last response is read */ - char *sendthis; /* allocated pointer to a buffer that is to be sent to the - server */ + char *sendthis; /* pointer to a buffer that is to be sent to the server */ size_t sendleft; /* number of bytes left to send from the sendthis buffer */ size_t sendsize; /* total size of the sendthis buffer */ struct curltime response; /* set to Curl_now() when a command has been sent @@ -64,6 +59,10 @@ struct pingpong { timediff_t response_time; /* When no timeout is given, this is the amount of milliseconds we await for a server response. */ struct dynbuf sendbuf; + struct dynbuf recvbuf; + size_t overflow; /* number of bytes left after a final response line */ + size_t nfinal; /* number of bytes in the final response line, which + after a match is first in the receice buffer */ /* Function pointers the protocols MUST implement and provide for the pingpong layer to function */ @@ -90,10 +89,7 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp, bool block, bool disconnecting); /* initialize stuff to prepare for reading a fresh new response */ -void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp); - -/* setup for the transfer */ -void Curl_pp_setup(struct pingpong *pp); +void Curl_pp_init(struct pingpong *pp); /* Returns timeout in ms. 0 or negative number means the timeout has already triggered */ @@ -113,7 +109,7 @@ timediff_t Curl_pp_state_timeout(struct Curl_easy *data, */ CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp, - const char *fmt, ...); + const char *fmt, ...) CURL_PRINTF(3, 4); /*********************************************************************** * @@ -128,7 +124,7 @@ CURLcode Curl_pp_sendf(struct Curl_easy *data, CURLcode Curl_pp_vsendf(struct Curl_easy *data, struct pingpong *pp, const char *fmt, - va_list args); + va_list args) CURL_PRINTF(3, 0); /* * Curl_pp_readresp() diff --git a/libs/libcurl/src/pop3.c b/libs/libcurl/src/pop3.c index b6ad724c10..f31e86fe31 100644 --- a/libs/libcurl/src/pop3.c +++ b/libs/libcurl/src/pop3.c @@ -77,6 +77,7 @@ #include "curl_sasl.h" #include "curl_md5.h" #include "warnless.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -124,7 +125,7 @@ const struct Curl_handler Curl_handler_pop3 = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_POP3, /* defport */ @@ -153,7 +154,7 @@ const struct Curl_handler Curl_handler_pop3s = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_POP3S, /* defport */ @@ -251,8 +252,8 @@ static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn, */ static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out) { - char *message = data->state.buffer; - size_t len = strlen(message); + char *message = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf); + size_t len = data->conn->proto.pop3c.pp.nfinal; if(len > 2) { /* Find the start of the message */ @@ -648,8 +649,8 @@ static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data, CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *line = data->state.buffer; - size_t len = strlen(line); + const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf); + size_t len = data->conn->proto.pop3c.pp.nfinal; (void)instate; /* no use for this yet */ @@ -657,44 +658,35 @@ static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data, failf(data, "Got unexpected pop3-server response"); result = CURLE_WEIRD_SERVER_REPLY; } - else { + else if(len > 3) { /* Does the server support APOP authentication? */ - if(len >= 4 && line[len - 2] == '>') { - /* Look for the APOP timestamp */ - size_t i; - for(i = 3; i < len - 2; ++i) { - if(line[i] == '<') { - /* Calculate the length of the timestamp */ - size_t timestamplen = len - 1 - i; - char *at; - if(!timestamplen) - break; - - /* Allocate some memory for the timestamp */ - pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1); - - if(!pop3c->apoptimestamp) - break; - - /* Copy the timestamp */ - memcpy(pop3c->apoptimestamp, line + i, timestamplen); - pop3c->apoptimestamp[timestamplen] = '\0'; - - /* If the timestamp does not contain '@' it is not (as required by - RFC-1939) conformant to the RFC-822 message id syntax, and we - therefore do not use APOP authentication. */ - at = strchr(pop3c->apoptimestamp, '@'); - if(!at) - Curl_safefree(pop3c->apoptimestamp); - else - /* Store the APOP capability */ - pop3c->authtypes |= POP3_TYPE_APOP; - break; - } + char *lt; + char *gt = NULL; + + /* Look for the APOP timestamp */ + lt = memchr(line, '<', len); + if(lt) + /* search the remainder for '>' */ + gt = memchr(lt, '>', len - (lt - line)); + if(gt) { + /* the length of the timestamp, including the brackets */ + size_t timestamplen = gt - lt + 1; + char *at = memchr(lt, '@', timestamplen); + /* If the timestamp does not contain '@' it is not (as required by + RFC-1939) conformant to the RFC-822 message id syntax, and we + therefore do not use APOP authentication. */ + if(at) { + /* dupe the timestamp */ + pop3c->apoptimestamp = Curl_memdup0(lt, timestamplen); + if(!pop3c->apoptimestamp) + return CURLE_OUT_OF_MEMORY; + /* Store the APOP capability */ + pop3c->authtypes |= POP3_TYPE_APOP; } } - result = pop3_perform_capa(data, conn); + if(!result) + result = pop3_perform_capa(data, conn); } return result; @@ -707,8 +699,8 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code, CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; struct pop3_conn *pop3c = &conn->proto.pop3c; - const char *line = data->state.buffer; - size_t len = strlen(line); + const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf); + size_t len = data->conn->proto.pop3c.pp.nfinal; (void)instate; /* no use for this yet */ @@ -795,7 +787,7 @@ static CURLcode pop3_state_starttls_resp(struct Curl_easy *data, (void)instate; /* no use for this yet */ /* Pipelining in response is forbidden. */ - if(data->conn->proto.pop3c.pp.cache_size) + if(data->conn->proto.pop3c.pp.overflow) return CURLE_WEIRD_SERVER_REPLY; if(pop3code != '+') { @@ -944,24 +936,29 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data, /* POP3 download */ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); - if(pp->cache) { - /* The header "cache" contains a bunch of data that is actually body - content so send it as such. Note that there may even be additional - "headers" after the body */ + if(pp->overflow) { + /* The recv buffer contains data that is actually body content so send + it as such. Note that there may even be additional "headers" after + the body */ + + /* keep only the overflow */ + Curl_dyn_tail(&pp->recvbuf, pp->overflow); + pp->nfinal = 0; /* done */ if(!data->req.no_body) { - result = Curl_pop3_write(data, pp->cache, pp->cache_size); + result = Curl_pop3_write(data, Curl_dyn_ptr(&pp->recvbuf), + Curl_dyn_len(&pp->recvbuf)); if(result) return result; } - /* Free the cache */ - Curl_safefree(pp->cache); - - /* Reset the cache size */ - pp->cache_size = 0; + /* reset the buffer */ + Curl_dyn_reset(&pp->recvbuf); + pp->overflow = 0; } } + else + pp->overflow = 0; /* End of DO phase */ pop3_state(data, POP3_STOP); @@ -1131,8 +1128,7 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done) Curl_sasl_init(&pop3c->sasl, data, &saslpop3); /* Initialise the pingpong layer */ - Curl_pp_setup(pp); - Curl_pp_init(data, pp); + Curl_pp_init(pp); /* Parse the URL options */ result = pop3_parse_url_options(conn); diff --git a/libs/libcurl/src/progress.c b/libs/libcurl/src/progress.c index a151cd2889..f15657155e 100644 --- a/libs/libcurl/src/progress.c +++ b/libs/libcurl/src/progress.c @@ -174,10 +174,18 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer, data->progress.t_startop = timestamp; break; case TIMER_STARTSINGLE: - /* This is set at the start of each single fetch */ + /* This is set at the start of each single transfer */ data->progress.t_startsingle = timestamp; data->progress.is_t_startransfer_set = false; break; + case TIMER_POSTQUEUE: + /* Set when the transfer starts (after potentially having been brought + back from the waiting queue). It needs to count from t_startop and not + t_startsingle since the latter is reset when a connection is brought + back from the pending queue. */ + data->progress.t_postqueue = + Curl_timediff_us(timestamp, data->progress.t_startop); + break; case TIMER_STARTACCEPT: data->progress.t_acceptdata = timestamp; break; diff --git a/libs/libcurl/src/progress.h b/libs/libcurl/src/progress.h index 686e29c7f2..745dc1d5bb 100644 --- a/libs/libcurl/src/progress.h +++ b/libs/libcurl/src/progress.h @@ -30,7 +30,8 @@ typedef enum { TIMER_NONE, TIMER_STARTOP, - TIMER_STARTSINGLE, + TIMER_STARTSINGLE, /* start of transfer, might get queued */ + TIMER_POSTQUEUE, /* start, immediately after dequeue */ TIMER_NAMELOOKUP, TIMER_CONNECT, TIMER_APPCONNECT, diff --git a/libs/libcurl/src/rand.c b/libs/libcurl/src/rand.c index 025f8bdf4f..a0865e25b7 100644 --- a/libs/libcurl/src/rand.c +++ b/libs/libcurl/src/rand.c @@ -201,7 +201,7 @@ CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num) { CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; - DEBUGASSERT(num > 0); + DEBUGASSERT(num); while(num) { unsigned int r; @@ -241,9 +241,11 @@ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, memset(buffer, 0, sizeof(buffer)); #endif - if((num/2 >= sizeof(buffer)) || !(num&1)) + if((num/2 >= sizeof(buffer)) || !(num&1)) { /* make sure it fits in the local buffer and that it is an odd number! */ + DEBUGF(infof(data, "invalid buffer size with Curl_rand_hex")); return CURLE_BAD_FUNCTION_ARGUMENT; + } num--; /* save one for null-termination */ diff --git a/libs/libcurl/src/rtsp.c b/libs/libcurl/src/rtsp.c index 3ad2efb690..17fff38511 100644 --- a/libs/libcurl/src/rtsp.c +++ b/libs/libcurl/src/rtsp.c @@ -58,21 +58,20 @@ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn, curl_socket_t *socks); /* - * Parse and write out any available RTP data. + * Parse and write out an RTSP response. * @param data the transfer * @param conn the connection * @param buf data read from connection * @param blen amount of data in buf - * @param consumed out, number of blen consumed + * @param is_eos TRUE iff this is the last write * @param readmore out, TRUE iff complete buf was consumed and more data * is needed */ -static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, - struct connectdata *conn, - const char *buf, - size_t blen, - size_t *pconsumed, - bool *readmore); +static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, + const char *buf, + size_t blen, + bool is_eos, + bool *done); static CURLcode rtsp_setup_connection(struct Curl_easy *data, struct connectdata *conn); @@ -115,7 +114,7 @@ const struct Curl_handler Curl_handler_rtsp = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtsp_disconnect, /* disconnect */ - rtsp_rtp_readwrite, /* readwrite */ + rtsp_rtp_write_resp, /* write_resp */ rtsp_conncheck, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_RTSP, /* defport */ @@ -590,26 +589,48 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) return result; } +/** + * write any BODY bytes missing to the client, ignore the rest. + */ +static CURLcode rtp_write_body_junk(struct Curl_easy *data, + const char *buf, + size_t blen) +{ + struct rtsp_conn *rtspc = &(data->conn->proto.rtspc); + curl_off_t body_remain; + bool in_body; + + in_body = (data->req.headerline && !rtspc->in_header) && + (data->req.size >= 0) && + (data->req.bytecount < data->req.size); + body_remain = in_body? (data->req.size - data->req.bytecount) : 0; + DEBUGASSERT(body_remain >= 0); + if(body_remain) { + if((curl_off_t)blen > body_remain) + blen = (size_t)body_remain; + return Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen); + } + return CURLE_OK; +} + static CURLcode rtsp_filter_rtp(struct Curl_easy *data, - struct connectdata *conn, const char *buf, size_t blen, - bool in_body, size_t *pconsumed) { - struct rtsp_conn *rtspc = &(conn->proto.rtspc); + struct rtsp_conn *rtspc = &(data->conn->proto.rtspc); CURLcode result = CURLE_OK; + size_t skip_len = 0; *pconsumed = 0; while(blen) { + bool in_body = (data->req.headerline && !rtspc->in_header) && + (data->req.size >= 0) && + (data->req.bytecount < data->req.size); switch(rtspc->state) { case RTP_PARSE_SKIP: { DEBUGASSERT(Curl_dyn_len(&rtspc->buf) == 0); - if(in_body && buf[0] != '$') { - /* in BODY and no valid start, do not consume and return */ - goto out; - } while(blen && buf[0] != '$') { if(!in_body && buf[0] == 'R' && data->set.rtspreq != RTSPREQ_RECEIVE) { @@ -624,13 +645,22 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data, goto out; } } - /* junk, consume without buffering */ + /* junk/BODY, consume without buffering */ *pconsumed += 1; ++buf; --blen; + ++skip_len; } if(blen && buf[0] == '$') { /* possible start of an RTP message, buffer */ + if(skip_len) { + /* end of junk/BODY bytes, flush */ + result = rtp_write_body_junk(data, + (char *)(buf - skip_len), skip_len); + skip_len = 0; + if(result) + goto out; + } if(Curl_dyn_addn(&rtspc->buf, buf, 1)) { result = CURLE_OUT_OF_MEMORY; goto out; @@ -650,35 +680,22 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data, if(!(data->state.rtp_channel_mask[idx] & (1 << off))) { /* invalid channel number, junk or BODY data */ rtspc->state = RTP_PARSE_SKIP; - if(in_body) { - /* we do not consume this byte, it is BODY data */ - DEBUGF(infof(data, "RTSP: invalid RTP channel %d in BODY, " - "treating as BODY data", idx)); - if(*pconsumed == 0) { - /* We did not consume the initial '$' in our buffer, but had - * it from an earlier call. We cannot un-consume it and have - * to write it directly as BODY data */ - result = Curl_client_write(data, CLIENTWRITE_BODY, - Curl_dyn_ptr(&rtspc->buf), 1); - Curl_dyn_free(&rtspc->buf); - if(result) - goto out; - } - else { - /* un-consume the '$' and leave */ - Curl_dyn_free(&rtspc->buf); - *pconsumed -= 1; - --buf; - ++blen; + DEBUGASSERT(skip_len == 0); + /* we do not consume this byte, it is BODY data */ + DEBUGF(infof(data, "RTSP: invalid RTP channel %d, skipping", idx)); + if(*pconsumed == 0) { + /* We did not consume the initial '$' in our buffer, but had + * it from an earlier call. We cannot un-consume it and have + * to write it directly as BODY data */ + result = rtp_write_body_junk(data, Curl_dyn_ptr(&rtspc->buf), 1); + if(result) goto out; - } } else { - /* not BODY, forget the junk '$'. Do not consume this byte, - * it might be a start */ - infof(data, "RTSP: invalid RTP channel %d, skipping", idx); - Curl_dyn_free(&rtspc->buf); + /* count the '$' as skip and continue */ + skip_len = 1; } + Curl_dyn_free(&rtspc->buf); break; } /* a valid channel, so we expect this to be a real RTP message */ @@ -754,52 +771,51 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data, } } out: + if(!result && skip_len) + result = rtp_write_body_junk(data, (char *)(buf - skip_len), skip_len); return result; } -static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, - struct connectdata *conn, - const char *buf, - size_t blen, - size_t *pconsumed, - bool *readmore) +static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, + const char *buf, + size_t blen, + bool is_eos, + bool *done) { - struct rtsp_conn *rtspc = &(conn->proto.rtspc); + struct rtsp_conn *rtspc = &(data->conn->proto.rtspc); CURLcode result = CURLE_OK; size_t consumed = 0; - bool in_body; if(!data->req.header) rtspc->in_header = FALSE; - in_body = (data->req.headerline && !rtspc->in_header) && - (data->req.size >= 0) && - (data->req.bytecount < data->req.size); - - *readmore = FALSE; - *pconsumed = 0; + *done = FALSE; if(!blen) { goto out; } + 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(!rtspc->in_header) { - result = rtsp_filter_rtp(data, conn, buf, blen, in_body, &consumed); + result = rtsp_filter_rtp(data, buf, blen, &consumed); if(result) goto out; - *pconsumed += consumed; buf += consumed; blen -= consumed; + /* either we consumed all or are at the start of header parsing */ + if(blen && !data->req.header) + DEBUGF(infof(data, "RTSP: %zu bytes, possibly excess in response body", + blen)); } /* we want to parse headers, do so */ if(data->req.header && blen) { rtspc->in_header = TRUE; - result = Curl_http_readwrite_headers(data, conn, buf, blen, - &consumed); + result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done); if(result) goto out; - *pconsumed += consumed; buf += consumed; blen -= consumed; @@ -807,26 +823,41 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, rtspc->in_header = FALSE; if(!rtspc->in_header) { - /* If header parsing is done and data left, extract RTP messages */ - in_body = (data->req.headerline && !rtspc->in_header) && - (data->req.size >= 0) && - (data->req.bytecount < data->req.size); - result = rtsp_filter_rtp(data, conn, buf, blen, in_body, &consumed); + /* If header parsing is done, extract interleaved RTP messages */ + if(data->req.size <= -1) { + /* Respect section 4.4 of rfc2326: If the Content-Length header is + absent, a length 0 must be assumed. */ + data->req.size = 0; + data->req.download_done = TRUE; + } + result = rtsp_filter_rtp(data, buf, blen, &consumed); if(result) goto out; - *pconsumed += consumed; + blen -= consumed; } } if(rtspc->state != RTP_PARSE_SKIP) - *readmore = TRUE; + *done = FALSE; + /* we SHOULD have consumed all bytes, unless the response is borked. + * In which case we write out the left over bytes, letting the client + * writer deal with it (it will report EXCESS and fail the transfer). */ + DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, done=%d " + " rtspc->state=%d, req.size=%" CURL_FORMAT_CURL_OFF_T ")", + blen, rtspc->in_header, *done, rtspc->state, data->req.size)); + if(!result && (is_eos || blen)) { + result = Curl_client_write(data, CLIENTWRITE_BODY| + (is_eos? CLIENTWRITE_EOS:0), + (char *)buf, blen); + } out: - if(!*readmore && data->set.rtspreq == RTSPREQ_RECEIVE) { + if((data->set.rtspreq == RTSPREQ_RECEIVE) && + (rtspc->state == RTP_PARSE_SKIP)) { /* In special mode RECEIVE, we just process one chunk of network * data, so we stop the transfer here, if we have no incomplete * RTP message pending. */ - data->req.keepon &= ~KEEP_RECV; + data->req.download_done = TRUE; } return result; } @@ -922,7 +953,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header) /* If the Session ID is set, then compare */ if(strlen(data->set.str[STRING_RTSP_SESSION_ID]) != idlen || - strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen) != 0) { + strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen)) { failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]", start, data->set.str[STRING_RTSP_SESSION_ID]); return CURLE_RTSP_SESSION_ERROR; @@ -934,11 +965,9 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header) */ /* Copy the id substring into a new buffer */ - data->set.str[STRING_RTSP_SESSION_ID] = malloc(idlen + 1); + data->set.str[STRING_RTSP_SESSION_ID] = Curl_memdup0(start, idlen); if(!data->set.str[STRING_RTSP_SESSION_ID]) return CURLE_OUT_OF_MEMORY; - memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, idlen); - (data->set.str[STRING_RTSP_SESSION_ID])[idlen] = '\0'; } } else if(checkprefix("Transport:", header)) { diff --git a/libs/libcurl/src/sendf.c b/libs/libcurl/src/sendf.c index efd1723f17..7686e3c5ad 100644 --- a/libs/libcurl/src/sendf.c +++ b/libs/libcurl/src/sendf.c @@ -296,13 +296,6 @@ static CURLcode chop_write(struct Curl_easy *data, if(!skip_body_write && ((type & CLIENTWRITE_BODY) || ((type & CLIENTWRITE_HEADER) && data->set.include_header))) { -#ifdef USE_WEBSOCKETS - if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) { - writebody = Curl_ws_writecb; - writebody_ptr = data; - } - else -#endif writebody = data->set.fwrite_func; } if((type & (CLIENTWRITE_HEADER|CLIENTWRITE_INFO)) && @@ -345,7 +338,7 @@ static CURLcode chop_write(struct Curl_easy *data, len -= chunklen; } -#ifndef CURL_DISABLE_HTTP +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API) /* HTTP header, but not status-line */ if((conn->handler->protocol & PROTO_FAMILY_HTTP) && (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) { @@ -404,10 +397,12 @@ CURLcode Curl_client_write(struct Curl_easy *data, #endif /* it is one of those, at least */ DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO)); - /* BODY is only BODY */ - DEBUGASSERT(!(type & CLIENTWRITE_BODY) || (type == CLIENTWRITE_BODY)); - /* INFO is only INFO */ - DEBUGASSERT(!(type & CLIENTWRITE_INFO) || (type == CLIENTWRITE_INFO)); + /* BODY is only BODY (with optional EOS) */ + DEBUGASSERT(!(type & CLIENTWRITE_BODY) || + ((type & ~(CLIENTWRITE_BODY|CLIENTWRITE_EOS)) == 0)); + /* INFO is only INFO (with optional EOS) */ + DEBUGASSERT(!(type & CLIENTWRITE_INFO) || + ((type & ~(CLIENTWRITE_INFO|CLIENTWRITE_EOS)) == 0)); if(!data->req.writer_stack) { result = do_init_stack(data); @@ -477,8 +472,6 @@ CURLcode Curl_cwriter_write(struct Curl_easy *data, struct Curl_cwriter *writer, int type, const char *buf, size_t nbytes) { - if(!nbytes) - return CURLE_OK; if(!writer) return CURLE_WRITE_ERROR; return writer->cwt->do_write(data, writer, type, buf, nbytes); @@ -556,7 +549,6 @@ static CURLcode cw_download_write(struct Curl_easy *data, { CURLcode result; size_t nwrite, excess_len = 0; - const char *excess_data = NULL; if(!(type & CLIENTWRITE_BODY)) { if((type & CLIENTWRITE_CONNECT) && data->set.suppress_connect_headers) @@ -564,13 +556,38 @@ static CURLcode cw_download_write(struct Curl_easy *data, return Curl_cwriter_write(data, writer->next, type, buf, nbytes); } + if(!data->req.bytecount) { + Curl_pgrsTime(data, TIMER_STARTTRANSFER); + if(data->req.exp100 > EXP100_SEND_DATA) + /* set time stamp to compare with when waiting for the 100 */ + data->req.start100 = Curl_now(); + } + + /* Here, we deal with REAL BODY bytes. All filtering and transfer + * encodings have been applied and only the true content, e.g. BODY, + * bytes are passed here. + * This allows us to check sizes, update stats, etc. independent + * from the protocol in play. */ + + 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)); + data->req.download_done = TRUE; + return CURLE_WEIRD_SERVER_REPLY; + } + + /* Determine if we see any bytes in excess to what is allowed. + * We write the allowed bytes and handle excess further below. + * This gives deterministic BODY writes on varying buffer receive + * lengths. */ nwrite = nbytes; if(-1 != data->req.maxdownload) { size_t wmax = get_max_body_write_len(data, data->req.maxdownload); if(nwrite > wmax) { excess_len = nbytes - wmax; nwrite = wmax; - excess_data = buf + nwrite; } if(nwrite == wmax) { @@ -578,6 +595,8 @@ static CURLcode cw_download_write(struct Curl_easy *data, } } + /* Error on too large filesize is handled below, after writing + * the permitted bytes */ if(data->set.max_filesize) { size_t wmax = get_max_body_write_len(data, data->set.max_filesize); if(nwrite > wmax) { @@ -585,6 +604,7 @@ static CURLcode cw_download_write(struct Curl_easy *data, } } + /* Update stats, write and report progress */ data->req.bytecount += nwrite; ++data->req.bodywrites; if(!data->req.ignorebody && nwrite) { @@ -597,23 +617,7 @@ static CURLcode cw_download_write(struct Curl_easy *data, return result; if(excess_len) { - if(data->conn->handler->readwrite) { - /* RTSP hack moved from transfer loop to here */ - bool readmore = FALSE; /* indicates data is incomplete, need more */ - size_t consumed = 0; - result = data->conn->handler->readwrite(data, data->conn, - excess_data, excess_len, - &consumed, &readmore); - if(result) - return result; - DEBUGASSERT(consumed <= excess_len); - excess_len -= consumed; - if(readmore) { - data->req.download_done = FALSE; - data->req.keepon |= KEEP_RECV; /* we're not done reading */ - } - } - if(excess_len && !data->req.ignorebody) { + if(!data->req.ignorebody) { infof(data, "Excess found writing body:" " excess = %zu" @@ -762,6 +766,21 @@ CURLcode Curl_cwriter_add(struct Curl_easy *data, return CURLE_OK; } +void Curl_cwriter_remove_by_name(struct Curl_easy *data, + const char *name) +{ + struct Curl_cwriter **anchor = &data->req.writer_stack; + + while(*anchor) { + if(!strcmp(name, (*anchor)->cwt->name)) { + struct Curl_cwriter *w = (*anchor); + *anchor = w->next; + Curl_cwriter_free(data, w); + continue; + } + anchor = &((*anchor)->next); + } +} /* * Internal read-from-socket function. This is meant to deal with plain diff --git a/libs/libcurl/src/sendf.h b/libs/libcurl/src/sendf.h index a871b8d098..abe91eabe7 100644 --- a/libs/libcurl/src/sendf.h +++ b/libs/libcurl/src/sendf.h @@ -49,6 +49,7 @@ #define CLIENTWRITE_CONNECT (1<<4) /* a CONNECT related HEADER */ #define CLIENTWRITE_1XX (1<<5) /* a 1xx response related HEADER */ #define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */ +#define CLIENTWRITE_EOS (1<<7) /* End Of transfer download Stream */ /** * Write `len` bytes at `prt` to the client. `type` indicates what @@ -147,6 +148,9 @@ size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase); CURLcode Curl_cwriter_add(struct Curl_easy *data, struct Curl_cwriter *writer); +void Curl_cwriter_remove_by_name(struct Curl_easy *data, + const char *name); + /** * Convenience method for calling `writer->do_write()` that * checks for NULL writer. diff --git a/libs/libcurl/src/setopt.c b/libs/libcurl/src/setopt.c index 5ad3c9456b..3bbca8be06 100644 --- a/libs/libcurl/src/setopt.c +++ b/libs/libcurl/src/setopt.c @@ -51,7 +51,7 @@ #include "altsvc.h" #include "hsts.h" #include "tftp.h" - +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -366,6 +366,17 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) else return CURLE_BAD_FUNCTION_ARGUMENT; break; + case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS: + /* + * Option that specifies how quickly a server response must be obtained + * before it is considered failure. For pingpong protocols. + */ + arg = va_arg(param, long); + if((arg >= 0) && (arg <= INT_MAX)) + data->set.server_response_timeout = (unsigned int)arg; + else + return CURLE_BAD_FUNCTION_ARGUMENT; + break; #ifndef CURL_DISABLE_TFTP case CURLOPT_TFTP_NO_OPTIONS: /* @@ -497,26 +508,17 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) (data->set.postfieldsize > (curl_off_t)((size_t)-1)))) result = CURLE_OUT_OF_MEMORY; else { - char *p; - - (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); - /* Allocate even when size == 0. This satisfies the need of possible - later address compare to detect the COPYPOSTFIELDS mode, and - to mark that postfields is used rather than read function or - form data. + later address compare to detect the COPYPOSTFIELDS mode, and to + mark that postfields is used rather than read function or form + data. */ - p = malloc((size_t)(data->set.postfieldsize? - data->set.postfieldsize:1)); - + 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 { - if(data->set.postfieldsize) - memcpy(p, argptr, (size_t)data->set.postfieldsize); - + else data->set.str[STRING_COPYPOSTFIELDS] = p; - } } } @@ -670,6 +672,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.opt_no_body = FALSE; /* this is implied */ Curl_mime_cleanpart(data->state.formp); Curl_safefree(data->state.formp); + data->state.mimepost = NULL; break; #endif @@ -977,6 +980,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) #ifndef CURL_DISABLE_FORM_API Curl_mime_cleanpart(data->state.formp); Curl_safefree(data->state.formp); + data->state.mimepost = NULL; #endif } break; @@ -3109,6 +3113,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) return CURLE_OUT_OF_MEMORY; } arg = va_arg(param, long); + if(!arg) { + DEBUGF(infof(data, "bad CURLOPT_ALTSVC_CTRL input")); + return CURLE_BAD_FUNCTION_ARGUMENT; + } result = Curl_altsvc_ctrl(data->asi, arg); if(result) return result; @@ -3163,5 +3171,9 @@ CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...) result = Curl_vsetopt(data, tag, arg); va_end(arg); +#ifdef DEBUGBUILD + if(result == CURLE_BAD_FUNCTION_ARGUMENT) + infof(data, "setopt arg 0x%x returned CURLE_BAD_FUNCTION_ARGUMENT", tag); +#endif return result; } diff --git a/libs/libcurl/src/setup-win32.h b/libs/libcurl/src/setup-win32.h index 2203c46a55..19f5cf154b 100644 --- a/libs/libcurl/src/setup-win32.h +++ b/libs/libcurl/src/setup-win32.h @@ -24,18 +24,53 @@ * ***************************************************************************/ +#undef USE_WINSOCK +/* ---------------------------------------------------------------- */ +/* Watt-32 TCP/IP SPECIFIC */ +/* ---------------------------------------------------------------- */ +#ifdef USE_WATT32 +# include +# undef byte +# undef word +# define HAVE_SYS_IOCTL_H +# define HAVE_SYS_SOCKET_H +# define HAVE_NETINET_IN_H +# define HAVE_NETDB_H +# define HAVE_ARPA_INET_H +# define SOCKET int +/* ---------------------------------------------------------------- */ +/* BSD-style lwIP TCP/IP stack SPECIFIC */ +/* ---------------------------------------------------------------- */ +#elif defined(USE_LWIPSOCK) + /* Define to use BSD-style lwIP TCP/IP stack. */ + /* #define USE_LWIPSOCK 1 */ +# undef HAVE_GETHOSTNAME +# undef LWIP_POSIX_SOCKETS_IO_NAMES +# undef RECV_TYPE_ARG1 +# undef RECV_TYPE_ARG3 +# undef SEND_TYPE_ARG1 +# undef SEND_TYPE_ARG3 +# define HAVE_GETHOSTBYNAME_R +# define HAVE_GETHOSTBYNAME_R_6 +# define LWIP_POSIX_SOCKETS_IO_NAMES 0 +# define RECV_TYPE_ARG1 int +# define RECV_TYPE_ARG3 size_t +# define SEND_TYPE_ARG1 int +# define SEND_TYPE_ARG3 size_t +#elif defined(_WIN32) +# define USE_WINSOCK 2 +#endif + /* * Include header files for windows builds before redefining anything. * Use this preprocessor block only to include or exclude windows.h, * winsock2.h or ws2tcpip.h. Any other windows thing belongs * to any other further and independent block. Under Cygwin things work * just as under linux (e.g. ) and the winsock headers should - * never be included when __CYGWIN__ is defined. configure script takes - * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK2_H, - * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. + * never be included when __CYGWIN__ is defined. */ -#ifdef HAVE_WINDOWS_H +#ifdef _WIN32 # if defined(UNICODE) && !defined(_UNICODE) # error "UNICODE is defined but _UNICODE is not defined" # endif @@ -53,12 +88,8 @@ # ifndef NOGDI # define NOGDI # endif -# ifdef HAVE_WINSOCK2_H -# include -# ifdef HAVE_WS2TCPIP_H -# include -# endif -# endif +# include +# include # include # include # include @@ -67,17 +98,6 @@ # endif #endif -/* - * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else - * undefine USE_WINSOCK. - */ - -#undef USE_WINSOCK - -#ifdef HAVE_WINSOCK2_H -# define USE_WINSOCK 2 -#endif - /* * Define _WIN32_WINNT_[OS] symbols because not all Windows build systems have * those symbols to compare against, and even those that do may be missing diff --git a/libs/libcurl/src/share.c b/libs/libcurl/src/share.c index 5898c713d3..96accead9a 100644 --- a/libs/libcurl/src/share.c +++ b/libs/libcurl/src/share.c @@ -133,13 +133,13 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) res = CURLSHE_BAD_OPTION; } if(!res) - share->specifier |= (1<specifier |= (unsigned int)(1<specifier &= ~(1<specifier &= ~(unsigned int)(1<specifier & (1<specifier & (unsigned int)(1<lockfunc) /* only call this if set! */ share->lockfunc(data, type, accesstype, share->clientdata); } @@ -281,7 +281,7 @@ Curl_share_unlock(struct Curl_easy *data, curl_lock_data type) if(!share) return CURLSHE_INVALID; - if(share->specifier & (1<specifier & (unsigned int)(1<unlockfunc) /* only call this if set! */ share->unlockfunc (data, type, share->clientdata); } diff --git a/libs/libcurl/src/smb.c b/libs/libcurl/src/smb.c index 130382c740..b9a9f5702c 100644 --- a/libs/libcurl/src/smb.c +++ b/libs/libcurl/src/smb.c @@ -272,7 +272,7 @@ const struct Curl_handler Curl_handler_smb = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smb_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_SMB, /* defport */ @@ -299,7 +299,7 @@ const struct Curl_handler Curl_handler_smbs = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smb_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ 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 b6da9ba679..aac4e83c67 100644 --- a/libs/libcurl/src/smtp.c +++ b/libs/libcurl/src/smtp.c @@ -130,7 +130,7 @@ const struct Curl_handler Curl_handler_smtp = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_SMTP, /* defport */ @@ -159,7 +159,7 @@ const struct Curl_handler Curl_handler_smtps = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_SMTPS, /* defport */ @@ -250,8 +250,8 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn, */ static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out) { - char *message = data->state.buffer; - size_t len = strlen(message); + char *message = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf); + size_t len = data->conn->proto.smtpc.pp.nfinal; if(len > 4) { /* Find the start of the message */ @@ -859,7 +859,7 @@ static CURLcode smtp_state_starttls_resp(struct Curl_easy *data, (void)instate; /* no use for this yet */ /* Pipelining in response is forbidden. */ - if(data->conn->proto.smtpc.pp.cache_size) + if(data->conn->proto.smtpc.pp.overflow) return CURLE_WEIRD_SERVER_REPLY; if(smtpcode != 220) { @@ -883,8 +883,8 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data, { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - const char *line = data->state.buffer; - size_t len = strlen(line); + const char *line = Curl_dyn_ptr(&smtpc->pp.recvbuf); + size_t len = smtpc->pp.nfinal; (void)instate; /* no use for this yet */ @@ -1033,8 +1033,8 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode, { CURLcode result = CURLE_OK; struct SMTP *smtp = data->req.p.smtp; - char *line = data->state.buffer; - size_t len = strlen(line); + char *line = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf); + size_t len = data->conn->proto.smtpc.pp.nfinal; (void)instate; /* no use for this yet */ @@ -1044,12 +1044,8 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode, result = CURLE_WEIRD_SERVER_REPLY; } else { - /* Temporarily add the LF character back and send as body to the client */ - if(!data->req.no_body) { - line[len] = '\n'; - result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1); - line[len] = '\0'; - } + if(!data->req.no_body) + result = Curl_client_write(data, CLIENTWRITE_BODY, line, len); if(smtpcode != 1) { if(smtp->rcpt) { @@ -1268,7 +1264,6 @@ static CURLcode smtp_statemachine(struct Curl_easy *data, break; case SMTP_QUIT: - /* fallthrough, just stop! */ default: /* internal error */ smtp_state(data, SMTP_STOP); @@ -1362,8 +1357,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done) Curl_sasl_init(&smtpc->sasl, data, &saslsmtp); /* Initialise the pingpong layer */ - Curl_pp_setup(pp); - Curl_pp_init(data, pp); + Curl_pp_init(pp); /* Parse the URL options */ result = smtp_parse_url_options(conn); @@ -1541,6 +1535,8 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected, static CURLcode smtp_do(struct Curl_easy *data, bool *done) { CURLcode result = CURLE_OK; + DEBUGASSERT(data); + DEBUGASSERT(data->conn); *done = FALSE; /* default to false */ /* Parse the custom request */ diff --git a/libs/libcurl/src/socketpair.c b/libs/libcurl/src/socketpair.c index 9d4020426f..90b51d9017 100644 --- a/libs/libcurl/src/socketpair.c +++ b/libs/libcurl/src/socketpair.c @@ -33,9 +33,6 @@ * This is a socketpair() implementation for Windows. */ #include -#include -#include -#include #include #else #ifdef HAVE_NETDB_H diff --git a/libs/libcurl/src/socks.c b/libs/libcurl/src/socks.c index 2a8f106510..ea733d9e98 100644 --- a/libs/libcurl/src/socks.c +++ b/libs/libcurl/src/socks.c @@ -71,9 +71,18 @@ enum connect_t { CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */ }; +#define CURL_SOCKS_BUF_SIZE 600 + +/* make sure we configure it not too low */ +#if CURL_SOCKS_BUF_SIZE < 600 +#error CURL_SOCKS_BUF_SIZE must be at least 600 +#endif + + struct socks_state { enum connect_t state; ssize_t outstanding; /* send this many bytes more */ + unsigned char buffer[CURL_SOCKS_BUF_SIZE]; unsigned char *outp; /* send from this pointer */ const char *hostname; @@ -249,7 +258,7 @@ static CURLproxycode socks_state_recv(struct Curl_cfilter *cf, failf(data, "connection to proxy closed"); return CURLPX_CLOSED; } - failf(data, "SOCKS4: Failed receiving %s: %s", description, + failf(data, "SOCKS: Failed receiving %s: %s", description, curl_easy_strerror(result)); return failcode; } @@ -278,14 +287,11 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, struct connectdata *conn = cf->conn; const bool protocol4a = (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE; - unsigned char *socksreq = (unsigned char *)data->state.buffer; + unsigned char *socksreq = sx->buffer; CURLcode result; CURLproxycode presult; struct Curl_dns_entry *dns = NULL; - /* make sure that the buffer is at least 600 bytes */ - DEBUGASSERT(READBUFFER_MIN >= 600); - switch(sx->state) { case CONNECT_SOCKS_INIT: /* SOCKS4 can only do IPv4, insist! */ @@ -339,8 +345,8 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, if(dns) { #ifdef CURLRES_ASYNCH - conn->resolve_async.dns = dns; - conn->resolve_async.done = TRUE; + data->state.async.dns = dns; + data->state.async.done = TRUE; #endif infof(data, "Hostname '%s' was found", sx->hostname); sxstate(sx, data, CONNECT_RESOLVED); @@ -353,9 +359,10 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, return CURLPX_OK; } } - /* FALLTHROUGH */ + FALLTHROUGH(); + case CONNECT_RESOLVED: CONNECT_RESOLVED: - case CONNECT_RESOLVED: { + { struct Curl_addrinfo *hp = NULL; /* * We cannot use 'hostent' as a struct that Curl_resolv() returns. It @@ -393,9 +400,9 @@ CONNECT_RESOLVED: if(!hp) return CURLPX_RESOLVE_HOST; } - /* FALLTHROUGH */ -CONNECT_REQ_INIT: + FALLTHROUGH(); case CONNECT_REQ_INIT: +CONNECT_REQ_INIT: /* * This is currently not supporting "Identification Protocol (RFC1413)". */ @@ -430,7 +437,7 @@ CONNECT_REQ_INIT: /* append hostname */ hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */ if((hostnamelen <= 255) && - (packetsize + hostnamelen < data->set.buffer_size)) + (packetsize + hostnamelen < sizeof(sx->buffer))) strcpy((char *)socksreq + packetsize, sx->hostname); else { failf(data, "SOCKS4: too long host name"); @@ -439,10 +446,11 @@ CONNECT_REQ_INIT: packetsize += hostnamelen; } sx->outp = socksreq; + DEBUGASSERT(packetsize <= sizeof(sx->buffer)); sx->outstanding = packetsize; sxstate(sx, data, CONNECT_REQ_SENDING); } - /* FALLTHROUGH */ + FALLTHROUGH(); case CONNECT_REQ_SENDING: /* Send request */ presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, @@ -458,7 +466,7 @@ CONNECT_REQ_INIT: sx->outp = socksreq; sxstate(sx, data, CONNECT_SOCKS_READ); - /* FALLTHROUGH */ + FALLTHROUGH(); case CONNECT_SOCKS_READ: /* Receive response */ presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, @@ -570,14 +578,14 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, o X'00' succeeded */ struct connectdata *conn = cf->conn; - unsigned char *socksreq = (unsigned char *)data->state.buffer; - int idx; + unsigned char *socksreq = sx->buffer; + size_t idx; CURLcode result; CURLproxycode presult; bool socks5_resolve_local = (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; const size_t hostname_len = strlen(sx->hostname); - ssize_t len = 0; + size_t len = 0; const unsigned char auth = data->set.socks5auth; bool allow_gssapi = FALSE; struct Curl_dns_entry *dns = NULL; @@ -620,6 +628,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, socksreq[1] = (unsigned char) (idx - 2); sx->outp = socksreq; + DEBUGASSERT(idx <= sizeof(sx->buffer)); sx->outstanding = idx; presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, "initial SOCKS5 request"); @@ -640,12 +649,12 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, /* remain in sending state */ return CURLPX_OK; } - /* FALLTHROUGH */ -CONNECT_SOCKS_READ_INIT: + FALLTHROUGH(); case CONNECT_SOCKS_READ_INIT: +CONNECT_SOCKS_READ_INIT: sx->outstanding = 2; /* expect two bytes */ sx->outp = socksreq; /* store it here */ - /* FALLTHROUGH */ + FALLTHROUGH(); case CONNECT_SOCKS_READ: presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, "initial SOCKS5 response"); @@ -746,10 +755,11 @@ CONNECT_AUTH_INIT: } len += proxy_password_len; sxstate(sx, data, CONNECT_AUTH_SEND); + DEBUGASSERT(len <= sizeof(sx->buffer)); sx->outstanding = len; sx->outp = socksreq; } - /* FALLTHROUGH */ + FALLTHROUGH(); case CONNECT_AUTH_SEND: presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH, "SOCKS5 sub-negotiation request"); @@ -762,7 +772,7 @@ CONNECT_AUTH_INIT: sx->outp = socksreq; sx->outstanding = 2; sxstate(sx, data, CONNECT_AUTH_READ); - /* FALLTHROUGH */ + FALLTHROUGH(); case CONNECT_AUTH_READ: presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH, "SOCKS5 sub-negotiation response"); @@ -781,9 +791,9 @@ CONNECT_AUTH_INIT: /* Everything is good so far, user was authenticated! */ sxstate(sx, data, CONNECT_REQ_INIT); - /* FALLTHROUGH */ -CONNECT_REQ_INIT: + FALLTHROUGH(); case CONNECT_REQ_INIT: +CONNECT_REQ_INIT: if(socks5_resolve_local) { enum resolve_t rc = Curl_resolv(data, sx->hostname, sx->remote_port, TRUE, &dns); @@ -806,8 +816,8 @@ CONNECT_REQ_INIT: if(dns) { #ifdef CURLRES_ASYNCH - conn->resolve_async.dns = dns; - conn->resolve_async.done = TRUE; + data->state.async.dns = dns; + data->state.async.done = TRUE; #endif infof(data, "SOCKS5: hostname '%s' found", sx->hostname); } @@ -820,9 +830,10 @@ CONNECT_REQ_INIT: return CURLPX_OK; } } - /* FALLTHROUGH */ + FALLTHROUGH(); + case CONNECT_RESOLVED: CONNECT_RESOLVED: - case CONNECT_RESOLVED: { + { char dest[MAX_IPADR_LEN]; /* printable address */ struct Curl_addrinfo *hp = NULL; if(dns) @@ -923,10 +934,10 @@ CONNECT_RESOLVE_REMOTE: infof(data, "SOCKS5 connect to %s:%d (remotely resolved)", sx->hostname, sx->remote_port); } - /* FALLTHROUGH */ + FALLTHROUGH(); -CONNECT_REQ_SEND: case CONNECT_REQ_SEND: +CONNECT_REQ_SEND: /* PORT MSB */ socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff); /* PORT LSB */ @@ -939,9 +950,10 @@ CONNECT_REQ_SEND: } #endif sx->outp = socksreq; + DEBUGASSERT(len <= sizeof(sx->buffer)); sx->outstanding = len; sxstate(sx, data, CONNECT_REQ_SENDING); - /* FALLTHROUGH */ + FALLTHROUGH(); case CONNECT_REQ_SENDING: presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST, "SOCKS5 connect request"); @@ -960,7 +972,7 @@ CONNECT_REQ_SEND: sx->outstanding = 10; /* minimum packet size is 10 */ sx->outp = socksreq; sxstate(sx, data, CONNECT_REQ_READ); - /* FALLTHROUGH */ + FALLTHROUGH(); case CONNECT_REQ_READ: presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK, "SOCKS5 connect request ack"); @@ -1038,6 +1050,7 @@ CONNECT_REQ_SEND: /* decrypt_gssapi_blockread already read the whole packet */ #endif if(len > 10) { + DEBUGASSERT(len <= sizeof(sx->buffer)); sx->outstanding = len - 10; /* get the rest */ sx->outp = &socksreq[10]; sxstate(sx, data, CONNECT_REQ_READ_MORE); @@ -1049,7 +1062,7 @@ CONNECT_REQ_SEND: #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) } #endif - /* FALLTHROUGH */ + FALLTHROUGH(); case CONNECT_REQ_READ_MORE: presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS, "SOCKS5 connect request address"); diff --git a/libs/libcurl/src/socks_gssapi.c b/libs/libcurl/src/socks_gssapi.c index 7a4bcf258e..d9dda91aa0 100644 --- a/libs/libcurl/src/socks_gssapi.c +++ b/libs/libcurl/src/socks_gssapi.c @@ -35,6 +35,7 @@ #include "timeval.h" #include "socks.h" #include "warnless.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -139,10 +140,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, /* prepare service name */ if(strchr(serviceptr, '/')) { service.length = serviceptr_length; - service.value = malloc(service.length); + service.value = Curl_memdup(serviceptr, service.length); if(!service.value) return CURLE_OUT_OF_MEMORY; - memcpy(service.value, serviceptr, service.length); gss_major_status = gss_import_name(&gss_minor_status, &service, (gss_OID) GSS_C_NULL_OID, &server); @@ -387,12 +387,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } else { gss_send_token.length = 1; - gss_send_token.value = malloc(1); + gss_send_token.value = Curl_memdup(&gss_enc, 1); if(!gss_send_token.value) { gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_OUT_OF_MEMORY; } - memcpy(gss_send_token.value, &gss_enc, 1); gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0, GSS_C_QOP_DEFAULT, &gss_send_token, diff --git a/libs/libcurl/src/socks_sspi.c b/libs/libcurl/src/socks_sspi.c index c5010a9197..dc14e7e3e7 100644 --- a/libs/libcurl/src/socks_sspi.c +++ b/libs/libcurl/src/socks_sspi.c @@ -331,9 +331,15 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, failf(data, "Failed to determine user name."); return CURLE_COULDNT_CONNECT; } - infof(data, "SOCKS5 server authenticated user %s with GSS-API.", - names.sUserName); - s_pSecFn->FreeContextBuffer(names.sUserName); + else { +#ifndef CURL_DISABLE_VERBOSE_STRINGS + char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName); + infof(data, "SOCKS5 server authenticated user %s with GSS-API.", + (user_utf8 ? user_utf8 : "(unknown)")); + curlx_unicodefree(user_utf8); +#endif + s_pSecFn->FreeContextBuffer(names.sUserName); + } /* Do encryption */ socksreq[0] = 1; /* GSS-API subnegotiation version */ diff --git a/libs/libcurl/src/strdup.c b/libs/libcurl/src/strdup.c index ee341ef27e..f3d8ed3846 100644 --- a/libs/libcurl/src/strdup.c +++ b/libs/libcurl/src/strdup.c @@ -101,21 +101,17 @@ void *Curl_memdup(const void *src, size_t length) /*************************************************************************** * - * Curl_strndup(source, length) + * Curl_memdup0(source, length) * * Copies the 'source' string to a newly allocated buffer (that is returned). - * Copies not more than 'length' bytes (up to a null terminator) then adds a - * null terminator. + * Copies 'length' bytes then adds a null terminator. * * Returns the new pointer or NULL on failure. * ***************************************************************************/ -void *Curl_strndup(const char *src, size_t length) +void *Curl_memdup0(const char *src, size_t length) { - char *buf = memchr(src, '\0', length); - if(buf) - length = buf - src; - buf = malloc(length + 1); + char *buf = malloc(length + 1); if(!buf) return NULL; memcpy(buf, src, length); diff --git a/libs/libcurl/src/strdup.h b/libs/libcurl/src/strdup.h index 7c7862db45..763952cc12 100644 --- a/libs/libcurl/src/strdup.h +++ b/libs/libcurl/src/strdup.h @@ -33,6 +33,6 @@ wchar_t* Curl_wcsdup(const wchar_t* src); #endif void *Curl_memdup(const void *src, size_t buffer_length); void *Curl_saferealloc(void *ptr, size_t size); -void *Curl_strndup(const char *src, size_t length); +void *Curl_memdup0(const char *src, size_t length); #endif /* HEADER_CURL_STRDUP_H */ diff --git a/libs/libcurl/src/strerror.c b/libs/libcurl/src/strerror.c index 57105759d2..8d4abe4198 100644 --- a/libs/libcurl/src/strerror.c +++ b/libs/libcurl/src/strerror.c @@ -319,6 +319,9 @@ curl_easy_strerror(CURLcode error) case CURLE_UNRECOVERABLE_POLL: return "Unrecoverable error in select/poll"; + case CURLE_TOO_LARGE: + return "A value or data field grew larger than allowed"; + /* error codes not used by current libcurl */ case CURLE_OBSOLETE20: case CURLE_OBSOLETE24: @@ -553,6 +556,9 @@ curl_url_strerror(CURLUcode error) case CURLUE_LACKS_IDN: return "libcurl lacks IDN support"; + case CURLUE_TOO_LARGE: + return "A value or data field is larger than allowed"; + case CURLUE_LAST: break; } @@ -572,10 +578,11 @@ curl_url_strerror(CURLUcode error) * Returns NULL if no error message was found for error code. */ static const char * -get_winsock_error (int err, char *buf, size_t len) +get_winsock_error(int err, char *buf, size_t len) { #ifndef CURL_DISABLE_VERBOSE_STRINGS const char *p; + size_t alen; #endif if(!len) @@ -755,8 +762,9 @@ get_winsock_error (int err, char *buf, size_t len) default: return NULL; } - strncpy(buf, p, len); - buf [len-1] = '\0'; + alen = strlen(p); + if(alen < len) + strcpy(buf, p); return buf; #endif } @@ -832,7 +840,6 @@ const char *Curl_strerror(int err, char *buf, size_t buflen) #endif int old_errno = errno; char *p; - size_t max; if(!buflen) return NULL; @@ -841,23 +848,22 @@ const char *Curl_strerror(int err, char *buf, size_t buflen) DEBUGASSERT(err >= 0); #endif - max = buflen - 1; *buf = '\0'; #if defined(_WIN32) || defined(_WIN32_WCE) #if defined(_WIN32) /* 'sys_nerr' is the maximum errno number, it is not widely portable */ if(err >= 0 && err < sys_nerr) - strncpy(buf, sys_errlist[err], max); + msnprintf(buf, buflen, "%s", sys_errlist[err]); else #endif { if( #ifdef USE_WINSOCK - !get_winsock_error(err, buf, max) && + !get_winsock_error(err, buf, buflen) && #endif - !get_winapi_error((DWORD)err, buf, max)) - msnprintf(buf, max, "Unknown error %d (%#x)", err, err); + !get_winapi_error((DWORD)err, buf, buflen)) + msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err); } #else /* not Windows coming up */ @@ -867,9 +873,9 @@ const char *Curl_strerror(int err, char *buf, size_t buflen) * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated * message string, or EINVAL if 'errnum' is not a valid error number. */ - if(0 != strerror_r(err, buf, max)) { + if(0 != strerror_r(err, buf, buflen)) { if('\0' == buf[0]) - msnprintf(buf, max, "Unknown error %d", err); + msnprintf(buf, buflen, "Unknown error %d", err); } #elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R) /* @@ -881,25 +887,23 @@ const char *Curl_strerror(int err, char *buf, size_t buflen) char buffer[256]; char *msg = strerror_r(err, buffer, sizeof(buffer)); if(msg) - strncpy(buf, msg, max); + msnprintf(buf, buflen, "%s", msg); else - msnprintf(buf, max, "Unknown error %d", err); + msnprintf(buf, buflen, "Unknown error %d", err); } #else { /* !checksrc! disable STRERROR 1 */ const char *msg = strerror(err); if(msg) - strncpy(buf, msg, max); + msnprintf(buf, buflen, "%s", msg); else - msnprintf(buf, max, "Unknown error %d", err); + msnprintf(buf, buflen, "Unknown error %d", err); } #endif #endif /* end of not Windows */ - buf[max] = '\0'; /* make sure the string is null-terminated */ - /* strip trailing '\r\n' or '\n'. */ p = strrchr(buf, '\n'); if(p && (p - buf) >= 2) @@ -943,8 +947,8 @@ const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen) #else { const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error"; - strncpy(buf, txt, buflen); - buf[buflen - 1] = '\0'; + if(strlen(txt) < buflen) + strcpy(buf, txt); } #endif @@ -1081,17 +1085,11 @@ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen) err); } else { - char txtbuf[80]; char msgbuf[256]; - - msnprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err); - if(get_winapi_error(err, msgbuf, sizeof(msgbuf))) - msnprintf(buf, buflen, "%s - %s", txtbuf, msgbuf); - else { - strncpy(buf, txtbuf, buflen); - buf[buflen - 1] = '\0'; - } + msnprintf(buf, buflen, "%s (0x%08X) - %s", txt, err, msgbuf); + else + msnprintf(buf, buflen, "%s (0x%08X)", txt, err); } #else @@ -1099,8 +1097,8 @@ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen) txt = "No error"; else txt = "Error"; - strncpy(buf, txt, buflen); - buf[buflen - 1] = '\0'; + if(buflen > strlen(txt)) + strcpy(buf, txt); #endif if(errno != old_errno) diff --git a/libs/libcurl/src/system_win32.c b/libs/libcurl/src/system_win32.c index 10d7fa9c27..fc20e09f31 100644 --- a/libs/libcurl/src/system_win32.c +++ b/libs/libcurl/src/system_win32.c @@ -38,16 +38,23 @@ LARGE_INTEGER Curl_freq; bool Curl_isVistaOrGreater; +bool Curl_isWindows8OrGreater; /* Handle of iphlpapp.dll */ static HMODULE s_hIpHlpApiDll = NULL; -/* Pointer to the if_nametoindex function */ +/* Function pointers */ IF_NAMETOINDEX_FN Curl_if_nametoindex = NULL; +FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW = NULL; +GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel = NULL; +GETADDRINFOEXW_FN Curl_GetAddrInfoExW = NULL; /* Curl_win32_init() performs win32 global initialization */ CURLcode Curl_win32_init(long flags) { +#ifdef USE_WINSOCK + HMODULE ws2_32Dll; +#endif /* CURL_GLOBAL_WIN32 controls the *optional* part of the initialization which is just for Winsock at the moment. Any required win32 initialization should take place after this block. */ @@ -104,6 +111,18 @@ CURLcode Curl_win32_init(long flags) Curl_if_nametoindex = pIfNameToIndex; } +#ifdef USE_WINSOCK + ws2_32Dll = GetModuleHandleA("ws2_32"); + if(ws2_32Dll) { + Curl_FreeAddrInfoExW = CURLX_FUNCTION_CAST(FREEADDRINFOEXW_FN, + GetProcAddress(ws2_32Dll, "FreeAddrInfoExW")); + Curl_GetAddrInfoExCancel = CURLX_FUNCTION_CAST(GETADDRINFOEXCANCEL_FN, + GetProcAddress(ws2_32Dll, "GetAddrInfoExCancel")); + Curl_GetAddrInfoExW = CURLX_FUNCTION_CAST(GETADDRINFOEXW_FN, + GetProcAddress(ws2_32Dll, "GetAddrInfoExW")); + } +#endif + /* curlx_verify_windows_version must be called during init at least once because it has its own initialization routine. */ if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT, @@ -113,6 +132,13 @@ CURLcode Curl_win32_init(long flags) else Curl_isVistaOrGreater = FALSE; + if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + Curl_isWindows8OrGreater = TRUE; + } + else + Curl_isWindows8OrGreater = FALSE; + QueryPerformanceFrequency(&Curl_freq); return CURLE_OK; } @@ -120,6 +146,9 @@ CURLcode Curl_win32_init(long flags) /* Curl_win32_cleanup() is the opposite of Curl_win32_init() */ void Curl_win32_cleanup(long init_flags) { + Curl_FreeAddrInfoExW = NULL; + Curl_GetAddrInfoExCancel = NULL; + Curl_GetAddrInfoExW = NULL; if(s_hIpHlpApiDll) { FreeLibrary(s_hIpHlpApiDll); s_hIpHlpApiDll = NULL; diff --git a/libs/libcurl/src/system_win32.h b/libs/libcurl/src/system_win32.h index f14ae8e4e5..aaae969f74 100644 --- a/libs/libcurl/src/system_win32.h +++ b/libs/libcurl/src/system_win32.h @@ -26,10 +26,11 @@ #include "curl_setup.h" -#if defined(_WIN32) +#ifdef _WIN32 extern LARGE_INTEGER Curl_freq; extern bool Curl_isVistaOrGreater; +extern bool Curl_isWindows8OrGreater; CURLcode Curl_win32_init(long flags); void Curl_win32_cleanup(long init_flags); @@ -40,6 +41,33 @@ typedef unsigned int(WINAPI *IF_NAMETOINDEX_FN)(const char *); /* This is used instead of if_nametoindex if available on Windows */ extern IF_NAMETOINDEX_FN Curl_if_nametoindex; +/* Identical copy of addrinfoexW/ADDRINFOEXW */ +typedef struct addrinfoexW_ +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + PWSTR ai_canonname; + struct sockaddr *ai_addr; + void *ai_blob; + size_t ai_bloblen; + LPGUID ai_provider; + struct addrinfoexW_ *ai_next; +} ADDRINFOEXW_; + +typedef void (CALLBACK *LOOKUP_COMPLETION_FN)(DWORD, DWORD, LPWSAOVERLAPPED); +typedef void (WSAAPI *FREEADDRINFOEXW_FN)(ADDRINFOEXW_*); +typedef int (WSAAPI *GETADDRINFOEXCANCEL_FN)(LPHANDLE); +typedef int (WSAAPI *GETADDRINFOEXW_FN)(PCWSTR, PCWSTR, DWORD, LPGUID, + const ADDRINFOEXW_*, ADDRINFOEXW_**, struct timeval*, LPOVERLAPPED, + LOOKUP_COMPLETION_FN, LPHANDLE); + +extern FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW; +extern GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel; +extern GETADDRINFOEXW_FN Curl_GetAddrInfoExW; + /* This is used to dynamically load DLLs */ HMODULE Curl_load_library(LPCTSTR filename); #else /* _WIN32 */ diff --git a/libs/libcurl/src/telnet.c b/libs/libcurl/src/telnet.c index 9f2cc0f2fb..f80326b913 100644 --- a/libs/libcurl/src/telnet.c +++ b/libs/libcurl/src/telnet.c @@ -160,6 +160,7 @@ struct TELNET { unsigned short subopt_wsy; /* Set with suboption NAWS */ TelnetReceive telrcv_state; struct curl_slist *telnet_vars; /* Environment variables */ + struct dynbuf out; /* output buffer */ /* suboptions */ unsigned char subbuffer[SUBBUFSIZE]; @@ -185,7 +186,7 @@ const struct Curl_handler Curl_handler_telnet = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_TELNET, /* defport */ @@ -204,6 +205,7 @@ CURLcode init_telnet(struct Curl_easy *data) if(!tn) return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&tn->out, 0xffff); data->req.p.telnet = tn; /* make us known */ tn->telrcv_state = CURL_TS_DATA; @@ -799,8 +801,10 @@ static CURLcode check_telnet_options(struct Curl_easy *data) was given on the command line */ if(data->state.aptr.user) { char buffer[256]; - if(str_is_nonascii(data->conn->user)) + if(str_is_nonascii(data->conn->user)) { + DEBUGF(infof(data, "set a non ASCII user name in telnet")); return CURLE_BAD_FUNCTION_ARGUMENT; + } msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user); beg = curl_slist_append(tn->telnet_vars, buffer); if(!beg) { @@ -826,23 +830,27 @@ static CURLcode check_telnet_options(struct Curl_easy *data) case 5: /* Terminal type */ if(strncasecompare(option, "TTYPE", 5)) { - strncpy(tn->subopt_ttype, arg, 31); - tn->subopt_ttype[31] = 0; /* String termination */ - tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; + size_t l = strlen(arg); + if(l < sizeof(tn->subopt_ttype)) { + strcpy(tn->subopt_ttype, arg); + tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; + break; + } } - else - result = CURLE_UNKNOWN_OPTION; + result = CURLE_UNKNOWN_OPTION; break; case 8: /* Display variable */ if(strncasecompare(option, "XDISPLOC", 8)) { - strncpy(tn->subopt_xdisploc, arg, 127); - tn->subopt_xdisploc[127] = 0; /* String termination */ - tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; + size_t l = strlen(arg); + if(l < sizeof(tn->subopt_xdisploc)) { + strcpy(tn->subopt_xdisploc, arg); + tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; + break; + } } - else - result = CURLE_UNKNOWN_OPTION; + result = CURLE_UNKNOWN_OPTION; break; case 7: @@ -1223,37 +1231,33 @@ process_iac: static CURLcode send_telnet_data(struct Curl_easy *data, char *buffer, ssize_t nread) { - ssize_t escapes, i, outlen; - unsigned char *outbuf = NULL; + ssize_t i, outlen; + unsigned char *outbuf; CURLcode result = CURLE_OK; - ssize_t bytes_written, total_written; + ssize_t bytes_written, total_written = 0; struct connectdata *conn = data->conn; + struct TELNET *tn = data->req.p.telnet; - /* Determine size of new buffer after escaping */ - escapes = 0; - for(i = 0; i < nread; i++) - if((unsigned char)buffer[i] == CURL_IAC) - escapes++; - outlen = nread + escapes; + DEBUGASSERT(tn); - if(outlen == nread) - outbuf = (unsigned char *)buffer; - else { - ssize_t j; - outbuf = malloc(nread + escapes + 1); - if(!outbuf) - return CURLE_OUT_OF_MEMORY; + if(memchr(buffer, CURL_IAC, nread)) { + /* only use the escape buffer when necessary */ + Curl_dyn_reset(&tn->out); - j = 0; - for(i = 0; i < nread; i++) { - outbuf[j++] = (unsigned char)buffer[i]; - if((unsigned char)buffer[i] == CURL_IAC) - outbuf[j++] = CURL_IAC; + for(i = 0; i < nread && !result; i++) { + result = Curl_dyn_addn(&tn->out, &buffer[i], 1); + if(!result && ((unsigned char)buffer[i] == CURL_IAC)) + /* IAC is FF in hex */ + result = Curl_dyn_addn(&tn->out, "\xff", 1); } - outbuf[j] = '\0'; - } - total_written = 0; + outlen = Curl_dyn_len(&tn->out); + outbuf = Curl_dyn_uptr(&tn->out); + } + else { + outlen = nread; + outbuf = (unsigned char *)buffer; + } while(!result && total_written < outlen) { /* Make sure socket is writable to avoid EWOULDBLOCK condition */ struct pollfd pfd[1]; @@ -1266,19 +1270,13 @@ static CURLcode send_telnet_data(struct Curl_easy *data, break; default: /* write! */ bytes_written = 0; - result = Curl_nwrite(data, FIRSTSOCKET, - outbuf + total_written, - outlen - total_written, - &bytes_written); + result = Curl_nwrite(data, FIRSTSOCKET, outbuf + total_written, + outlen - total_written, &bytes_written); total_written += bytes_written; break; } } - /* Free malloc copy if escaped */ - if(outbuf != (unsigned char *)buffer) - free(outbuf); - return result; } @@ -1294,6 +1292,7 @@ static CURLcode telnet_done(struct Curl_easy *data, curl_slist_free_all(tn->telnet_vars); tn->telnet_vars = NULL; + Curl_dyn_free(&tn->out); return CURLE_OK; } @@ -1321,7 +1320,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) ssize_t nread; struct curltime now; bool keepon = TRUE; - char *buf = data->state.buffer; + char buffer[4*1024]; struct TELNET *tn; *done = TRUE; /* unconditionally */ @@ -1378,7 +1377,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) /* Keep on listening and act on events */ while(keepon) { - const DWORD buf_size = (DWORD)data->set.buffer_size; + const DWORD buf_size = (DWORD)sizeof(buffer); DWORD waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout); switch(waitret) { @@ -1389,7 +1388,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) if(data->set.is_fread_set) { size_t n; /* read from user-supplied method */ - n = data->state.fread_func(buf, 1, buf_size, data->state.in); + n = data->state.fread_func(buffer, 1, buf_size, data->state.in); if(n == CURL_READFUNC_ABORT) { keepon = FALSE; result = CURLE_READ_ERROR; @@ -1417,7 +1416,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) if(!readfile_read) break; - if(!ReadFile(stdin_handle, buf, buf_size, + if(!ReadFile(stdin_handle, buffer, buf_size, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; @@ -1425,7 +1424,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } } - result = send_telnet_data(data, buf, readfile_read); + result = send_telnet_data(data, buffer, readfile_read); if(result) { keepon = FALSE; break; @@ -1436,14 +1435,14 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) case WAIT_OBJECT_0 + 1: { - if(!ReadFile(stdin_handle, buf, buf_size, + if(!ReadFile(stdin_handle, buffer, buf_size, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; break; } - result = send_telnet_data(data, buf, readfile_read); + result = send_telnet_data(data, buffer, readfile_read); if(result) { keepon = FALSE; break; @@ -1465,7 +1464,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } if(events.lNetworkEvents & FD_READ) { /* read data from network */ - result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread); + result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread); /* read would've blocked. Loop again */ if(result == CURLE_AGAIN) break; @@ -1481,7 +1480,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) break; } - result = telrcv(data, (unsigned char *) buf, nread); + result = telrcv(data, (unsigned char *) buffer, nread); if(result) { keepon = FALSE; break; @@ -1542,11 +1541,11 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) case 0: /* timeout */ pfd[0].revents = 0; pfd[1].revents = 0; - /* FALLTHROUGH */ + FALLTHROUGH(); default: /* read! */ if(pfd[0].revents & POLLIN) { /* read data from network */ - result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread); + result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread); /* read would've blocked. Loop again */ if(result == CURLE_AGAIN) break; @@ -1572,7 +1571,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) total_dl += nread; result = Curl_pgrsSetDownloadCounter(data, total_dl); if(!result) - result = telrcv(data, (unsigned char *)buf, nread); + result = telrcv(data, (unsigned char *)buffer, nread); if(result) { keepon = FALSE; break; @@ -1590,12 +1589,12 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) nread = 0; if(poll_cnt == 2) { if(pfd[1].revents & POLLIN) { /* read from in file */ - nread = read(pfd[1].fd, buf, data->set.buffer_size); + nread = read(pfd[1].fd, buffer, sizeof(buffer)); } } else { /* read from user-supplied method */ - nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size, + nread = (int)data->state.fread_func(buffer, 1, sizeof(buffer), data->state.in); if(nread == CURL_READFUNC_ABORT) { keepon = FALSE; @@ -1606,7 +1605,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } if(nread > 0) { - result = send_telnet_data(data, buf, nread); + result = send_telnet_data(data, buffer, nread); if(result) { keepon = FALSE; break; diff --git a/libs/libcurl/src/tftp.c b/libs/libcurl/src/tftp.c index 9f0877cbf2..d655a16de1 100644 --- a/libs/libcurl/src/tftp.c +++ b/libs/libcurl/src/tftp.c @@ -181,7 +181,7 @@ const struct Curl_handler Curl_handler_tftp = { ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ tftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_TFTP, /* defport */ diff --git a/libs/libcurl/src/transfer.c b/libs/libcurl/src/transfer.c index 1fe0bbae06..bdfab6459e 100644 --- a/libs/libcurl/src/transfer.c +++ b/libs/libcurl/src/transfer.c @@ -413,321 +413,148 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) return TRUE; } +/** + * Receive raw response data for the transfer. + * @param data the transfer + * @param buf buffer to keep response data received + * @param blen length of `buf` + * @param eos_reliable if EOS detection in underlying connection is reliable + * @param err error code in case of -1 return + * @return number of bytes read or -1 for error + */ +static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data, + char *buf, size_t blen, + bool eos_reliable, + CURLcode *err) +{ + ssize_t nread; + + DEBUGASSERT(blen > 0); + /* If we are reading BODY data and the connection does NOT handle EOF + * and we know the size of the BODY data, limit the read amount */ + if(!eos_reliable && !data->req.header && data->req.size != -1) { + curl_off_t totalleft = data->req.size - data->req.bytecount; + if(totalleft <= 0) + blen = 0; + else if(totalleft < (curl_off_t)blen) + blen = (size_t)totalleft; + } + + if(!blen) { + /* want nothing - continue as if read nothing. */ + DEBUGF(infof(data, "readwrite_data: we're done")); + *err = CURLE_OK; + return 0; + } + + *err = Curl_read(data, data->conn->sockfd, buf, blen, &nread); + if(*err) + return -1; + DEBUGASSERT(nread >= 0); + *err = CURLE_OK; + return nread; +} + /* * Go ahead and do a read if we have a readable socket or if * the stream was rewound (in which case we have data in a * buffer) - * - * return '*comeback' TRUE if we didn't properly drain the socket so this - * function should get called again without select() or similar in between! */ static CURLcode readwrite_data(struct Curl_easy *data, - struct connectdata *conn, struct SingleRequest *k, - int *didwhat, bool *done, - bool *comeback) + int *didwhat, bool *done) { + struct connectdata *conn = data->conn; CURLcode result = CURLE_OK; char *buf; size_t blen; - size_t consumed; - int maxloops = 100; - curl_off_t max_recv = data->set.max_recv_speed? - data->set.max_recv_speed : CURL_OFF_T_MAX; - bool data_eof_handled = FALSE; + int maxloops = 10; + curl_off_t total_received = 0; + bool is_multiplex = FALSE; DEBUGASSERT(data->state.buffer); *done = FALSE; - *comeback = FALSE; /* This is where we loop until we have read everything there is to read or we get a CURLE_AGAIN */ do { - bool is_empty_data = FALSE; - size_t bytestoread = data->set.buffer_size; - /* For HTTP/2 and HTTP/3, read data without caring about the content - length. This is safe because body in HTTP/2 is always segmented - thanks to its framing layer. Meanwhile, we have to call Curl_read - to ensure that http2_handle_stream_close is called when we read all - incoming bytes for a particular stream. */ - bool is_http3 = Curl_conn_is_http3(data, conn, FIRSTSOCKET); - data_eof_handled = is_http3 || Curl_conn_is_http2(data, conn, FIRSTSOCKET); - - /* Each loop iteration starts with a fresh buffer and handles - * all data read into it. */ + bool is_eos = FALSE; + size_t bytestoread; + ssize_t nread; + + if(!is_multiplex) { + /* Multiplexed connection have inherent handling of EOF and we do not + * have to carefully restrict the amount we try to read. + * Multiplexed changes only in one direction. */ + is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET); + } + buf = data->state.buffer; - blen = 0; - - /* If we are reading BODY data and the connection does NOT handle EOF - * and we know the size of the BODY data, limit the read amount */ - if(!k->header && !data_eof_handled && k->size != -1) { - curl_off_t totalleft = k->size - k->bytecount; - if(totalleft <= 0) - bytestoread = 0; - else if(totalleft < (curl_off_t)bytestoread) - bytestoread = (size_t)totalleft; + bytestoread = data->set.buffer_size; + + /* Observe any imposed speed limit */ + if(bytestoread && data->set.max_recv_speed) { + curl_off_t net_limit = data->set.max_recv_speed - total_received; + if(net_limit <= 0) + break; + if((size_t)net_limit < bytestoread) + bytestoread = (size_t)net_limit; } - if(bytestoread) { - /* receive data from the network! */ - ssize_t nread; /* number of bytes read */ - result = Curl_read(data, conn->sockfd, buf, bytestoread, &nread); + nread = Curl_xfer_recv_resp(data, buf, bytestoread, + is_multiplex, &result); + if(nread < 0) { if(CURLE_AGAIN == result) { result = CURLE_OK; break; /* get out of loop */ } - else if(result) - goto out; - DEBUGASSERT(nread >= 0); - blen = (size_t)nread; - } - else { - /* read nothing but since we wanted nothing we consider this an OK - situation to proceed from */ - DEBUGF(infof(data, "readwrite_data: we're done")); - } - - if(!k->bytecount) { - Curl_pgrsTime(data, TIMER_STARTTRANSFER); - if(k->exp100 > EXP100_SEND_DATA) - /* set time stamp to compare with when waiting for the 100 */ - k->start100 = Curl_now(); + goto out; /* real error */ } + /* We only get a 0-length read on EndOfStream */ + blen = (size_t)nread; + is_eos = (blen == 0); *didwhat |= KEEP_RECV; - /* indicates data of zero size, i.e. empty file */ - is_empty_data = ((blen == 0) && (k->bodywrites == 0)) ? TRUE : FALSE; - - if(0 < blen || is_empty_data) { - /* data->state.buffer is allocated 1 byte larger than - * data->set.buffer_size admits. *wink* */ - /* TODO: we should really not rely on this being 0-terminated, since - * the actual data read might contain 0s. */ - buf[blen] = 0; - } if(!blen) { /* if we receive 0 or less here, either the data transfer is done or the server closed the connection and we bail out from this! */ - if(data_eof_handled) + if(is_multiplex) DEBUGF(infof(data, "nread == 0, stream closed, bailing")); else DEBUGF(infof(data, "nread <= 0, server closed connection, bailing")); - k->keepon = 0; /* stop sending as well */ - if(!is_empty_data) - break; - } - - if(conn->handler->readwrite) { - bool readmore = FALSE; /* indicates data is incomplete, need more */ - consumed = 0; - result = conn->handler->readwrite(data, conn, buf, blen, - &consumed, &readmore); - if(result) - goto out; - if(readmore) - break; - buf += consumed; - blen -= consumed; - if(k->download_done) { - /* We've stopped dealing with input, get out of the do-while loop */ - if(blen > 0) { - infof(data, - "Excess found:" - " excess = %zu" - " url = %s (zero-length body)", - blen, data->state.up.path); - } - - /* we make sure that this socket isn't read more now */ - k->keepon &= ~KEEP_RECV; + if(k->eos_written) { /* already did write this to client, leave */ + k->keepon = 0; /* stop sending as well */ break; } } + total_received += blen; -#ifndef CURL_DISABLE_HTTP - /* Since this is a two-state thing, we check if we are parsing - headers at the moment or not. */ - if(k->header) { - consumed = 0; - result = Curl_http_readwrite_headers(data, conn, buf, blen, &consumed); - if(result) - goto out; - buf += consumed; - blen -= consumed; - - if(conn->handler->readwrite && - (k->maxdownload <= 0 && blen > 0)) { - bool readmore = FALSE; /* indicates data is incomplete, need more */ - consumed = 0; - result = conn->handler->readwrite(data, conn, buf, blen, - &consumed, &readmore); - if(result) - goto out; - if(readmore) - break; - buf += consumed; - blen -= consumed; - } - - if(k->download_done) { - /* We've stopped dealing with input, get out of the do-while loop */ - if(blen > 0) { - infof(data, - "Excess found:" - " excess = %zu" - " url = %s (zero-length body)", - blen, data->state.up.path); - } - - /* we make sure that this socket isn't read more now */ - k->keepon &= ~KEEP_RECV; - break; - } - } -#endif /* CURL_DISABLE_HTTP */ - - - /* This is not an 'else if' since it may be a rest from the header - parsing, where the beginning of the buffer is headers and the end - is non-headers. */ - if(!k->header && (blen > 0 || is_empty_data)) { - - if(data->req.no_body && blen > 0) { - /* data arrives although we want none, bail out */ - streamclose(conn, "ignoring body"); - DEBUGF(infof(data, "did not want a BODY, but seeing %zu bytes", - blen)); - *done = TRUE; - result = CURLE_WEIRD_SERVER_REPLY; - goto out; - } - -#ifndef CURL_DISABLE_HTTP - if(0 == k->bodywrites && !is_empty_data) { - /* These checks are only made the first time we are about to - write a piece of the body */ - if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) { - /* HTTP-only checks */ - result = Curl_http_firstwrite(data, conn, done); - if(result || *done) - goto out; - } - } /* this is the first time we write a body part */ -#endif /* CURL_DISABLE_HTTP */ - -#ifndef CURL_DISABLE_HTTP - if(k->chunk) { - /* - * Here comes a chunked transfer flying and we need to decode this - * properly. While the name says read, this function both reads - * and writes away the data. - */ - CURLcode extra; - CHUNKcode res; - - consumed = 0; - res = Curl_httpchunk_read(data, buf, blen, &consumed, &extra); - - if(CHUNKE_OK < res) { - if(CHUNKE_PASSTHRU_ERROR == res) { - failf(data, "Failed reading the chunked-encoded stream"); - result = extra; - goto out; - } - failf(data, "%s in chunked-encoding", Curl_chunked_strerror(res)); - result = CURLE_RECV_ERROR; - goto out; - } - - buf += consumed; - blen -= consumed; - if(CHUNKE_STOP == res) { - /* we're done reading chunks! */ - k->keepon &= ~KEEP_RECV; /* read no more */ - /* chunks read successfully, download is complete */ - k->download_done = TRUE; - - /* N number of bytes at the end of the str buffer that weren't - written to the client. */ - if(conn->chunk.datasize) { - infof(data, "Leftovers after chunking: % " - CURL_FORMAT_CURL_OFF_T "u bytes", - conn->chunk.datasize); - } - } - /* If it returned OK, we just keep going */ - } -#endif /* CURL_DISABLE_HTTP */ - - max_recv -= blen; - - if(!k->chunk && (blen || k->badheader || is_empty_data)) { - /* If this is chunky transfer, it was already written */ - - if(k->badheader) { - /* we parsed a piece of data wrongly assuming it was a header - and now we output it as body instead */ - size_t headlen = Curl_dyn_len(&data->state.headerb); - - /* Don't let excess data pollute body writes */ - if(k->maxdownload != -1 && (curl_off_t)headlen > k->maxdownload) - headlen = (size_t)k->maxdownload; - - result = Curl_client_write(data, CLIENTWRITE_BODY, - Curl_dyn_ptr(&data->state.headerb), - headlen); - if(result) - goto out; - } - - if(blen) { -#ifndef CURL_DISABLE_POP3 - if(conn->handler->protocol & PROTO_FAMILY_POP3) { - result = k->ignorebody? CURLE_OK : - Curl_pop3_write(data, buf, blen); - } - else -#endif /* CURL_DISABLE_POP3 */ - result = Curl_client_write(data, CLIENTWRITE_BODY, buf, blen); - } - k->badheader = FALSE; /* taken care of now */ - - if(result) - goto out; - } - - if(k->download_done && !is_http3) { - /* HTTP/3 over QUIC should keep reading until QUIC connection - is closed. In contrast to HTTP/2 which can stop reading - from TCP connection, HTTP/3 over QUIC needs ACK from server - to ensure stream closure. It should keep reading. */ - k->keepon &= ~KEEP_RECV; /* we're done reading */ - } - } /* if(!header and data to read) */ + result = Curl_xfer_write_resp(data, buf, blen, is_eos, done); + if(result || *done) + goto out; - if(is_empty_data) { - /* if we received nothing, the server closed the connection and we - are done */ - k->keepon &= ~KEEP_RECV; - k->download_done = TRUE; + /* if we are done, we stop receiving. On multiplexed connections, + * we should read the EOS. Which may arrive as meta data after + * the bytes. Not taking it in might lead to RST of streams. */ + if((!is_multiplex && data->req.download_done) || is_eos) { + data->req.keepon &= ~KEEP_RECV; } - - if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV)) { - /* this is a paused or stopped transfer */ + /* if we are PAUSEd or stopped receiving, leave the loop */ + if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV)) break; - } - } while((max_recv > 0) && data_pending(data) && maxloops--); + } while(maxloops-- && data_pending(data)); - if(maxloops <= 0 || max_recv <= 0) { - /* we mark it as read-again-please */ - data->state.dselect_bits = CURL_CSELECT_IN; - *comeback = TRUE; + if(maxloops <= 0) { + /* did not read until EAGAIN, mark read-again-please */ + data->state.select_bits = CURL_CSELECT_IN; + if((k->keepon & KEEP_SENDBITS) == KEEP_SEND) + data->state.select_bits |= CURL_CSELECT_OUT; } if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && - (conn->bits.close || data_eof_handled)) { + (conn->bits.close || is_multiplex)) { /* When we've read the entire thing and the close bit is set, the server may now close the connection. If there's now any kind of sending going on from our side, we need to stop that immediately. */ @@ -1023,46 +850,41 @@ static int select_bits_paused(struct Curl_easy *data, int select_bits) * of our state machine are handling PAUSED transfers correctly. So, we * do not want to go there. * NOTE: we are only interested in PAUSE, not HOLD. */ - return (((select_bits & CURL_CSELECT_IN) && - (data->req.keepon & KEEP_RECV_PAUSE)) || - ((select_bits & CURL_CSELECT_OUT) && - (data->req.keepon & KEEP_SEND_PAUSE))); + + /* if there is data in a direction not paused, return false */ + if(((select_bits & CURL_CSELECT_IN) && + !(data->req.keepon & KEEP_RECV_PAUSE)) || + ((select_bits & CURL_CSELECT_OUT) && + !(data->req.keepon & KEEP_SEND_PAUSE))) + return FALSE; + + return (data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)); } /* * Curl_readwrite() is the low-level function to be called when data is to * be read and written to/from the connection. - * - * return '*comeback' TRUE if we didn't properly drain the socket so this - * function should get called again without select() or similar in between! */ -CURLcode Curl_readwrite(struct connectdata *conn, - struct Curl_easy *data, - bool *done, - bool *comeback) +CURLcode Curl_readwrite(struct Curl_easy *data, + bool *done) { + struct connectdata *conn = data->conn; struct SingleRequest *k = &data->req; CURLcode result; struct curltime now; int didwhat = 0; int select_bits; - if(data->state.dselect_bits) { - if(select_bits_paused(data, data->state.dselect_bits)) { + 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 * this transfer gets unpaused. */ - DEBUGF(infof(data, "readwrite, dselect_bits, early return on PAUSED")); + DEBUGF(infof(data, "readwrite, select_bits, early return on PAUSED")); result = CURLE_OK; goto out; } - select_bits = data->state.dselect_bits; - data->state.dselect_bits = 0; - } - else if(conn->cselect_bits) { - /* CAVEAT: adding `select_bits_paused()` check here makes test640 hang - * (among others). Which hints at strange state handling in FTP land... */ - select_bits = conn->cselect_bits; - conn->cselect_bits = 0; + select_bits = data->state.select_bits; + data->state.select_bits = 0; } else { curl_socket_t fd_read; @@ -1100,7 +922,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, the stream was rewound (in which case we have data in a buffer) */ if((k->keepon & KEEP_RECV) && (select_bits & CURL_CSELECT_IN)) { - result = readwrite_data(data, conn, k, &didwhat, done, comeback); + result = readwrite_data(data, k, &didwhat, done); if(result || *done) goto out; } @@ -1196,21 +1018,6 @@ CURLcode Curl_readwrite(struct connectdata *conn, result = CURLE_PARTIAL_FILE; goto out; } - if(!(data->req.no_body) && k->chunk && - (conn->chunk.state != CHUNK_STOP)) { - /* - * In chunked mode, return an error if the connection is closed prior to - * the empty (terminating) chunk is read. - * - * The condition above used to check for - * conn->proto.http->chunk.datasize != 0 which is true after reading - * *any* chunk, not just the empty chunk. - * - */ - failf(data, "transfer closed with outstanding read data remaining"); - result = CURLE_PARTIAL_FILE; - goto out; - } if(Curl_pgrsUpdate(data)) { result = CURLE_ABORTED_BY_CALLBACK; goto out; @@ -1225,52 +1032,6 @@ out: return result; } -/* - * Curl_single_getsock() gets called by the multi interface code when the app - * has requested to get the sockets for the current connection. This function - * will then be called once for every connection that the multi interface - * keeps track of. This function will only be called for connections that are - * in the proper state to have this information available. - */ -int Curl_single_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *sock) -{ - int bitmap = GETSOCK_BLANK; - unsigned sockindex = 0; - - if(conn->handler->perform_getsock) - return conn->handler->perform_getsock(data, conn, sock); - - /* don't include HOLD and PAUSE connections */ - if((data->req.keepon & KEEP_RECVBITS) == KEEP_RECV) { - - DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD); - - bitmap |= GETSOCK_READSOCK(sockindex); - sock[sockindex] = conn->sockfd; - } - - /* don't include HOLD and PAUSE connections */ - if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) { - if((conn->sockfd != conn->writesockfd) || - bitmap == GETSOCK_BLANK) { - /* only if they are not the same socket and we have a readable - one, we increase index */ - if(bitmap != GETSOCK_BLANK) - sockindex++; /* increase index if we need two entries */ - - DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD); - - sock[sockindex] = conn->writesockfd; - } - - bitmap |= GETSOCK_WRITESOCK(sockindex); - } - - return bitmap; -} - /* Curl_init_CONNECT() gets called each time the handle switches to CONNECT which means this gets called once for each subsequent redirect etc */ void Curl_init_CONNECT(struct Curl_easy *data) @@ -1917,3 +1678,41 @@ Curl_setup_transfer( } /* if(k->getheader || !data->req.no_body) */ } + +CURLcode Curl_xfer_write_resp(struct Curl_easy *data, + char *buf, size_t blen, + bool is_eos, bool *done) +{ + CURLcode result = CURLE_OK; + + if(data->conn->handler->write_resp) { + /* protocol handlers offering this function take full responsibility + * for writing all received download data to the client. */ + result = data->conn->handler->write_resp(data, buf, blen, is_eos, done); + } + else { + /* No special handling by protocol handler, write all received data + * as BODY to the client. */ + if(blen || is_eos) { + int cwtype = CLIENTWRITE_BODY; + if(is_eos) + cwtype |= CLIENTWRITE_EOS; + +#ifndef CURL_DISABLE_POP3 + if(blen && data->conn->handler->protocol & PROTO_FAMILY_POP3) { + result = data->req.ignorebody? CURLE_OK : + Curl_pop3_write(data, buf, blen); + } + else +#endif /* CURL_DISABLE_POP3 */ + result = Curl_client_write(data, cwtype, buf, blen); + } + } + + if(!result && is_eos) { + /* If we wrote the EOS, we are definitely done */ + data->req.eos_written = TRUE; + data->req.download_done = TRUE; + } + return result; +} diff --git a/libs/libcurl/src/transfer.h b/libs/libcurl/src/transfer.h index 612fca5edd..b269f7a44f 100644 --- a/libs/libcurl/src/transfer.h +++ b/libs/libcurl/src/transfer.h @@ -45,9 +45,7 @@ typedef enum { CURLcode Curl_follow(struct Curl_easy *data, char *newurl, followtype type); -CURLcode Curl_readwrite(struct connectdata *conn, - struct Curl_easy *data, bool *done, - bool *comeback); +CURLcode Curl_readwrite(struct Curl_easy *data, bool *done); int Curl_single_getsock(struct Curl_easy *data, struct connectdata *conn, curl_socket_t *socks); CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, @@ -59,6 +57,23 @@ CURLcode Curl_get_upload_buffer(struct Curl_easy *data); CURLcode Curl_done_sending(struct Curl_easy *data, struct SingleRequest *k); +/** + * Write the transfer raw response bytes, as received from the connection. + * Will handle all passed bytes or return an error. By default, this will + * write the bytes as BODY to the client. Protocols may provide a + * "write_resp" callback in their handler to add specific treatment. E.g. + * HTTP parses response headers and passes them differently to the client. + * @param data the transfer + * @param buf the raw response bytes + * @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, + bool is_eos, bool *done); + /* This sets up a forthcoming transfer */ void Curl_setup_transfer (struct Curl_easy *data, diff --git a/libs/libcurl/src/url.c b/libs/libcurl/src/url.c index 243a603c8b..eab74ab2c0 100644 --- a/libs/libcurl/src/url.c +++ b/libs/libcurl/src/url.c @@ -298,6 +298,10 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_safefree(data->info.contenttype); Curl_safefree(data->info.wouldredirect); + /* this destroys the channel and we cannot use it anymore after this */ + Curl_resolver_cancel(data); + Curl_resolver_cleanup(data->state.async.resolver); + data_priority_cleanup(data); /* No longer a dirty share, if it exists */ @@ -430,11 +434,13 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) /* Set the default CA cert bundle/path detected/specified at build time. * - * If Schannel is the selected SSL backend then these locations are - * ignored. We allow setting CA location for schannel only when explicitly - * specified by the user via CURLOPT_CAINFO / --cacert. + * If Schannel or SecureTransport is the selected SSL backend then these + * locations are ignored. We allow setting CA location for schannel and + * securetransport when explicitly specified by the user via + * CURLOPT_CAINFO / --cacert. */ - if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) { + if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL && + Curl_ssl_backend() != CURLSSLBACKEND_SECURETRANSPORT) { #if defined(CURL_CA_BUNDLE) result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); if(result) @@ -514,6 +520,13 @@ CURLcode Curl_open(struct Curl_easy **curl) data->magic = CURLEASY_MAGIC_NUMBER; + result = Curl_resolver_init(data, &data->state.async.resolver); + if(result) { + DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); + free(data); + return result; + } + result = Curl_init_userdefined(data); if(!result) { Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER); @@ -530,6 +543,7 @@ CURLcode Curl_open(struct Curl_easy **curl) } if(result) { + Curl_resolver_cleanup(data->state.async.resolver); Curl_dyn_free(&data->state.headerb); Curl_freeset(data); free(data); @@ -563,7 +577,6 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn) Curl_conn_cf_discard_all(data, conn, (int)i); } - Curl_resolver_cleanup(conn->resolve_async.resolver); Curl_free_idnconverted_hostname(&conn->host); Curl_free_idnconverted_hostname(&conn->conn_to_host); #ifndef CURL_DISABLE_PROXY @@ -581,9 +594,6 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn) Curl_safefree(conn->sasl_authzid); Curl_safefree(conn->options); Curl_safefree(conn->oauth_bearer); -#ifndef CURL_DISABLE_HTTP - Curl_dyn_free(&conn->trailer); -#endif Curl_safefree(conn->host.rawalloc); /* host name buffer */ Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ Curl_safefree(conn->hostname_resolve); @@ -663,7 +673,6 @@ void Curl_disconnect(struct Curl_easy *data, conn->handler->disconnect(data, conn, dead_connection); conn_shutdown(data); - Curl_resolver_cancel(data); /* detach it again */ Curl_detach_connection(data); @@ -1346,6 +1355,8 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ + conn->sockfd = CURL_SOCKET_BAD; + conn->writesockfd = CURL_SOCKET_BAD; conn->connection_id = -1; /* no ID */ conn->port = -1; /* unknown at this point */ conn->remote_port = -1; /* unknown at this point */ @@ -1680,8 +1691,9 @@ static CURLcode findprotocol(struct Curl_easy *data, /* The protocol was not found in the table, but we don't have to assign it to anything since it is already assigned to a dummy-struct in the create_conn() function when the connectdata struct is allocated. */ - failf(data, "Protocol \"%s\" not supported or disabled in " LIBCURL_NAME, - protostr); + failf(data, "Protocol \"%s\" %s%s", protostr, + p ? "disabled" : "not supported", + data->state.this_is_a_follow ? " (in redirect)":""); return CURLE_UNSUPPORTED_PROTOCOL; } @@ -3739,35 +3751,7 @@ static CURLcode create_conn(struct Curl_easy *data, goto out; } - result = Curl_resolver_init(data, &conn->resolve_async.resolver); - if(result) { - DEBUGF(fprintf(stderr, "Error: resolver_init failed\n")); - goto out; - } - Curl_attach_connection(data, conn); - -#ifdef USE_ARES - result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]); - if(result && result != CURLE_NOT_BUILT_IN) - goto out; - - result = Curl_set_dns_interface(data, - data->set.str[STRING_DNS_INTERFACE]); - if(result && result != CURLE_NOT_BUILT_IN) - goto out; - - result = Curl_set_dns_local_ip4(data, - data->set.str[STRING_DNS_LOCAL_IP4]); - if(result && result != CURLE_NOT_BUILT_IN) - goto out; - - result = Curl_set_dns_local_ip6(data, - data->set.str[STRING_DNS_LOCAL_IP6]); - if(result && result != CURLE_NOT_BUILT_IN) - goto out; -#endif /* USE_ARES */ - result = Curl_conncache_add_conn(data); if(result) goto out; diff --git a/libs/libcurl/src/urlapi.c b/libs/libcurl/src/urlapi.c index 1a94e7f4cf..70b63983f7 100644 --- a/libs/libcurl/src/urlapi.c +++ b/libs/libcurl/src/urlapi.c @@ -126,6 +126,9 @@ static const char *find_host_sep(const char *url) return sep < query ? sep : query; } +/* convert CURLcode to CURLUcode */ +#define cc2cu(x) ((x) == CURLE_TOO_LARGE ? CURLUE_TOO_LARGE : \ + CURLUE_OUT_OF_MEMORY) /* * Decide whether a character in a URL must be escaped. */ @@ -146,6 +149,7 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url, bool left = !query; const unsigned char *iptr; const unsigned char *host_sep = (const unsigned char *) url; + CURLcode result; if(!relative) host_sep = (const unsigned char *) find_host_sep(url); @@ -154,20 +158,19 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url, len; iptr++, len--) { if(iptr < host_sep) { - if(Curl_dyn_addn(o, iptr, 1)) - return CURLUE_OUT_OF_MEMORY; + result = Curl_dyn_addn(o, iptr, 1); + if(result) + return cc2cu(result); continue; } if(*iptr == ' ') { - if(left) { - if(Curl_dyn_addn(o, "%20", 3)) - return CURLUE_OUT_OF_MEMORY; - } - else { - if(Curl_dyn_addn(o, "+", 1)) - return CURLUE_OUT_OF_MEMORY; - } + if(left) + result = Curl_dyn_addn(o, "%20", 3); + else + result = Curl_dyn_addn(o, "+", 1); + if(result) + return cc2cu(result); continue; } @@ -178,13 +181,12 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url, char out[3]={'%'}; out[1] = hexdigits[*iptr>>4]; out[2] = hexdigits[*iptr & 0xf]; - if(Curl_dyn_addn(o, out, 3)) - return CURLUE_OUT_OF_MEMORY; - } - else { - if(Curl_dyn_addn(o, iptr, 1)) - return CURLUE_OUT_OF_MEMORY; + result = Curl_dyn_addn(o, out, 3); } + else + result = Curl_dyn_addn(o, iptr, 1); + if(result) + return cc2cu(result); } return CURLUE_OK; @@ -248,7 +250,7 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen, * * Note that this function destroys the 'base' string. */ -static char *concat_url(char *base, const char *relurl) +static CURLcode concat_url(char *base, const char *relurl, char **newurl) { /*** TRY to append this new path to the old URL @@ -260,6 +262,9 @@ static char *concat_url(char *base, const char *relurl) char *pathsep; bool host_changed = FALSE; const char *useurl = relurl; + CURLcode result = CURLE_OK; + CURLUcode uc; + *newurl = NULL; /* protsep points to the start of the host name */ protsep = strstr(base, "//"); @@ -360,21 +365,27 @@ static char *concat_url(char *base, const char *relurl) Curl_dyn_init(&newest, CURL_MAX_INPUT_LENGTH); /* copy over the root url part */ - if(Curl_dyn_add(&newest, base)) - return NULL; + result = Curl_dyn_add(&newest, base); + if(result) + return result; /* check if we need to append a slash */ if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0])) ; else { - if(Curl_dyn_addn(&newest, "/", 1)) - return NULL; + result = Curl_dyn_addn(&newest, "/", 1); + if(result) + return result; } /* then append the new piece on the right side */ - urlencode_str(&newest, useurl, strlen(useurl), !host_changed, FALSE); + uc = urlencode_str(&newest, useurl, strlen(useurl), !host_changed, + FALSE); + if(uc) + return (uc == CURLUE_TOO_LARGE) ? CURLE_TOO_LARGE : CURLE_OUT_OF_MEMORY; - return Curl_dyn_ptr(&newest); + *newurl = Curl_dyn_ptr(&newest); + return CURLE_OK; } /* scan for byte values <= 31, 127 and sometimes space */ @@ -712,24 +723,30 @@ static int ipv4_normalize(struct dynbuf *host) Curl_dyn_reset(host); result = Curl_dyn_addf(host, "%u.%u.%u.%u", - parts[0] >> 24, (parts[0] >> 16) & 0xff, - (parts[0] >> 8) & 0xff, parts[0] & 0xff); + (unsigned int)(parts[0] >> 24), + (unsigned int)((parts[0] >> 16) & 0xff), + (unsigned int)((parts[0] >> 8) & 0xff), + (unsigned int)(parts[0] & 0xff)); break; case 1: /* a.b -- 8.24 bits */ if((parts[0] > 0xff) || (parts[1] > 0xffffff)) return HOST_NAME; Curl_dyn_reset(host); result = Curl_dyn_addf(host, "%u.%u.%u.%u", - parts[0], (parts[1] >> 16) & 0xff, - (parts[1] >> 8) & 0xff, parts[1] & 0xff); + (unsigned int)(parts[0]), + (unsigned int)((parts[1] >> 16) & 0xff), + (unsigned int)((parts[1] >> 8) & 0xff), + (unsigned int)(parts[1] & 0xff)); break; case 2: /* a.b.c -- 8.8.16 bits */ if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xffff)) return HOST_NAME; Curl_dyn_reset(host); result = Curl_dyn_addf(host, "%u.%u.%u.%u", - parts[0], parts[1], (parts[2] >> 8) & 0xff, - parts[2] & 0xff); + (unsigned int)(parts[0]), + (unsigned int)(parts[1]), + (unsigned int)((parts[2] >> 8) & 0xff), + (unsigned int)(parts[2] & 0xff)); break; case 3: /* a.b.c.d -- 8.8.8.8 bits */ if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff) || @@ -737,7 +754,10 @@ static int ipv4_normalize(struct dynbuf *host) return HOST_NAME; Curl_dyn_reset(host); result = Curl_dyn_addf(host, "%u.%u.%u.%u", - parts[0], parts[1], parts[2], parts[3]); + (unsigned int)(parts[0]), + (unsigned int)(parts[1]), + (unsigned int)(parts[2]), + (unsigned int)(parts[3])); break; } if(result) @@ -766,7 +786,7 @@ static CURLUcode urldecode_host(struct dynbuf *host) result = Curl_dyn_addn(host, decoded, dlen); free(decoded); if(result) - return CURLUE_OUT_OF_MEMORY; + return cc2cu(result); } return CURLUE_OK; @@ -779,22 +799,24 @@ static CURLUcode parse_authority(struct Curl_URL *u, bool has_scheme) { size_t offset; - CURLUcode result; + CURLUcode uc; + CURLcode result; /* * Parse the login details and strip them out of the host name. */ - result = parse_hostname_login(u, auth, authlen, flags, &offset); - if(result) + uc = parse_hostname_login(u, auth, authlen, flags, &offset); + if(uc) goto out; - if(Curl_dyn_addn(host, auth + offset, authlen - offset)) { - result = CURLUE_OUT_OF_MEMORY; + result = Curl_dyn_addn(host, auth + offset, authlen - offset); + if(result) { + uc = cc2cu(result); goto out; } - result = Curl_parse_port(u, host, has_scheme); - if(result) + uc = Curl_parse_port(u, host, has_scheme); + if(uc) goto out; if(!Curl_dyn_len(host)) @@ -804,24 +826,24 @@ static CURLUcode parse_authority(struct Curl_URL *u, case HOST_IPV4: break; case HOST_IPV6: - result = ipv6_parse(u, Curl_dyn_ptr(host), Curl_dyn_len(host)); + uc = ipv6_parse(u, Curl_dyn_ptr(host), Curl_dyn_len(host)); break; case HOST_NAME: - result = urldecode_host(host); - if(!result) - result = hostname_check(u, Curl_dyn_ptr(host), Curl_dyn_len(host)); + uc = urldecode_host(host); + if(!uc) + uc = hostname_check(u, Curl_dyn_ptr(host), Curl_dyn_len(host)); break; case HOST_ERROR: - result = CURLUE_OUT_OF_MEMORY; + uc = CURLUE_OUT_OF_MEMORY; break; case HOST_BAD: default: - result = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */ + uc = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */ break; } out: - return result; + return uc; } CURLUcode Curl_url_set_authority(CURLU *u, const char *authority, @@ -1070,8 +1092,9 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) len = path - ptr; if(len) { - if(Curl_dyn_addn(&host, ptr, len)) { - result = CURLUE_OUT_OF_MEMORY; + CURLcode code = Curl_dyn_addn(&host, ptr, len); + if(code) { + result = cc2cu(code); goto fail; } uncpath = TRUE; @@ -1224,14 +1247,13 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) if(flags & CURLU_URLENCODE) { struct dynbuf enc; Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); - if(urlencode_str(&enc, fragment + 1, fraglen - 1, TRUE, FALSE)) { - result = CURLUE_OUT_OF_MEMORY; + result = urlencode_str(&enc, fragment + 1, fraglen - 1, TRUE, FALSE); + if(result) goto fail; - } u->fragment = Curl_dyn_ptr(&enc); } else { - u->fragment = Curl_strndup(fragment + 1, fraglen - 1); + u->fragment = Curl_memdup0(fragment + 1, fraglen - 1); if(!u->fragment) { result = CURLUE_OUT_OF_MEMORY; goto fail; @@ -1242,7 +1264,6 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) pathlen -= fraglen; } - DEBUGASSERT(pathlen < urllen); query = memchr(path, '?', pathlen); if(query) { size_t qlen = fragment ? (size_t)(fragment - query) : @@ -1253,14 +1274,13 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) struct dynbuf enc; Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); /* skip the leading question mark */ - if(urlencode_str(&enc, query + 1, qlen - 1, TRUE, TRUE)) { - result = CURLUE_OUT_OF_MEMORY; + result = urlencode_str(&enc, query + 1, qlen - 1, TRUE, TRUE); + if(result) goto fail; - } u->query = Curl_dyn_ptr(&enc); } else { - u->query = Curl_strndup(query + 1, qlen - 1); + u->query = Curl_memdup0(query + 1, qlen - 1); if(!u->query) { result = CURLUE_OUT_OF_MEMORY; goto fail; @@ -1280,10 +1300,9 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) if(pathlen && (flags & CURLU_URLENCODE)) { struct dynbuf enc; Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); - if(urlencode_str(&enc, path, pathlen, TRUE, FALSE)) { - result = CURLUE_OUT_OF_MEMORY; + result = urlencode_str(&enc, path, pathlen, TRUE, FALSE); + if(result) goto fail; - } pathlen = Curl_dyn_len(&enc); path = u->path = Curl_dyn_ptr(&enc); } @@ -1294,7 +1313,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) } else { if(!u->path) { - u->path = Curl_strndup(path, pathlen); + u->path = Curl_memdup0(path, pathlen); if(!u->path) { result = CURLUE_OUT_OF_MEMORY; goto fail; @@ -1592,7 +1611,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, if(ptr) { size_t partlen = strlen(ptr); size_t i = 0; - *part = Curl_strndup(ptr, partlen); + *part = Curl_memdup0(ptr, partlen); if(!*part) return CURLUE_OUT_OF_MEMORY; if(plusdecode) { @@ -1619,10 +1638,11 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, } if(urlencode) { struct dynbuf enc; + CURLUcode uc; Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); - if(urlencode_str(&enc, *part, partlen, TRUE, - what == CURLUPART_QUERY)) - return CURLUE_OUT_OF_MEMORY; + uc = urlencode_str(&enc, *part, partlen, TRUE, what == CURLUPART_QUERY); + if(uc) + return uc; free(*part); *part = Curl_dyn_ptr(&enc); } @@ -1807,7 +1827,8 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, * If the existing contents is enough for a URL, allow a relative URL to * replace it. */ - CURLUcode result; + CURLcode result; + CURLUcode uc; char *oldurl; char *redired_url; @@ -1827,14 +1848,14 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, /* apply the relative part to create a new URL * and replace the existing one with it. */ - redired_url = concat_url(oldurl, part); + result = concat_url(oldurl, part, &redired_url); free(oldurl); - if(!redired_url) - return CURLUE_OUT_OF_MEMORY; + if(result) + return cc2cu(result); - result = parseurl_and_replace(redired_url, u, flags); + uc = parseurl_and_replace(redired_url, u, flags); free(redired_url); - return result; + return uc; } default: return CURLUE_UNKNOWN_PART; @@ -1848,7 +1869,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, if(leadingslash && (part[0] != '/')) { CURLcode result = Curl_dyn_addn(&enc, "/", 1); if(result) - return CURLUE_OUT_OF_MEMORY; + return cc2cu(result); } if(urlencode) { const unsigned char *i; @@ -1868,7 +1889,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, equalsencode = FALSE; result = Curl_dyn_addn(&enc, i, 1); if(result) - return CURLUE_OUT_OF_MEMORY; + return cc2cu(result); } else { char out[3]={'%'}; @@ -1876,7 +1897,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, out[2] = hexdigits[*i & 0xf]; result = Curl_dyn_addn(&enc, out, 3); if(result) - return CURLUE_OUT_OF_MEMORY; + return cc2cu(result); } } } @@ -1884,7 +1905,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, char *p; CURLcode result = Curl_dyn_add(&enc, part); if(result) - return CURLUE_OUT_OF_MEMORY; + return cc2cu(result); p = Curl_dyn_ptr(&enc); while(*p) { /* make sure percent encoded are lower case */ diff --git a/libs/libcurl/src/urldata.h b/libs/libcurl/src/urldata.h index b5b6bf866b..b49e87bdd5 100644 --- a/libs/libcurl/src/urldata.h +++ b/libs/libcurl/src/urldata.h @@ -583,7 +583,7 @@ struct hostname { (((data)->req.keepon & KEEP_SENDBITS) == KEEP_SEND) /* transfer receive is not on PAUSE or HOLD */ #define CURL_WANT_RECV(data) \ - (!((data)->req.keepon & (KEEP_RECV_PAUSE|KEEP_RECV_HOLD))) + (((data)->req.keepon & KEEP_RECVBITS) == KEEP_RECV) #if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH) #define USE_CURL_ASYNC @@ -683,7 +683,8 @@ struct SingleRequest { enum expect100 exp100; /* expect 100 continue state */ enum upgrade101 upgr101; /* 101 upgrade state */ - /* Content unencoding stack. See sec 3.5, RFC2616. */ + /* Client Writer stack, handles trasnfer- and content-encodings, protocol + * checks, pausing by client callbacks. */ struct Curl_cwriter *writer_stack; time_t timeofdoc; long bodywrites; @@ -730,11 +731,10 @@ struct SingleRequest { #ifndef CURL_DISABLE_COOKIES unsigned char setcookies; #endif - unsigned char writer_stack_depth; /* Unencoding stack depth. */ BIT(header); /* incoming data has HTTP header */ - BIT(badheader); /* header parsing found sth not a header */ BIT(content_range); /* set TRUE if Content-Range: was found */ BIT(download_done); /* set to TRUE when download is complete */ + BIT(eos_written); /* iff EOS has been written to client */ BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding upload and we're uploading the last chunk */ BIT(ignorebody); /* we read a response-body but we ignore it! */ @@ -816,10 +816,10 @@ struct Curl_handler { bool dead_connection); /* If used, this function gets called from transfer.c:readwrite_data() to - allow the protocol to do extra reads/writes */ - CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn, - const char *buf, size_t blen, - size_t *pconsumed, bool *readmore); + 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, bool *done); /* This function can perform various checks on the connection. See CONNCHECK_* for more information about the checks that can be performed, @@ -898,11 +898,6 @@ struct ldapconninfo; struct connectdata { struct Curl_llist_element bundle_node; /* conncache */ - /* chunk is for HTTP chunked encoding, but is in the general connectdata - struct only because we can do just about any protocol through an HTTP - proxy and an HTTP proxy may in fact respond using chunked encoding */ - struct Curl_chunker chunk; - curl_closesocket_callback fclosesocket; /* function closing the socket(s) */ void *closesocket_client; @@ -921,9 +916,6 @@ struct connectdata { multi_done(). This entry will be NULL if the connection is reused as then there is no name resolve done. */ struct Curl_dns_entry *dns_entry; -#ifdef USE_CURL_ASYNC - struct Curl_async resolve_async; /* asynchronous name resolver data */ -#endif /* 'remote_addr' is the particular IP we connected to. it is owned, set * and NULLed by the connected socket filter (if there is one). */ @@ -1028,11 +1020,6 @@ struct connectdata { struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */ #endif -#ifndef CURL_DISABLE_HTTP - /* for chunked-encoded trailer */ - struct dynbuf trailer; -#endif - union { #ifndef CURL_DISABLE_FTP struct ftp_conn ftpc; @@ -1103,7 +1090,6 @@ struct connectdata { unsigned short localport; unsigned short secondary_port; /* secondary socket remote port to connect to (ftp) */ - unsigned char cselect_bits; /* bitmask of socket events */ unsigned char alpn; /* APLN TLS negotiated protocol, a CURL_HTTP_VERSION* value */ #ifndef CURL_DISABLE_PROXY @@ -1193,6 +1179,7 @@ struct Progress { curl_off_t dlspeed; curl_off_t ulspeed; + timediff_t t_postqueue; timediff_t t_nslookup; timediff_t t_connect; timediff_t t_appconnect; @@ -1382,6 +1369,9 @@ struct UrlState { #endif struct auth authhost; /* auth details for host */ struct auth authproxy; /* auth details for proxy */ +#ifdef USE_CURL_ASYNC + struct Curl_async async; /* asynchronous name resolver data */ +#endif #if defined(USE_OPENSSL) /* void instead of ENGINE to avoid bleeding OpenSSL into this header */ @@ -1479,7 +1469,7 @@ struct UrlState { server involved in this request */ unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any) is this */ - unsigned char dselect_bits; /* != 0 -> bitmask of socket events for this + unsigned char select_bits; /* != 0 -> bitmask of socket events for this transfer overriding anything the socket may report */ #ifdef CURLDEBUG diff --git a/libs/libcurl/src/vauth/digest_sspi.c b/libs/libcurl/src/vauth/digest_sspi.c index 996b83d50e..d61c8386bc 100644 --- a/libs/libcurl/src/vauth/digest_sspi.c +++ b/libs/libcurl/src/vauth/digest_sspi.c @@ -211,8 +211,10 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) infof(data, "schannel: InitializeSecurityContext failed: %s", Curl_sspi_strerror(status, buffer, sizeof(buffer))); +#endif return CURLE_AUTH_ERROR; } @@ -603,8 +605,10 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; +#if !defined(CURL_DISABLE_VERBOSE_STRINGS) infof(data, "schannel: InitializeSecurityContext failed: %s", Curl_sspi_strerror(status, buffer, sizeof(buffer))); +#endif return CURLE_AUTH_ERROR; } diff --git a/libs/libcurl/src/vauth/krb5_gssapi.c b/libs/libcurl/src/vauth/krb5_gssapi.c index 2b7b21534e..655f908300 100644 --- a/libs/libcurl/src/vauth/krb5_gssapi.c +++ b/libs/libcurl/src/vauth/krb5_gssapi.c @@ -226,7 +226,8 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, /* Extract the security layer and the maximum message size */ indata = output_token.value; sec_layer = indata[0]; - max_size = (indata[1] << 16) | (indata[2] << 8) | indata[3]; + max_size = ((unsigned int)indata[1] << 16) | + ((unsigned int)indata[2] << 8) | indata[3]; /* Free the challenge as it is not required anymore */ gss_release_buffer(&unused_status, &output_token); diff --git a/libs/libcurl/src/vauth/krb5_sspi.c b/libs/libcurl/src/vauth/krb5_sspi.c index fe2fdb3732..78999232e3 100644 --- a/libs/libcurl/src/vauth/krb5_sspi.c +++ b/libs/libcurl/src/vauth/krb5_sspi.c @@ -319,7 +319,8 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, /* Extract the security layer and the maximum message size */ indata = input_buf[1].pvBuffer; sec_layer = indata[0]; - max_size = (indata[1] << 16) | (indata[2] << 8) | indata[3]; + max_size = ((unsigned long)indata[1] << 16) | + ((unsigned long)indata[2] << 8) | indata[3]; /* Free the challenge as it is not required anymore */ s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); diff --git a/libs/libcurl/src/vauth/ntlm.c b/libs/libcurl/src/vauth/ntlm.c index 0cdf1a159f..a434497d42 100644 --- a/libs/libcurl/src/vauth/ntlm.c +++ b/libs/libcurl/src/vauth/ntlm.c @@ -44,6 +44,7 @@ #include "warnless.h" #include "rand.h" #include "vtls/vtls.h" +#include "strdup.h" #define BUILDING_CURL_NTLM_MSGS_C #include "vauth/vauth.h" @@ -184,11 +185,10 @@ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data, } free(ntlm->target_info); /* replace any previous data */ - ntlm->target_info = malloc(target_info_len); + ntlm->target_info = Curl_memdup(&type2[target_info_offset], + target_info_len); if(!ntlm->target_info) return CURLE_OUT_OF_MEMORY; - - memcpy(ntlm->target_info, &type2[target_info_offset], target_info_len); } } diff --git a/libs/libcurl/src/vauth/ntlm_sspi.c b/libs/libcurl/src/vauth/ntlm_sspi.c index b2cf248181..f8c3558603 100644 --- a/libs/libcurl/src/vauth/ntlm_sspi.c +++ b/libs/libcurl/src/vauth/ntlm_sspi.c @@ -34,6 +34,7 @@ #include "warnless.h" #include "curl_multibyte.h" #include "sendf.h" +#include "strdup.h" /* The last #include files should be: */ #include "curl_memory.h" @@ -213,11 +214,10 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, } /* Store the challenge for later use */ - ntlm->input_token = malloc(Curl_bufref_len(type2) + 1); + ntlm->input_token = Curl_memdup0((const char *)Curl_bufref_ptr(type2), + Curl_bufref_len(type2)); if(!ntlm->input_token) return CURLE_OUT_OF_MEMORY; - memcpy(ntlm->input_token, Curl_bufref_ptr(type2), Curl_bufref_len(type2)); - ntlm->input_token[Curl_bufref_len(type2)] = '\0'; ntlm->input_token_len = Curl_bufref_len(type2); return CURLE_OK; @@ -314,7 +314,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, &type_3_desc, &attrs, &expiry); if(status != SEC_E_OK) { - infof(data, "NTLM handshake failure (type-3 message): Status=%x", + infof(data, "NTLM handshake failure (type-3 message): Status=%lx", status); if(status == SEC_E_INSUFFICIENT_MEMORY) diff --git a/libs/libcurl/src/version.c b/libs/libcurl/src/version.c index 86c8aff13b..b98c831177 100644 --- a/libs/libcurl/src/version.c +++ b/libs/libcurl/src/version.c @@ -211,8 +211,12 @@ char *curl_version(void) #endif #ifdef USE_LIBPSL - msnprintf(psl_version, sizeof(psl_version), "libpsl/%s", psl_get_version()); - src[i++] = psl_version; + { + int num = psl_check_version_number(0); + msnprintf(psl_version, sizeof(psl_version), "libpsl/%d.%d.%d", + num >> 16, (num >> 8) & 0xff, num & 0xff); + src[i++] = psl_version; + } #endif #ifdef USE_SSH diff --git a/libs/libcurl/src/vquic/curl_msh3.c b/libs/libcurl/src/vquic/curl_msh3.c index bf8220470c..9835ccc5e1 100644 --- a/libs/libcurl/src/vquic/curl_msh3.c +++ b/libs/libcurl/src/vquic/curl_msh3.c @@ -204,8 +204,8 @@ static void drain_stream_from_other_thread(struct Curl_easy *data, bits = CURL_CSELECT_IN; if(stream && !stream->upload_done) bits |= CURL_CSELECT_OUT; - if(data->state.dselect_bits != bits) { - data->state.dselect_bits = bits; + if(data->state.select_bits != bits) { + data->state.select_bits = bits; /* cannot expire from other thread */ } } @@ -220,8 +220,8 @@ static void drain_stream(struct Curl_cfilter *cf, bits = CURL_CSELECT_IN; if(stream && !stream->upload_done) bits |= CURL_CSELECT_OUT; - if(data->state.dselect_bits != bits) { - data->state.dselect_bits = bits; + if(data->state.select_bits != bits) { + data->state.select_bits = bits; Curl_expire(data, 0, EXPIRE_RUN_NOW); } } diff --git a/libs/libcurl/src/vquic/curl_ngtcp2.c b/libs/libcurl/src/vquic/curl_ngtcp2.c index 9584065f5a..d004c9d27f 100644 --- a/libs/libcurl/src/vquic/curl_ngtcp2.c +++ b/libs/libcurl/src/vquic/curl_ngtcp2.c @@ -41,7 +41,6 @@ #include "vtls/gtls.h" #elif defined(USE_WOLFSSL) #include -#include "vtls/wolfssl.h" #endif #include "urldata.h" @@ -61,6 +60,7 @@ #include "inet_pton.h" #include "vquic.h" #include "vquic_int.h" +#include "vquic-tls.h" #include "vtls/keylog.h" #include "vtls/vtls.h" #include "curl_ngtcp2.h" @@ -73,9 +73,6 @@ #include "memdebug.h" -#define H3_ALPN_H3_29 "\x5h3-29" -#define H3_ALPN_H3 "\x2h3" - #define QUIC_MAX_STREAMS (256*1024) #define QUIC_MAX_DATA (1*1024*1024) #define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS) @@ -101,25 +98,6 @@ (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) -#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) -#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 - - /* * Store ngtcp2 version info in this buffer. */ @@ -134,6 +112,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; ngtcp2_path connected_path; ngtcp2_conn *qconn; ngtcp2_cid dcid; @@ -143,30 +122,16 @@ struct cf_ngtcp2_ctx { ngtcp2_transport_params transport_params; ngtcp2_ccerr last_error; ngtcp2_crypto_conn_ref conn_ref; -#ifdef USE_OPENSSL - SSL_CTX *sslctx; - SSL *ssl; -#elif defined(USE_GNUTLS) - struct gtls_instance *gtls; -#elif defined(USE_WOLFSSL) - WOLFSSL_CTX *sslctx; - WOLFSSL *ssl; -#endif struct cf_call_data call_data; nghttp3_conn *h3conn; nghttp3_settings h3settings; struct curltime started_at; /* time the current attempt started */ struct curltime handshake_at; /* time connect handshake finished */ - 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 */ size_t max_stream_window; /* max flow window for one stream */ uint64_t max_idle_ms; /* max idle time for QUIC connection */ int qlogfd; - BIT(got_first_byte); /* if first byte was received */ -#ifdef USE_OPENSSL - BIT(x509_store_setup); /* if x509 store has been set up */ -#endif }; /* How to access `call_data` from a cf_ngtcp2 filter */ @@ -292,8 +257,8 @@ static void h3_drain_stream(struct Curl_cfilter *cf, bits = CURL_CSELECT_IN; if(stream && stream->upload_left && !stream->send_closed) bits |= CURL_CSELECT_OUT; - if(data->state.dselect_bits != bits) { - data->state.dselect_bits = bits; + if(data->state.select_bits != bits) { + data->state.select_bits = bits; Curl_expire(data, 0, EXPIRE_RUN_NOW); } } @@ -413,388 +378,8 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx, } } -#ifdef USE_OPENSSL -static void keylog_callback(const SSL *ssl, const char *line) -{ - (void)ssl; - Curl_tls_keylog_write_line(line); -} -#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; -} -#elif defined(USE_WOLFSSL) -#if defined(HAVE_SECRET_CALLBACK) -static void keylog_callback(const WOLFSSL *ssl, const char *line) -{ - (void)ssl; - Curl_tls_keylog_write_line(line); -} -#endif -#endif - static int init_ngh3_conn(struct Curl_cfilter *cf); -#ifdef USE_OPENSSL -static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx, - struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct ssl_primary_config *conn_config; - CURLcode result = CURLE_FAILED_INIT; - - SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); - if(!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 defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) - if(ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) { - failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed"); - goto out; - } -#else - if(ngtcp2_crypto_quictls_configure_client_context(ssl_ctx) != 0) { - failf(data, "ngtcp2_crypto_quictls_configure_client_context failed"); - goto out; - } -#endif - - SSL_CTX_set_default_verify_paths(ssl_ctx); - - { - const char *curves = conn_config->curves ? - conn_config->curves : QUIC_GROUPS; - if(!SSL_CTX_set1_curves_list(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(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(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(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, ssl_ctx); - if(result) - goto out; - ctx->x509_store_setup = TRUE; - } - Curl_set_in_callback(data, true); - result = (*data->set.ssl.fsslctx)(data, 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: - *pssl_ctx = result? NULL : ssl_ctx; - if(result && ssl_ctx) - SSL_CTX_free(ssl_ctx); - return result; -} - -static CURLcode quic_set_client_cert(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_ngtcp2_ctx *ctx = cf->ctx; - SSL_CTX *ssl_ctx = ctx->sslctx; - 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 quic_init_ssl(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_ngtcp2_ctx *ctx = cf->ctx; - const uint8_t *alpn = NULL; - size_t alpnlen = 0; - - DEBUGASSERT(!ctx->ssl); - ctx->ssl = SSL_new(ctx->sslctx); - - SSL_set_app_data(ctx->ssl, &ctx->conn_ref); - SSL_set_connect_state(ctx->ssl); - SSL_set_quic_use_legacy_codepoint(ctx->ssl, 0); - - alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3; - alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1; - if(alpn) - SSL_set_alpn_protos(ctx->ssl, alpn, (int)alpnlen); - - /* set SNI */ - if(ctx->peer.sni) { - if(!SSL_set_tlsext_host_name(ctx->ssl, ctx->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 CURLcode quic_init_ssl(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct ssl_primary_config *conn_config; - CURLcode result; - gnutls_datum_t alpn[2]; - /* 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, - &ctx->peer, ctx->gtls, pverifyresult); - if(result) - return result; - - gnutls_session_set_ptr(ctx->gtls->session, &ctx->conn_ref); - - if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls->session) != 0) { - CURL_TRC_CF(data, cf, - "ngtcp2_crypto_gnutls_configure_client_session failed\n"); - return CURLE_QUIC_CONNECT_ERROR; - } - - 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); - } - - /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */ - alpn[0].data = (unsigned char *)H3_ALPN_H3_29 + 1; - alpn[0].size = sizeof(H3_ALPN_H3_29) - 2; - alpn[1].data = (unsigned char *)H3_ALPN_H3 + 1; - alpn[1].size = sizeof(H3_ALPN_H3) - 2; - - gnutls_alpn_set_protocols(ctx->gtls->session, - alpn, 2, GNUTLS_ALPN_MANDATORY); - return CURLE_OK; -} -#elif defined(USE_WOLFSSL) - -static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx, - struct Curl_cfilter *cf, struct Curl_easy *data) -{ - CURLcode result = CURLE_FAILED_INIT; - struct ssl_primary_config *conn_config; - WOLFSSL_CTX *ssl_ctx = NULL; - - conn_config = Curl_ssl_cf_get_primary_config(cf); - if(!conn_config) { - result = CURLE_FAILED_INIT; - goto out; - } - - ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); - if(!ssl_ctx) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - if(ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx) != 0) { - failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed"); - result = CURLE_FAILED_INIT; - goto out; - } - - wolfSSL_CTX_set_default_verify_paths(ssl_ctx); - - if(wolfSSL_CTX_set_cipher_list(ssl_ctx, conn_config->cipher_list13 ? - conn_config->cipher_list13 : - QUIC_CIPHERS) != 1) { - char error_buffer[256]; - ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer)); - failf(data, "wolfSSL failed to set ciphers: %s", error_buffer); - goto out; - } - - if(wolfSSL_CTX_set1_groups_list(ssl_ctx, conn_config->curves ? - conn_config->curves : - (char *)QUIC_GROUPS) != 1) { - failf(data, "wolfSSL failed to set curves"); - goto out; - } - - /* Open the file if a TLS or QUIC backend has not done this before. */ - Curl_tls_keylog_open(); - if(Curl_tls_keylog_enabled()) { -#if defined(HAVE_SECRET_CALLBACK) - wolfSSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback); -#else - failf(data, "wolfSSL was built without keylog callback"); - goto out; -#endif - } - - if(conn_config->verifypeer) { - const char * const ssl_cafile = conn_config->CAfile; - const char * const ssl_capath = conn_config->CApath; - - wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); - if(ssl_cafile || ssl_capath) { - /* tell wolfSSL where to find CA certificates that are used to verify - the server's certificate. */ - int rc = - wolfSSL_CTX_load_verify_locations_ex(ssl_ctx, ssl_cafile, ssl_capath, - WOLFSSL_LOAD_FLAG_IGNORE_ERR); - if(SSL_SUCCESS != rc) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate verify locations:" - " CAfile: %s CApath: %s", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - goto out; - } - infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); - infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); - } -#ifdef CURL_CA_FALLBACK - else { - /* verifying the peer without any CA certificates won't work so - use wolfssl's built-in default as fallback */ - wolfSSL_CTX_set_default_verify_paths(ssl_ctx); - } -#endif - } - else { - wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL); - } - - /* give application a chance to interfere with SSL set up. */ - if(data->set.ssl.fsslctx) { - Curl_set_in_callback(data, true); - result = (*data->set.ssl.fsslctx)(data, 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: - *pssl_ctx = result? NULL : ssl_ctx; - if(result && ssl_ctx) - SSL_CTX_free(ssl_ctx); - return result; -} - -/** SSL callbacks ***/ - -static CURLcode quic_init_ssl(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_ngtcp2_ctx *ctx = cf->ctx; - const uint8_t *alpn = NULL; - size_t alpnlen = 0; - /* this will need some attention when HTTPS proxy over QUIC get fixed */ - const char * const hostname = cf->conn->host.name; - - (void)data; - DEBUGASSERT(!ctx->ssl); - ctx->ssl = wolfSSL_new(ctx->sslctx); - - wolfSSL_set_app_data(ctx->ssl, &ctx->conn_ref); - wolfSSL_set_connect_state(ctx->ssl); - wolfSSL_set_quic_use_legacy_codepoint(ctx->ssl, 0); - - alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3; - alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1; - if(alpn) - wolfSSL_set_alpn_protos(ctx->ssl, alpn, (int)alpnlen); - - /* set SNI */ - wolfSSL_UseSNI(ctx->ssl, WOLFSSL_SNI_HOST_NAME, - hostname, (unsigned short)strlen(hostname)); - - return CURLE_OK; -} -#endif /* defined(USE_WOLFSSL) */ - static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data) { (void)user_data; @@ -1157,18 +742,22 @@ static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf, struct easy_pollset *ps) { struct cf_ngtcp2_ctx *ctx = cf->ctx; - bool want_recv = CURL_WANT_RECV(data); - bool want_send = CURL_WANT_SEND(data); + bool want_recv, want_send; - if(ctx->qconn && (want_recv || want_send)) { + if(!ctx->qconn) + return; + + 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 cf_call_data save; bool c_exhaust, s_exhaust; CF_DATA_SAVE(save, cf, data); - c_exhaust = !ngtcp2_conn_get_cwnd_left(ctx->qconn) || - !ngtcp2_conn_get_max_data_left(ctx->qconn); - s_exhaust = stream && stream->id >= 0 && stream->quic_flow_blocked; + c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) || + !ngtcp2_conn_get_max_data_left(ctx->qconn)); + s_exhaust = want_send && stream && stream->id >= 0 && + stream->quic_flow_blocked; want_recv = (want_recv || c_exhaust || s_exhaust); want_send = (!s_exhaust && want_send) || !Curl_bufq_is_empty(&ctx->q.sendbuf); @@ -1894,6 +1483,8 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, sent = (ssize_t)len; goto out; } + CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) " + "-> stream closed", stream->id, len); *err = CURLE_HTTP3; sent = -1; goto out; @@ -1944,49 +1535,12 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct ssl_primary_config *conn_config; - CURLcode result = CURLE_OK; - - conn_config = Curl_ssl_cf_get_primary_config(cf); - if(!conn_config) - return CURLE_FAILED_INIT; cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ cf->conn->httpversion = 30; cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; - 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, &ctx->peer, server_cert); - X509_free(server_cert); - if(result) - return result; -#elif defined(USE_GNUTLS) - result = Curl_gtls_verifyserver(data, ctx->gtls->session, - conn_config, &data->set.ssl, &ctx->peer, - data->set.str[STRING_SSL_PINNEDPUBLICKEY]); - if(result) - return result; -#elif defined(USE_WOLFSSL) - if(!ctx->peer.sni || - wolfSSL_check_domain_name(ctx->ssl, ctx->peer.sni) == SSL_FAILURE) - return CURLE_PEER_FAILED_VERIFICATION; -#endif - infof(data, "Verified certificate just fine"); - } - 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; + return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); } static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, @@ -2050,14 +1604,9 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, pktx_update_time(pktx, cf); } -#ifdef USE_OPENSSL - if(!ctx->x509_store_setup) { - result = Curl_ssl_setup_x509_store(cf, data, ctx->sslctx); - if(result) - return result; - ctx->x509_store_setup = TRUE; - } -#endif + result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); + if(result) + return result; for(i = 0; i < pkts_max; i += pkts_chunk) { pktx->pkt_count = 0; @@ -2382,25 +1931,7 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx) if(ctx->qlogfd != -1) { close(ctx->qlogfd); } -#ifdef USE_OPENSSL - if(ctx->ssl) - SSL_free(ctx->ssl); - if(ctx->sslctx) - SSL_CTX_free(ctx->sslctx); -#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); - } -#elif defined(USE_WOLFSSL) - if(ctx->ssl) - wolfSSL_free(ctx->ssl); - if(ctx->sslctx) - wolfSSL_CTX_free(ctx->sslctx); -#endif + Curl_vquic_tls_cleanup(&ctx->tls); vquic_ctx_free(&ctx->q); if(ctx->h3conn) nghttp3_conn_del(ctx->h3conn); @@ -2459,6 +1990,37 @@ 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) +{ + (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) { + 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) { + failf(data, "ngtcp2_crypto_quictls_configure_client_context failed"); + return CURLE_FAILED_INIT; + } +#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */ +#elif defined(USE_GNUTLS) + if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls->session) != 0) { + failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed"); + return CURLE_FAILED_INIT; + } +#elif defined(USE_WOLFSSL) + if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->ssl_ctx) != 0) { + failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed"); + return CURLE_FAILED_INIT; + } +#endif + return CURLE_OK; +} + /* * Might be called twice for happy eyeballs. */ @@ -2483,21 +2045,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, if(result) return result; -#ifdef USE_OPENSSL - result = quic_ssl_ctx(&ctx->sslctx, cf, data); - if(result) - return result; - - result = quic_set_client_cert(cf, data); - if(result) - return result; -#elif defined(USE_WOLFSSL) - result = quic_ssl_ctx(&ctx->sslctx, cf, data); - if(result) - return result; -#endif - - result = quic_init_ssl(cf, data); +#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); if(result) return result; @@ -2544,9 +2095,9 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, return CURLE_QUIC_CONNECT_ERROR; #ifdef USE_GNUTLS - ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->gtls->session); + ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls->session); #else - ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->ssl); + ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ssl); #endif ngtcp2_ccerr_default(&ctx->last_error); @@ -2677,8 +2228,8 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, return CURLE_OK; } case CF_QUERY_CONNECT_REPLY_MS: - if(ctx->got_first_byte) { - timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at); + if(ctx->q.got_first_byte) { + timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at); *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX; } else @@ -2686,8 +2237,8 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, return CURLE_OK; case CF_QUERY_TIMER_CONNECT: { struct curltime *when = pres2; - if(ctx->got_first_byte) - *when = ctx->first_byte_at; + if(ctx->q.got_first_byte) + *when = ctx->q.first_byte_at; return CURLE_OK; } case CF_QUERY_TIMER_APPCONNECT: { diff --git a/libs/libcurl/src/vquic/curl_osslq.c b/libs/libcurl/src/vquic/curl_osslq.c new file mode 100644 index 0000000000..82fda51971 --- /dev/null +++ b/libs/libcurl/src/vquic/curl_osslq.c @@ -0,0 +1,2237 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) + +#include +#include +#include +#include + +#include "urldata.h" +#include "sendf.h" +#include "strdup.h" +#include "rand.h" +#include "multiif.h" +#include "strcase.h" +#include "cfilters.h" +#include "cf-socket.h" +#include "connect.h" +#include "progress.h" +#include "strerror.h" +#include "dynbuf.h" +#include "http1.h" +#include "select.h" +#include "inet_pton.h" +#include "vquic.h" +#include "vquic_int.h" +#include "vquic-tls.h" +#include "vtls/keylog.h" +#include "vtls/vtls.h" +#include "vtls/openssl.h" +#include "curl_osslq.h" + +#include "warnless.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* A stream window is the maximum amount we need to buffer for + * each active transfer. We use HTTP/3 flow control and only ACK + * when we take things out of the buffer. + * Chunk size is large enough to take a full DATA frame */ +#define H3_STREAM_WINDOW_SIZE (128 * 1024) +#define H3_STREAM_CHUNK_SIZE (16 * 1024) +/* The pool keeps spares around and half of a full stream windows + * seems good. More does not seem to improve performance. + * The benefit of the pool is that stream buffer to not keep + * spares. So memory consumption goes down when streams run empty, + * have a large upload done, etc. */ +#define H3_STREAM_POOL_SPARES \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2 +/* Receive and Send max number of chunks just follows from the + * chunk size and window size */ +#define H3_STREAM_RECV_CHUNKS \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) +#define H3_STREAM_SEND_CHUNKS \ + (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) + +#ifndef ARRAYSIZE +#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +typedef uint32_t sslerr_t; +#else +typedef unsigned long sslerr_t; +#endif + + +/* How to access `call_data` from a cf_osslq filter */ +#undef CF_CTX_CALL_DATA +#define CF_CTX_CALL_DATA(cf) \ + ((struct cf_osslq_ctx *)(cf)->ctx)->call_data + +static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data); + +static const char *SSL_ERROR_to_str(int err) +{ + switch(err) { + case SSL_ERROR_NONE: + return "SSL_ERROR_NONE"; + case SSL_ERROR_SSL: + return "SSL_ERROR_SSL"; + case SSL_ERROR_WANT_READ: + return "SSL_ERROR_WANT_READ"; + case SSL_ERROR_WANT_WRITE: + return "SSL_ERROR_WANT_WRITE"; + case SSL_ERROR_WANT_X509_LOOKUP: + return "SSL_ERROR_WANT_X509_LOOKUP"; + case SSL_ERROR_SYSCALL: + return "SSL_ERROR_SYSCALL"; + case SSL_ERROR_ZERO_RETURN: + return "SSL_ERROR_ZERO_RETURN"; + case SSL_ERROR_WANT_CONNECT: + return "SSL_ERROR_WANT_CONNECT"; + case SSL_ERROR_WANT_ACCEPT: + return "SSL_ERROR_WANT_ACCEPT"; +#if defined(SSL_ERROR_WANT_ASYNC) + case SSL_ERROR_WANT_ASYNC: + return "SSL_ERROR_WANT_ASYNC"; +#endif +#if defined(SSL_ERROR_WANT_ASYNC_JOB) + case SSL_ERROR_WANT_ASYNC_JOB: + return "SSL_ERROR_WANT_ASYNC_JOB"; +#endif +#if defined(SSL_ERROR_WANT_EARLY) + case SSL_ERROR_WANT_EARLY: + return "SSL_ERROR_WANT_EARLY"; +#endif + default: + return "SSL_ERROR unknown"; + } +} + +/* Return error string for last OpenSSL error */ +static char *ossl_strerror(unsigned long error, char *buf, size_t size) +{ + DEBUGASSERT(size); + *buf = '\0'; + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) + ERR_error_string_n((uint32_t)error, buf, size); +#else + ERR_error_string_n(error, buf, size); +#endif + + if(!*buf) { + const char *msg = error ? "Unknown error" : "No error"; + if(strlen(msg) < size) + strcpy(buf, msg); + } + + return buf; +} + +static CURLcode make_bio_addr(BIO_ADDR **pbio_addr, + const struct Curl_sockaddr_ex *addr) +{ + BIO_ADDR *ba; + CURLcode result = CURLE_FAILED_INIT; + + ba = BIO_ADDR_new(); + if(!ba) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + switch(addr->family) { + case AF_INET: { + struct sockaddr_in * const sin = + (struct sockaddr_in * const)(void *)&addr->sa_addr; + if(!BIO_ADDR_rawmake(ba, AF_INET, &sin->sin_addr, + sizeof(sin->sin_addr), sin->sin_port)) { + goto out; + } + result = CURLE_OK; + break; + } +#ifdef ENABLE_IPV6 + case AF_INET6: { + struct sockaddr_in6 * const sin = + (struct sockaddr_in6 * const)(void *)&addr->sa_addr; + if(!BIO_ADDR_rawmake(ba, AF_INET6, &sin->sin6_addr, + sizeof(sin->sin6_addr), sin->sin6_port)) { + } + result = CURLE_OK; + break; + } +#endif /* ENABLE_IPV6 */ + default: + /* sunsupported */ + DEBUGASSERT(0); + break; + } + +out: + if(result && ba) { + BIO_ADDR_free(ba); + ba = NULL; + } + *pbio_addr = ba; + return result; +} + +/* QUIC stream (not necessarily H3) */ +struct cf_osslq_stream { + int64_t id; + SSL *ssl; + struct bufq recvbuf; /* QUIC war data recv buffer */ + BIT(recvd_eos); + BIT(closed); + BIT(reset); + BIT(send_blocked); +}; + +static CURLcode cf_osslq_stream_open(struct cf_osslq_stream *s, + SSL *conn, + uint64_t flags, + struct bufc_pool *bufcp, + void *user_data) +{ + DEBUGASSERT(!s->ssl); + Curl_bufq_initp(&s->recvbuf, bufcp, 1, BUFQ_OPT_NONE); + s->ssl = SSL_new_stream(conn, flags); + if(!s->ssl) { + return CURLE_FAILED_INIT; + } + s->id = SSL_get_stream_id(s->ssl); + SSL_set_app_data(s->ssl, user_data); + return CURLE_OK; +} + +static void cf_osslq_stream_cleanup(struct cf_osslq_stream *s) +{ + if(s->ssl) { + SSL_set_app_data(s->ssl, NULL); + SSL_free(s->ssl); + } + Curl_bufq_free(&s->recvbuf); + memset(s, 0, sizeof(*s)); +} + +static void cf_osslq_stream_close(struct cf_osslq_stream *s) +{ + if(s->ssl) { + SSL_free(s->ssl); + s->ssl = NULL; + } +} + +struct cf_osslq_h3conn { + nghttp3_conn *conn; + nghttp3_settings settings; + struct cf_osslq_stream s_ctrl; + struct cf_osslq_stream s_qpack_enc; + struct cf_osslq_stream s_qpack_dec; + struct cf_osslq_stream remote_ctrl[3]; /* uni streams opened by the peer */ + size_t remote_ctrl_n; /* number of peer streams opened */ +}; + +static void cf_osslq_h3conn_cleanup(struct cf_osslq_h3conn *h3) +{ + size_t i; + + if(h3->conn) + nghttp3_conn_del(h3->conn); + cf_osslq_stream_cleanup(&h3->s_ctrl); + cf_osslq_stream_cleanup(&h3->s_qpack_enc); + cf_osslq_stream_cleanup(&h3->s_qpack_dec); + for(i = 0; i < h3->remote_ctrl_n; ++i) { + cf_osslq_stream_cleanup(&h3->remote_ctrl[i]); + } +} + +struct cf_osslq_ctx { + struct cf_quic_ctx q; + struct ssl_peer peer; + struct quic_tls_ctx tls; + struct cf_call_data call_data; + struct cf_osslq_h3conn h3; + struct curltime started_at; /* time the current attempt started */ + struct curltime handshake_at; /* time connect handshake finished */ + 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 */ + 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 */ +#ifdef USE_OPENSSL + BIT(x509_store_setup); /* if x509 store has been set up */ + BIT(protocol_shutdown); /* QUIC connection is shut down */ +#endif +}; + +static void cf_osslq_ctx_clear(struct cf_osslq_ctx *ctx) +{ + struct cf_call_data save = ctx->call_data; + + cf_osslq_h3conn_cleanup(&ctx->h3); + Curl_vquic_tls_cleanup(&ctx->tls); + vquic_ctx_free(&ctx->q); + Curl_bufcp_free(&ctx->stream_bufcp); + Curl_ssl_peer_cleanup(&ctx->peer); + + memset(ctx, 0, sizeof(*ctx)); + ctx->call_data = save; +} + +static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + if(ctx && ctx->tls.ssl) { + /* TODO: send connection close */ + CURL_TRC_CF(data, cf, "cf_osslq_close()"); + cf_osslq_ctx_clear(ctx); + } + + cf->connected = FALSE; + CF_DATA_RESTORE(cf, save); +} + +static void cf_osslq_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + CURL_TRC_CF(data, cf, "destroy"); + if(ctx) { + CURL_TRC_CF(data, cf, "cf_osslq_destroy()"); + cf_osslq_ctx_clear(ctx); + free(ctx); + } + cf->ctx = NULL; + /* No CF_DATA_RESTORE(cf, save) possible */ + (void)save; +} + +static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3, + SSL *stream_ssl, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + int64_t stream_id = SSL_get_stream_id(stream_ssl); + + 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); + SSL_free(stream_ssl); + return CURLE_FAILED_INIT; + } + switch(SSL_get_stream_type(stream_ssl)) { + case SSL_STREAM_TYPE_READ: { + struct cf_osslq_stream *nstream = &h3->remote_ctrl[h3->remote_ctrl_n++]; + nstream->id = stream_id; + nstream->ssl = stream_ssl; + Curl_bufq_initp(&nstream->recvbuf, &ctx->stream_bufcp, 1, BUFQ_OPT_NONE); + CURL_TRC_CF(data, cf, "[%" PRId64 "] accepted new remote uni stream", + stream_id); + break; + } + default: + CURL_TRC_CF(data, cf, "[%" PRId64 "] rejecting remote non-uni-read" + " stream", stream_id); + SSL_free(stream_ssl); + return CURLE_FAILED_INIT; + } + return CURLE_OK; + +} + +static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf, + struct Curl_easy *data, + int detail, CURLcode def_result) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = def_result; + sslerr_t errdetail; + char ebuf[256] = "unknown"; + const char *err_descr = ebuf; + long lerr; + int lib; + int reason; + struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); + + errdetail = ERR_get_error(); + lib = ERR_GET_LIB(errdetail); + reason = ERR_GET_REASON(errdetail); + + if((lib == ERR_LIB_SSL) && + ((reason == SSL_R_CERTIFICATE_VERIFY_FAILED) || + (reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) { + result = CURLE_PEER_FAILED_VERIFICATION; + + lerr = SSL_get_verify_result(ctx->tls.ssl); + if(lerr != X509_V_OK) { + ssl_config->certverifyresult = lerr; + msnprintf(ebuf, sizeof(ebuf), + "SSL certificate problem: %s", + X509_verify_cert_error_string(lerr)); + } + else + err_descr = "SSL certificate verification failed"; + } +#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED) + /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on + OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */ + else if((lib == ERR_LIB_SSL) && + (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) { + /* If client certificate is required, communicate the + error to client */ + result = CURLE_SSL_CLIENTCERT; + ossl_strerror(errdetail, ebuf, sizeof(ebuf)); + } +#endif + else if((lib == ERR_LIB_SSL) && (reason == SSL_R_PROTOCOL_IS_SHUTDOWN)) { + ctx->protocol_shutdown = TRUE; + err_descr = "QUIC connectin has been shut down"; + result = def_result; + } + else { + result = def_result; + ossl_strerror(errdetail, ebuf, sizeof(ebuf)); + } + + /* detail is already set to the SSL error above */ + + /* If we e.g. use SSLv2 request-method and the server doesn't like us + * (RST connection, etc.), OpenSSL gives no explanation whatsoever and + * the SO_ERROR is also lost. + */ + if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { + char extramsg[80]=""; + int sockerr = SOCKERRNO; + const char *r_ip = NULL; + int r_port = 0; + + Curl_cf_socket_peek(cf->next, data, NULL, NULL, + &r_ip, &r_port, NULL, NULL); + if(sockerr && detail == SSL_ERROR_SYSCALL) + Curl_strerror(sockerr, extramsg, sizeof(extramsg)); + failf(data, "QUIC connect: %s in connection to %s:%d (%s)", + extramsg[0] ? extramsg : SSL_ERROR_to_str(detail), + ctx->peer.dispname, r_port, r_ip); + } + else { + /* Could be a CERT problem */ + failf(data, "%s", err_descr); + } + return result; +} + +static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + + cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + cf->conn->httpversion = 30; + cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; + + return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); +} + +/** + * All about the H3 internals of a stream + */ +struct h3_stream_ctx { + struct cf_osslq_stream s; + struct bufq sendbuf; /* h3 request body */ + struct bufq recvbuf; /* h3 response 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 */ + size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */ + 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 */ + bool resp_hds_complete; /* we have a complete, final response */ + bool closed; /* TRUE on stream close */ + bool reset; /* TRUE on stream reset */ + bool send_closed; /* stream is local closed */ + 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) + +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); + + if(!data || !data->req.p.http) { + failf(data, "initialization failure, transfer not http initialized"); + return CURLE_FAILED_INIT; + } + + if(stream) + return CURLE_OK; + + stream = calloc(1, sizeof(*stream)); + if(!stream) + return CURLE_OUT_OF_MEMORY; + + stream->s.id = -1; + /* on send, we control how much we put into the buffer */ + Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp, + H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE); + stream->sendbuf_len_in_flight = 0; + /* on recv, we need a flexible buffer limit since we also write + * headers to it that are not counted against the nghttp3 flow limits. */ + Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp, + H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); + stream->recv_buf_nonflow = 0; + Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); + + H3_STREAM_LCTX(data) = stream; + 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); + + (void)cf; + if(stream) { + CURL_TRC_CF(data, cf, "[%"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, + NGHTTP3_H3_REQUEST_CANCELLED); + nghttp3_conn_set_stream_user_data(ctx->h3.conn, stream->s.id, NULL); + 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; + } +} + +static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf, + struct Curl_easy *data, + int64_t stream_id) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + struct Curl_easy *sdata; + + if(stream && stream->s.id == stream_id) { + return &stream->s; + } + else if(ctx->h3.s_ctrl.id == stream_id) { + return &ctx->h3.s_ctrl; + } + else if(ctx->h3.s_qpack_enc.id == stream_id) { + return &ctx->h3.s_qpack_enc; + } + else if(ctx->h3.s_qpack_dec.id == stream_id) { + return &ctx->h3.s_qpack_dec; + } + 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; + } + } + } + return NULL; +} + +static void h3_drain_stream(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + unsigned char bits; + + (void)cf; + bits = CURL_CSELECT_IN; + if(stream && stream->upload_left && !stream->send_closed) + bits |= CURL_CSELECT_OUT; + if(data->state.select_bits != bits) { + data->state.select_bits = bits; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } +} + +static CURLcode h3_data_pause(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool pause) +{ + if(!pause) { + /* unpaused. make it run again right away */ + h3_drain_stream(cf, data); + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } + return CURLE_OK; +} + +static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, + 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 h3_stream_ctx *stream = H3_STREAM_CTX(data); + (void)conn; + (void)stream_id; + + /* we might be called by nghttp3 after we already cleaned up */ + if(!stream) + return 0; + + stream->closed = TRUE; + stream->error3 = 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, + stream->s.id, stream->error3); + } + else { + CURL_TRC_CF(data, cf, "[%" PRId64 "] CLOSED", stream->s.id); + } + h3_drain_stream(cf, data); + return 0; +} + +/* + * 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 + * `data`'s overflow buffer. + */ +static CURLcode write_resp_raw(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, size_t memlen, + bool flow) +{ + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result = CURLE_OK; + ssize_t nwritten; + + (void)cf; + if(!stream) { + return CURLE_RECV_ERROR; + } + nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result); + if(nwritten < 0) { + return result; + } + + if(!flow) + stream->recv_buf_nonflow += (size_t)nwritten; + + if((size_t)nwritten < memlen) { + /* This MUST not happen. Our recbuf is dimensioned to hold the + * full max_stream_window and then some for this very reason. */ + DEBUGASSERT(0); + return CURLE_RECV_ERROR; + } + return result; +} + +static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id, + const uint8_t *buf, size_t buflen, + void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result; + + (void)conn; + (void)stream3_id; + + if(!stream) + return NGHTTP3_ERR_CALLBACK_FAILURE; + + result = write_resp_raw(cf, data, buf, buflen, TRUE); + if(result) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %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", + stream->s.id, buflen, stream->download_recvd); + h3_drain_stream(cf, data); + return 0; +} + +static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id, + size_t consumed, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + + (void)conn; + (void)stream_id; + if(stream) + CURL_TRC_CF(data, cf, "[%" PRId64 "] deferred consume %zu bytes", + stream->s.id, consumed); + return 0; +} + +static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id, + 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; + 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); + CURLcode result = CURLE_OK; + (void)conn; + (void)stream_id; + (void)token; + (void)flags; + (void)cf; + + /* we might have cleaned up this transfer already */ + if(!stream) + 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_raw(cf, data, line, ncopy, FALSE); + if(result) { + return -1; + } + } + else { + /* store as an HTTP1-style header */ + CURL_TRC_CF(data, cf, "[%" 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); + if(result) { + return -1; + } + result = write_resp_raw(cf, data, ": ", 2, FALSE); + if(result) { + return -1; + } + result = write_resp_raw(cf, data, h3val.base, h3val.len, FALSE); + if(result) { + return -1; + } + result = write_resp_raw(cf, data, "\r\n", 2, FALSE); + if(result) { + return -1; + } + } + return 0; +} + +static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id, + int fin, void *user_data, void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURLcode result = CURLE_OK; + (void)conn; + (void)stream_id; + (void)fin; + (void)cf; + + if(!stream) + return 0; + /* add a CRLF only if we've received some headers */ + result = write_resp_raw(cf, data, "\r\n", 2, FALSE); + if(result) { + return -1; + } + + CURL_TRC_CF(data, cf, "[%" PRId64 "] end_headers, status=%d", + stream_id, stream->status_code); + if(stream->status_code / 100 != 1) { + stream->resp_hds_complete = TRUE; + } + h3_drain_stream(cf, data); + return 0; +} + +static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id, + 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 h3_stream_ctx *stream = H3_STREAM_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); + cf_osslq_stream_close(&stream->s); + return 0; +} + +static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id, + 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 h3_stream_ctx *stream = H3_STREAM_CTX(data); + int rv; + (void)conn; + + if(stream && stream->s.ssl) { + 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); + if(!rv) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static nghttp3_ssize +cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id, + nghttp3_vec *vec, size_t veccnt, + uint32_t *pflags, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + ssize_t nwritten = 0; + size_t nvecs = 0; + (void)cf; + (void)conn; + (void)stream_id; + (void)user_data; + (void)veccnt; + + if(!stream) + return NGHTTP3_ERR_CALLBACK_FAILURE; + /* nghttp3 keeps references to the sendbuf data until it is ACKed + * by the server (see `cb_h3_acked_req_body()` for updates). + * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf` + * that we have already passed to nghttp3, but which have not been + * ACKed yet. + * Any amount beyond `sendbuf_len_in_flight` we need still to pass + * to nghttp3. Do that now, if we can. */ + if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) { + nvecs = 0; + while(nvecs < veccnt && + Curl_bufq_peek_at(&stream->sendbuf, + stream->sendbuf_len_in_flight, + (const unsigned char **)&vec[nvecs].base, + &vec[nvecs].len)) { + stream->sendbuf_len_in_flight += vec[nvecs].len; + nwritten += vec[nvecs].len; + ++nvecs; + } + DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */ + } + + if(nwritten > 0 && stream->upload_left != -1) + stream->upload_left -= nwritten; + + /* When we stopped sending and everything in `sendbuf` is "in flight", + * we are at the end of the request body. */ + if(stream->upload_left == 0) { + *pflags = NGHTTP3_DATA_FLAG_EOF; + stream->send_closed = TRUE; + } + else if(!nwritten) { + /* Not EOF, and nothing to give, we signal WOULDBLOCK. */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> AGAIN", + stream->s.id); + return NGHTTP3_ERR_WOULDBLOCK; + } + + CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> " + "%d vecs%s with %zu (buffered=%zu, left=%" + CURL_FORMAT_CURL_OFF_T ")", + stream->s.id, (int)nvecs, + *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"", + nwritten, Curl_bufq_len(&stream->sendbuf), + stream->upload_left); + return (nghttp3_ssize)nvecs; +} + +static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, + uint64_t datalen, void *user_data, + void *stream_user_data) +{ + struct Curl_cfilter *cf = user_data; + struct Curl_easy *data = stream_user_data; + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + size_t skiplen; + + (void)cf; + if(!stream) + return 0; + /* The server acknowledged `datalen` of bytes from our request body. + * This is a delta. We have kept this data in `sendbuf` for + * re-transmissions and can free it now. */ + if(datalen >= (uint64_t)stream->sendbuf_len_in_flight) + skiplen = stream->sendbuf_len_in_flight; + else + skiplen = (size_t)datalen; + Curl_bufq_skip(&stream->sendbuf, skiplen); + stream->sendbuf_len_in_flight -= skiplen; + + /* Everything ACKed, we resume upload processing */ + if(!stream->sendbuf_len_in_flight) { + int rv = nghttp3_conn_resume_stream(conn, stream_id); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + +static nghttp3_callbacks ngh3_callbacks = { + cb_h3_acked_stream_data, + cb_h3_stream_close, + cb_h3_recv_data, + cb_h3_deferred_consume, + NULL, /* begin_headers */ + cb_h3_recv_header, + cb_h3_end_headers, + NULL, /* begin_trailers */ + cb_h3_recv_header, + NULL, /* end_trailers */ + cb_h3_stop_sending, + NULL, /* end_stream */ + cb_h3_reset_stream, + NULL, /* shutdown */ + NULL /* recv_settings */ +}; + +static CURLcode cf_osslq_h3conn_init(struct cf_osslq_ctx *ctx, SSL *conn, + void *user_data) +{ + struct cf_osslq_h3conn *h3 = &ctx->h3; + CURLcode result; + int rc; + + nghttp3_settings_default(&h3->settings); + rc = nghttp3_conn_client_new(&h3->conn, + &ngh3_callbacks, + &h3->settings, + nghttp3_mem_default(), + user_data); + if(rc) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + result = cf_osslq_stream_open(&h3->s_ctrl, conn, + SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI, + &ctx->stream_bufcp, NULL); + if(result) { + result = CURLE_QUIC_CONNECT_ERROR; + goto out; + } + result = cf_osslq_stream_open(&h3->s_qpack_enc, conn, + SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI, + &ctx->stream_bufcp, NULL); + if(result) { + result = CURLE_QUIC_CONNECT_ERROR; + goto out; + } + result = cf_osslq_stream_open(&h3->s_qpack_dec, conn, + SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI, + &ctx->stream_bufcp, NULL); + if(result) { + result = CURLE_QUIC_CONNECT_ERROR; + goto out; + } + + rc = nghttp3_conn_bind_control_stream(h3->conn, h3->s_ctrl.id); + if(rc) { + result = CURLE_QUIC_CONNECT_ERROR; + goto out; + } + rc = nghttp3_conn_bind_qpack_streams(h3->conn, h3->s_qpack_enc.id, + h3->s_qpack_dec.id); + if(rc) { + result = CURLE_QUIC_CONNECT_ERROR; + goto out; + } + + result = CURLE_OK; +out: + return result; +} + +static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result; + int rv; + const struct Curl_sockaddr_ex *peer_addr = NULL; + int peer_port; + BIO *bio = NULL; + BIO_ADDR *baddr = NULL; + + Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, + H3_STREAM_POOL_SPARES); + result = Curl_ssl_peer_init(&ctx->peer, cf); + 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); + if(result) + goto out; + + result = vquic_ctx_init(&ctx->q); + if(result) + goto out; + + result = CURLE_QUIC_CONNECT_ERROR; + Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, + &peer_addr, NULL, &peer_port, NULL, NULL); + if(!peer_addr) + goto out; + + ctx->q.local_addrlen = sizeof(ctx->q.local_addr); + rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr, + &ctx->q.local_addrlen); + if(rv == -1) + goto out; + + result = make_bio_addr(&baddr, peer_addr); + if(result) { + failf(data, "error creating BIO_ADDR from sockaddr"); + goto out; + } + + bio = BIO_new_dgram(ctx->q.sockfd, BIO_NOCLOSE); + if(!bio) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + if(!SSL_set1_initial_peer_addr(ctx->tls.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)) { + failf(data, "failed to turn off blocking mode"); + result = CURLE_FAILED_INIT; + goto out; + } + + SSL_set_bio(ctx->tls.ssl, bio, bio); + bio = NULL; + SSL_set_connect_state(ctx->tls.ssl); + SSL_set_incoming_stream_policy(ctx->tls.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); + +out: + if(bio) + BIO_free(bio); + if(baddr) + BIO_ADDR_free(baddr); + CURL_TRC_CF(data, cf, "QUIC tls init -> %d", result); + return result; +} + +struct h3_quic_recv_ctx { + struct Curl_cfilter *cf; + struct Curl_easy *data; + struct cf_osslq_stream *s; +}; + +static ssize_t h3_quic_recv(void *reader_ctx, + unsigned char *buf, size_t len, + CURLcode *err) +{ + struct h3_quic_recv_ctx *x = reader_ctx; + size_t nread; + int rv; + + *err = CURLE_OK; + rv = SSL_read_ex(x->s->ssl, buf, len, &nread); + if(rv <= 0) { + int detail = SSL_get_error(x->s->ssl, rv); + if(detail == SSL_ERROR_WANT_READ || detail == SSL_ERROR_WANT_WRITE) { + *err = CURLE_AGAIN; + return -1; + } + else if(detail == SSL_ERROR_ZERO_RETURN) { + CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> EOS", + x->s->id); + x->s->recvd_eos = TRUE; + return 0; + } + else if(SSL_get_stream_read_state(x->s->ssl) == + SSL_STREAM_STATE_RESET_REMOTE) { + uint64_t app_error_code = NGHTTP3_H3_NO_ERROR; + SSL_get_stream_read_error_code(x->s->ssl, &app_error_code); + CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> RESET, " + "rv=%d, app_err=%" PRIu64, + x->s->id, rv, app_error_code); + if(app_error_code != NGHTTP3_H3_NO_ERROR) { + x->s->reset = TRUE; + } + x->s->recvd_eos = TRUE; + return 0; + } + else { + *err = cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR); + return -1; + } + } + else { + /* CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] h3_quic_recv -> %zu bytes", + x->s->id, nread); */ + } + return (ssize_t)nread; +} + +static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + ssize_t nread; + struct h3_quic_recv_ctx x; + int rv, eagain = FALSE; + size_t total_recv_len = 0; + + DEBUGASSERT(s); + if(s->closed) + return CURLE_OK; + + x.cf = cf; + x.data = data; + x.s = s; + while(s->ssl && !s->closed && !eagain && + (total_recv_len < H3_STREAM_CHUNK_SIZE)) { + if(Curl_bufq_is_empty(&s->recvbuf) && !s->recvd_eos) { + while(!eagain && !s->recvd_eos && !Curl_bufq_is_full(&s->recvbuf)) { + nread = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &result); + if(nread < 0) { + if(result != CURLE_AGAIN) + goto out; + result = CURLE_OK; + eagain = TRUE; + } + } + } + + /* Forward what we have to nghttp3 */ + if(!Curl_bufq_is_empty(&s->recvbuf)) { + const unsigned char *buf; + size_t blen; + + 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 " + "to nghttp3 -> %zd", s->id, blen, nread); + if(nread < 0) { + failf(data, "nghttp3_conn_read_stream(len=%zu) error: %s", + blen, nghttp3_strerror((int)nread)); + result = CURLE_RECV_ERROR; + goto out; + } + /* success, `nread` is the flow for QUIC to count as "consumed", + * not sure how that will work with OpenSSL. Anyways, without error, + * all data that we passed is not owned by nghttp3. */ + Curl_bufq_skip(&s->recvbuf, blen); + total_recv_len += blen; + } + } + + /* When we forwarded everything, handle RESET/EOS */ + if(Curl_bufq_is_empty(&s->recvbuf) && !s->closed) { + result = CURLE_OK; + if(s->reset) { + uint64_t app_error; + if(!SSL_get_stream_read_error_code(s->ssl, &app_error)) { + failf(data, "SSL_get_stream_read_error_code returned error"); + result = CURLE_RECV_ERROR; + goto out; + } + rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id, app_error); + s->closed = TRUE; + if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + failf(data, "nghttp3_conn_close_stream returned error: %s", + nghttp3_strerror(rv)); + result = CURLE_RECV_ERROR; + goto out; + } + } + else if(s->recvd_eos) { + 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", + s->id, rv); + if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + failf(data, "nghttp3_conn_close_stream returned error: %s", + nghttp3_strerror(rv)); + result = CURLE_RECV_ERROR; + goto out; + } + } + } + } +out: + if(result) + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_osslq_stream_recv -> %d", + s->id, result); + return result; +} + +static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(!ctx->tls.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); + 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); + result = cf_osslq_ssl_err(cf, data, detail, CURLE_RECV_ERROR); + } + + if(ctx->h3.conn) { + size_t i; + for(i = 0; i < ctx->h3.remote_ctrl_n; ++i) { + result = cf_osslq_stream_recv(&ctx->h3.remote_ctrl[i], cf, data); + if(result) + goto out; + } + } + + if(ctx->h3.conn) { + struct Curl_easy *sdata; + struct h3_stream_ctx *stream; + /* PULL all open streams */ + 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); + if(stream && !stream->closed && + !Curl_bufq_is_full(&stream->recvbuf)) { + result = cf_osslq_stream_recv(&stream->s, cf, sdata); + if(result) + goto out; + } + } + } + } + +out: + CURL_TRC_CF(data, cf, "progress_ingress -> %d", result); + return result; +} + +/* Iterate over all streams and check if blocked can be unblocked */ +static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct Curl_easy *sdata; + struct h3_stream_ctx *stream; + + if(ctx->h3.conn) { + for(sdata = data->multi->easyp; sdata; sdata = sdata->next) { + if(sdata->conn == data->conn) { + stream = H3_STREAM_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); + stream->s.send_blocked = FALSE; + h3_drain_stream(cf, sdata); + CURL_TRC_CF(sdata, cf, "unblocked"); + } + } + } + } + return CURLE_OK; +} + +static CURLcode h3_send_streams(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(!ctx->tls.ssl || !ctx->h3.conn) + goto out; + + for(;;) { + struct cf_osslq_stream *s = NULL; + nghttp3_vec vec[16]; + nghttp3_ssize n, i; + int64_t stream_id; + size_t written; + int eos, ok, rv; + size_t total_len, acked_len = 0; + bool blocked = FALSE; + + n = nghttp3_conn_writev_stream(ctx->h3.conn, &stream_id, &eos, + vec, ARRAYSIZE(vec)); + if(n < 0) { + failf(data, "nghttp3_conn_writev_stream returned error: %s", + nghttp3_strerror((int)n)); + result = CURLE_SEND_ERROR; + goto out; + } + if(stream_id < 0) { + result = CURLE_OK; + goto out; + } + + /* 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); + result = CURLE_SEND_ERROR; + goto out; + } + /* Now write the data to the stream's SSL*, it may not all fit! */ + DEBUGASSERT(s->id == stream_id); + for(i = 0, total_len = 0; i < n; ++i) { + total_len += vec[i].len; + } + for(i = 0; (i < n) && !blocked; ++i) { + /* Without stream->s.ssl, we closed that already, so + * pretend the write did succeed. */ + written = vec[i].len; + ok = !s->ssl || SSL_write_ex(s->ssl, vec[i].base, vec[i].len, + &written); + 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); + acked_len += vec[i].len; + } + else { + int detail = SSL_get_error(s->ssl, 0); + switch(detail) { + 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); + 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", + s->id, vec[i].len, detail); + result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR); + goto out; + } + } + } + + if(acked_len > 0 || (eos && !s->send_blocked)) { + /* Since QUIC buffers the data written internally, we can tell + * nghttp3 that it can move forward on it */ + rv = nghttp3_conn_add_write_offset(ctx->h3.conn, s->id, acked_len); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + failf(data, "nghttp3_conn_add_write_offset returned error: %s\n", + nghttp3_strerror(rv)); + result = CURLE_SEND_ERROR; + goto out; + } + rv = nghttp3_conn_add_ack_offset(ctx->h3.conn, s->id, acked_len); + if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { + failf(data, "nghttp3_conn_add_ack_offset returned error: %s\n", + nghttp3_strerror(rv)); + result = CURLE_SEND_ERROR; + goto out; + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] forwarded %zu/%zu h3 bytes " + "to QUIC, eos=%d", s->id, acked_len, total_len, eos); + } + + if(eos && !s->send_blocked) { + /* wrote everything and H3 indicates end of stream */ + CURL_TRC_CF(data, cf, "[%" PRId64 "] closing QUIC stream", s->id); + SSL_stream_conclude(s->ssl, 0); + } + } + +out: + CURL_TRC_CF(data, cf, "h3_send_streams -> %d", result); + return result; +} + +static CURLcode cf_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(!ctx->tls.ssl) + goto out; + + ERR_clear_error(); + result = h3_send_streams(cf, data); + if(result) + goto out; + + if(!SSL_handle_events(ctx->tls.ssl)) { + int detail = SSL_get_error(ctx->tls.ssl, 0); + result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR); + } + + result = cf_osslq_check_and_unblock(cf, data); + +out: + CURL_TRC_CF(data, cf, "progress_egress -> %d", result); + return result; +} + +static CURLcode check_and_set_expiry(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct timeval tv; + timediff_t timeoutms; + int is_infinite = TRUE; + + if(ctx->tls.ssl && + SSL_get_event_timeout(ctx->tls.ssl, &tv, &is_infinite) && + !is_infinite) { + timeoutms = curlx_tvtoms(&tv); + /* QUIC want to be called again latest at the returned timeout */ + if(timeoutms <= 0) { + result = cf_progress_ingress(cf, data); + if(result) + goto out; + result = cf_progress_egress(cf, data); + if(result) + goto out; + if(SSL_get_event_timeout(ctx->tls.ssl, &tv, &is_infinite)) { + timeoutms = curlx_tvtoms(&tv); + } + } + if(!is_infinite) { + Curl_expire(data, timeoutms, EXPIRE_QUIC); + CURL_TRC_CF(data, cf, "QUIC expiry in %ldms", (long)timeoutms); + } + } +out: + return result; +} + +static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool blocking, bool *done) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct cf_call_data save; + struct curltime now; + int err; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + /* Connect the UDP filter first */ + if(!cf->next->connected) { + result = Curl_conn_cf_connect(cf->next, data, blocking, done); + if(result || !*done) + return result; + } + + *done = FALSE; + now = Curl_now(); + CF_DATA_SAVE(save, cf, data); + + if(ctx->reconnect_at.tv_sec && Curl_timediff(now, ctx->reconnect_at) < 0) { + /* Not time yet to attempt the next connect */ + CURL_TRC_CF(data, cf, "waiting for reconnect time"); + goto out; + } + + if(!ctx->tls.ssl) { + ctx->started_at = now; + result = cf_osslq_ctx_start(cf, data); + if(result) + goto out; + } + + if(!ctx->got_first_byte) { + int readable = SOCKET_READABLE(ctx->q.sockfd, 0); + if(readable > 0 && (readable & CURL_CSELECT_IN)) { + ctx->got_first_byte = TRUE; + ctx->first_byte_at = Curl_now(); + } + } + + ERR_clear_error(); + err = SSL_do_handshake(ctx->tls.ssl); + + if(err == 1) { + /* connected */ + ctx->handshake_at = now; + CURL_TRC_CF(data, cf, "handshake complete after %dms", + (int)Curl_timediff(now, ctx->started_at)); + result = cf_osslq_verify_peer(cf, data); + if(!result) { + CURL_TRC_CF(data, cf, "peer verified"); + cf->connected = TRUE; + cf->conn->alpn = CURL_HTTP_VERSION_3; + *done = TRUE; + connkeep(cf->conn, "HTTP/3 default"); + } + } + else { + int detail = SSL_get_error(ctx->tls.ssl, err); + switch(detail) { + case SSL_ERROR_WANT_READ: + CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_RECV"); + result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); + goto out; + case SSL_ERROR_WANT_WRITE: + CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_SEND"); + result = CURLE_OK; + goto out; +#ifdef SSL_ERROR_WANT_ASYNC + case SSL_ERROR_WANT_ASYNC: + CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_ASYNC"); + result = CURLE_OK; + goto out; +#endif +#ifdef SSL_ERROR_WANT_RETRY_VERIFY + case SSL_ERROR_WANT_RETRY_VERIFY: + result = CURLE_OK; + goto out; +#endif + default: + result = cf_osslq_ssl_err(cf, data, detail, CURLE_COULDNT_CONNECT); + goto out; + } + } + +out: + if(result == CURLE_RECV_ERROR && ctx->tls.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 + * that as a "weird" reply. */ + result = CURLE_WEIRD_SERVER_REPLY; + } + +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(result) { + const char *r_ip = NULL; + int r_port = 0; + + Curl_cf_socket_peek(cf->next, data, NULL, NULL, + &r_ip, &r_port, NULL, NULL); + infof(data, "QUIC connect to %s port %u failed: %s", + r_ip, r_port, curl_easy_strerror(result)); + } +#endif + if(!result) + result = check_and_set_expiry(cf, data); + if(result || *done) + CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done); + CF_DATA_RESTORE(cf, save); + return result; +} + +static ssize_t h3_stream_open(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 = NULL; + struct dynhds h2_headers; + size_t nheader; + nghttp3_nv *nva = NULL; + int rc = 0; + unsigned int i; + ssize_t nwritten = -1; + nghttp3_data_reader reader; + nghttp3_data_reader *preader = NULL; + + Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); + + *err = h3_data_setup(cf, data); + if(*err) + goto out; + stream = H3_STREAM_CTX(data); + DEBUGASSERT(stream); + if(!stream) { + *err = CURLE_FAILED_INIT; + goto out; + } + + nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); + if(nwritten < 0) + goto out; + if(!stream->h1.done) { + /* need more data */ + goto out; + } + DEBUGASSERT(stream->h1.req); + + *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); + if(*err) { + nwritten = -1; + goto out; + } + /* no longer needed */ + Curl_h1_req_parse_free(&stream->h1); + + nheader = Curl_dynhds_count(&h2_headers); + nva = malloc(sizeof(nghttp3_nv) * nheader); + if(!nva) { + *err = CURLE_OUT_OF_MEMORY; + nwritten = -1; + goto out; + } + + for(i = 0; i < nheader; ++i) { + struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i); + nva[i].name = (unsigned char *)e->name; + nva[i].namelen = e->namelen; + nva[i].value = (unsigned char *)e->value; + nva[i].valuelen = e->valuelen; + nva[i].flags = NGHTTP3_NV_FLAG_NONE; + } + + DEBUGASSERT(stream->s.id == -1); + *err = cf_osslq_stream_open(&stream->s, ctx->tls.ssl, 0, + &ctx->stream_bufcp, data); + if(*err) { + failf(data, "can't get bidi streams"); + *err = CURLE_SEND_ERROR; + goto out; + } + + switch(data->state.httpreq) { + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + case HTTPREQ_PUT: + /* known request body size or -1 */ + if(data->state.infilesize != -1) + stream->upload_left = data->state.infilesize; + else + /* data sending without specifying the data amount up front */ + stream->upload_left = -1; /* unknown */ + break; + default: + /* there is not request body */ + stream->upload_left = 0; /* no request body */ + break; + } + + stream->send_closed = (stream->upload_left == 0); + if(!stream->send_closed) { + reader.read_data = cb_h3_read_req_body; + preader = &reader; + } + + rc = nghttp3_conn_submit_request(ctx->h3.conn, stream->s.id, + nva, nheader, preader, data); + if(rc) { + switch(rc) { + case NGHTTP3_ERR_CONN_CLOSING: + CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send, " + "connection is closing", stream->s.id); + break; + default: + CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send -> %d (%s)", + stream->s.id, rc, nghttp3_strerror(rc)); + break; + } + *err = CURLE_SEND_ERROR; + nwritten = -1; + goto out; + } + + if(Curl_trc_is_verbose(data)) { + infof(data, "[HTTP/3] [%" 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, + (int)nva[i].namelen, nva[i].name, + (int)nva[i].valuelen, nva[i].value); + } + } + +out: + free(nva); + Curl_dynhds_free(&h2_headers); + return nwritten; +} + +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 cf_call_data save; + ssize_t nwritten; + CURLcode result; + + CF_DATA_SAVE(save, cf, data); + DEBUGASSERT(cf->connected); + DEBUGASSERT(ctx->tls.ssl); + DEBUGASSERT(ctx->h3.conn); + *err = CURLE_OK; + + result = cf_progress_ingress(cf, data); + if(result) { + *err = result; + nwritten = -1; + goto out; + } + + result = cf_progress_egress(cf, data); + if(result) { + *err = result; + nwritten = -1; + goto out; + } + + if(!stream || stream->s.id < 0) { + nwritten = h3_stream_open(cf, data, buf, len, err); + if(nwritten < 0) { + CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err); + goto out; + } + stream = H3_STREAM_CTX(data); + } + else if(stream->upload_blocked_len) { + /* the data in `buf` has already been submitted or added to the + * buffers, but have been EAGAINed on the last invocation. */ + DEBUGASSERT(len >= stream->upload_blocked_len); + if(len < stream->upload_blocked_len) { + /* Did we get called again with a smaller `len`? This should not + * happen. We are not prepared to handle that. */ + failf(data, "HTTP/3 send again with decreased length"); + *err = CURLE_HTTP3; + nwritten = -1; + goto out; + } + nwritten = (ssize_t)stream->upload_blocked_len; + stream->upload_blocked_len = 0; + } + else if(stream->closed) { + if(stream->resp_hds_complete) { + /* Server decided to close the stream after having sent us a final + * response. This is valid if it is not interested in the request + * body. This happens on 30x or 40x responses. + * We silently discard the data sent, since this is not a transport + * error situation. */ + CURL_TRC_CF(data, cf, "[%" 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) " + "-> stream closed", stream->s.id, len); + *err = CURLE_HTTP3; + nwritten = -1; + goto out; + } + else { + nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err); + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send, add to " + "sendbuf(len=%zu) -> %zd, %d", + stream->s.id, len, nwritten, *err); + if(nwritten < 0) { + goto out; + } + + (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id); + } + + result = cf_progress_egress(cf, data); + if(result) { + *err = result; + nwritten = -1; + } + + if(stream && nwritten > 0 && stream->sendbuf_len_in_flight) { + /* We have unacknowledged DATA and cannot report success to our + * 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), " + "%zu bytes in flight -> EGAIN", stream->s.id, len, + stream->sendbuf_len_in_flight); + *err = CURLE_AGAIN; + nwritten = -1; + } + +out: + result = check_and_set_expiry(cf, data); + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d", + stream? stream->s.id : -1, len, nwritten, *err); + CF_DATA_RESTORE(cf, save); + return nwritten; +} + +static ssize_t recv_closed_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h3_stream_ctx *stream, + CURLcode *err) +{ + ssize_t nread = -1; + + (void)cf; + if(stream->reset) { + failf(data, + "HTTP/3 stream %" PRId64 " reset by server", stream->s.id); + *err = stream->resp_hds_complete? 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", + stream->s.id); + *err = CURLE_HTTP3; + goto out; + } + *err = CURLE_OK; + nread = 0; + +out: + return nread; +} + +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); + ssize_t nread = -1; + struct cf_call_data save; + CURLcode result; + + (void)ctx; + CF_DATA_SAVE(save, cf, data); + DEBUGASSERT(cf->connected); + DEBUGASSERT(ctx); + DEBUGASSERT(ctx->tls.ssl); + DEBUGASSERT(ctx->h3.conn); + *err = CURLE_OK; + + if(!stream) { + *err = CURLE_RECV_ERROR; + goto out; + } + + if(!Curl_bufq_is_empty(&stream->recvbuf)) { + nread = Curl_bufq_read(&stream->recvbuf, + (unsigned char *)buf, len, err); + if(nread < 0) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) " + "-> %zd, %d", stream->s.id, len, nread, *err); + goto out; + } + } + + result = cf_progress_ingress(cf, data); + if(result) { + *err = result; + nread = -1; + goto out; + } + + /* recvbuf had nothing before, maybe after progressing ingress? */ + if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) { + nread = Curl_bufq_read(&stream->recvbuf, + (unsigned char *)buf, len, err); + if(nread < 0) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) " + "-> %zd, %d", stream->s.id, len, nread, *err); + goto out; + } + } + + if(nread > 0) { + h3_drain_stream(cf, data); + } + else { + if(stream->closed) { + nread = recv_closed_stream(cf, data, stream, err); + goto out; + } + *err = CURLE_AGAIN; + nread = -1; + } + +out: + if(cf_progress_egress(cf, data)) { + *err = CURLE_SEND_ERROR; + nread = -1; + } + else { + CURLcode result2 = check_and_set_expiry(cf, data); + if(result2) { + *err = result2; + nread = -1; + } + } + CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(len=%zu) -> %zd, %d", + stream? stream->s.id : -1, len, nread, *err); + CF_DATA_RESTORE(cf, save); + return nread; +} + +/* + * Called from transfer.c:data_pending to know if we should keep looping + * to receive more data from the connection. + */ +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); + (void)cf; + return stream && !Curl_bufq_is_empty(&stream->recvbuf); +} + +static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + (void)arg1; + (void)arg2; + switch(event) { + case CF_CTRL_DATA_SETUP: + break; + case CF_CTRL_DATA_PAUSE: + result = h3_data_pause(cf, data, (arg1 != 0)); + break; + case CF_CTRL_DATA_DETACH: + h3_data_done(cf, data); + break; + case CF_CTRL_DATA_DONE: + h3_data_done(cf, data); + break; + case CF_CTRL_DATA_DONE_SEND: { + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + if(stream && !stream->send_closed) { + stream->send_closed = TRUE; + stream->upload_left = Curl_bufq_len(&stream->sendbuf); + (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id); + } + break; + } + case CF_CTRL_DATA_IDLE: { + struct h3_stream_ctx *stream = H3_STREAM_CTX(data); + CURL_TRC_CF(data, cf, "data idle"); + if(stream && !stream->closed) { + result = check_and_set_expiry(cf, data); + } + break; + } + default: + break; + } + CF_DATA_RESTORE(cf, save); + return result; +} + +static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + bool alive = FALSE; + struct cf_call_data save; + + CF_DATA_SAVE(save, cf, data); + *input_pending = FALSE; + if(!ctx->tls.ssl) + goto out; + + /* TODO: how to check negotiated connection idle time? */ + + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + goto out; + + alive = TRUE; + if(*input_pending) { + CURLcode result; + /* This happens before we've sent off a request and the connection is + not in use by any other transfer, there shouldn't be any data here, + only "protocol frames" */ + *input_pending = FALSE; + result = cf_progress_ingress(cf, data); + CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result); + alive = result? FALSE : TRUE; + } + +out: + CF_DATA_RESTORE(cf, save); + return alive; +} + +static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + + if(!ctx->tls.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)); + } + else { + /* once connected, we only modify the socket if it is present. + * this avoids adding it for paused transfers. */ + bool want_recv, want_send; + 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)); + } + } +} + +static CURLcode cf_osslq_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct cf_osslq_ctx *ctx = cf->ctx; + struct cf_call_data save; + + switch(query) { + case CF_QUERY_MAX_CONCURRENT: { + /* TODO: how to get this? */ + CF_DATA_SAVE(save, cf, data); + *pres1 = 100; + CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1); + CF_DATA_RESTORE(cf, save); + return CURLE_OK; + } + case CF_QUERY_CONNECT_REPLY_MS: + if(ctx->got_first_byte) { + timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at); + *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX; + } + else + *pres1 = -1; + return CURLE_OK; + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + if(ctx->got_first_byte) + *when = ctx->first_byte_at; + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + if(cf->connected) + *when = ctx->handshake_at; + return CURLE_OK; + } + default: + break; + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +struct Curl_cftype Curl_cft_http3 = { + "HTTP/3", + CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX, + 0, + cf_osslq_destroy, + cf_osslq_connect, + cf_osslq_close, + Curl_cf_def_get_host, + cf_osslq_adjust_pollset, + cf_osslq_data_pending, + cf_osslq_send, + cf_osslq_recv, + cf_osslq_data_event, + cf_osslq_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_osslq_query, +}; + +CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai) +{ + struct cf_osslq_ctx *ctx = NULL; + struct Curl_cfilter *cf = NULL, *udp_cf = NULL; + CURLcode result; + + (void)data; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + cf_osslq_ctx_clear(ctx); + + result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); + if(result) + goto out; + + result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); + if(result) + goto out; + + cf->conn = conn; + udp_cf->conn = cf->conn; + udp_cf->sockindex = cf->sockindex; + cf->next = udp_cf; + +out: + *pcf = (!result)? cf : NULL; + if(result) { + if(udp_cf) + Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); + Curl_safefree(cf); + Curl_safefree(ctx); + } + return result; +} + +bool Curl_conn_is_osslq(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex) +{ + struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL; + + (void)data; + for(; cf; cf = cf->next) { + if(cf->cft == &Curl_cft_http3) + return TRUE; + if(cf->cft->flags & CF_TYPE_IP_CONNECT) + return FALSE; + } + return FALSE; +} + +/* + * Store ngtcp2 version info in this buffer. + */ +void Curl_osslq_ver(char *p, size_t len) +{ + const nghttp3_info *ht3 = nghttp3_version(0); + (void)msnprintf(p, len, "nghttp3/%s", ht3->version_str); +} + +#endif /* USE_OPENSSL_QUIC && USE_NGHTTP3 */ diff --git a/libs/libcurl/src/vquic/curl_osslq.h b/libs/libcurl/src/vquic/curl_osslq.h new file mode 100644 index 0000000000..f34d84baf8 --- /dev/null +++ b/libs/libcurl/src/vquic/curl_osslq.h @@ -0,0 +1,51 @@ +#ifndef HEADER_CURL_VQUIC_CURL_OSSLQ_H +#define HEADER_CURL_VQUIC_CURL_OSSLQ_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) + +#ifdef HAVE_NETINET_UDP_H +#include +#endif + +struct Curl_cfilter; + +#include "urldata.h" + +void Curl_osslq_ver(char *p, size_t len); + +CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai); + +bool Curl_conn_is_osslq(const struct Curl_easy *data, + const struct connectdata *conn, + int sockindex); +#endif + +#endif /* HEADER_CURL_VQUIC_CURL_OSSLQ_H */ diff --git a/libs/libcurl/src/vquic/curl_quiche.c b/libs/libcurl/src/vquic/curl_quiche.c index 9cf0617f11..263b9180f7 100644 --- a/libs/libcurl/src/vquic/curl_quiche.c +++ b/libs/libcurl/src/vquic/curl_quiche.c @@ -43,6 +43,7 @@ #include "http1.h" #include "vquic.h" #include "vquic_int.h" +#include "vquic-tls.h" #include "curl_quiche.h" #include "transfer.h" #include "inet_pton.h" @@ -84,31 +85,22 @@ void Curl_quiche_ver(char *p, size_t len) (void)msnprintf(p, len, "quiche/%s", quiche_version()); } -static void keylog_callback(const SSL *ssl, const char *line) -{ - (void)ssl; - Curl_tls_keylog_write_line(line); -} - struct cf_quiche_ctx { struct cf_quic_ctx q; struct ssl_peer peer; + struct quic_tls_ctx tls; quiche_conn *qconn; quiche_config *cfg; quiche_h3_conn *h3c; quiche_h3_config *h3config; uint8_t scid[QUICHE_MAX_CONN_ID_LEN]; - SSL_CTX *sslctx; - SSL *ssl; struct curltime started_at; /* time the current attempt started */ struct curltime handshake_at; /* time connect handshake finished */ - 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 */ curl_off_t data_recvd; uint64_t max_idle_ms; /* max idle time for QUIC conn */ BIT(goaway); /* got GOAWAY from server */ - BIT(got_first_byte); /* if first byte was received */ BIT(x509_store_setup); /* if x509 store has been set up */ }; @@ -123,121 +115,25 @@ static void quiche_debug_log(const char *line, void *argp) static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx) { if(ctx) { - vquic_ctx_free(&ctx->q); - if(ctx->qconn) - quiche_conn_free(ctx->qconn); - if(ctx->h3config) - quiche_h3_config_free(ctx->h3config); if(ctx->h3c) quiche_h3_conn_free(ctx->h3c); + if(ctx->h3config) + quiche_h3_config_free(ctx->h3config); + if(ctx->qconn) + quiche_conn_free(ctx->qconn); if(ctx->cfg) quiche_config_free(ctx->cfg); - Curl_bufcp_free(&ctx->stream_bufcp); + /* quiche just freed ctx->tls.ssl */ + ctx->tls.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); memset(ctx, 0, sizeof(*ctx)); } } -static CURLcode quic_x509_store_setup(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_quiche_ctx *ctx = cf->ctx; - struct ssl_primary_config *conn_config; - - conn_config = Curl_ssl_cf_get_primary_config(cf); - if(!conn_config) - return CURLE_FAILED_INIT; - - if(!ctx->x509_store_setup) { - if(conn_config->verifypeer) { - const char * const ssl_cafile = conn_config->CAfile; - const char * const ssl_capath = conn_config->CApath; - if(ssl_cafile || ssl_capath) { - SSL_CTX_set_verify(ctx->sslctx, SSL_VERIFY_PEER, NULL); - /* tell OpenSSL where to find CA certificates that are used to verify - the server's certificate. */ - if(!SSL_CTX_load_verify_locations(ctx->sslctx, ssl_cafile, - ssl_capath)) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate verify locations:" - " CAfile: %s CApath: %s", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - return CURLE_SSL_CACERT_BADFILE; - } - infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); - infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); - } -#ifdef CURL_CA_FALLBACK - else { - /* verifying the peer without any CA certificates won't work so - use openssl's built-in default as fallback */ - SSL_CTX_set_default_verify_paths(ctx->sslctx); - } -#endif - } - ctx->x509_store_setup = TRUE; - } - return CURLE_OK; -} - -static CURLcode quic_ssl_setup(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct cf_quiche_ctx *ctx = cf->ctx; - struct ssl_primary_config *conn_config; - CURLcode result; - - conn_config = Curl_ssl_cf_get_primary_config(cf); - if(!conn_config) - return CURLE_FAILED_INIT; - - result = Curl_ssl_peer_init(&ctx->peer, cf); - if(result) - return result; - - DEBUGASSERT(!ctx->sslctx); - ctx->sslctx = SSL_CTX_new(TLS_method()); - if(!ctx->sslctx) - return CURLE_OUT_OF_MEMORY; - - SSL_CTX_set_alpn_protos(ctx->sslctx, - (const uint8_t *)QUICHE_H3_APPLICATION_PROTOCOL, - sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1); - - SSL_CTX_set_default_verify_paths(ctx->sslctx); - - /* 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->sslctx, keylog_callback); - } - - if(conn_config->curves && - !SSL_CTX_set1_curves_list(ctx->sslctx, conn_config->curves)) { - failf(data, "failed setting curves list for QUIC: '%s'", - conn_config->curves); - return CURLE_SSL_CIPHER; - } - - ctx->ssl = SSL_new(ctx->sslctx); - if(!ctx->ssl) - return CURLE_QUIC_CONNECT_ERROR; - - SSL_set_app_data(ctx->ssl, cf); - - if(ctx->peer.sni) { - if(!SSL_set_tlsext_host_name(ctx->ssl, ctx->peer.sni)) { - failf(data, "Failed set SNI"); - SSL_free(ctx->ssl); - ctx->ssl = NULL; - return CURLE_QUIC_CONNECT_ERROR; - } - } - - return CURLE_OK; -} - /** * All about the H3 internals of a stream */ @@ -337,8 +233,8 @@ static void drain_stream(struct Curl_cfilter *cf, bits = CURL_CSELECT_IN; if(stream && !stream->send_closed && stream->upload_left) bits |= CURL_CSELECT_OUT; - if(data->state.dselect_bits != bits) { - data->state.dselect_bits = bits; + if(data->state.select_bits != bits) { + data->state.select_bits = bits; Curl_expire(data, 0, EXPIRE_RUN_NOW); } } @@ -668,7 +564,7 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, return CURLE_OK; } else if(QUICHE_ERR_TLS_FAIL == nread) { - long verify_ok = SSL_get_verify_result(ctx->ssl); + long verify_ok = SSL_get_verify_result(ctx->tls.ssl); if(verify_ok != X509_V_OK) { failf(r->data, "SSL certificate problem: %s", X509_verify_cert_error_string(verify_ok)); @@ -696,7 +592,7 @@ static CURLcode cf_process_ingress(struct Curl_cfilter *cf, CURLcode result; DEBUGASSERT(ctx->qconn); - result = quic_x509_store_setup(cf, data); + result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); if(result) return result; @@ -836,7 +732,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf, if(stream->reset) { failf(data, "HTTP/3 stream %" PRId64 " reset by server", stream->id); - *err = stream->resp_got_header? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; + *err = stream->resp_got_header? CURLE_PARTIAL_FILE : CURLE_HTTP3; CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, was reset -> %d", stream->id, *err); } @@ -846,7 +742,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf, " all response header fields, treated as error", stream->id); /* *err = CURLE_PARTIAL_FILE; */ - *err = CURLE_RECV_ERROR; + *err = CURLE_HTTP3; CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, closed incomplete" " -> %d", stream->id, *err); } @@ -1078,6 +974,28 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data, goto out; stream = H3_STREAM_CTX(data); } + else if(stream->closed) { + if(stream->resp_hds_complete) { + /* sending request body on a stream that has been closed by the + * server. If the server has send us a final response, we should + * silently discard the send data. + * This happens for example on redirects where the server, instead + * of reading the full request body just closed the stream after + * 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" + "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) " + "-> stream closed", stream->id, len); + *err = CURLE_HTTP3; + nwritten = -1; + goto out; + } else { bool eof = (stream->upload_left >= 0 && (curl_off_t)len >= stream->upload_left); @@ -1095,20 +1013,11 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data, nwritten = -1; goto out; } - else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE && - stream->closed && stream->resp_hds_complete) { - /* sending request body on a stream that has been closed by the - * server. If the server has send us a final response, we should - * silently discard the send data. - * This happens for example on redirects where the server, instead - * of reading the full request body just closed the stream after - * 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" - "on closed stream with response", stream->id); - *err = CURLE_OK; - nwritten = (ssize_t)len; + else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) { + CURL_TRC_CF(data, cf, "[%" PRId64 "] 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) { @@ -1167,16 +1076,19 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf, struct easy_pollset *ps) { struct cf_quiche_ctx *ctx = cf->ctx; - bool want_recv = CURL_WANT_RECV(data); - bool want_send = CURL_WANT_SEND(data); + bool want_recv, want_send; + + if(!ctx->qconn) + return; - if(ctx->qconn && (want_recv || want_send)) { + 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); 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 = stream && stream->id >= 0 && + s_exhaust = want_send && stream && stream->id >= 0 && (stream->quic_flow_blocked || !stream_is_writeable(cf, data)); want_recv = (want_recv || c_exhaust || s_exhaust); want_send = (!s_exhaust && want_send) || @@ -1261,66 +1173,6 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf, return result; } -static CURLcode cf_verify_peer(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_quiche_ctx *ctx = cf->ctx; - struct ssl_primary_config *conn_config; - CURLcode result = CURLE_OK; - - conn_config = Curl_ssl_cf_get_primary_config(cf); - if(!conn_config) - return CURLE_FAILED_INIT; - - cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - cf->conn->httpversion = 30; - cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; - - if(conn_config->verifyhost) { - X509 *server_cert; - server_cert = SSL_get_peer_certificate(ctx->ssl); - if(!server_cert) { - result = CURLE_PEER_FAILED_VERIFICATION; - goto out; - } - result = Curl_ossl_verifyhost(data, cf->conn, &ctx->peer, server_cert); - X509_free(server_cert); - if(result) - goto out; - } - else - CURL_TRC_CF(data, cf, "Skipped certificate verification"); - - ctx->h3config = quiche_h3_config_new(); - if(!ctx->h3config) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - /* Create a new HTTP/3 connection on the QUIC connection. */ - ctx->h3c = quiche_h3_conn_new_with_transport(ctx->qconn, ctx->h3config); - if(!ctx->h3c) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - if(data->set.ssl.certinfo) - /* asked to gather certificate info */ - (void)Curl_ossl_certchain(data, ctx->ssl); - -out: - if(result) { - if(ctx->h3config) { - quiche_h3_config_free(ctx->h3config); - ctx->h3config = NULL; - } - if(ctx->h3c) { - quiche_h3_conn_free(ctx->h3c); - ctx->h3c = NULL; - } - } - return result; -} - static CURLcode cf_connect_start(struct Curl_cfilter *cf, struct Curl_easy *data) { @@ -1348,6 +1200,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, if(result) return result; + result = Curl_ssl_peer_init(&ctx->peer, cf); + if(result) + return result; + ctx->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION); if(!ctx->cfg) { failf(data, "can't create quiche config"); @@ -1376,9 +1232,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1); - DEBUGASSERT(!ctx->ssl); - DEBUGASSERT(!ctx->sslctx); - result = quic_ssl_setup(cf, data); + result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, + QUICHE_H3_APPLICATION_PROTOCOL, + sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1, + NULL, cf); if(result) return result; @@ -1399,7 +1256,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->ssl, false); + ctx->cfg, ctx->tls.ssl, false); if(!ctx->qconn) { failf(data, "can't create quiche connection"); return CURLE_OUT_OF_MEMORY; @@ -1438,6 +1295,18 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, return CURLE_OK; } +static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_quiche_ctx *ctx = cf->ctx; + + cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + cf->conn->httpversion = 30; + cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; + + return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); +} + static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, struct Curl_easy *data, bool blocking, bool *done) @@ -1489,9 +1358,21 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, ctx->handshake_at = ctx->q.last_op; CURL_TRC_CF(data, cf, "handshake complete after %dms", (int)Curl_timediff(ctx->handshake_at, ctx->started_at)); - result = cf_verify_peer(cf, data); + result = cf_quiche_verify_peer(cf, data); if(!result) { CURL_TRC_CF(data, cf, "peer verified"); + ctx->h3config = quiche_h3_config_new(); + if(!ctx->h3config) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + /* Create a new HTTP/3 connection on the QUIC connection. */ + ctx->h3c = quiche_h3_conn_new_with_transport(ctx->qconn, ctx->h3config); + if(!ctx->h3c) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } cf->connected = TRUE; cf->conn->alpn = CURL_HTTP_VERSION_3; *done = TRUE; @@ -1564,8 +1445,8 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, return CURLE_OK; } case CF_QUERY_CONNECT_REPLY_MS: - if(ctx->got_first_byte) { - timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at); + if(ctx->q.got_first_byte) { + timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at); *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX; } else @@ -1573,8 +1454,8 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, return CURLE_OK; case CF_QUERY_TIMER_CONNECT: { struct curltime *when = pres2; - if(ctx->got_first_byte) - *when = ctx->first_byte_at; + if(ctx->q.got_first_byte) + *when = ctx->q.first_byte_at; return CURLE_OK; } case CF_QUERY_TIMER_APPCONNECT: { diff --git a/libs/libcurl/src/vquic/vquic-tls.c b/libs/libcurl/src/vquic/vquic-tls.c new file mode 100644 index 0000000000..29c23ef58c --- /dev/null +++ b/libs/libcurl/src/vquic/vquic-tls.c @@ -0,0 +1,609 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(ENABLE_QUIC) && \ + (defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL)) + +#ifdef USE_OPENSSL +#include +#include "vtls/openssl.h" +#elif defined(USE_GNUTLS) +#include +#include +#include +#include +#include +#include "vtls/gtls.h" +#elif defined(USE_WOLFSSL) +#include +#include +#include +#include "vtls/wolfssl.h" +#endif + +#include "urldata.h" +#include "curl_trc.h" +#include "cfilters.h" +#include "multiif.h" +#include "vtls/keylog.h" +#include "vtls/vtls.h" +#include "vquic-tls.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifndef ARRAYSIZE +#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) +#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) +{ + (void)ssl; + Curl_tls_keylog_write_line(line); +} +#endif + +static CURLcode curl_wssl_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; + + conn_config = Curl_ssl_cf_get_primary_config(cf); + if(!conn_config) { + result = CURLE_FAILED_INIT; + goto out; + } + + ctx->ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); + if(!ctx->ssl_ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + if(ctx_setup) { + result = ctx_setup(ctx, cf, data); + if(result) + goto out; + } + + wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx); + + if(wolfSSL_CTX_set_cipher_list(ctx->ssl_ctx, conn_config->cipher_list13 ? + conn_config->cipher_list13 : + QUIC_CIPHERS) != 1) { + char error_buffer[256]; + ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer)); + failf(data, "wolfSSL failed to set ciphers: %s", error_buffer); + goto out; + } + + if(wolfSSL_CTX_set1_groups_list(ctx->ssl_ctx, conn_config->curves ? + conn_config->curves : + (char *)QUIC_GROUPS) != 1) { + failf(data, "wolfSSL failed to set curves"); + goto out; + } + + /* Open the file if a TLS or QUIC backend has not done this before. */ + Curl_tls_keylog_open(); + if(Curl_tls_keylog_enabled()) { +#if defined(HAVE_SECRET_CALLBACK) + wolfSSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback); +#else + failf(data, "wolfSSL was built without keylog callback"); + goto out; +#endif + } + + if(conn_config->verifypeer) { + const char * const ssl_cafile = conn_config->CAfile; + const char * const ssl_capath = conn_config->CApath; + + wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL); + if(ssl_cafile || ssl_capath) { + /* tell wolfSSL where to find CA certificates that are used to verify + the server's certificate. */ + int rc = + wolfSSL_CTX_load_verify_locations_ex(ctx->ssl_ctx, ssl_cafile, + ssl_capath, + WOLFSSL_LOAD_FLAG_IGNORE_ERR); + if(SSL_SUCCESS != rc) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + goto out; + } + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } +#ifdef CURL_CA_FALLBACK + else { + /* verifying the peer without any CA certificates won't work so + use wolfssl's built-in default as fallback */ + wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx); + } +#endif + } + else { + wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_NONE, NULL); + } + + /* give application a chance to interfere with SSL set up. */ + if(data->set.ssl.fsslctx) { + 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; +} + +/** SSL callbacks ***/ + +static CURLcode curl_wssl_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) +{ + (void)data; + DEBUGASSERT(!ctx->ssl); + DEBUGASSERT(ctx->ssl_ctx); + ctx->ssl = wolfSSL_new(ctx->ssl_ctx); + + wolfSSL_set_app_data(ctx->ssl, user_data); + wolfSSL_set_connect_state(ctx->ssl); + wolfSSL_set_quic_use_legacy_codepoint(ctx->ssl, 0); + + if(alpn) + wolfSSL_set_alpn_protos(ctx->ssl, (const unsigned char *)alpn, + (int)alpn_len); + + if(peer->sni) { + wolfSSL_UseSNI(ctx->ssl, WOLFSSL_SNI_HOST_NAME, + peer->sni, (unsigned short)strlen(peer->sni)); + } + + return CURLE_OK; +} +#endif /* defined(USE_WOLFSSL) */ + +CURLcode Curl_vquic_tls_init(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) +{ + 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); +#elif defined(USE_GNUTLS) + (void)result; + return curl_gtls_init_ctx(ctx, cf, data, peer, alpn, alpn_len, + ctx_setup, user_data); +#elif defined(USE_WOLFSSL) + result = curl_wssl_init_ctx(ctx, cf, data, ctx_setup); + if(result) + return result; + + return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, 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) +{ +#ifdef USE_OPENSSL + if(ctx->ssl) + SSL_free(ctx->ssl); + if(ctx->ssl_ctx) + SSL_CTX_free(ctx->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); + } +#elif defined(USE_WOLFSSL) + if(ctx->ssl) + wolfSSL_free(ctx->ssl); + if(ctx->ssl_ctx) + wolfSSL_CTX_free(ctx->ssl_ctx); +#endif + memset(ctx, 0, sizeof(*ctx)); +} + +CURLcode Curl_vquic_tls_before_recv(struct quic_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(result) + return result; + ctx->x509_store_setup = TRUE; + } +#else + (void)ctx; (void)cf; (void)data; +#endif + return CURLE_OK; +} + +CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ssl_peer *peer) +{ + struct ssl_primary_config *conn_config; + CURLcode result = CURLE_OK; + + conn_config = Curl_ssl_cf_get_primary_config(cf); + 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; +#elif defined(USE_GNUTLS) + 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"); + } + 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) */ diff --git a/libs/libcurl/src/vquic/vquic-tls.h b/libs/libcurl/src/vquic/vquic-tls.h new file mode 100644 index 0000000000..60dc7b18b6 --- /dev/null +++ b/libs/libcurl/src/vquic/vquic-tls.h @@ -0,0 +1,98 @@ +#ifndef HEADER_CURL_VQUIC_TLS_H +#define HEADER_CURL_VQUIC_TLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "bufq.h" + +#if defined(ENABLE_QUIC) && \ + (defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL)) + +struct quic_tls_ctx { +#ifdef USE_OPENSSL + SSL_CTX *ssl_ctx; + SSL *ssl; +#elif defined(USE_GNUTLS) + struct gtls_instance *gtls; +#elif defined(USE_WOLFSSL) + WOLFSSL_CTX *ssl_ctx; + WOLFSSL *ssl; +#endif + BIT(x509_store_setup); /* if x509 store has been set up */ +}; + +/** + * Callback passed to `Curl_vquic_tls_init()` that can + * do early initializations on the not otherwise configured TLS + * instances created. This varies by TLS backend: + * - 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); + +/** + * Initialize the QUIC TLS instances based of the SSL configurations + * for the connection filter, transfer and peer. + * @param ctx the TLS context to initialize + * @param cf the connection filter involved + * @param data the transfer involved + * @param peer the peer that will be connected to + * @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 + */ +CURLcode Curl_vquic_tls_init(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); + +/** + * Cleanup all data that has been initialized. + */ +void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx); + +CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data); + +/** + * 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, + struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ssl_peer *peer); + +#endif /* !ENABLE_QUIC && (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 8b9c1ae223..8a6bb99aac 100644 --- a/libs/libcurl/src/vquic/vquic.c +++ b/libs/libcurl/src/vquic/vquic.c @@ -46,6 +46,7 @@ #include "curl_trc.h" #include "curl_msh3.h" #include "curl_ngtcp2.h" +#include "curl_osslq.h" #include "curl_quiche.h" #include "rand.h" #include "vquic.h" @@ -74,6 +75,8 @@ void Curl_quic_ver(char *p, size_t len) { #if defined(USE_NGTCP2) && defined(USE_NGHTTP3) Curl_ngtcp2_ver(p, len); +#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) + Curl_osslq_ver(p, len); #elif defined(USE_QUICHE) Curl_quiche_ver(p, len); #elif defined(USE_MSH3) @@ -179,7 +182,7 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf, qctx->no_gso = TRUE; return send_packet_no_gso(cf, data, qctx, pkt, pktlen, gsolen, psent); } - /* FALLTHROUGH */ + FALLTHROUGH(); default: failf(data, "sendmsg() returned %zd (errno %d)", sent, SOCKERRNO); return CURLE_SEND_ERROR; @@ -543,8 +546,13 @@ CURLcode vquic_recv_packets(struct Curl_cfilter *cf, #else result = recvfrom_packets(cf, data, qctx, max_pkts, recv_cb, userp); #endif - if(!result) + if(!result) { + if(!qctx->got_first_byte) { + qctx->got_first_byte = TRUE; + qctx->first_byte_at = qctx->last_op; + } qctx->last_io = qctx->last_op; + } return result; } @@ -603,6 +611,8 @@ CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf, DEBUGASSERT(transport == TRNSPRT_QUIC); #if defined(USE_NGTCP2) && defined(USE_NGHTTP3) return Curl_cf_ngtcp2_create(pcf, data, conn, ai); +#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) + return Curl_cf_osslq_create(pcf, data, conn, ai); #elif defined(USE_QUICHE) return Curl_cf_quiche_create(pcf, data, conn, ai); #elif defined(USE_MSH3) @@ -622,6 +632,8 @@ bool Curl_conn_is_http3(const struct Curl_easy *data, { #if defined(USE_NGTCP2) && defined(USE_NGHTTP3) return Curl_conn_is_ngtcp2(data, conn, sockindex); +#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) + return Curl_conn_is_osslq(data, conn, sockindex); #elif defined(USE_QUICHE) return Curl_conn_is_quiche(data, conn, sockindex); #elif defined(USE_MSH3) diff --git a/libs/libcurl/src/vquic/vquic_int.h b/libs/libcurl/src/vquic/vquic_int.h index dc50593cd9..ce7983029a 100644 --- a/libs/libcurl/src/vquic/vquic_int.h +++ b/libs/libcurl/src/vquic/vquic_int.h @@ -40,6 +40,7 @@ struct cf_quic_ctx { socklen_t local_addrlen; /* length of local address */ struct bufq sendbuf; /* buffer for sending one or more packets */ + struct curltime first_byte_at; /* when first byte was recvd */ struct curltime last_op; /* last (attempted) send/recv operation */ struct curltime last_io; /* last successful socket IO */ size_t gsolen; /* length of individual packets in send buf */ @@ -48,7 +49,8 @@ struct cf_quic_ctx { #ifdef DEBUGBUILD int wblock_percent; /* percent of writes doing EAGAIN */ #endif - bool no_gso; /* do not use gso on sending */ + BIT(got_first_byte); /* if first byte was received */ + BIT(no_gso); /* do not use gso on sending */ }; CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx); diff --git a/libs/libcurl/src/vssh/libssh.c b/libs/libcurl/src/vssh/libssh.c index 71a64cd5e8..59b8bf872b 100644 --- a/libs/libcurl/src/vssh/libssh.c +++ b/libs/libcurl/src/vssh/libssh.c @@ -31,6 +31,8 @@ #include +/* in 0.10.0 or later, ignore deprecated warnings */ +#define SSH_SUPPRESS_DEPRECATED #include #include @@ -89,14 +91,6 @@ #include "curl_memory.h" #include "memdebug.h" -/* in 0.10.0 or later, ignore deprecated warnings */ -#if defined(__GNUC__) && \ - (LIBSSH_VERSION_MINOR >= 10) || \ - (LIBSSH_VERSION_MAJOR > 0) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - /* A recent macro provided by libssh. Or make our own. */ #ifndef SSH_STRING_FREE_CHAR #define SSH_STRING_FREE_CHAR(x) \ @@ -167,7 +161,7 @@ const struct Curl_handler Curl_handler_scp = { ZERO_NULL, /* domore_getsock */ myssh_getsock, /* perform_getsock */ scp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_SSH, /* defport */ @@ -194,7 +188,7 @@ const struct Curl_handler Curl_handler_sftp = { ZERO_NULL, /* domore_getsock */ myssh_getsock, /* perform_getsock */ sftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_SSH, /* defport */ @@ -445,11 +439,8 @@ static int myssh_is_known(struct Curl_easy *data) keymatch = CURLKHMATCH_OK; break; case SSH_KNOWN_HOSTS_OTHER: - /* fallthrough */ case SSH_KNOWN_HOSTS_NOT_FOUND: - /* fallthrough */ case SSH_KNOWN_HOSTS_UNKNOWN: - /* fallthrough */ case SSH_KNOWN_HOSTS_ERROR: keymatch = CURLKHMATCH_MISSING; break; @@ -465,7 +456,6 @@ static int myssh_is_known(struct Curl_easy *data) keymatch = CURLKHMATCH_OK; break; case SSH_SERVER_FILE_NOT_FOUND: - /* fallthrough */ case SSH_SERVER_NOT_KNOWN: keymatch = CURLKHMATCH_MISSING; break; @@ -629,7 +619,7 @@ restart: if(rc < 0) return SSH_ERROR; - /* FALLTHROUGH */ + FALLTHROUGH(); case 1: sshc->kbd_state = 1; @@ -704,7 +694,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) ssh_set_blocking(sshc->ssh_session, 0); state(data, SSH_S_STARTUP); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_S_STARTUP: rc = ssh_connect(sshc->ssh_session); @@ -719,7 +709,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) state(data, SSH_HOSTKEY); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_HOSTKEY: rc = myssh_is_known(data); @@ -729,7 +719,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) } state(data, SSH_AUTHLIST); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_AUTHLIST:{ sshc->authed = FALSE; @@ -910,7 +900,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) break; } state(data, SSH_AUTH_PASS); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_AUTH_PASS: rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd); @@ -973,7 +963,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) break; } state(data, SSH_SFTP_REALPATH); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_SFTP_REALPATH: /* * Get the "home" directory @@ -1161,22 +1151,22 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) } else if(statvfs) { #ifdef _MSC_VER - #define LIBSSH_VFS_SIZE_MASK "I64u" + #define CURL_LIBSSH_VFS_SIZE_MASK "I64u" #else - #define LIBSSH_VFS_SIZE_MASK PRIu64 + #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64 #endif char *tmp = aprintf("statvfs:\n" - "f_bsize: %" LIBSSH_VFS_SIZE_MASK "\n" - "f_frsize: %" LIBSSH_VFS_SIZE_MASK "\n" - "f_blocks: %" LIBSSH_VFS_SIZE_MASK "\n" - "f_bfree: %" LIBSSH_VFS_SIZE_MASK "\n" - "f_bavail: %" LIBSSH_VFS_SIZE_MASK "\n" - "f_files: %" LIBSSH_VFS_SIZE_MASK "\n" - "f_ffree: %" LIBSSH_VFS_SIZE_MASK "\n" - "f_favail: %" LIBSSH_VFS_SIZE_MASK "\n" - "f_fsid: %" LIBSSH_VFS_SIZE_MASK "\n" - "f_flag: %" LIBSSH_VFS_SIZE_MASK "\n" - "f_namemax: %" LIBSSH_VFS_SIZE_MASK "\n", + "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n", statvfs->f_bsize, statvfs->f_frsize, statvfs->f_blocks, statvfs->f_bfree, statvfs->f_bavail, statvfs->f_files, @@ -1318,13 +1308,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) } /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ do { + char scratch[4*1024]; size_t readthisamountnow = - (data->state.resume_from - passed > data->set.buffer_size) ? - (size_t)data->set.buffer_size : - curlx_sotouz(data->state.resume_from - passed); + (data->state.resume_from - passed > + (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread = - data->state.fread_func(data->state.buffer, 1, + data->state.fread_func(scratch, 1, readthisamountnow, data->state.in); passed += actuallyread; @@ -1370,7 +1361,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) /* we want to use the _sending_ function even when the socket turns out readable as the underlying libssh sftp send function will deal with both accordingly */ - conn->cselect_bits = CURL_CSELECT_OUT; + data->state.select_bits = CURL_CSELECT_OUT; /* since we don't really wait for anything at this point, we want the state machine to move on as soon as possible so we set a very short @@ -1560,7 +1551,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) sshc->readdir_longentry = NULL; state(data, SSH_SFTP_READDIR_BOTTOM); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_SFTP_READDIR_BOTTOM: if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1)) result = CURLE_OUT_OF_MEMORY; @@ -1740,7 +1731,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) /* we want to use the _receiving_ function even when the socket turns out writableable as the underlying libssh recv function will deal with both accordingly */ - conn->cselect_bits = CURL_CSELECT_IN; + data->state.select_bits = CURL_CSELECT_IN; if(result) { /* this should never occur; the close state should be entered @@ -1868,7 +1859,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) /* we want to use the _sending_ function even when the socket turns out readable as the underlying libssh scp send function will deal with both accordingly */ - conn->cselect_bits = CURL_CSELECT_OUT; + data->state.select_bits = CURL_CSELECT_OUT; state(data, SSH_STOP); @@ -1884,7 +1875,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) break; } state(data, SSH_SCP_DOWNLOAD); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_SCP_DOWNLOAD:{ curl_off_t bytecount; @@ -1908,7 +1899,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) /* we want to use the _receiving_ function even when the socket turns out writableable as the underlying libssh recv function will deal with both accordingly */ - conn->cselect_bits = CURL_CSELECT_IN; + data->state.select_bits = CURL_CSELECT_IN; state(data, SSH_STOP); break; @@ -1948,7 +1939,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) ssh_set_blocking(sshc->ssh_session, 0); state(data, SSH_SESSION_DISCONNECT); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_SESSION_DISCONNECT: /* during weird times when we've been prematurely aborted, the channel @@ -1971,7 +1962,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) data->state.most_recent_ftp_entrypath = NULL; state(data, SSH_SESSION_FREE); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_SESSION_FREE: if(sshc->ssh_session) { ssh_free(sshc->ssh_session); @@ -2022,7 +2013,6 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) break; case SSH_QUIT: - /* fallthrough, just stop! */ default: /* internal error */ sshc->nextstate = SSH_NO_STATE; @@ -2613,7 +2603,7 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex, return -1; } - /* FALLTHROUGH */ + FALLTHROUGH(); case 1: conn->proto.sshc.sftp_recv_state = 1; @@ -2957,10 +2947,4 @@ void Curl_ssh_version(char *buffer, size_t buflen) (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0)); } -#if defined(__GNUC__) && \ - (LIBSSH_VERSION_MINOR >= 10) || \ - (LIBSSH_VERSION_MAJOR > 0) -#pragma GCC diagnostic pop -#endif - #endif /* USE_LIBSSH */ diff --git a/libs/libcurl/src/vssh/libssh2.c b/libs/libcurl/src/vssh/libssh2.c index 430f4e2ef3..32c6764be9 100644 --- a/libs/libcurl/src/vssh/libssh2.c +++ b/libs/libcurl/src/vssh/libssh2.c @@ -138,7 +138,7 @@ const struct Curl_handler Curl_handler_scp = { ZERO_NULL, /* domore_getsock */ ssh_getsock, /* perform_getsock */ scp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ssh_attach, /* attach */ PORT_SSH, /* defport */ @@ -167,7 +167,7 @@ const struct Curl_handler Curl_handler_sftp = { ZERO_NULL, /* domore_getsock */ ssh_getsock, /* perform_getsock */ sftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ssh_attach, /* attach */ PORT_SSH, /* defport */ @@ -589,10 +589,9 @@ static CURLcode ssh_knownhost(struct Curl_easy *data) switch(rc) { default: /* unknown return codes will equal reject */ - /* FALLTHROUGH */ case CURLKHSTAT_REJECT: state(data, SSH_SESSION_FREE); - /* FALLTHROUGH */ + FALLTHROUGH(); case CURLKHSTAT_DEFER: /* DEFER means bail out but keep the SSH_HOSTKEY state */ result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; @@ -601,9 +600,8 @@ static CURLcode ssh_knownhost(struct Curl_easy *data) /* remove old host+key that doesn't match */ if(host) libssh2_knownhost_del(sshc->kh, host); - /* FALLTHROUGH */ + FALLTHROUGH(); case CURLKHSTAT_FINE: - /* FALLTHROUGH */ case CURLKHSTAT_FINE_ADD_TO_FILE: /* proceed */ if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) { @@ -997,7 +995,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) } state(data, SSH_S_STARTUP); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_S_STARTUP: rc = session_startup(sshc->ssh_session, sock); @@ -1016,7 +1014,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) state(data, SSH_HOSTKEY); - /* FALLTHROUGH */ + FALLTHROUGH(); case SSH_HOSTKEY: /* * Before we authenticate we should check the hostkey's fingerprint @@ -1961,22 +1959,22 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) } else if(rc == 0) { #ifdef _MSC_VER - #define LIBSSH2_VFS_SIZE_MASK "I64u" + #define CURL_LIBSSH2_VFS_SIZE_MASK "I64u" #else - #define LIBSSH2_VFS_SIZE_MASK "llu" + #define CURL_LIBSSH2_VFS_SIZE_MASK "llu" #endif char *tmp = aprintf("statvfs:\n" - "f_bsize: %" LIBSSH2_VFS_SIZE_MASK "\n" - "f_frsize: %" LIBSSH2_VFS_SIZE_MASK "\n" - "f_blocks: %" LIBSSH2_VFS_SIZE_MASK "\n" - "f_bfree: %" LIBSSH2_VFS_SIZE_MASK "\n" - "f_bavail: %" LIBSSH2_VFS_SIZE_MASK "\n" - "f_files: %" LIBSSH2_VFS_SIZE_MASK "\n" - "f_ffree: %" LIBSSH2_VFS_SIZE_MASK "\n" - "f_favail: %" LIBSSH2_VFS_SIZE_MASK "\n" - "f_fsid: %" LIBSSH2_VFS_SIZE_MASK "\n" - "f_flag: %" LIBSSH2_VFS_SIZE_MASK "\n" - "f_namemax: %" LIBSSH2_VFS_SIZE_MASK "\n", + "f_bsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_frsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_blocks: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_bfree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_bavail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_files: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_ffree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_favail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_fsid: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_flag: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n" + "f_namemax: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n", statvfs.f_bsize, statvfs.f_frsize, statvfs.f_blocks, statvfs.f_bfree, statvfs.f_bavail, statvfs.f_files, @@ -2160,14 +2158,15 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) } /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ do { + char scratch[4*1024]; size_t readthisamountnow = - (data->state.resume_from - passed > data->set.buffer_size) ? - (size_t)data->set.buffer_size : - curlx_sotouz(data->state.resume_from - passed); + (data->state.resume_from - passed > + (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread; Curl_set_in_callback(data, true); - actuallyread = data->state.fread_func(data->state.buffer, 1, + actuallyread = data->state.fread_func(scratch, 1, readthisamountnow, data->state.in); Curl_set_in_callback(data, false); @@ -2213,7 +2212,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) /* we want to use the _sending_ function even when the socket turns out readable as the underlying libssh2 sftp send function will deal with both accordingly */ - conn->cselect_bits = CURL_CSELECT_OUT; + data->state.select_bits = CURL_CSELECT_OUT; /* since we don't really wait for anything at this point, we want the state machine to move on as soon as possible so we set a very short @@ -2602,7 +2601,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) /* we want to use the _receiving_ function even when the socket turns out writableable as the underlying libssh2 recv function will deal with both accordingly */ - conn->cselect_bits = CURL_CSELECT_IN; + data->state.select_bits = CURL_CSELECT_IN; if(result) { /* this should never occur; the close state should be entered @@ -2757,7 +2756,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) /* we want to use the _sending_ function even when the socket turns out readable as the underlying libssh2 scp send function will deal with both accordingly */ - conn->cselect_bits = CURL_CSELECT_OUT; + data->state.select_bits = CURL_CSELECT_OUT; state(data, SSH_STOP); } @@ -2819,7 +2818,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) /* we want to use the _receiving_ function even when the socket turns out writableable as the underlying libssh2 recv function will deal with both accordingly */ - conn->cselect_bits = CURL_CSELECT_IN; + data->state.select_bits = CURL_CSELECT_IN; if(result) { state(data, SSH_SCP_CHANNEL_FREE); @@ -3024,7 +3023,6 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) break; case SSH_QUIT: - /* fallthrough, just stop! */ default: /* internal error */ sshc->nextstate = SSH_NO_STATE; @@ -3292,6 +3290,27 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) #ifndef CURL_DISABLE_PROXY if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) { + /* + Setup libssh2 callbacks to make it read/write TLS from the socket. + + ssize_t + recvcb(libssh2_socket_t sock, void *buffer, size_t length, + int flags, void **abstract); + + ssize_t + sendcb(libssh2_socket_t sock, const void *buffer, size_t length, + int flags, void **abstract); + + */ +#if LIBSSH2_VERSION_NUM >= 0x010b01 + infof(data, "Uses HTTPS proxy"); + libssh2_session_callback_set2(sshc->ssh_session, + LIBSSH2_CALLBACK_RECV, + (libssh2_cb_generic *)ssh_tls_recv); + libssh2_session_callback_set2(sshc->ssh_session, + LIBSSH2_CALLBACK_SEND, + (libssh2_cb_generic *)ssh_tls_send); +#else /* * This crazy union dance is here to avoid assigning a void pointer a * function pointer as it is invalid C. The problem is of course that @@ -3312,22 +3331,11 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) sshsend.sendptr = ssh_tls_send; infof(data, "Uses HTTPS proxy"); - /* - Setup libssh2 callbacks to make it read/write TLS from the socket. - - ssize_t - recvcb(libssh2_socket_t sock, void *buffer, size_t length, - int flags, void **abstract); - - ssize_t - sendcb(libssh2_socket_t sock, const void *buffer, size_t length, - int flags, void **abstract); - - */ libssh2_session_callback_set(sshc->ssh_session, LIBSSH2_CALLBACK_RECV, sshrecv.recvp); libssh2_session_callback_set(sshc->ssh_session, LIBSSH2_CALLBACK_SEND, sshsend.sendp); +#endif /* Store the underlying TLS recv/send function pointers to be used when reading from the proxy */ diff --git a/libs/libcurl/src/vssh/wolfssh.c b/libs/libcurl/src/vssh/wolfssh.c index 346d1875b0..5583398915 100644 --- a/libs/libcurl/src/vssh/wolfssh.c +++ b/libs/libcurl/src/vssh/wolfssh.c @@ -42,6 +42,7 @@ #include "select.h" #include "multiif.h" #include "warnless.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -92,7 +93,7 @@ const struct Curl_handler Curl_handler_scp = { ZERO_NULL, /* domore_getsock */ wssh_getsock, /* perform_getsock */ wscp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_SSH, /* defport */ @@ -121,7 +122,7 @@ const struct Curl_handler Curl_handler_sftp = { ZERO_NULL, /* domore_getsock */ wssh_getsock, /* perform_getsock */ wsftp_disconnect, /* disconnect */ - ZERO_NULL, /* readwrite */ + ZERO_NULL, /* write_resp */ ZERO_NULL, /* connection_check */ ZERO_NULL, /* attach connection */ PORT_SSH, /* defport */ @@ -512,15 +513,9 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) return CURLE_OK; } else if(name && (rc == WS_SUCCESS)) { - sshc->homedir = malloc(name->fSz + 1); - if(!sshc->homedir) { + sshc->homedir = Curl_memdup0(name->fName, name->fSz); + if(!sshc->homedir) sshc->actualcode = CURLE_OUT_OF_MEMORY; - } - else { - memcpy(sshc->homedir, name->fName, name->fSz); - sshc->homedir[name->fSz] = 0; - infof(data, "wolfssh SFTP realpath succeeded"); - } wolfSSH_SFTPNAME_list_free(name); state(data, SSH_STOP); return CURLE_OK; @@ -646,14 +641,15 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) } /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ do { + char scratch[4*1024]; size_t readthisamountnow = - (data->state.resume_from - passed > data->set.buffer_size) ? - (size_t)data->set.buffer_size : - curlx_sotouz(data->state.resume_from - passed); + (data->state.resume_from - passed > + (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); size_t actuallyread; Curl_set_in_callback(data, true); - actuallyread = data->state.fread_func(data->state.buffer, 1, + actuallyread = data->state.fread_func(scratch, 1, readthisamountnow, data->state.in); Curl_set_in_callback(data, false); @@ -699,7 +695,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) /* we want to use the _sending_ function even when the socket turns out readable as the underlying libssh2 sftp send function will deal with both accordingly */ - conn->cselect_bits = CURL_CSELECT_OUT; + data->state.select_bits = CURL_CSELECT_OUT; /* since we don't really wait for anything at this point, we want the state machine to move on as soon as possible so we set a very short @@ -795,7 +791,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) /* we want to use the _receiving_ function even when the socket turns out writableable as the underlying libssh2 recv function will deal with both accordingly */ - conn->cselect_bits = CURL_CSELECT_IN; + data->state.select_bits = CURL_CSELECT_IN; if(result) { /* this should never occur; the close state should be entered diff --git a/libs/libcurl/src/vtls/bearssl.c b/libs/libcurl/src/vtls/bearssl.c index 3bda30328c..924802c61f 100644 --- a/libs/libcurl/src/vtls/bearssl.c +++ b/libs/libcurl/src/vtls/bearssl.c @@ -509,7 +509,6 @@ static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data, { uint16_t selected_ciphers[NUM_OF_CIPHERS]; size_t selected_count = 0; - char cipher_name[CIPHER_NAME_BUF_LEN]; const char *cipher_start = ciphers; const char *cipher_end; size_t i, j; @@ -518,41 +517,48 @@ static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data, 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 == '\0') + if(!*cipher_start) break; cipher_end = cipher_start; - while(*cipher_end != '\0' && !is_separator(*cipher_end)) + while(*cipher_end && !is_separator(*cipher_end)) ++cipher_end; - j = cipher_end - cipher_start < CIPHER_NAME_BUF_LEN - 1 ? - cipher_end - cipher_start : CIPHER_NAME_BUF_LEN - 1; - strncpy(cipher_name, cipher_start, j); - cipher_name[j] = '\0'; + + 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_name, "TLS_", 4)) { + if(strncasecompare(cipher, "TLS_", 4)) { for(i = 0; i < NUM_OF_CIPHERS && - !strcasecompare(cipher_name, ciphertable[i].name); ++i); + (strlen(ciphertable[i].name) == clen) && + !strncasecompare(cipher, ciphertable[i].name, clen); ++i); } else { for(i = 0; i < NUM_OF_CIPHERS && - !strcasecompare(cipher_name, ciphertable[i].alias_name); ++i); + (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", cipher_name); + infof(data, "BearSSL: unknown cipher in list: %.*s", + (int)clen, cipher); continue; } /* No duplicates allowed */ for(j = 0; j < selected_count && - selected_ciphers[j] != ciphertable[i].num; j++); + selected_ciphers[j] != ciphertable[i].num; j++); if(j < selected_count) { - infof(data, "BearSSL: duplicate cipher in list: %s", cipher_name); + infof(data, "BearSSL: duplicate cipher in list: %.*s", + (int)clen, cipher); continue; } diff --git a/libs/libcurl/src/vtls/gtls.c b/libs/libcurl/src/vtls/gtls.c index bd78eb5030..dd40380738 100644 --- a/libs/libcurl/src/vtls/gtls.c +++ b/libs/libcurl/src/vtls/gtls.c @@ -584,13 +584,9 @@ CURLcode gtls_client_init(struct Curl_easy *data, /* Only add SRP to the cipher list if SRP is requested. Otherwise * GnuTLS will disable TLS 1.3 support. */ if(config->username) { - size_t len = strlen(prioritylist); - - char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1); + char *prioritysrp = aprintf("%s:" GNUTLS_SRP, prioritylist); if(!prioritysrp) return CURLE_OUT_OF_MEMORY; - strcpy(prioritysrp, prioritylist); - strcpy(prioritysrp + len, ":" GNUTLS_SRP); rc = gnutls_priority_set_direct(gtls->session, prioritysrp, &err); free(prioritysrp); @@ -822,16 +818,17 @@ Curl_gtls_verifyserver(struct Curl_easy *data, char certname[65] = ""; /* limited to 64 chars by ASN.1 */ size_t size; time_t certclock; - const char *ptr; int rc; CURLcode result = CURLE_OK; #ifndef CURL_DISABLE_VERBOSE_STRINGS + const char *ptr; unsigned int algo; unsigned int bits; gnutls_protocol_t version = gnutls_protocol_get_version(session); #endif long * const certverifyresult = &ssl_config->certverifyresult; +#ifndef CURL_DISABLE_VERBOSE_STRINGS /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), gnutls_cipher_get(session), @@ -839,6 +836,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data, infof(data, "SSL connection using %s / %s", gnutls_protocol_get_name(version), ptr); +#endif /* This function will return the peer's raw certificate (chain) as sent by the peer. These certificates are in raw format (DER encoded for diff --git a/libs/libcurl/src/vtls/mbedtls.c b/libs/libcurl/src/vtls/mbedtls.c index 292c933291..c008eace9b 100644 --- a/libs/libcurl/src/vtls/mbedtls.c +++ b/libs/libcurl/src/vtls/mbedtls.c @@ -36,6 +36,13 @@ /* Define this to enable lots of debugging for mbedTLS */ /* #define MBEDTLS_DEBUG */ +#ifdef __GNUC__ +#pragma GCC diagnostic push +/* mbedTLS (as of v3.5.1) has a duplicate function declaration + in its public headers. Disable the warning that detects it. */ +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + #include #if MBEDTLS_VERSION_NUMBER >= 0x02040000 #include @@ -56,6 +63,10 @@ # endif #endif +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + #include "urldata.h" #include "sendf.h" #include "inet_pton.h" @@ -67,6 +78,7 @@ #include "select.h" #include "multiif.h" #include "mbedtls_threadlock.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -153,7 +165,6 @@ static void mbed_debug(void *context, int level, const char *f_name, infof(data, "%s", line); (void) level; } -#else #endif static int mbedtls_bio_cf_write(void *bio, @@ -165,6 +176,9 @@ static int mbedtls_bio_cf_write(void *bio, CURLcode result; DEBUGASSERT(data); + if(!data) + return 0; + nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result); CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d", blen, nwritten, result); @@ -182,6 +196,8 @@ static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen) CURLcode result; DEBUGASSERT(data); + if(!data) + return 0; /* OpenSSL catches this case, so should we. */ if(!buf) return 0; @@ -367,11 +383,10 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null terminated even when provided the exact length, forcing us to waste extra memory here. */ - unsigned char *newblob = malloc(ca_info_blob->len + 1); + unsigned char *newblob = Curl_memdup0(ca_info_blob->data, + ca_info_blob->len); if(!newblob) return CURLE_OUT_OF_MEMORY; - memcpy(newblob, ca_info_blob->data, ca_info_blob->len); - newblob[ca_info_blob->len] = 0; /* null terminate */ ret = mbedtls_x509_crt_parse(&backend->cacert, newblob, ca_info_blob->len + 1); free(newblob); @@ -441,11 +456,10 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null terminated even when provided the exact length, forcing us to waste extra memory here. */ - unsigned char *newblob = malloc(ssl_cert_blob->len + 1); + unsigned char *newblob = Curl_memdup0(ssl_cert_blob->data, + ssl_cert_blob->len); if(!newblob) return CURLE_OUT_OF_MEMORY; - memcpy(newblob, ssl_cert_blob->data, ssl_cert_blob->len); - newblob[ssl_cert_blob->len] = 0; /* null terminate */ ret = mbedtls_x509_crt_parse(&backend->clicert, newblob, ssl_cert_blob->len + 1); free(newblob); @@ -1207,6 +1221,9 @@ static int mbedtls_init(void) static void mbedtls_cleanup(void) { +#ifdef THREADING_SUPPORT + mbedtls_entropy_free(&ts_entropy); +#endif /* THREADING_SUPPORT */ (void)Curl_mbedtlsthreadlock_thread_cleanup(); } diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c index fcc4e4eb0b..be6780b7ed 100644 --- a/libs/libcurl/src/vtls/openssl.c +++ b/libs/libcurl/src/vtls/openssl.c @@ -954,8 +954,9 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size) #endif if(!*buf) { - strncpy(buf, (error ? "Unknown error" : "No error"), size); - buf[size - 1] = '\0'; + const char *msg = error ? "Unknown error" : "No error"; + if(strlen(msg) < size) + strcpy(buf, msg); } return buf; @@ -1087,6 +1088,7 @@ static int ssl_ui_reader(UI *ui, UI_STRING *uis) UI_set_result(ui, uis, password); return 1; } + FALLTHROUGH(); default: break; } @@ -1105,6 +1107,7 @@ static int ssl_ui_writer(UI *ui, UI_STRING *uis) (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { return 1; } + FALLTHROUGH(); default: break; } @@ -1522,7 +1525,7 @@ fail: case SSL_FILETYPE_PEM: if(cert_done) break; - /* FALLTHROUGH */ + FALLTHROUGH(); case SSL_FILETYPE_ASN1: cert_use_result = key_blob ? SSL_CTX_use_PrivateKey_blob(ctx, key_blob, file_type, key_passwd) : @@ -1752,7 +1755,7 @@ static int ossl_init(void) static void ossl_cleanup(void) { #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ - !defined(LIBRESSL_VERSION_NUMBER) + (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL) /* OpenSSL 1.1 deprecates all these cleanup functions and turns them into no-ops in OpenSSL 1.0 compatibility mode */ #else @@ -2848,7 +2851,7 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); return CURLE_NOT_BUILT_IN; #endif - /* FALLTHROUGH */ + FALLTHROUGH(); case CURL_SSLVERSION_TLSv1_2: #if OPENSSL_VERSION_NUMBER >= 0x1000100FL *ctx_options |= SSL_OP_NO_TLSv1_1; @@ -2856,7 +2859,7 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, failf(data, OSSL_PACKAGE " was built without TLS 1.2 support"); return CURLE_NOT_BUILT_IN; #endif - /* FALLTHROUGH */ + FALLTHROUGH(); case CURL_SSLVERSION_TLSv1_1: #if OPENSSL_VERSION_NUMBER >= 0x1000100FL *ctx_options |= SSL_OP_NO_TLSv1; @@ -2864,7 +2867,7 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, failf(data, OSSL_PACKAGE " was built without TLS 1.1 support"); return CURLE_NOT_BUILT_IN; #endif - /* FALLTHROUGH */ + FALLTHROUGH(); case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1: break; @@ -2875,12 +2878,12 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, #if OPENSSL_VERSION_NUMBER >= 0x1000100FL *ctx_options |= SSL_OP_NO_TLSv1_1; #endif - /* FALLTHROUGH */ + FALLTHROUGH(); case CURL_SSLVERSION_MAX_TLSv1_1: #if OPENSSL_VERSION_NUMBER >= 0x1000100FL *ctx_options |= SSL_OP_NO_TLSv1_2; #endif - /* FALLTHROUGH */ + FALLTHROUGH(); case CURL_SSLVERSION_MAX_TLSv1_2: #ifdef TLS1_3_VERSION *ctx_options |= SSL_OP_NO_TLSv1_3; @@ -3174,6 +3177,8 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf, bool imported_native_ca = false; bool imported_ca_info_blob = false; + CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d", + ssl_cafile? ssl_cafile : "none", !!ca_info_blob); if(!store) return CURLE_OUT_OF_MEMORY; @@ -4346,6 +4351,20 @@ static CURLcode servercert(struct Curl_cfilter *cf, /* don't do this after Session ID reuse */ result = verifystatus(cf, data); if(result) { + /* when verifystatus failed, remove the session id from the cache again + if present */ + if(!Curl_ssl_cf_is_proxy(cf)) { + void *old_ssl_sessionid = NULL; + bool incache; + Curl_ssl_sessionid_lock(data); + incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL)); + if(incache) { + infof(data, "Remove session ID again from cache"); + Curl_ssl_delsessionid(data, old_ssl_sessionid); + } + Curl_ssl_sessionid_unlock(data); + } + X509_free(backend->server_cert); backend->server_cert = NULL; return result; @@ -4592,10 +4611,10 @@ static ssize_t ossl_send(struct Curl_cfilter *cf, ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)); else if(sockerr) Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); - else { - strncpy(error_buffer, SSL_ERROR_to_str(err), sizeof(error_buffer)); - error_buffer[sizeof(error_buffer) - 1] = '\0'; - } + else + msnprintf(error_buffer, sizeof(error_buffer), "%s", + SSL_ERROR_to_str(err)); + failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d", error_buffer, sockerr); *curlcode = CURLE_SEND_ERROR; @@ -4688,10 +4707,9 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf, ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)); else if(sockerr && err == SSL_ERROR_SYSCALL) Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); - else { - strncpy(error_buffer, SSL_ERROR_to_str(err), sizeof(error_buffer)); - error_buffer[sizeof(error_buffer) - 1] = '\0'; - } + else + msnprintf(error_buffer, sizeof(error_buffer), "%s", + SSL_ERROR_to_str(err)); failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d", error_buffer, sockerr); *curlcode = CURLE_RECV_ERROR; diff --git a/libs/libcurl/src/vtls/rustls.c b/libs/libcurl/src/vtls/rustls.c index d30325d098..f0eb1443e6 100644 --- a/libs/libcurl/src/vtls/rustls.c +++ b/libs/libcurl/src/vtls/rustls.c @@ -156,7 +156,7 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf, size_t errorlen; rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); failf(data, "rustls_connection_process_new_packets: %.*s", - errorlen, errorbuf); + (int)errorlen, errorbuf); *err = map_error(rresult); return -1; } @@ -225,7 +225,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, char errorbuf[255]; size_t errorlen; rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); - failf(data, "rustls_connection_read: %.*s", errorlen, errorbuf); + failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf); *err = CURLE_READ_ERROR; nread = -1; goto out; @@ -301,7 +301,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, &plainwritten); if(rresult != RUSTLS_RESULT_OK) { rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); - failf(data, "rustls_connection_write: %.*s", errorlen, errorbuf); + failf(data, "rustls_connection_write: %.*s", (int)errorlen, errorbuf); *err = CURLE_WRITE_ERROR; return -1; } @@ -459,7 +459,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, } if(result != RUSTLS_RESULT_OK) { rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen); - failf(data, "rustls_client_connection_new: %.*s", errorlen, errorbuf); + failf(data, "rustls_client_connection_new: %.*s", (int)errorlen, errorbuf); return CURLE_COULDNT_CONNECT; } rustls_connection_set_userdata(rconn, backend); @@ -563,8 +563,8 @@ cr_connect_common(struct Curl_cfilter *cf, return CURLE_SSL_CONNECT_ERROR; } if(blocking && 0 == what) { - failf(data, "rustls connection timeout after %d ms", - socket_check_timeout); + failf(data, "rustls connection timeout after %" + CURL_FORMAT_TIMEDIFF_T " ms", socket_check_timeout); return CURLE_OPERATION_TIMEDOUT; } if(0 == what) { diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c index c04f968f29..64a31f155d 100644 --- a/libs/libcurl/src/vtls/schannel.c +++ b/libs/libcurl/src/vtls/schannel.c @@ -439,6 +439,12 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path, return CURLE_OK; } #endif + +static bool algo(const char *check, char *namep, size_t nlen) +{ + return (strlen(check) == nlen) && !strncmp(check, namep, nlen); +} + static CURLcode schannel_acquire_credential_handle(struct Curl_cfilter *cf, struct Curl_easy *data) @@ -660,7 +666,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, cert_showfilename_error); else failf(data, "schannel: Failed to import cert file %s, " - "last error is 0x%x", + "last error is 0x%lx", cert_showfilename_error, errorcode); return CURLE_SSL_CERTPROBLEM; } @@ -671,7 +677,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, if(!client_certs[0]) { failf(data, "schannel: Failed to get certificate from file %s" - ", last error is 0x%x", + ", last error is 0x%lx", cert_showfilename_error, GetLastError()); CertCloseStore(cert_store, 0); return CURLE_SSL_CERTPROBLEM; @@ -684,10 +690,15 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name, cert_store_path); if(!cert_store) { - failf(data, "schannel: Failed to open cert store %x %s, " - "last error is 0x%x", - cert_store_name, cert_store_path, GetLastError()); + char *path_utf8 = + curlx_convert_tchar_to_UTF8(cert_store_path); + failf(data, "schannel: Failed to open cert store %lx %s, " + "last error is 0x%lx", + cert_store_name, + (path_utf8 ? path_utf8 : "(unknown)"), + GetLastError()); free(cert_store_path); + curlx_unicodefree(path_utf8); curlx_unicodefree(cert_path); return CURLE_SSL_CERTPROBLEM; } @@ -790,9 +801,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, char *startCur = ciphers13; int algCount = 0; - char tmp[LONGEST_ALG_ID] = { 0 }; char *nameEnd; - size_t n; disable_aes_gcm_sha384 = TRUE; disable_aes_gcm_sha256 = TRUE; @@ -801,40 +810,34 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, disable_aes_ccm_sha256 = TRUE; while(startCur && (0 != *startCur) && (algCount < remaining_ciphers)) { + size_t n; + char *namep; nameEnd = strchr(startCur, ':'); n = nameEnd ? (size_t)(nameEnd - startCur) : strlen(startCur); + namep = startCur; - /* reject too-long cipher names */ - if(n > (LONGEST_ALG_ID - 1)) { - failf(data, "schannel: Cipher name too long, not checked"); - return CURLE_SSL_CIPHER; - } - - strncpy(tmp, startCur, n); - tmp[n] = 0; - - if(disable_aes_gcm_sha384 - && !strcmp("TLS_AES_256_GCM_SHA384", tmp)) { + if(disable_aes_gcm_sha384 && + algo("TLS_AES_256_GCM_SHA384", namep, n)) { disable_aes_gcm_sha384 = FALSE; } else if(disable_aes_gcm_sha256 - && !strcmp("TLS_AES_128_GCM_SHA256", tmp)) { + && algo("TLS_AES_128_GCM_SHA256", namep, n)) { disable_aes_gcm_sha256 = FALSE; } else if(disable_chacha_poly - && !strcmp("TLS_CHACHA20_POLY1305_SHA256", tmp)) { + && algo("TLS_CHACHA20_POLY1305_SHA256", namep, n)) { disable_chacha_poly = FALSE; } else if(disable_aes_ccm_8_sha256 - && !strcmp("TLS_AES_128_CCM_8_SHA256", tmp)) { + && algo("TLS_AES_128_CCM_8_SHA256", namep, n)) { disable_aes_ccm_8_sha256 = FALSE; } else if(disable_aes_ccm_sha256 - && !strcmp("TLS_AES_128_CCM_SHA256", tmp)) { + && algo("TLS_AES_128_CCM_SHA256", namep, n)) { disable_aes_ccm_sha256 = FALSE; } else { - failf(data, "schannel: Unknown TLS 1.3 cipher: %s", tmp); + failf(data, "schannel: Unknown TLS 1.3 cipher: %.*s", (int)n, namep); return CURLE_SSL_CIPHER; } @@ -1195,9 +1198,8 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) cur += proto.len; *list_len = curlx_uitous(cur - list_start_index); - *extension_len = *list_len + - (unsigned short)sizeof(unsigned int) + - (unsigned short)sizeof(unsigned short); + *extension_len = (unsigned int)(*list_len + + sizeof(unsigned int) + sizeof(unsigned short)); InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); @@ -2332,10 +2334,10 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, else { #ifndef CURL_DISABLE_VERBOSE_STRINGS char buffer[STRERROR_LEN]; -#endif - *err = CURLE_RECV_ERROR; infof(data, "schannel: failed to read data from server: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); +#endif + *err = CURLE_RECV_ERROR; goto cleanup; } } diff --git a/libs/libcurl/src/vtls/schannel_verify.c b/libs/libcurl/src/vtls/schannel_verify.c index 0c9c00c16a..743f3b059e 100644 --- a/libs/libcurl/src/vtls/schannel_verify.c +++ b/libs/libcurl/src/vtls/schannel_verify.c @@ -172,7 +172,7 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store, /* Sanity check that the cert_context object is the right type */ if(CERT_QUERY_CONTENT_CERT != actual_content_type) { failf(data, - "schannel: unexpected content type '%d' when extracting " + "schannel: unexpected content type '%lu' when extracting " "certificate from CA file '%s'", actual_content_type, ca_file_text); result = CURLE_SSL_CACERT_BADFILE; @@ -753,7 +753,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, failf(data, "schannel: CertGetCertificateChain trust error" " CERT_TRUST_REVOCATION_STATUS_UNKNOWN"); else - failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x", + failf(data, "schannel: CertGetCertificateChain error mask: 0x%08lx", dwTrustErrorMask); result = CURLE_PEER_FAILED_VERIFICATION; } diff --git a/libs/libcurl/src/vtls/sectransp.c b/libs/libcurl/src/vtls/sectransp.c index 26b673016e..eb43d08c5b 100644 --- a/libs/libcurl/src/vtls/sectransp.c +++ b/libs/libcurl/src/vtls/sectransp.c @@ -906,7 +906,6 @@ static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection, return rtn; } -#ifndef CURL_DISABLE_VERBOSE_STRINGS CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) { /* The first ciphers in the ciphertable are continuous. Here we do small @@ -925,7 +924,6 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) } return ciphertable[SSL_NULL_WITH_NULL_NULL].name; } -#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ #if CURL_BUILD_MAC CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) @@ -2369,19 +2367,15 @@ static CURLcode verify_cert(struct Curl_cfilter *cf, const struct curl_blob *ca_info_blob, SSLContextRef ctx) { - int result; + CURLcode result; unsigned char *certbuf; size_t buflen; + bool free_certbuf = FALSE; if(ca_info_blob) { CURL_TRC_CF(data, cf, "verify_peer, CA from config blob"); - certbuf = (unsigned char *)malloc(ca_info_blob->len + 1); - if(!certbuf) { - return CURLE_OUT_OF_MEMORY; - } + certbuf = ca_info_blob->data; buflen = ca_info_blob->len; - memcpy(certbuf, ca_info_blob->data, ca_info_blob->len); - certbuf[ca_info_blob->len]='\0'; } else if(cafile) { CURL_TRC_CF(data, cf, "verify_peer, CA from file '%s'", cafile); @@ -2389,12 +2383,14 @@ static CURLcode verify_cert(struct Curl_cfilter *cf, failf(data, "SSL: failed to read or invalid CA certificate"); return CURLE_SSL_CACERT_BADFILE; } + free_certbuf = TRUE; } else return CURLE_SSL_CACERT_BADFILE; result = verify_cert_buf(cf, data, certbuf, buflen, ctx); - free(certbuf); + if(free_certbuf) + free(certbuf); return result; } diff --git a/libs/libcurl/src/vtls/vtls.c b/libs/libcurl/src/vtls/vtls.c index f37907c494..6deb512879 100644 --- a/libs/libcurl/src/vtls/vtls.c +++ b/libs/libcurl/src/vtls/vtls.c @@ -883,28 +883,21 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, size_t valuelen) { struct curl_certinfo *ci = &data->info.certs; - char *output; struct curl_slist *nl; CURLcode result = CURLE_OK; - size_t labellen = strlen(label); - size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */ + struct dynbuf build; - output = malloc(outlen); - if(!output) - return CURLE_OUT_OF_MEMORY; - - /* sprintf the label and colon */ - msnprintf(output, outlen, "%s:", label); + Curl_dyn_init(&build, 10000); - /* memcpy the value (it might not be null-terminated) */ - memcpy(&output[labellen + 1], value, valuelen); - - /* null-terminate the output */ - output[labellen + 1 + valuelen] = 0; + if(Curl_dyn_add(&build, label) || + Curl_dyn_addn(&build, ":", 1) || + Curl_dyn_addn(&build, value, valuelen)) + return CURLE_OUT_OF_MEMORY; - nl = Curl_slist_append_nodup(ci->certinfo[certnum], output); + nl = Curl_slist_append_nodup(ci->certinfo[certnum], + Curl_dyn_ptr(&build)); if(!nl) { - free(output); + Curl_dyn_free(&build); curl_slist_free_all(ci->certinfo[certnum]); result = CURLE_OUT_OF_MEMORY; } @@ -1002,7 +995,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, /* only do this if pinnedpubkey starts with "sha256//", length 8 */ if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { CURLcode encode; - size_t encodedlen = 0, pinkeylen; + size_t encodedlen = 0; char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos; unsigned char *sha256sumdigest; @@ -1030,13 +1023,11 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, infof(data, " public key hash: sha256//%s", encoded); /* it starts with sha256//, copy so we can modify it */ - pinkeylen = strlen(pinnedpubkey) + 1; - pinkeycopy = malloc(pinkeylen); + pinkeycopy = strdup(pinnedpubkey); if(!pinkeycopy) { Curl_safefree(encoded); return CURLE_OUT_OF_MEMORY; } - memcpy(pinkeycopy, pinnedpubkey, pinkeylen); /* point begin_pos to the copy, and start extracting keys */ begin_pos = pinkeycopy; do { @@ -1422,17 +1413,13 @@ static size_t multissl_version(char *buffer, size_t size) backends_len = p - backends; } - if(!size) - return 0; - - if(size <= backends_len) { - strncpy(buffer, backends, size - 1); - buffer[size - 1] = '\0'; - return size - 1; + if(size) { + if(backends_len < size) + strcpy(buffer, backends); + else + *buffer = 0; /* did not fit */ } - - strcpy(buffer, backends); - return backends_len; + return 0; } static int multissl_setup(const struct Curl_ssl *backend) @@ -1728,18 +1715,34 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf, { struct cf_call_data save; ssize_t nread; + size_t ntotal = 0; CF_DATA_SAVE(save, cf, data); *err = CURLE_OK; - nread = Curl_ssl->recv_plain(cf, data, buf, len, err); - if(nread > 0) { - DEBUGASSERT((size_t)nread <= len); - } - else if(nread == 0) { - /* eof */ + /* Do receive until we fill the buffer somehwhat or EGAIN, error or EOF */ + while(!ntotal || (len - ntotal) > (4*1024)) { *err = CURLE_OK; + nread = Curl_ssl->recv_plain(cf, data, buf + ntotal, len - ntotal, err); + if(nread < 0) { + if(*err == CURLE_AGAIN && ntotal > 0) { + /* we EAGAINed after having reed data, return the success amount */ + *err = CURLE_OK; + break; + } + /* we have a an error to report */ + goto out; + } + else if(nread == 0) { + /* eof */ + break; + } + ntotal += (size_t)nread; + DEBUGASSERT((size_t)ntotal <= len); } - CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len, nread, *err); + nread = (ssize_t)ntotal; +out: + CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len, + nread, *err); CF_DATA_RESTORE(cf, save); return nread; } @@ -1855,6 +1858,8 @@ struct Curl_cftype Curl_cft_ssl = { ssl_cf_query, }; +#ifndef CURL_DISABLE_PROXY + struct Curl_cftype Curl_cft_ssl_proxy = { "SSL-PROXY", CF_TYPE_SSL, @@ -1873,6 +1878,8 @@ struct Curl_cftype Curl_cft_ssl_proxy = { Curl_cf_def_query, }; +#endif /* !CURL_DISABLE_PROXY */ + static CURLcode cf_ssl_create(struct Curl_cfilter **pcf, struct Curl_easy *data, struct connectdata *conn) @@ -1980,8 +1987,12 @@ bool Curl_ssl_supports(struct Curl_easy *data, int option) static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf) { for(; cf; cf = cf->next) { - if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy) + if(cf->cft == &Curl_cft_ssl) + return cf; +#ifndef CURL_DISABLE_PROXY + if(cf->cft == &Curl_cft_ssl_proxy) return cf; +#endif } return NULL; } @@ -2027,7 +2038,12 @@ 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 } struct ssl_config_data * diff --git a/libs/libcurl/src/vtls/vtls.h b/libs/libcurl/src/vtls/vtls.h index 111d17f32c..0bfefd0502 100644 --- a/libs/libcurl/src/vtls/vtls.h +++ b/libs/libcurl/src/vtls/vtls.h @@ -228,7 +228,9 @@ struct ssl_primary_config * Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf); extern struct Curl_cftype Curl_cft_ssl; +#ifndef CURL_DISABLE_PROXY extern struct Curl_cftype Curl_cft_ssl_proxy; +#endif #else /* if not USE_SSL */ diff --git a/libs/libcurl/src/vtls/wolfssl.c b/libs/libcurl/src/vtls/wolfssl.c index 32681520a0..349d077ec4 100644 --- a/libs/libcurl/src/vtls/wolfssl.c +++ b/libs/libcurl/src/vtls/wolfssl.c @@ -583,12 +583,25 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(ssl_config->primary.clientcert && ssl_config->key) { int file_type = do_file_type(ssl_config->cert_type); - if(wolfSSL_CTX_use_certificate_file(backend->ctx, - ssl_config->primary.clientcert, - file_type) != 1) { - failf(data, "unable to use client certificate (no key or wrong pass" - " phrase?)"); - return CURLE_SSL_CONNECT_ERROR; + if(file_type == WOLFSSL_FILETYPE_PEM) { + if(wolfSSL_CTX_use_certificate_chain_file(backend->ctx, + ssl_config->primary.clientcert) + != 1) { + failf(data, "unable to use client certificate"); + return CURLE_SSL_CONNECT_ERROR; + } + } + else if(file_type == WOLFSSL_FILETYPE_ASN1) { + if(wolfSSL_CTX_use_certificate_file(backend->ctx, + ssl_config->primary.clientcert, + file_type) != 1) { + failf(data, "unable to use client certificate"); + return CURLE_SSL_CONNECT_ERROR; + } + } + else { + failf(data, "unknown cert type"); + return CURLE_BAD_FUNCTION_ARGUMENT; } file_type = do_file_type(ssl_config->key_type); @@ -1084,9 +1097,7 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf, *curlcode = CURLE_OK; return 0; case SSL_ERROR_NONE: - /* FALLTHROUGH */ case SSL_ERROR_WANT_READ: - /* FALLTHROUGH */ case SSL_ERROR_WANT_WRITE: /* there's data pending, re-invoke wolfSSL_read() */ CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen); diff --git a/libs/libcurl/src/vtls/x509asn1.c b/libs/libcurl/src/vtls/x509asn1.c index 0ce971c7ba..50a5fb5e9f 100644 --- a/libs/libcurl/src/vtls/x509asn1.c +++ b/libs/libcurl/src/vtls/x509asn1.c @@ -97,6 +97,11 @@ #define CURL_ASN1_CHARACTER_STRING 29 #define CURL_ASN1_BMP_STRING 30 +/* Max sixes */ + +#define MAX_X509_STR 10000 +#define MAX_X509_CERT 100000 + #ifdef WANT_EXTRACT_CERTINFO /* ASN.1 OID table entry. */ struct Curl_OID { @@ -255,61 +260,61 @@ static const struct Curl_OID *searchOID(const char *oid) } /* - * Convert an ASN.1 Boolean value into its string representation. Return the - * dynamically allocated string, or NULL if source is not an ASN.1 Boolean - * value. + * Convert an ASN.1 Boolean value into its string representation. + * + * Return error code. */ -static const char *bool2str(const char *beg, const char *end) +static CURLcode bool2str(struct dynbuf *store, + const char *beg, const char *end) { if(end - beg != 1) - return NULL; - return strdup(*beg? "TRUE": "FALSE"); + return CURLE_BAD_FUNCTION_ARGUMENT; + return Curl_dyn_add(store, *beg? "TRUE": "FALSE"); } /* * Convert an ASN.1 octet string to a printable string. - * Return the dynamically allocated string, or NULL if an error occurs. + * + * Return error code. */ -static const char *octet2str(const char *beg, const char *end) +static CURLcode octet2str(struct dynbuf *store, + const char *beg, const char *end) { - struct dynbuf buf; - CURLcode result; - - Curl_dyn_init(&buf, 3 * CURL_ASN1_MAX + 1); - result = Curl_dyn_addn(&buf, "", 0); + CURLcode result = CURLE_OK; while(!result && beg < end) - result = Curl_dyn_addf(&buf, "%02x:", (unsigned char) *beg++); + result = Curl_dyn_addf(store, "%02x:", (unsigned char) *beg++); - return Curl_dyn_ptr(&buf); + return result; } -static const char *bit2str(const char *beg, const char *end) +static CURLcode bit2str(struct dynbuf *store, + const char *beg, const char *end) { - /* Convert an ASN.1 bit string to a printable string. - Return the dynamically allocated string, or NULL if an error occurs. */ + /* Convert an ASN.1 bit string to a printable string. */ if(++beg > end) - return NULL; - return octet2str(beg, end); + return CURLE_BAD_FUNCTION_ARGUMENT; + return octet2str(store, beg, end); } /* * Convert an ASN.1 integer value into its string representation. - * Return the dynamically allocated string, or NULL if source is not an - * ASN.1 integer value. + * + * Returns error. */ -static const char *int2str(const char *beg, const char *end) +static CURLcode int2str(struct dynbuf *store, + const char *beg, const char *end) { unsigned int val = 0; size_t n = end - beg; if(!n) - return NULL; + return CURLE_BAD_FUNCTION_ARGUMENT; if(n > 4) - return octet2str(beg, end); + return octet2str(store, beg, end); /* Represent integers <= 32-bit as a single value. */ if(*beg & 0x80) @@ -318,25 +323,24 @@ static const char *int2str(const char *beg, const char *end) do val = (val << 8) | *(const unsigned char *) beg++; while(beg < end); - return curl_maprintf("%s%x", val >= 10? "0x": "", val); + return Curl_dyn_addf(store, "%s%x", val >= 10? "0x": "", val); } /* - * Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the - * destination buffer dynamically. The allocation size will normally be too - * large: this is to avoid buffer overflows. - * Terminate the string with a nul byte and return the converted - * string length. + * Convert from an ASN.1 typed string to UTF8. + * + * The result is stored in a dynbuf that is inited by the user of this + * function. + * + * Returns error. */ -static ssize_t -utf8asn1str(char **to, int type, const char *from, const char *end) +static CURLcode +utf8asn1str(struct dynbuf *to, int type, const char *from, const char *end) { size_t inlength = end - from; int size = 1; - size_t outlength; - char *buf; + CURLcode result = CURLE_OK; - *to = NULL; switch(type) { case CURL_ASN1_BMP_STRING: size = 2; @@ -352,133 +356,85 @@ utf8asn1str(char **to, int type, const char *from, const char *end) case CURL_ASN1_UTF8_STRING: break; default: - return -1; /* Conversion not supported. */ + return CURLE_BAD_FUNCTION_ARGUMENT; /* Conversion not supported. */ } if(inlength % size) - return -1; /* Length inconsistent with character size. */ - if(inlength / size > (SIZE_T_MAX - 1) / 4) - return -1; /* Too big. */ - buf = malloc(4 * (inlength / size) + 1); - if(!buf) - return -1; /* Not enough memory. */ + /* Length inconsistent with character size. */ + return CURLE_BAD_FUNCTION_ARGUMENT; if(type == CURL_ASN1_UTF8_STRING) { /* Just copy. */ - outlength = inlength; - if(outlength) - memcpy(buf, from, outlength); + if(inlength) + result = Curl_dyn_addn(to, from, inlength); } else { - for(outlength = 0; from < end;) { - int charsize; - unsigned int wc; + while(!result && (from < end)) { + char buf[4]; /* decode buffer */ + int charsize = 1; + unsigned int wc = 0; - wc = 0; switch(size) { case 4: wc = (wc << 8) | *(const unsigned char *) from++; wc = (wc << 8) | *(const unsigned char *) from++; - /* FALLTHROUGH */ + FALLTHROUGH(); case 2: wc = (wc << 8) | *(const unsigned char *) from++; - /* FALLTHROUGH */ + FALLTHROUGH(); default: /* case 1: */ wc = (wc << 8) | *(const unsigned char *) from++; } - charsize = 1; if(wc >= 0x00000080) { if(wc >= 0x00000800) { if(wc >= 0x00010000) { if(wc >= 0x00200000) { free(buf); - return -1; /* Invalid char. size for target encoding. */ + /* Invalid char. size for target encoding. */ + return CURLE_WEIRD_SERVER_REPLY; } - buf[outlength + 3] = (char) (0x80 | (wc & 0x3F)); + buf[3] = (char) (0x80 | (wc & 0x3F)); wc = (wc >> 6) | 0x00010000; charsize++; } - buf[outlength + 2] = (char) (0x80 | (wc & 0x3F)); + buf[2] = (char) (0x80 | (wc & 0x3F)); wc = (wc >> 6) | 0x00000800; charsize++; } - buf[outlength + 1] = (char) (0x80 | (wc & 0x3F)); + buf[1] = (char) (0x80 | (wc & 0x3F)); wc = (wc >> 6) | 0x000000C0; charsize++; } - buf[outlength] = (char) wc; - outlength += charsize; + buf[0] = (char) wc; + result = Curl_dyn_addn(to, buf, charsize); } } - buf[outlength] = '\0'; - *to = buf; - return outlength; -} - -/* - * Convert an ASN.1 String into its UTF-8 string representation. - * Return the dynamically allocated string, or NULL if an error occurs. - */ -static const char *string2str(int type, const char *beg, const char *end) -{ - char *buf; - if(utf8asn1str(&buf, type, beg, end) < 0) - return NULL; - return buf; -} - -/* - * Decimal ASCII encode unsigned integer `x' into the buflen sized buffer at - * buf. Return the total number of encoded digits, even if larger than - * `buflen'. - */ -static size_t encodeUint(char *buf, size_t buflen, unsigned int x) -{ - size_t i = 0; - unsigned int y = x / 10; - - if(y) { - i = encodeUint(buf, buflen, y); - x -= y * 10; - } - if(i < buflen) - buf[i] = (char) ('0' + x); - i++; - if(i < buflen) - buf[i] = '\0'; /* Store a terminator if possible. */ - return i; + return result; } /* * Convert an ASN.1 OID into its dotted string representation. - * Store the result in th `n'-byte buffer at `buf'. - * Return the converted string length, or 0 on errors. + * + * Return error code. */ -static size_t encodeOID(char *buf, size_t buflen, - const char *beg, const char *end) +static CURLcode encodeOID(struct dynbuf *store, + const char *beg, const char *end) { - size_t i; unsigned int x; unsigned int y; + CURLcode result = CURLE_OK; /* Process the first two numbers. */ y = *(const unsigned char *) beg++; x = y / 40; y -= x * 40; - i = encodeUint(buf, buflen, x); - if(i < buflen) - buf[i] = '.'; - i++; - if(i >= buflen) - i += encodeUint(NULL, 0, y); - else - i += encodeUint(buf + i, buflen - i, y); + + result = Curl_dyn_addf(store, "%u.%u", x, y); + if(result) + return result; /* Process the trailing numbers. */ while(beg < end) { - if(i < buflen) - buf[i] = '.'; - i++; x = 0; do { if(x & 0xFF000000) @@ -486,46 +442,42 @@ static size_t encodeOID(char *buf, size_t buflen, y = *(const unsigned char *) beg++; x = (x << 7) | (y & 0x7F); } while(y & 0x80); - if(i >= buflen) - i += encodeUint(NULL, 0, x); - else - i += encodeUint(buf + i, buflen - i, x); + result = Curl_dyn_addf(store, ".%u", x); } - if(i < buflen) - buf[i] = '\0'; - return i; + return result; } /* * Convert an ASN.1 OID into its dotted or symbolic string representation. - * Return the dynamically allocated string, or NULL if an error occurs. + * + * Return error code. */ -static const char *OID2str(const char *beg, const char *end, bool symbolic) +static CURLcode OID2str(struct dynbuf *store, + const char *beg, const char *end, bool symbolic) { - char *buf = NULL; + CURLcode result = CURLE_OK; if(beg < end) { - size_t buflen = encodeOID(NULL, 0, beg, end); - if(buflen) { - buf = malloc(buflen + 1); /* one extra for the zero byte */ - if(buf) { - encodeOID(buf, buflen, beg, end); - buf[buflen] = '\0'; - - if(symbolic) { - const struct Curl_OID *op = searchOID(buf); - if(op) { - free(buf); - buf = strdup(op->textoid); - } - } + if(symbolic) { + struct dynbuf buf; + Curl_dyn_init(&buf, MAX_X509_STR); + result = encodeOID(&buf, beg, end); + + if(!result) { + const struct Curl_OID *op = searchOID(Curl_dyn_ptr(&buf)); + if(op) + result = Curl_dyn_add(store, op->textoid); + Curl_dyn_free(&buf); } } + else + result = encodeOID(store, beg, end); } - return buf; + return result; } -static const char *GTime2str(const char *beg, const char *end) +static CURLcode GTime2str(struct dynbuf *store, + const char *beg, const char *end) { const char *tzp; const char *fracp; @@ -548,12 +500,12 @@ static const char *GTime2str(const char *beg, const char *end) break; case 2: sec1 = fracp[-2]; - /* FALLTHROUGH */ + FALLTHROUGH(); case 1: sec2 = fracp[-1]; break; default: - return NULL; + return CURLE_BAD_FUNCTION_ARGUMENT; } /* Scan for timezone, measure fractional seconds. */ @@ -582,7 +534,8 @@ static const char *GTime2str(const char *beg, const char *end) } tzl = end - tzp; - return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s", + return Curl_dyn_addf(store, + "%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s", beg, beg + 4, beg + 6, beg + 8, beg + 10, sec1, sec2, fracl? ".": "", (int)fracl, fracp, @@ -590,10 +543,12 @@ static const char *GTime2str(const char *beg, const char *end) } /* - * Convert an ASN.1 UTC time to a printable string. - * Return the dynamically allocated string, or NULL if an error occurs. + * Convert an ASN.1 UTC time to a printable string. + * + * Return error code. */ -static const char *UTime2str(const char *beg, const char *end) +static CURLcode UTime2str(struct dynbuf *store, + const char *beg, const char *end) { const char *tzp; size_t tzl; @@ -606,15 +561,16 @@ static const char *UTime2str(const char *beg, const char *end) switch(tzp - sec) { case 0: sec = "00"; + FALLTHROUGH(); case 2: break; default: - return NULL; + return CURLE_BAD_FUNCTION_ARGUMENT; } /* Process timezone. */ if(tzp >= end) - return NULL; + return CURLE_BAD_FUNCTION_ARGUMENT; if(*tzp == 'Z') { tzp = "GMT"; end = tzp + 3; @@ -623,7 +579,7 @@ static const char *UTime2str(const char *beg, const char *end) tzp++; tzl = end - tzp; - return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s", + return Curl_dyn_addf(store, "%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s", 20 - (*beg >= '5'), beg, beg + 2, beg + 4, beg + 6, beg + 8, sec, (int)tzl, tzp); @@ -631,34 +587,45 @@ static const char *UTime2str(const char *beg, const char *end) /* * Convert an ASN.1 element to a printable string. - * Return the dynamically allocated string, or NULL if an error occurs. + * + * Return error */ -static const char *ASN1tostr(struct Curl_asn1Element *elem, int type) +static CURLcode ASN1tostr(struct dynbuf *store, + struct Curl_asn1Element *elem, int type) { + CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; if(elem->constructed) - return NULL; /* No conversion of structured elements. */ + return CURLE_OK; /* No conversion of structured elements. */ if(!type) type = elem->tag; /* Type not forced: use element tag as type. */ switch(type) { case CURL_ASN1_BOOLEAN: - return bool2str(elem->beg, elem->end); + result = bool2str(store, elem->beg, elem->end); + break; case CURL_ASN1_INTEGER: case CURL_ASN1_ENUMERATED: - return int2str(elem->beg, elem->end); + result = int2str(store, elem->beg, elem->end); + break; case CURL_ASN1_BIT_STRING: - return bit2str(elem->beg, elem->end); + result = bit2str(store, elem->beg, elem->end); + break; case CURL_ASN1_OCTET_STRING: - return octet2str(elem->beg, elem->end); + result = octet2str(store, elem->beg, elem->end); + break; case CURL_ASN1_NULL: - return strdup(""); + result = Curl_dyn_addn(store, "", 1); + break; case CURL_ASN1_OBJECT_IDENTIFIER: - return OID2str(elem->beg, elem->end, TRUE); + result = OID2str(store, elem->beg, elem->end, TRUE); + break; case CURL_ASN1_UTC_TIME: - return UTime2str(elem->beg, elem->end); + result = UTime2str(store, elem->beg, elem->end); + break; case CURL_ASN1_GENERALIZED_TIME: - return GTime2str(elem->beg, elem->end); + result = GTime2str(store, elem->beg, elem->end); + break; case CURL_ASN1_UTF8_STRING: case CURL_ASN1_NUMERIC_STRING: case CURL_ASN1_PRINTABLE_STRING: @@ -667,87 +634,96 @@ static const char *ASN1tostr(struct Curl_asn1Element *elem, int type) case CURL_ASN1_VISIBLE_STRING: case CURL_ASN1_UNIVERSAL_STRING: case CURL_ASN1_BMP_STRING: - return string2str(type, elem->beg, elem->end); + result = utf8asn1str(store, type, elem->beg, elem->end); + break; } - return NULL; /* Unsupported. */ + return result; } /* - * ASCII encode distinguished name at `dn' into the `buflen'-sized buffer at - * `buf'. + * ASCII encode distinguished name at `dn' into the store dynbuf. * - * Returns the total string length, even if larger than `buflen' or -1 on - * error. + * Returns error. */ -static ssize_t encodeDN(char *buf, size_t buflen, struct Curl_asn1Element *dn) +static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn) { struct Curl_asn1Element rdn; struct Curl_asn1Element atv; struct Curl_asn1Element oid; struct Curl_asn1Element value; - size_t l = 0; const char *p1; const char *p2; const char *p3; const char *str; + CURLcode result = CURLE_OK; + bool added = FALSE; + struct dynbuf temp; + Curl_dyn_init(&temp, MAX_X509_STR); for(p1 = dn->beg; p1 < dn->end;) { p1 = getASN1Element(&rdn, p1, dn->end); - if(!p1) - return -1; + if(!p1) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; + } for(p2 = rdn.beg; p2 < rdn.end;) { p2 = getASN1Element(&atv, p2, rdn.end); - if(!p2) - return -1; + if(!p2) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; + } p3 = getASN1Element(&oid, atv.beg, atv.end); - if(!p3) - return -1; - if(!getASN1Element(&value, p3, atv.end)) - return -1; - str = ASN1tostr(&oid, 0); - if(!str) - return -1; + if(!p3) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; + } + if(!getASN1Element(&value, p3, atv.end)) { + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto error; + } + Curl_dyn_reset(&temp); + result = ASN1tostr(&temp, &oid, 0); + if(result) + goto error; + + str = Curl_dyn_ptr(&temp); /* Encode delimiter. If attribute has a short uppercase name, delimiter is ", ". */ - if(l) { - for(p3 = str; ISUPPER(*p3); p3++) - ; - for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) { - if(l < buflen) - buf[l] = *p3; - l++; - } + for(p3 = str; ISUPPER(*p3); p3++) + ; + if(added) { + if(p3 - str > 2) + result = Curl_dyn_addn(store, "/", 1); + else + result = Curl_dyn_addn(store, ", ", 2); + if(result) + goto error; } /* Encode attribute name. */ - for(p3 = str; *p3; p3++) { - if(l < buflen) - buf[l] = *p3; - l++; - } - free((char *) str); + result = Curl_dyn_add(store, str); + if(result) + goto error; /* Generate equal sign. */ - if(l < buflen) - buf[l] = '='; - l++; + result = Curl_dyn_addn(store, "=", 1); + if(result) + goto error; /* Generate value. */ - str = ASN1tostr(&value, 0); - if(!str) - return -1; - for(p3 = str; *p3; p3++) { - if(l < buflen) - buf[l] = *p3; - l++; - } - free((char *) str); + result = ASN1tostr(store, &value, 0); + if(result) + goto error; + Curl_dyn_reset(&temp); + added = TRUE; /* use separator for next */ } } +error: + Curl_dyn_free(&temp); - return l; + return result; } #endif /* WANT_EXTRACT_CERTINFO */ @@ -876,25 +852,9 @@ int Curl_parseX509(struct Curl_X509certificate *cert, #ifdef WANT_EXTRACT_CERTINFO -/* - * Copy at most 64-characters, terminate with a newline and returns the - * effective number of stored characters. - */ -static size_t copySubstring(char *to, const char *from) -{ - size_t i; - for(i = 0; i < 64; i++) { - to[i] = *from; - if(!*from++) - break; - } - - to[i++] = '\n'; - return i; -} - -static const char *dumpAlgo(struct Curl_asn1Element *param, - const char *beg, const char *end) +static CURLcode dumpAlgo(struct dynbuf *store, + struct Curl_asn1Element *param, + const char *beg, const char *end) { struct Curl_asn1Element oid; @@ -902,14 +862,16 @@ static const char *dumpAlgo(struct Curl_asn1Element *param, beg = getASN1Element(&oid, beg, end); if(!beg) - return NULL; + return CURLE_BAD_FUNCTION_ARGUMENT; param->header = NULL; param->tag = 0; param->beg = param->end = end; - if(beg < end) - if(!getASN1Element(param, beg, end)) - return NULL; - return OID2str(oid.beg, oid.end, TRUE); + if(beg < end) { + const char *p = getASN1Element(param, beg, end); + if(!p) + return CURLE_BAD_FUNCTION_ARGUMENT; + } + return OID2str(store, oid.beg, oid.end, TRUE); } /* @@ -926,24 +888,47 @@ static CURLcode ssl_push_certinfo(struct Curl_easy *data, return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen); } -/* return 0 on success, 1 on error */ -static int do_pubkey_field(struct Curl_easy *data, int certnum, - const char *label, struct Curl_asn1Element *elem) +/* + * This is a convenience function for push_certinfo_len that takes a + * dynbuf value. + * + * It also does the verbose output if !certnum. + */ +static CURLcode ssl_push_certinfo_dyn(struct Curl_easy *data, + int certnum, + const char *label, + struct dynbuf *ptr) { - const char *output; - CURLcode result = CURLE_OK; + size_t valuelen = Curl_dyn_len(ptr); + char *value = Curl_dyn_ptr(ptr); + + CURLcode result = Curl_ssl_push_certinfo_len(data, certnum, label, + value, valuelen); + + if(!certnum && !result) + infof(data, " %s: %s", label, value); + + return result; +} + +static CURLcode do_pubkey_field(struct Curl_easy *data, int certnum, + const char *label, + struct Curl_asn1Element *elem) +{ + CURLcode result; + struct dynbuf out; + + Curl_dyn_init(&out, MAX_X509_STR); /* Generate a certificate information record for the public key. */ - output = ASN1tostr(elem, 0); - if(output) { + result = ASN1tostr(&out, elem, 0); + if(!result) { if(data->set.ssl.certinfo) - result = ssl_push_certinfo(data, certnum, label, output); - if(!certnum && !result) - infof(data, " %s: %s", label, output); - free((char *) output); + result = ssl_push_certinfo_dyn(data, certnum, label, &out); + Curl_dyn_free(&out); } - return result ? 1 : 0; + return result; } /* return 0 on success, 1 on error */ @@ -964,7 +949,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, */ const size_t len = ((pubkey->end - pubkey->beg - 2) * 4); if(!certnum) - infof(data, " ECC Public Key (%lu bits)", len); + infof(data, " ECC Public Key (%zu bits)", len); if(data->set.ssl.certinfo) { char q[sizeof(len) * 8 / 3 + 1]; (void)msnprintf(q, sizeof(q), "%zu", len); @@ -998,7 +983,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, if(len > 32) elem.beg = q; /* Strip leading zero bytes. */ if(!certnum) - infof(data, " RSA Public Key (%lu bits)", len); + infof(data, " RSA Public Key (%zu bits)", len); if(data->set.ssl.certinfo) { char r[sizeof(len) * 8 / 3 + 1]; msnprintf(r, sizeof(r), "%zu", len); @@ -1049,24 +1034,12 @@ static int do_pubkey(struct Curl_easy *data, int certnum, /* * Convert an ASN.1 distinguished name into a printable string. - * Return the dynamically allocated string, or NULL if an error occurs. + * Return error. */ -static const char *DNtostr(struct Curl_asn1Element *dn) +static CURLcode DNtostr(struct dynbuf *store, + struct Curl_asn1Element *dn) { - char *buf = NULL; - ssize_t buflen = encodeDN(NULL, 0, dn); - - if(buflen >= 0) { - buf = malloc(buflen + 1); - if(buf) { - if(encodeDN(buf, buflen + 1, dn) == -1) { - free(buf); - return NULL; - } - buf[buflen] = '\0'; - } - } - return buf; + return encodeDN(store, dn); } CURLcode Curl_extract_certinfo(struct Curl_easy *data, @@ -1076,19 +1049,19 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, { struct Curl_X509certificate cert; struct Curl_asn1Element param; - const char *ccp; - char *cp1; - size_t cl1; - char *cp2; + char *certptr; + size_t clen; + struct dynbuf out; CURLcode result = CURLE_OK; unsigned int version; - size_t i; - size_t j; + const char *ptr; + int rc; if(!data->set.ssl.certinfo) if(certnum) return CURLE_OK; + Curl_dyn_init(&out, MAX_X509_STR); /* Prepare the certificate information for curl_easy_getinfo(). */ /* Extract the certificate ASN.1 elements. */ @@ -1096,135 +1069,126 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, return CURLE_PEER_FAILED_VERIFICATION; /* Subject. */ - ccp = DNtostr(&cert.subject); - if(!ccp) - return CURLE_OUT_OF_MEMORY; + result = DNtostr(&out, &cert.subject); + if(result) + goto done; if(data->set.ssl.certinfo) { - result = ssl_push_certinfo(data, certnum, "Subject", ccp); + result = ssl_push_certinfo_dyn(data, certnum, "Subject", &out); if(result) - return result; + goto done; } - if(!certnum) - infof(data, "%2d Subject: %s", certnum, ccp); - free((char *) ccp); + Curl_dyn_reset(&out); /* Issuer. */ - ccp = DNtostr(&cert.issuer); - if(!ccp) - return CURLE_OUT_OF_MEMORY; + result = DNtostr(&out, &cert.issuer); + if(result) + goto done; if(data->set.ssl.certinfo) { - result = ssl_push_certinfo(data, certnum, "Issuer", ccp); + result = ssl_push_certinfo_dyn(data, certnum, "Issuer", &out); + if(result) + goto done; } - if(!certnum) - infof(data, " Issuer: %s", ccp); - free((char *) ccp); - if(result) - return result; + Curl_dyn_reset(&out); /* Version (always fits in less than 32 bits). */ version = 0; - for(ccp = cert.version.beg; ccp < cert.version.end; ccp++) - version = (version << 8) | *(const unsigned char *) ccp; + for(ptr = cert.version.beg; ptr < cert.version.end; ptr++) + version = (version << 8) | *(const unsigned char *) ptr; if(data->set.ssl.certinfo) { - ccp = curl_maprintf("%x", version); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - result = ssl_push_certinfo(data, certnum, "Version", ccp); - free((char *) ccp); + result = Curl_dyn_addf(&out, "%x", version); + if(result) + goto done; + result = ssl_push_certinfo_dyn(data, certnum, "Version", &out); if(result) - return result; + goto done; + Curl_dyn_reset(&out); } - if(!certnum) - infof(data, " Version: %u (0x%x)", version + 1, version); /* Serial number. */ - ccp = ASN1tostr(&cert.serialNumber, 0); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - result = ssl_push_certinfo(data, certnum, "Serial Number", ccp); - if(!certnum) - infof(data, " Serial Number: %s", ccp); - free((char *) ccp); + result = ASN1tostr(&out, &cert.serialNumber, 0); if(result) - return result; + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Serial Number", &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); /* Signature algorithm .*/ - ccp = dumpAlgo(¶m, cert.signatureAlgorithm.beg, - cert.signatureAlgorithm.end); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - result = ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp); - if(!certnum) - infof(data, " Signature Algorithm: %s", ccp); - free((char *) ccp); + result = dumpAlgo(&out, ¶m, cert.signatureAlgorithm.beg, + cert.signatureAlgorithm.end); if(result) - return result; + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Signature Algorithm", + &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); /* Start Date. */ - ccp = ASN1tostr(&cert.notBefore, 0); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - result = ssl_push_certinfo(data, certnum, "Start Date", ccp); - if(!certnum) - infof(data, " Start Date: %s", ccp); - free((char *) ccp); + result = ASN1tostr(&out, &cert.notBefore, 0); if(result) - return result; + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Start Date", &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); /* Expire Date. */ - ccp = ASN1tostr(&cert.notAfter, 0); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - result = ssl_push_certinfo(data, certnum, "Expire Date", ccp); - if(!certnum) - infof(data, " Expire Date: %s", ccp); - free((char *) ccp); + result = ASN1tostr(&out, &cert.notAfter, 0); if(result) - return result; + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Expire Date", &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); /* Public Key Algorithm. */ - ccp = dumpAlgo(¶m, cert.subjectPublicKeyAlgorithm.beg, - cert.subjectPublicKeyAlgorithm.end); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - result = ssl_push_certinfo(data, certnum, "Public Key Algorithm", - ccp); - if(!result) { - int ret; - if(!certnum) - infof(data, " Public Key Algorithm: %s", ccp); - ret = do_pubkey(data, certnum, ccp, ¶m, &cert.subjectPublicKey); - if(ret) - result = CURLE_OUT_OF_MEMORY; /* the most likely error */ - } - free((char *) ccp); + result = dumpAlgo(&out, ¶m, cert.subjectPublicKeyAlgorithm.beg, + cert.subjectPublicKeyAlgorithm.end); if(result) - return result; + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Public Key Algorithm", + &out); + if(result) + goto done; + } + + rc = do_pubkey(data, certnum, Curl_dyn_ptr(&out), + ¶m, &cert.subjectPublicKey); + if(rc) { + result = CURLE_OUT_OF_MEMORY; /* the most likely error */ + goto done; + } + Curl_dyn_reset(&out); /* Signature. */ - ccp = ASN1tostr(&cert.signature, 0); - if(!ccp) - return CURLE_OUT_OF_MEMORY; - if(data->set.ssl.certinfo) - result = ssl_push_certinfo(data, certnum, "Signature", ccp); - if(!certnum) - infof(data, " Signature: %s", ccp); - free((char *) ccp); + result = ASN1tostr(&out, &cert.signature, 0); if(result) - return result; + goto done; + if(data->set.ssl.certinfo) { + result = ssl_push_certinfo_dyn(data, certnum, "Signature", &out); + if(result) + goto done; + } + Curl_dyn_reset(&out); /* Generate PEM certificate. */ result = Curl_base64_encode(cert.certificate.beg, cert.certificate.end - cert.certificate.beg, - &cp1, &cl1); + &certptr, &clen); if(result) - return result; - /* Compute the number of characters in final certificate string. Format is: + goto done; + + /* Generate the final output certificate string. Format is: -----BEGIN CERTIFICATE-----\n \n . @@ -1232,207 +1196,34 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, . -----END CERTIFICATE-----\n */ - i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26; - cp2 = malloc(i + 1); - if(!cp2) { - free(cp1); - return CURLE_OUT_OF_MEMORY; - } - /* Build the certificate string. */ - i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----"); - for(j = 0; j < cl1; j += 64) - i += copySubstring(cp2 + i, cp1 + j); - i += copySubstring(cp2 + i, "-----END CERTIFICATE-----"); - cp2[i] = '\0'; - free(cp1); - if(data->set.ssl.certinfo) - result = ssl_push_certinfo(data, certnum, "Cert", cp2); - if(!certnum) - infof(data, "%s", cp2); - free(cp2); - return result; -} -#endif /* WANT_EXTRACT_CERTINFO */ - -#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */ + Curl_dyn_reset(&out); -#ifdef WANT_VERIFYHOST - -static const char *checkOID(const char *beg, const char *end, - const char *oid) -{ - struct Curl_asn1Element e; - const char *ccp; - const char *p; - bool matched; - - /* Check if first ASN.1 element at `beg' is the given OID. - Return a pointer in the source after the OID if found, else NULL. */ - - ccp = getASN1Element(&e, beg, end); - if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER) - return NULL; - - p = OID2str(e.beg, e.end, FALSE); - if(!p) - return NULL; - - matched = !strcmp(p, oid); - free((char *) p); - return matched? ccp: NULL; -} - -CURLcode Curl_verifyhost(struct Curl_cfilter *cf, - struct Curl_easy *data, - const char *beg, const char *end) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); - struct Curl_X509certificate cert; - struct Curl_asn1Element dn; - struct Curl_asn1Element elem; - struct Curl_asn1Element ext; - struct Curl_asn1Element name; - const char *p; - const char *q; - char *dnsname; - int matched = -1; - size_t addrlen = (size_t) -1; - ssize_t len; - size_t hostlen; - -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif - - /* Verify that connection server matches info in X509 certificate at - `beg'..`end'. */ - - if(!conn_config->verifyhost) - return CURLE_OK; - - if(Curl_parseX509(&cert, beg, end)) - return CURLE_PEER_FAILED_VERIFICATION; - - hostlen = strlen(connssl->peer.hostname); - - /* Get the server IP address. */ -#ifdef ENABLE_IPV6 - if(cf->conn->bits.ipv6_ip && - Curl_inet_pton(AF_INET6, connssl->peer.hostname, &addr)) - addrlen = sizeof(struct in6_addr); - else -#endif - if(Curl_inet_pton(AF_INET, connssl->peer.hostname, &addr)) - addrlen = sizeof(struct in_addr); - - /* Process extensions. */ - for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) { - p = getASN1Element(&ext, p, cert.extensions.end); - if(!p) - return CURLE_PEER_FAILED_VERIFICATION; - - /* Check if extension is a subjectAlternativeName. */ - ext.beg = checkOID(ext.beg, ext.end, sanOID); - if(ext.beg) { - ext.beg = getASN1Element(&elem, ext.beg, ext.end); - if(!ext.beg) - return CURLE_PEER_FAILED_VERIFICATION; - /* Skip critical if present. */ - if(elem.tag == CURL_ASN1_BOOLEAN) { - ext.beg = getASN1Element(&elem, ext.beg, ext.end); - if(!ext.beg) - return CURLE_PEER_FAILED_VERIFICATION; - } - /* Parse the octet string contents: is a single sequence. */ - if(!getASN1Element(&elem, elem.beg, elem.end)) - return CURLE_PEER_FAILED_VERIFICATION; - /* Check all GeneralNames. */ - for(q = elem.beg; matched != 1 && q < elem.end;) { - q = getASN1Element(&name, q, elem.end); - if(!q) - break; - switch(name.tag) { - case 2: /* DNS name. */ - len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, - name.beg, name.end); - if(len > 0 && (size_t)len == strlen(dnsname)) - matched = Curl_cert_hostcheck(dnsname, (size_t)len, - connssl->peer.hostname, hostlen); - else - matched = 0; - free(dnsname); - break; - - case 7: /* IP address. */ - matched = (size_t)(name.end - name.beg) == addrlen && - !memcmp(&addr, name.beg, addrlen); - break; - } - } - } - } - - switch(matched) { - case 1: - /* an alternative name matched the server hostname */ - infof(data, " subjectAltName: %s matched", connssl->dispname); - return CURLE_OK; - case 0: - /* an alternative name field existed, but didn't match and then - we MUST fail */ - infof(data, " subjectAltName does not match %s", connssl->dispname); - return CURLE_PEER_FAILED_VERIFICATION; - } - - /* Process subject. */ - name.header = NULL; - name.beg = name.end = ""; - q = cert.subject.beg; - /* we have to look to the last occurrence of a commonName in the - distinguished one to get the most significant one. */ - while(q < cert.subject.end) { - q = getASN1Element(&dn, q, cert.subject.end); - if(!q) - break; - for(p = dn.beg; p < dn.end;) { - p = getASN1Element(&elem, p, dn.end); - if(!p) - return CURLE_PEER_FAILED_VERIFICATION; - /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */ - elem.beg = checkOID(elem.beg, elem.end, cnOID); - if(elem.beg) - name = elem; /* Latch CN. */ - } - } - - /* Check the CN if found. */ - if(!getASN1Element(&elem, name.beg, name.end)) - failf(data, "SSL: unable to obtain common name from peer certificate"); - else { - len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end); - if(len < 0) { - free(dnsname); - return CURLE_OUT_OF_MEMORY; - } - if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */ - failf(data, "SSL: illegal cert name field"); - else if(Curl_cert_hostcheck((const char *) dnsname, - len, connssl->peer.hostname, hostlen)) { - infof(data, " common name: %s (matched)", dnsname); - free(dnsname); - return CURLE_OK; + /* Build the certificate string. */ + result = Curl_dyn_add(&out, "-----BEGIN CERTIFICATE-----\n"); + if(!result) { + size_t j = 0; + + while(!result && (j < clen)) { + size_t chunksize = (clen - j) > 64 ? 64 : (clen - j); + result = Curl_dyn_addn(&out, &certptr[j], chunksize); + if(!result) + result = Curl_dyn_addn(&out, "\n", 1); + j += chunksize; } - else - failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", dnsname, connssl->dispname); - free(dnsname); + if(!result) + result = Curl_dyn_add(&out, "-----END CERTIFICATE-----\n"); } + free(certptr); + if(!result) + if(data->set.ssl.certinfo) + result = ssl_push_certinfo_dyn(data, certnum, "Cert", &out); - return CURLE_PEER_FAILED_VERIFICATION; +done: + Curl_dyn_free(&out); + return result; } -#endif /* WANT_VERIFYHOST */ +#endif /* WANT_EXTRACT_CERTINFO */ + +#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */ diff --git a/libs/libcurl/src/ws.c b/libs/libcurl/src/ws.c index 5c8db777f1..0caca18f05 100644 --- a/libs/libcurl/src/ws.c +++ b/libs/libcurl/src/ws.c @@ -24,7 +24,7 @@ #include "curl_setup.h" #include -#ifdef USE_WEBSOCKETS +#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) #include "urldata.h" #include "bufq.h" @@ -225,6 +225,10 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, dec->payload_len = (dec->head[2] << 8) | dec->head[3]; break; case 10: + if(dec->head[2] > 127) { + failf(data, "WS: frame length longer than 64 signed not supported"); + return CURLE_RECV_ERROR; + } dec->payload_len = ((curl_off_t)dec->head[2] << 56) | (curl_off_t)dec->head[3] << 48 | (curl_off_t)dec->head[4] << 40 | @@ -296,7 +300,7 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec, case WS_DEC_INIT: ws_dec_reset(dec); dec->state = WS_DEC_HEAD; - /* FALLTHROUGH */ + FALLTHROUGH(); case WS_DEC_HEAD: result = ws_dec_read_head(dec, data, inraw); if(result) { @@ -321,7 +325,7 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec, dec->state = WS_DEC_INIT; break; } - /* FALLTHROUGH */ + FALLTHROUGH(); case WS_DEC_PAYLOAD: result = ws_dec_pass_payload(dec, data, inraw, write_payload, write_ctx); ws_dec_info(dec, data, "passing"); @@ -350,6 +354,136 @@ static void update_meta(struct websocket *ws, ws->frame.bytesleft = (payload_len - payload_offset - cur_len); } +/* WebSockets decoding client writer */ +struct ws_cw_ctx { + struct Curl_cwriter super; + struct bufq buf; +}; + +static CURLcode ws_cw_init(struct Curl_easy *data, + struct Curl_cwriter *writer) +{ + struct ws_cw_ctx *ctx = (struct ws_cw_ctx *)writer; + (void)data; + Curl_bufq_init2(&ctx->buf, WS_CHUNK_SIZE, 1, BUFQ_OPT_SOFT_LIMIT); + return CURLE_OK; +} + +static void ws_cw_close(struct Curl_easy *data, struct Curl_cwriter *writer) +{ + struct ws_cw_ctx *ctx = (struct ws_cw_ctx *)writer; + (void) data; + Curl_bufq_free(&ctx->buf); +} + +struct ws_cw_dec_ctx { + struct Curl_easy *data; + struct websocket *ws; + struct Curl_cwriter *next_writer; + int cw_type; +}; + +static ssize_t ws_cw_dec_next(const unsigned char *buf, size_t buflen, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + void *user_data, + CURLcode *err) +{ + struct ws_cw_dec_ctx *ctx = user_data; + struct Curl_easy *data = ctx->data; + struct websocket *ws = ctx->ws; + curl_off_t remain = (payload_len - (payload_offset + buflen)); + + (void)frame_age; + if((frame_flags & CURLWS_PING) && !remain) { + /* auto-respond to PINGs, only works for single-frame payloads atm */ + size_t bytes; + infof(data, "WS: auto-respond to PING with a PONG"); + /* send back the exact same content as a PONG */ + *err = curl_ws_send(data, buf, buflen, &bytes, 0, CURLWS_PONG); + if(*err) + return -1; + } + else if(buflen || !remain) { + /* forward the decoded frame to the next client writer. */ + update_meta(ws, frame_age, frame_flags, payload_offset, + payload_len, buflen); + + *err = Curl_cwriter_write(data, ctx->next_writer, ctx->cw_type, + (const char *)buf, buflen); + if(*err) + return -1; + } + *err = CURLE_OK; + return (ssize_t)buflen; +} + +static CURLcode ws_cw_write(struct Curl_easy *data, + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) +{ + struct ws_cw_ctx *ctx = (struct ws_cw_ctx *)writer; + struct websocket *ws; + CURLcode result; + + if(!(type & CLIENTWRITE_BODY) || data->set.ws_raw_mode) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); + + ws = data->conn->proto.ws; + if(!ws) { + failf(data, "WS: not a websocket transfer"); + return CURLE_FAILED_INIT; + } + + if(nbytes) { + ssize_t nwritten; + nwritten = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf, + nbytes, &result); + if(nwritten < 0) { + infof(data, "WS: error adding data to buffer %d", result); + return result; + } + } + + while(!Curl_bufq_is_empty(&ctx->buf)) { + struct ws_cw_dec_ctx pass_ctx; + pass_ctx.data = data; + pass_ctx.ws = ws; + pass_ctx.next_writer = writer->next; + pass_ctx.cw_type = type; + result = ws_dec_pass(&ws->dec, data, &ctx->buf, + ws_cw_dec_next, &pass_ctx); + if(result == CURLE_AGAIN) + /* insufficient amount of data, keep it for later. + * we pretend to have written all since we have a copy */ + return CURLE_OK; + else if(result) { + infof(data, "WS: decode error %d", (int)result); + return result; + } + } + + if((type & CLIENTWRITE_EOS) && !Curl_bufq_is_empty(&ctx->buf)) { + infof(data, "WS: decode ending with %zd frame bytes remaining", + Curl_bufq_len(&ctx->buf)); + return CURLE_RECV_ERROR; + } + + return CURLE_OK; +} + +/* WebSocket payload decoding client writer. */ +static const struct Curl_cwtype ws_cw_decode = { + "ws-decode", + NULL, + ws_cw_init, + ws_cw_write, + ws_cw_close, + sizeof(struct ws_cw_ctx) +}; + + static void ws_enc_info(struct ws_encoder *enc, struct Curl_easy *data, const char *msg) { @@ -410,6 +544,13 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data, size_t hlen; ssize_t n; + if(payload_len < 0) { + failf(data, "WS: starting new frame with negative payload length %" + CURL_FORMAT_CURL_OFF_T, payload_len); + *err = CURLE_SEND_ERROR; + return -1; + } + if(enc->payload_remain > 0) { /* trying to write a new frame before the previous one is finished */ failf(data, "WS: starting new frame with %zd bytes from last one" @@ -607,6 +748,7 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, { struct SingleRequest *k = &data->req; struct websocket *ws; + struct Curl_cwriter *ws_dec_writer; CURLcode result; DEBUGASSERT(data->conn); @@ -616,7 +758,8 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, if(!ws) return CURLE_OUT_OF_MEMORY; data->conn->proto.ws = ws; - Curl_bufq_init(&ws->recvbuf, WS_CHUNK_SIZE, WS_CHUNK_COUNT); + Curl_bufq_init2(&ws->recvbuf, WS_CHUNK_SIZE, WS_CHUNK_COUNT, + BUFQ_OPT_SOFT_LIMIT); Curl_bufq_init2(&ws->sendbuf, WS_CHUNK_SIZE, WS_CHUNK_COUNT, BUFQ_OPT_SOFT_LIMIT); ws_dec_init(&ws->dec); @@ -655,6 +798,18 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x", ws->enc.mask[0], ws->enc.mask[1], ws->enc.mask[2], ws->enc.mask[3]); + /* Install our client writer that decodes WS frames payload */ + result = Curl_cwriter_create(&ws_dec_writer, data, &ws_cw_decode, + CURL_CW_CONTENT_DECODE); + if(result) + return result; + + result = Curl_cwriter_add(data, ws_dec_writer); + if(result) { + Curl_cwriter_free(data, ws_dec_writer); + return result; + } + if(data->set.connect_only) { ssize_t nwritten; /* In CONNECT_ONLY setup, the payloads from `mem` need to be received @@ -666,105 +821,15 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, return result; infof(data, "%zu bytes websocket payload", nread); } - k->upgr101 = UPGR101_RECEIVED; - - return result; -} - -static ssize_t ws_client_write(const unsigned char *buf, size_t buflen, - int frame_age, int frame_flags, - curl_off_t payload_offset, - curl_off_t payload_len, - void *userp, - CURLcode *err) -{ - struct Curl_easy *data = userp; - struct websocket *ws; - size_t wrote; - curl_off_t remain = (payload_len - (payload_offset + buflen)); - - (void)frame_age; - if(!data->conn || !data->conn->proto.ws) { - *err = CURLE_FAILED_INIT; - return -1; - } - ws = data->conn->proto.ws; - - if((frame_flags & CURLWS_PING) && !remain) { - /* auto-respond to PINGs, only works for single-frame payloads atm */ - size_t bytes; - infof(data, "WS: auto-respond to PING with a PONG"); - /* send back the exact same content as a PONG */ - *err = curl_ws_send(data, buf, buflen, &bytes, 0, CURLWS_PONG); - if(*err) - return -1; - } - else if(buflen || !remain) { - /* deliver the decoded frame to the user callback. The application - * may invoke curl_ws_meta() to access frame information. */ - update_meta(ws, frame_age, frame_flags, payload_offset, - payload_len, buflen); - Curl_set_in_callback(data, true); - wrote = data->set.fwrite_func((char *)buf, 1, - buflen, data->set.out); - Curl_set_in_callback(data, false); - if(wrote != buflen) { - *err = CURLE_RECV_ERROR; - return -1; + else { /* !connect_only */ + /* And pass any additional data to the writers */ + if(nread) { + result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)mem, nread); } } - *err = CURLE_OK; - return (ssize_t)buflen; -} - -/* Curl_ws_writecb() is the write callback for websocket traffic. The - websocket data is provided to this raw, in chunks. This function should - handle/decode the data and call the "real" underlying callback accordingly. -*/ -size_t Curl_ws_writecb(char *buffer, size_t size /* 1 */, - size_t nitems, void *userp) -{ - struct Curl_easy *data = userp; - - if(data->set.ws_raw_mode) - return data->set.fwrite_func(buffer, size, nitems, data->set.out); - else if(nitems) { - struct websocket *ws; - CURLcode result; - - if(!data->conn || !data->conn->proto.ws) { - failf(data, "WS: not a websocket transfer"); - return nitems - 1; - } - ws = data->conn->proto.ws; - - if(buffer) { - ssize_t nwritten; - - nwritten = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)buffer, - nitems, &result); - if(nwritten < 0) { - infof(data, "WS: error adding data to buffer %d", (int)result); - return nitems - 1; - } - buffer = NULL; - } - - while(!Curl_bufq_is_empty(&ws->recvbuf)) { + k->upgr101 = UPGR101_RECEIVED; - result = ws_dec_pass(&ws->dec, data, &ws->recvbuf, - ws_client_write, data); - if(result == CURLE_AGAIN) - /* insufficient amount of data, keep it for later. - * we pretend to have written all since we have a copy */ - return nitems; - else if(result) { - infof(data, "WS: decode error %d", (int)result); - return nitems - 1; - } - } - } - return nitems; + return result; } struct ws_collect { @@ -997,8 +1062,11 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer, ws = data->conn->proto.ws; if(data->set.ws_raw_mode) { - if(fragsize || flags) + if(fragsize || flags) { + DEBUGF(infof(data, "ws_send: " + "fragsize and flags cannot be non-zero in raw mode")); return CURLE_BAD_FUNCTION_ARGUMENT; + } if(!buflen) /* nothing to do */ return CURLE_OK; @@ -1071,14 +1139,23 @@ static void ws_free(struct connectdata *conn) } } +static CURLcode ws_setup_conn(struct Curl_easy *data, + struct connectdata *conn) +{ + /* websockets is 1.1 only (for now) */ + data->state.httpwant = CURL_HTTP_VERSION_1_1; + return Curl_http_setup_conn(data, conn); +} + + void Curl_ws_done(struct Curl_easy *data) { (void)data; } -CURLcode Curl_ws_disconnect(struct Curl_easy *data, - struct connectdata *conn, - bool dead_connection) +static CURLcode ws_disconnect(struct Curl_easy *data, + struct connectdata *conn, + bool dead_connection) { (void)data; (void)dead_connection; @@ -1096,6 +1173,57 @@ CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) return NULL; } +const struct Curl_handler Curl_handler_ws = { + "WS", /* scheme */ + ws_setup_conn, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + Curl_http_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + Curl_http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ws_disconnect, /* disconnect */ + Curl_http_write_resp, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_HTTP, /* defport */ + CURLPROTO_WS, /* protocol */ + CURLPROTO_HTTP, /* family */ + PROTOPT_CREDSPERREQUEST | /* flags */ + PROTOPT_USERPWDCTRL +}; + +#ifdef USE_SSL +const struct Curl_handler Curl_handler_wss = { + "WSS", /* scheme */ + ws_setup_conn, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + Curl_http_connect, /* connect_it */ + NULL, /* connecting */ + ZERO_NULL, /* doing */ + NULL, /* proto_getsock */ + Curl_http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ws_disconnect, /* disconnect */ + Curl_http_write_resp, /* write_resp */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_HTTPS, /* defport */ + CURLPROTO_WSS, /* protocol */ + CURLPROTO_HTTP, /* family */ + PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | /* flags */ + PROTOPT_USERPWDCTRL +}; +#endif + + #else CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, diff --git a/libs/libcurl/src/ws.h b/libs/libcurl/src/ws.h index 20b9103ac6..af26e3f140 100644 --- a/libs/libcurl/src/ws.h +++ b/libs/libcurl/src/ws.h @@ -25,7 +25,7 @@ ***************************************************************************/ #include "curl_setup.h" -#ifdef USE_WEBSOCKETS +#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) #ifdef USE_HYPER #define REQTYPE void @@ -75,11 +75,14 @@ struct websocket { CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req); CURLcode Curl_ws_accept(struct Curl_easy *data, const char *mem, size_t len); -size_t Curl_ws_writecb(char *buffer, size_t size, size_t nitems, void *userp); void Curl_ws_done(struct Curl_easy *data); -CURLcode Curl_ws_disconnect(struct Curl_easy *data, - struct connectdata *conn, - bool dead_connection); + +extern const struct Curl_handler Curl_handler_ws; +#ifdef USE_SSL +extern const struct Curl_handler Curl_handler_wss; +#endif + + #else #define Curl_ws_request(x,y) CURLE_OK #define Curl_ws_done(x) Curl_nop_stmt -- cgit v1.2.3