diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2022-12-02 16:18:16 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2022-12-02 16:18:16 +0300 |
commit | 22a73deb46c33ab8539b522286f0fb9b3364f856 (patch) | |
tree | af3cf69e9e6ebc887a5add5491b2fcebbfdff06a /contrib | |
parent | 2e7d246d83a0077f08e6fed36594fc2087949502 (diff) | |
download | ydb-22a73deb46c33ab8539b522286f0fb9b3364f856.tar.gz |
Update contrib/libs/curl to 7.86.0
Diffstat (limited to 'contrib')
156 files changed, 4699 insertions, 3194 deletions
diff --git a/contrib/libs/curl/CMakeLists.darwin.txt b/contrib/libs/curl/CMakeLists.darwin.txt index 93bb8cc36c..12351cd941 100644 --- a/contrib/libs/curl/CMakeLists.darwin.txt +++ b/contrib/libs/curl/CMakeLists.darwin.txt @@ -51,7 +51,6 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/content_encoding.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/cookie.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_addrinfo.c - ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_ctype.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_des.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_endian.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_fnmatch.c @@ -70,7 +69,6 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_threads.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/dict.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/doh.c - ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/dotdot.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/dynbuf.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/easy.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/easygetopt.c @@ -120,6 +118,7 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/multi.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/netrc.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/nonblock.c + ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/noproxy.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/openldap.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/parsedate.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/pingpong.c @@ -190,4 +189,5 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/vtls/x509asn1.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/warnless.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/wildcard.c + ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/ws.c ) diff --git a/contrib/libs/curl/CMakeLists.linux-aarch64.txt b/contrib/libs/curl/CMakeLists.linux-aarch64.txt index 02e21e69af..c34da9e006 100644 --- a/contrib/libs/curl/CMakeLists.linux-aarch64.txt +++ b/contrib/libs/curl/CMakeLists.linux-aarch64.txt @@ -47,7 +47,6 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/content_encoding.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/cookie.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_addrinfo.c - ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_ctype.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_des.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_endian.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_fnmatch.c @@ -66,7 +65,6 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_threads.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/dict.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/doh.c - ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/dotdot.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/dynbuf.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/easy.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/easygetopt.c @@ -116,6 +114,7 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/multi.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/netrc.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/nonblock.c + ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/noproxy.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/openldap.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/parsedate.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/pingpong.c @@ -186,4 +185,5 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/vtls/x509asn1.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/warnless.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/wildcard.c + ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/ws.c ) diff --git a/contrib/libs/curl/CMakeLists.linux.txt b/contrib/libs/curl/CMakeLists.linux.txt index 02e21e69af..c34da9e006 100644 --- a/contrib/libs/curl/CMakeLists.linux.txt +++ b/contrib/libs/curl/CMakeLists.linux.txt @@ -47,7 +47,6 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/content_encoding.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/cookie.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_addrinfo.c - ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_ctype.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_des.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_endian.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_fnmatch.c @@ -66,7 +65,6 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/curl_threads.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/dict.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/doh.c - ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/dotdot.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/dynbuf.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/easy.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/easygetopt.c @@ -116,6 +114,7 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/multi.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/netrc.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/nonblock.c + ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/noproxy.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/openldap.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/parsedate.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/pingpong.c @@ -186,4 +185,5 @@ target_sources(contrib-libs-curl PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/vtls/x509asn1.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/warnless.c ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/wildcard.c + ${CMAKE_SOURCE_DIR}/contrib/libs/curl/lib/ws.c ) diff --git a/contrib/libs/curl/README b/contrib/libs/curl/README index 9705f41988..f5efbd70a6 100644 --- a/contrib/libs/curl/README +++ b/contrib/libs/curl/README @@ -13,7 +13,7 @@ README libcurl is the library curl is using to do its job. It is readily available to be used by your software. Read the libcurl.3 man page to - learn how! + learn how. You find answers to the most frequent questions we get in the FAQ document. @@ -36,7 +36,7 @@ WEBSITE GIT - To download the very latest source off the GIT server do this: + To download the latest source code off the GIT server, do this: git clone https://github.com/curl/curl.git @@ -44,7 +44,7 @@ GIT SECURITY PROBLEMS - Report suspected security problems via our HackerOne page and not in public! + Report suspected security problems via our HackerOne page and not in public. https://hackerone.com/curl diff --git a/contrib/libs/curl/RELEASE-NOTES b/contrib/libs/curl/RELEASE-NOTES index 30165420bb..9b70c8c86e 100644 --- a/contrib/libs/curl/RELEASE-NOTES +++ b/contrib/libs/curl/RELEASE-NOTES @@ -1,379 +1,423 @@ -curl and libcurl 7.85.0 +curl and libcurl 7.86.0 - Public curl releases: 210 + Public curl releases: 211 Command line options: 248 - curl_easy_setopt() options: 299 - Public functions in libcurl: 88 - Contributors: 2690 + curl_easy_setopt() options: 300 + Public functions in libcurl: 91 + Contributors: 2733 This release includes the following changes: - o quic: add support via wolfSSL [142] - o schannel: Add TLS 1.3 support [96] - o setopt: add CURLOPT_PROTOCOLS_STR and CURLOPT_REDIR_PROTOCOLS_STR [30] + o NPN: remove support for and use of [16] + o Websockets: initial support [23] This release includes the following bugfixes: - o amigaos: fix threaded resolver on AmigaOS 4.x [133] - o amissl: allow AmiSSL to be used with AmigaOS 4.x builds [115] - o amissl: make AmiSSL v5 a minimum requirement [117] - o asyn-ares: make a single alloc out of hostname + async data [123] - o asyn-thread: fix socket leak on OOM [128] - o asyn-thread: make getaddrinfo_complete return CURLcode [53] - o base64: base64url encoding has no padding [41] - o BUGS.md: improve language [62] - o build: improve OS string in CMake and `config-win32.h` [15] - o cert.d: clarify that escape character works for file paths [161] - o cirrus.yml: replace py38-pip with py39-pip [63] - o cirrus/freebsd-ci: bootstrap the pip installer [104] - o cmake: add detection of threadsafe feature [163] - o cmake: do not force Windows target versions [28] - o cmake: fix build for mingw cross compile [33] - o cmake: link curl to its dependencies with PRIVATE [57] - o cmake: remove APPEND in export(TARGETS) [58] - o cmake: set feature PSL if present [168] - o cmake: support ngtcp2 boringssl backend [18] - o cmdline-opts/gen.pl: improve performance [97] - o config: remove the check for and use of SIZEOF_SHORT [129] - o configure: -pthread not available on AmigaOS 4.x [118] - o configure: check for the stdatomic.h header in configure [7] - o configure: fix --disable-headers-api [55] - o configure: fix broken m4 syntax in TLS options [145] - o configure: fixup bsdsocket detection code for AmigaOS 4.x [110] - o configure: if asked to use TLS, fail if no TLS lib was detected [156] - o configure: introduce CURL_SIZEOF [130] - o connect: add quic connection information [100] - o connect: close the happy eyeballs loser connection when using QUIC [109] - o connect: revert the use of IP*_RECVERR [102] - o connect: set socktype/protocol correctly [114] - o cookie: reject cookies with "control bytes" [152] - o cookie: treat a blank domain in Set-Cookie: as non-existing [40] - o cookie: use %zu to infof() for size_t values [26] - o curl-compilers.m4: make icc use -diag* options and disable two warnings [84] - o curl-config: quote directories with potential space [132] - o curl-confopts: remove leftover AC_REQUIREs [91] - o curl-functions.m4: check whether atomics can link [86] - o curl-wolfssl.m4: add options header when building test code [87] - o curl.h: CURLE_CONV_FAILED is obsoleted [4] - o curl.h: include <sys/select.h> on SunOS [151] - o curl: output warning when a cookie is dropped due to size [5] - o curl: writeout: fix repeated header outputs [47] - o Curl_close: call Curl_resolver_cancel to avoid memory-leak [124] - o curl_easy_header: Add CURLH_PSEUDO to sanity check [94] - o curl_mime_data.3: polish the wording [6] - o curl_multi_timeout.3: clarify usage [48] - o CURLINFO_SPEED_UPLOAD/DOWNLOAD.3: fix examples [121] - o CURLOPT_BUFFERSIZE.3: add upload buffersize to see also [159] - o CURLOPT_CONNECT_ONLY.3: clarify multi API use [64] - o CURLOPT_SERVER_RESPONSE_TIMEOUT: the new name [16] - o digest: fix memory leak, fix not quoted 'opaque' [66] - o digest: fix missing increment of 'nc' value for auth-int [39] - o digest: pass over leading spaces in qop values [119] - o digest: reject broken header with session protocol but without qop [120] - o docs/cmdline-opts/gen.pl: encode leading single and double quotes [138] - o docs/cmdline-opts: fix example and categories for --form-escape [125] - o docs/cmdline: mark fail and fail-with-body as mutually exclusive [98] - o docs: add dns category to --resolve [95] - o docs: explain curl_easy_escape/unescape curl handle is ignored [23] - o docs: remove him/her/he/she from documentation [103] - o doh: move doh related struct definitions to doh.h [45] - o doh: use https protocol by default [51] - o easy_lock.h: include sched.h if available to fix build [13] - o easy_lock.h: use __asm__ instead of asm to fix build [11] - o easy_lock: fix build for mingw [34] - o easy_lock: fix build with icc [54] - o easy_lock: fix the #ifdef conditional for ia32_pause [8] - o easy_lock: switch to using atomic_int instead of bool [9] - o easyoptions: fix icc warning [42] - o escape: remove outdated comment [25] - o examples/curlx.c: remove [150] - o file: add handling of native AmigaOS paths [108] - o file: fix icc enumerated type mixed with another type warning [92] - o ftp: use a correct expire ID for timer expiry [88] - o getinfo: return better error on NULL as first argument [21] - o GHA: add two Intel compiler CI jobs [85] - o GHA: move libressl CI from zuul to GitHub [144] - o gha: move over ngtcp2-gnutls CI job from zuul [162] - o GHA: mv CI torture test from Zuul [135] - o h2h3: fix overriding the 'TE: Trailers' header [43] - o hostip: resolve *.localhost to 127.0.0.1/::1 [127] - o HTTP3.md: update to msh3 v0.4.0 [126] - o http: typecast the httpreq assignment to avoid icc compiler warning [76] - o http_aws_sigv4.c: remove two unusued includes [36] - o http_chunks: remove an assign + typecast [82] - o hyper: customize test1274 to how hyper unfolds headers [131] - o hyper: enable obs-folded multiline headers [101] - o hyper: use wakers for curl pause/resume [2] - o imap: use ISALNUM() for alphanumeric checks [134] - o ldap: adapt to conn->port now being an 'int' [106] - o lib/curl_path.c: add ISC to license expression [1] - o lib3026: reduce the number of threads to 100 [44] - o libcurl-security.3: fix typo on macro "SH_" [12] - o libssh2: make atime/mtime date overflow return error [148] - o libssh2: provide symlink name in SFTP dir listing [155] - o libssh: ignore deprecation warnings [157] - o libssh: make atime/mtime date overflow return error [149] - o Makefile.m32: add `CURL_RC` and `CURL_STRIP` variables [ci skip] [17] - o Makefile.m32: add `NGTCP2_LIBS` option [ci skip] [38] - o makefile.m32: add support for custom ARCH [ci skip] [27] - o Makefile.m32: allow -nghttp3/-ngtcp2 without -ssl [ci skip] [141] - o Makefile.m32: do not set the libcurl.rc debug flag [ci skip] [3] - o Makefile.m32: stop trying to build libcares.a [ci skip] [46] - o memdebug: add annotation attributes [143] - o mprintf: fix *dyn_vprintf() when out-of-memory [90] - o mprintf: make dprintf_formatf never return negative [49] - o msh3: fix the QUIC disconnect function [107] - o multi: fix the return code from Curl_pgrsDone() [80] - o multi: have curl_multi_remove_handle close CONNECT_ONLY transfer [136] - o multi: use a pipe instead of a socketpair on apple platforms [154] - o multi: use larger dns hash table for multi interface [140] - o multi_wait: fix and improve Curl_poll error handling on Windows [146] - o multi_wait: fix skipping to populate revents for extra_fds [147] - o netrc.d: remove spurious quote [37] - o netrc: Use the password from lines without login [166] - o ngtcp2: Fix build error due to change in nghttp3 prototypes [61] - o ngtcp2: fix incompatible function pointer types [10] - o ngtcp2: Fix missing initialization of nghttp3_nv.flags [31] - o ngtcp2: fix stall or busy loop on STOP_SENDING with upload data [19] - o ngtcp2: implement cb_h3_stop_sending and cb_h3_reset_stream callbacks [59] - o openssl: add `CURL_BORINGSSL_VERSION` to identify BoringSSL [24] - o openssl: add cert path in error message [160] - o openssl: add details to "unable to set client certificate" error [116] - o openssl: fix BoringSSL symbol conflicts with LDAP and Schannel [52] - o quiche: fix build failure [99] - o select: do not return fatal error on EINTR from poll() [32] - o sendf: fix paused header writes since after the header API [89] - o sendf: make Curl_debug a void function [81] - o sendf: skip storing HTTP headers if HTTP disabled [73] - o sendf: store the header type in an usigned char to avoid icc warnings [79] - o splay: avoid using -1 in unsigned variable [78] - o test3026: add support for Windows using native Win32 threads [65] - o test3026: require 'threadsafe' [56] - o test44[2-4]: add '--resolve' to the keywords [122] - o tests/server/sockfilt.c: avoid race condition without a mutex [139] - o tests: fix http2 tests to use CRLF headers [153] - o tests: several enumerated type cleanups [67] - o THANKS: merged two entries for Evgeny Grin - o tidy-up: delete unused build configuration macros [93] - o tool: reintroduce set file comment code for AmigaOS [111] - o tool_cfgable: make 'synthetic_error' a plain bool [70] - o tool_formparse: fix variable may be used before its value is set [72] - o tool_getparam: make --doh-url "" switch it off [60] - o tool_getparam: repair cleanarg [22] - o tool_operate: better cleanup of easy handle in exit path [20] - o tool_paramhlp: fix "enumerated type mixed with another type" [68] - o tool_paramhlp: make check_protocol return ParameterError [71] - o tool_progress: avoid division by zero in parallel progress meter [35] - o tool_writeout: fix enumerated type mixed with another type [69] - o trace: 0x7F character is non-printable [50] - o unit1303: four tests should have TRUE for 'connecting' [158] - o url: enumerated type mixed with another type [74] - o url: really use the user provided in the url when netrc entry exists [165] - o url: reject URLs with hostnames longer than 65535 bytes [137] - o url: treat missing usernames in netrc as empty [167] - o urldata: change second proxytype field to unsigned char to match [75] - o urldata: make 'negnpn' use less storage [112] - o urldata: make state.httpreq an unsigned char [77] - o urldata: make three *_proto struct fields smaller [113] - o urldata: move smaller fields down in connectdata struct [105] - o urldata: reduce size of several struct fields [14] - o vtls: make Curl_ssl_backend() return the enum type curl_sslbackend [83] - o windows: improve random source [29] + o altsvc: reject bad port numbers [86] + o altsvc: use 'h3' for h3 [46] + o amiga: do not hardcode openssl/zlib into the os config [158] + o amiga: set SIZEOF_CURL_OFF_T=8 by default [150] + o amigaos: add missing curl header [159] + o asyn-ares: set hint flags when calling ares_getaddrinfo [93] + o autotools: allow --enable-symbol-hiding with windows [65] + o autotools: allow unix sockets on Windows [144] + o autotools: reduce brute-force when detecting recv/send arg list [66] + o aws_sigv4: fix header computation [139] + o bearssl: make it proper C89 compliant + o CI/GHA: cancel outdated CI runs on new PR changes [20] + o CI/GHA: merge msh3 and openssl3 builds into linux workflow [110] + o cirrus-ci: add macOS build with m1 [81] + o cirrus: use make LDFLAGS=-all-static instead of curl_LDFLAGS [129] + o cli tool: do not use disabled protocols + o cmake: add missing inet_ntop check [145] + o cmake: add the check of HAVE_SOCKETPAIR [98] + o cmake: define BUILDING_LIBCURL in lib/CMakeLists, not config.h [5] + o cmake: delete duplicate HAVE_GETADDRINFO test [149] + o cmake: enable more detection on Windows [143] + o cmake: fix original MinGW builds [177] + o cmake: improve usability of CMake build as a sub-project [186] + o cmake: set HAVE_GETADDRINFO_THREADSAFE on Windows [147] + o cmake: set HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID on Windows [146] + o cmake: sync HAVE_SIGNAL detection with autotools [148] + o cmdline/docs: add a required 'multi' keyword for each option [160] + o configure: correct the wording when checking grep -E [13] + o configure: deprecate builds with small curl_off_t [89] + o configure: fail if '--without-ssl' + explicit parameter for an ssl lib [164] + o configure: the ngtcp2 option should default to 'no' [125] + o connect: change verbose IPv6 address:port to [address]:port [83] + o connect: fix builds without AF_INET6 [152] + o connect: fix Curl_updateconninfo for TRNSPRT_UNIX [108] + o connect: fix the wrong error message on connect failures [55] + o content_encoding: use writer struct subclasses for different encodings [8] + o cookie: reject cookie names or content with TAB characters [94] + o ctype: remove all use of <ctype.h>, use our own versions [12] + o curl-compilers.m4: for gcc + want warnings, set gnu89 standard [72] + o curl-compilers.m4: use -O2 as default optimize for clang [6] + o curl-wolfssl.m4: error out if wolfSSL is not usable [102] + o curl.h: fix mention of wrong error code in comment + o curl/add_file_name_to_url: use the libcurl URL parser [99] + o curl/add_parallel_transfers: better error handling [101] + o curl/get_url_file_name: use libcurl URL parser [97] + o curl: warn for --ssl use, considered insecure [49] + o curl_ctype: convert to macros-only [10] + o curl_easy_pause.3: unpausing is as fast as possible [14] + o curl_escape.3: fix typo [50] + o curl_setup: disable use of FLOSS for 64-bit NonStop builds [69] + o curl_setup: include curl.h after platform setup headers [37] + o curl_setup: include only system.h instead of curl.h [34] + o curl_strequal.3: fix argument typo [60] + o curl_url_set.3: document CURLU_APPENDQUERY proper [96] + o CURLMOPT_PIPELINING.3: dedup manpage xref [111] + o CURLOPT_ACCEPT_ENCODING.3: remove "four" as they are five [85] + o CURLOPT_AUTOREFERER.3: highlight the privacy leak risk [161] + o CURLOPT_COOKIEFILE: insist on "" for enable-without-file [119] + o CURLOPT_COOKIELIST.3: fix formatting mistake [80] + o CURLOPT_DNS_INTERFACE.3: mention it works for almost all protocols [15] + o CURLOPT_MIMEPOST.3: add an (inline) example [126] + o CURLOPT_POSTFIELDS.3: refer to CURLOPT_MIMEPOST [167] + o CURLOPT_PROXY_SSLCERT_BLOB.3: this is for HTTPS proxies [9] + o CURLOPT_WILDCARDMATCH.3: Fix backslash escaping under single quotes [172] + o CURLSHOPT_UNLOCKFUNC.3: the callback has no 'access' argument [84] + o DEPRECATE.md: Support for systems without 64 bit data types [19] + o docs/examples: avoid deprecated options in examples where possible [115] + o docs/INSTALL: update Android Instructions for newer NDKs [151] + o docs/libcurl/symbols-in-versions: add several missing symbols + o docs: 100+ spellfixes + o docs: correct missing uppercase in Markdown files [38] + o docs: document more server names for test files + o docs: fix deprecation versions inconsistencies [123] + o docs: make sure libcurl opts examples pass in long arguments [182] + o docs: remove mentions of deprecated '--without-openssl' parameter [170] + o docs: tag curl options better in man pages + o docs: tell about disabled protocols in CURLOPT_*PROTOCOLS_STR. + o docs: update sourceforge project links [95] + o easy: fix the #include order [53] + o easy: fix the altsvc init for curl_easy_duphandle [77] + o easy_lock: check for HAVE_STDATOMIC_H as well [187] + o examples/chkspeed: improve portability [48] + o formdata: fix warning: 'CURLformoption' is promoted to 'int' [24] + o ftp: ignore a 550 response to MDTM [1] + o ftp: remove redundant if [163] + o functypes: provide the recv and send arg and return types [87] + o getparameter: return PARAM_MANUAL_REQUESTED for -M even when disabled [17] + o GHA: build tests in a separate step from the running of them [78] + o GHA: run proselint on markdown files [22] + o github: initial CODEOWNERS setup for CI configuration [52] + o header: define public API functions as extern c [26] + o headers: reset the requests counter at transfer start [25] + o hostip: guard PF_INET6 use [157] + o hostip: lazily wait to figure out if IPv6 works until needed [36] + o http, vauth: always provide Curl_allow_auth_to_host() functionality [90] + o http2: make nghttp2 less picky about field whitespace [27] + o HTTP3.md: update Caddy example [76] + o http: try parsing Retry-After: as a number first [122] + o http_proxy: restore the protocol pointer on error [104] + o httpput-postfields.c: shorten string for C89 compliance [57] + o ldap: delete stray CURL_HAS_MOZILLA_LDAP reference [79] + o lib1560: extended to verify detect/reject of unknown schemes + o lib517: fix C89 constant signedness [73] + o lib: add missing limits.h includes [35] + o lib: add required Win32 setup definitions in setup-win32.h [4] + o lib: prepare the incoming of additional protocols [71] + o lib: sanitize conditional exclusion around MIME [82] + o lib: set more flags in config-win32.h [109] + o lib: the number four in a sequence is the "fourth" [28] + o libssh: if sftp_init fails, don't get the sftp error code [132] + o Makefile.m32: deduplicate build rules [131] + o Makefile.m32: drop CROSSPREFIX and our CC/AR defaults [137] + o Makefile.m32: exclude libs & libpaths for shared mode exes [127] + o Makefile.m32: fix regression with tool_hugehelp [130] + o Makefile.m32: major rework [92] + o Makefile.m32: reintroduce CROSSPREFIX and -W -Wall [179] + o Makefile.m32: support more options [142] + o manpage-syntax.pl: all libcurl option symbols should be \fI-tagged [75] + o manpages: Fix spelling of "allows to" -> "allows one to" [171] + o misc: ISSPACE() => ISBLANK() [11] + o misc: use the term "null-terminate" consistently [41] + o mprintf: reject two kinds of precision for the same argument [162] + o mprintf: use snprintf if available [74] + o mqtt: return error for too long topic [133] + o mqtt: spell out CONNECT in comments [166] + o msh3: change the static_assert to make the code C89 + o netrc: compare user name case sensitively [118] + o netrc: replace fgets with Curl_get_line [174] + o netrc: use the URL-decoded user [103] + o ngtcp2: fix build errors due to changes in ngtcp2 library [107] + o ngtcp2: fix C89 compliance nit + o noproxy: support proxies specified using cidr notation [184] + o openssl: make certinfo available for QUIC [91] + o README.md: add GHA status badges for Linux and macOS builds [40] + o RELEASE-PROCEDURE.md: mention patch releases [21] + o resolve: make forced IPv4 resolve only use A queries [61] + o runtests: fix uninitialized value on ignored tests [128] + o schannel: ban server ALPN change during recv renegotiation [63] + o schannel: don't reset recv/send function pointers on renegotiation [156] + o schannel: when importing PFX, disable key persistence [141] + o scripts: use `grep -E` instead of `egrep` [30] + o setopt: use the handler table for protocol name to number conversions [45] + o setopt: when POST is set, reset the 'upload' field [51] + o setup-win32: no longer define UNICODE/_UNICODE implicitly [3] + o single_transfer: use the libcurl URL parser when appending query parts [100] + o smb: replace CURL_WIN32 with WIN32 [138] + o strcase: add and use Curl_timestrcmp [106] + o strerror: improve two URL API error messages + o symbol-scan.pl: also check for LIBCURL* symbols [43] + o symbol-scan.pl: scan and verify .3 man pages [42] + o symbols-in-versions: add missing LIBCURL* symbols + o symbols-in-versions: CURLOPT_ENCODING is deprecated since 7.21.6 + o test1119: scan all public headers [44] + o test1275: verify uppercase after period in markdown [135] + o test972: verify the output without using external tool [32] + o tests/certs/scripts: insert standard curl source headers [169] + o tests/Makefile: remove run time stats from ci-test [120] + o tests: avoid CreateThread if _beginthreadex is available [155] + o tests: fix tag syntax errors in test files + o tests: skip mime/form tests when mime is not built-in [54] + o tidy-up: delete parallel/unused feature flags [117] + o tidy-up: delete unused HAVE_STRUCT_POLLFD [134] + o TODO: provide the error body from a CONNECT response [67] + o tool: avoid generating ambiguous escaped characters in --libcurl [124] + o tool: remove dead code [70] + o tool: reorganize function c_escape around a dynbuf [121] + o tool_hugehelp: make hugehelp a blank macro when disabled [7] + o tool_main: exit at once if out of file descriptors [113] + o tool_operate: avoid a few #ifdefs for disabled-libcurl builds [29] + o tool_operate: more transfer cleanup after parallel transfer fail [165] + o tool_operate: prevent over-queuing in parallel mode [176] + o tool_operate: reduce errorbuffer allocs [173] + o tool_paramhelp: asserts verify maximum sizes for string loading [112] + o tool_paramhelp: make the max argument a 'double' [136] + o tool_progress: remove 'Qd' from the parallel progress bar [175] + o tool_setopt: use better English in --libcurl source comments [39] + o tool_xattr: save the original URL, not the final redirected one [181] + o unit test 1655: make it C89-compliant [59] + o url: a zero-length userinfo part in the URL is still a (blank) user [64] + o url: allow non-HTTPS HSTS-matching for debug builds [105] + o url: rename function due to name-clash in Watt-32 [62] + o url: use IDN decoded names for HSTS checks [140] + o urlapi: detect scheme better when not guessing [56] + o urlapi: fix parsing URL without slash with CURLU_URLENCODE [154] + o urlapi: leaner with fewer allocs [2] + o urlapi: reject more bad characters from the host name field [88] + o winbuild/MakefileBuild.vc: handle spaces in libssh(2) include paths [18] + o winbuild: use NMake batch-rules for compilation [47] + o windows: add .rc support to autotools builds [33] + o windows: adjust name of two internal public functions [58] + o windows: autotools .rc warnings fixup [68] + o wolfSSL: fix session management bug. [31] This release includes the following known bugs: o see docs/KNOWN_BUGS (https://curl.se/docs/knownbugs.html) +Planned upcoming removals include: + + o NSS + o Support for systems without 64 bit data types + + See https://curl.se/dev/deprecate.html for details + This release would not have looked like this without help, code, reports and advice from friends like these: - Adam Sampson, Alessandro Ghedini, Alexandre Bury, Andreas Sommer, - Andrew Lambert, Axel Chong, Brad Forschinger, Brian Carpenter, - Cering on github, Chris Paulson-Ellis, Chris Young, Daniel Katz, - Daniel Stenberg, David Carlier, dEajL3kA on github, Domen Kožar, - Dominik Thalhammer, Don J Olmstead, Dustin Howett, Emanuele Torre, - Emil Engler, Érico Nogueira Rolim, Even Rouault, Evgeny Grin (Karlson2k), - Fabian Fischer, Fabian Keil, Gisle Vanem, Gwen Shapira, Harry Sintonen, - highmtworks on github, Ivan Tsybulin, Jacob Tolar, Jakub Zakrzewski, - Jilayne Lovejoy, Joshua Root, jurisuk on github, jvvprasad78 on github, - Kai Pastor, Litter White, lwthiker on github, Marcel Raad, Marc Hörsken, - Marco Kamner, MasterInQuestion on github, Matthew Thompson, Maxim Ivanov, - Michael Trebilcock, Michał Antoniak, Nao Yonashiro, Nick Banks, - Oliver Roberts, opensignature on github, Orgad Shaneh, Patrick Monnerat, - Philip H, privetryan on github, Ray Satiro, rcombs on github, Rosen Penev, - Ryan Schmidt, Ryan Sleevi, rzrymiak on github, Samuel Henrique, - Sean McArthur, Sergey Ogryzkov, Somnath Kundu, Stefan Eissing, - Sukanya Hanumanthu, Tatsuhiro Tsujikawa, Ted Lyngmo, TheKnarf on github, - Thomas Weißschuh, Tobias Nygren, Viktor Szakats, vlubart on github, Wu Zheng, - Wyatt O'Day, Xiaoke Wang, yiyuaner on github - (79 contributors) + 12932 on github, a1346054 on github, Aftab Alam, ajak in #curl, + Andrew Lambert, Benjamin Loison, Brad Harder, bsergean on github, + Christopher Sauer, Dan Fandrich, Daniel Gustafsson, Daniel Hallberg, + Daniel Stenberg, David Hu, David McLaughlin, Dmitry Karpov, Dominik Klemba, + Don J Olmstead, Dustin Howett, Edoardo Lolletti, Eloy Degen, Emanuele Torre, + Emilio López, Gisle Vanem, Hayden Roche, Hiroki Kurosawa, James Fuller, + Jeremy Maitin-Shepard, Joel Depooter, John Bampton, Jonas Haag, + jurisuk on github, justchen1369 on github, Keitagit-kun on github, + Kelly Kaoudis, Marcel Raad, Marc Hörsken, Mark Itzcovitz, Martin Ågren, + Martin Strunz, Mathieu Carbonneaux, Matthias Gatto, Matt Holt, Max Dymond, + Michael Drake, Michael Heimpold, n0name321 on github, Orgad Shaneh, + Patrick Monnerat, Paul Seligman, Peter Goodman, Petr Štetiar, Philip H, + Philip H., Philip Heiduck, ProceduralMan on github, Randall S. Becker, + Ray Satiro, Rickard Hallerbäck, RobBotic1 on github, Robby Simpson, + Samuel Henrique, Sergey Bronnikov, ShadowZzj on github, Shaun Mirani, + ssdbest on github, Thiago Suchorski, Tobias Schaefer, Trail of Bits, + Vasiliy Ulyanov, Viktor Szakats, Xiang Xiao, Yuriy Chernyshov, + zhanghu on xiaomi + (74 contributors) References to bug reports and discussions on issues: - [1] = https://curl.se/bug/?i=9073 - [2] = https://curl.se/bug/?i=9070 - [3] = https://curl.se/bug/?i=9069 - [4] = https://curl.se/bug/?i=9067 - [5] = https://curl.se/bug/?i=9064 - [6] = https://curl.se/bug/?i=9063 - [7] = https://curl.se/bug/?i=9059 - [8] = https://curl.se/bug/?i=9058 - [9] = https://curl.se/bug/?i=9055 - [10] = https://curl.se/bug/?i=9056 - [11] = https://curl.se/bug/?i=9056 - [12] = https://curl.se/bug/?i=9057 - [13] = https://curl.se/bug/?i=9054 - [14] = https://curl.se/bug/?i=9106 - [15] = https://curl.se/bug/?i=9117 - [16] = https://curl.se/bug/?i=9104 - [17] = https://curl.se/bug/?i=9132 - [18] = https://curl.se/bug/?i=9065 - [19] = https://curl.se/bug/?i=9122 - [20] = https://curl.se/bug/?i=9114 - [21] = https://curl.se/bug/?i=9114 - [22] = https://curl.se/bug/?i=9128 - [23] = https://curl.se/bug/?i=9115 - [24] = https://curl.se/bug/?i=9113 - [25] = https://curl.se/bug/?i=9115 - [26] = https://curl.se/bug/?i=9095 - [27] = https://curl.se/bug/?i=9092 - [28] = https://curl.se/bug/?i=9046 - [29] = https://curl.se/bug/?i=9027 - [30] = https://curl.se/bug/?i=8992 - [31] = https://curl.se/bug/?i=9118 - [32] = https://bugs.archlinux.org/task/75201 - [33] = https://curl.se/bug/?i=9084 - [34] = https://curl.se/bug/?i=8997 - [35] = https://curl.se/bug/?i=9082 - [36] = https://curl.se/bug/?i=9080 - [37] = https://curl.se/bug/?i=9111 - [38] = https://curl.se/bug/?i=9109 - [39] = https://curl.se/bug/?i=9090 - [40] = https://curl.se/bug/?i=9164 - [41] = https://curl.se/bug/?i=9139 - [42] = https://curl.se/bug/?i=9176 - [43] = https://curl.se/bug/?i=9170 - [44] = https://curl.se/bug/?i=9172 - [45] = https://curl.se/bug/?i=9174 - [46] = https://curl.se/bug/?i=9169 - [47] = https://curl.se/bug/?i=9150 - [48] = https://curl.se/bug/?i=9155 - [49] = https://curl.se/bug/?i=9149 - [50] = https://curl.se/bug/?i=9162 - [51] = https://curl.se/bug/?i=9163 - [52] = https://curl.se/bug/?i=9110 - [53] = https://curl.se/bug/?i=9081 - [54] = https://curl.se/bug/?i=9081 - [55] = https://curl.se/bug/?i=9134 - [56] = https://curl.se/bug/?i=9141 - [57] = https://curl.se/bug/?i=9125 - [58] = https://curl.se/bug/?i=9124 - [59] = https://curl.se/bug/?i=9135 - [60] = https://curl.se/bug/?i=9207 - [61] = https://curl.se/bug/?i=9204 - [62] = https://curl.se/bug/?i=9205 - [63] = https://curl.se/bug/?i=9201 - [64] = https://curl.se/bug/?i=9244 - [65] = https://curl.se/bug/?i=9012 - [66] = https://curl.se/bug/?i=9199 - [67] = https://curl.se/bug/?i=9179 - [68] = https://curl.se/bug/?i=9179 - [69] = https://curl.se/bug/?i=9179 - [70] = https://curl.se/bug/?i=9179 - [71] = https://curl.se/bug/?i=9179 - [72] = https://curl.se/bug/?i=9179 - [73] = https://curl.se/bug/?i=9179 - [74] = https://curl.se/bug/?i=9179 - [75] = https://curl.se/bug/?i=9179 - [76] = https://curl.se/bug/?i=9179 - [77] = https://curl.se/bug/?i=9179 - [78] = https://curl.se/bug/?i=9179 - [79] = https://curl.se/bug/?i=9179 - [80] = https://curl.se/bug/?i=9179 - [81] = https://curl.se/bug/?i=9179 - [82] = https://curl.se/bug/?i=9179 - [83] = https://curl.se/bug/?i=9179 - [84] = https://curl.se/bug/?i=9179 - [85] = https://curl.se/bug/?i=9179 - [86] = https://curl.se/bug/?i=9190 - [87] = https://curl.se/bug/?i=9187 - [88] = https://curl.se/bug/?i=9184 - [89] = https://curl.se/bug/?i=9180 - [90] = https://curl.se/bug/?i=9185 - [91] = https://curl.se/bug/?i=9183 - [92] = https://curl.se/bug/?i=9181 - [93] = https://curl.se/bug/?i=9044 - [94] = https://curl.se/bug/?i=9235 - [95] = https://curl.se/bug/?i=9229 - [96] = https://curl.se/bug/?i=8419 - [97] = https://curl.se/bug/?i=9230 - [98] = https://curl.se/bug/?i=9221 - [99] = https://curl.se/bug/?i=9223 - [100] = https://curl.se/bug/?i=9286 - [101] = https://curl.se/bug/?i=9216 - [102] = https://curl.se/bug/?i=9209 - [103] = https://curl.se/bug/?i=9208 - [104] = https://curl.se/bug/?i=9213 - [105] = https://curl.se/bug/?i=9280 - [106] = https://curl.se/bug/?i=9281 - [107] = https://curl.se/bug/?i=8915 - [108] = https://curl.se/bug/?i=9259 - [109] = https://curl.se/bug/?i=9303 - [110] = https://curl.se/bug/?i=9268 - [111] = https://curl.se/bug/?i=9258 - [112] = https://curl.se/bug/?i=9279 - [113] = https://curl.se/bug/?i=9278 - [114] = https://curl.se/bug/?i=9274 - [115] = https://curl.se/bug/?i=9269 - [116] = https://curl.se/bug/?i=9228 - [117] = https://curl.se/bug/?i=9267 - [118] = https://curl.se/bug/?i=9266 - [119] = https://curl.se/bug/?i=9264 - [120] = https://curl.se/bug/?i=9077 - [121] = https://curl.se/bug/?i=9239 - [122] = https://curl.se/bug/?i=9250 - [123] = https://curl.se/bug/?i=9310 - [124] = https://curl.se/bug/?i=9310 - [125] = https://curl.se/bug/?i=9298 - [126] = https://curl.se/bug/?i=9297 - [127] = https://curl.se/bug/?i=9192 - [128] = https://curl.se/bug/?i=9310 - [129] = https://curl.se/bug/?i=9291 - [130] = https://curl.se/bug/?i=9291 - [131] = https://curl.se/bug/?i=9217 - [132] = https://curl.se/bug/?i=9253 - [133] = https://curl.se/bug/?i=9265 - [134] = https://curl.se/bug/?i=9289 - [135] = https://curl.se/bug/?i=9310 - [136] = https://curl.se/bug/?i=9335 - [137] = https://curl.se/bug/?i=9317 - [138] = https://curl.se/bug/?i=9352 - [139] = https://curl.se/bug/?i=9023 - [140] = https://curl.se/bug/?i=9376 - [141] = https://curl.se/bug/?i=9314 - [142] = https://curl.se/bug/?i=9290 - [143] = https://curl.se/bug/?i=9306 - [144] = https://curl.se/bug/?i=9309 - [145] = https://curl.se/bug/?i=9344 - [146] = https://curl.se/bug/?i=9372 - [147] = https://curl.se/bug/?i=9361 - [148] = https://curl.se/bug/?i=9328 - [149] = https://curl.se/bug/?i=9328 - [150] = https://curl.se/bug/?i=9330 - [151] = https://curl.se/bug/?i=9329 - [152] = https://curl.se/docs/CVE-2022-35252.html - [153] = https://curl.se/bug/?i=9364 - [154] = https://curl.se/bug/?i=6132 - [155] = https://curl.se/bug/?i=9369 - [156] = https://curl.se/bug/?i=9367 - [157] = https://curl.se/bug/?i=9382 - [158] = https://curl.se/bug/?i=9356 - [159] = https://curl.se/bug/?i=9354 - [160] = https://curl.se/bug/?i=9349 - [161] = https://curl.se/bug/?i=9349 - [162] = https://curl.se/bug/?i=9331 - [163] = https://curl.se/bug/?i=9312 - [165] = https://curl.se/bug/?i=9243 - [166] = https://curl.se/bug/?i=9248 - [167] = https://curl.se/bug/?i=8653 - [168] = https://curl.se/bug/?i=9391 + [1] = https://curl.se/bug/?i=9357 + [2] = https://curl.se/bug/?i=9408 + [3] = https://curl.se/bug/?i=9375 + [4] = https://curl.se/bug/?i=9375 + [5] = https://curl.se/bug/?i=9498 + [6] = https://curl.se/bug/?i=9444 + [7] = https://curl.se/bug/?i=9485 + [8] = https://curl.se/bug/?i=9455 + [9] = https://curl.se/bug/?i=9434 + [10] = https://curl.se/bug/?i=9429 + [11] = https://curl.se/bug/?i=9432 + [12] = https://curl.se/bug/?i=9433 + [13] = https://curl.se/bug/?i=9471 + [14] = https://curl.se/bug/?i=9410 + [15] = https://curl.se/bug/?i=9427 + [16] = https://curl.se/bug/?i=9307 + [17] = https://curl.se/bug/?i=9485 + [18] = https://curl.se/mail/lib-2022-09/0038.html + [19] = https://curl.se/bug/?i=9604 + [20] = https://curl.se/bug/?i=9533 + [21] = https://curl.se/bug/?i=9495 + [22] = https://curl.se/bug/?i=9520 + [23] = https://curl.se/bug/?i=8995 + [24] = https://curl.se/bug/?i=9484 + [25] = https://curl.se/bug/?i=9424 + [26] = https://curl.se/bug/?i=9424 + [27] = https://curl.se/bug/?i=9448 + [28] = https://curl.se/bug/?i=9535 + [29] = https://curl.se/bug/?i=9486 + [30] = https://curl.se/bug/?i=9491 + [31] = https://curl.se/bug/?i=9492 + [32] = https://curl.se/bug/?i=9563 + [33] = https://curl.se/bug/?i=9521 + [34] = https://curl.se/bug/?i=9453 + [35] = https://curl.se/bug/?i=9453 + [36] = https://curl.se/bug/?i=9553 + [37] = https://curl.se/bug/?i=9453 + [38] = https://curl.se/bug/?i=9474 + [39] = https://curl.se/bug/?i=9475 + [40] = https://curl.se/bug/?i=9530 + [41] = https://curl.se/bug/?i=9527 + [42] = https://curl.se/bug/?i=9544 + [43] = https://curl.se/bug/?i=9544 + [44] = https://curl.se/bug/?i=9544 + [45] = https://curl.se/bug/?i=9472 + [46] = https://curl.se/bug/?i=9515 + [47] = https://curl.se/bug/?i=9512 + [48] = https://curl.se/bug/?i=9562 + [49] = https://curl.se/bug/?i=9519 + [50] = https://curl.se/bug/?i=9517 + [51] = https://curl.se/bug/?i=9507 + [52] = https://curl.se/bug/?i=9505 + [53] = https://curl.se/bug/?i=9560 + [54] = https://curl.se/bug/?i=9596 + [55] = https://curl.se/bug/?i=9549 + [56] = https://curl.se/bug/?i=9503 + [57] = https://curl.se/bug/?i=9555 + [58] = https://curl.se/bug/?i=9598 + [59] = https://curl.se/bug/?i=9551 + [60] = https://curl.se/bug/?i=9548 + [61] = https://curl.se/bug/?i=9540 + [62] = https://curl.se/bug/?i=9585 + [63] = https://curl.se/bug/?i=9463 + [64] = https://curl.se/bug/?i=9088 + [65] = https://curl.se/bug/?i=9586 + [66] = https://curl.se/bug/?i=9591 + [67] = https://curl.se/bug/?i=9513 + [68] = https://curl.se/bug/?i=9582 + [69] = https://curl.se/bug/?i=9575 + [70] = https://curl.se/bug/?i=9576 + [71] = https://curl.se/bug/?i=9534 + [72] = https://curl.se/bug/?i=9542 + [73] = https://curl.se/bug/?i=9572 + [74] = https://curl.se/bug/?i=9569 + [75] = https://curl.se/bug/?i=9574 + [76] = https://curl.se/bug/?i=9623 + [77] = https://curl.se/bug/?i=9624 + [78] = https://curl.se/bug/?i=9619 + [79] = https://curl.se/bug/?i=9625 + [80] = https://curl.se/bug/?i=9639 + [81] = https://curl.se/bug/?i=9565 + [82] = https://curl.se/bug/?i=9610 + [83] = https://curl.se/mail/archive-2022-02/0041.html + [84] = https://curl.se/bug/?i=9612 + [85] = https://curl.se/bug/?i=9614 + [86] = https://curl.se/bug/?i=9607 + [87] = https://curl.se/bug/?i=9592 + [88] = https://curl.se/bug/?i=9608 + [89] = https://curl.se/bug/?i=9605 + [90] = https://curl.se/bug/?i=9600 + [91] = https://curl.se/bug/?i=9584 + [92] = https://curl.se/bug/?i=9632 + [93] = https://curl.se/bug/?i=9694 + [94] = https://curl.se/bug/?i=9659 + [95] = https://curl.se/bug/?i=9630 + [96] = https://curl.se/bug/?i=9628 + [97] = https://curl.se/bug/?i=9684 + [98] = https://curl.se/bug/?i=9686 + [99] = https://curl.se/bug/?i=9683 + [100] = https://curl.se/bug/?i=9681 + [101] = https://curl.se/bug/?i=9729 + [102] = https://curl.se/bug/?i=9682 + [103] = https://curl.se/bug/?i=9709 + [104] = https://curl.se/bug/?i=9790 + [105] = https://curl.se/bug/?i=9728 + [106] = https://curl.se/bug/?i=9658 + [107] = https://curl.se/bug/?i=9747 + [108] = https://curl.se/bug/?i=9664 + [109] = https://curl.se/bug/?i=9712 + [110] = https://curl.se/bug/?i=9646 + [111] = https://curl.se/bug/?i=9776 + [112] = https://curl.se/bug/?i=9719 + [113] = https://curl.se/bug/?i=9663 + [115] = https://curl.se/bug/?i=9661 + [117] = https://curl.se/bug/?i=9652 + [118] = https://curl.se/bug/?i=9657 + [119] = https://curl.se/bug/?i=9654 + [120] = https://curl.se/bug/?i=9656 + [121] = https://curl.se/bug/?i=9653 + [122] = https://curl.se/bug/?i=9718 + [123] = https://curl.se/bug/?i=9711 + [124] = https://curl.se/bug/?i=9643 + [125] = https://curl.se/mail/lib-2022-10/0007.html + [126] = https://curl.se/bug/?i=9637 + [127] = https://curl.se/bug/?i=9651 + [128] = https://curl.se/bug/?i=9648 + [129] = https://curl.se/bug/?i=9633 + [130] = https://curl.se/bug/?i=9645 + [131] = https://curl.se/bug/?i=9642 + [132] = https://curl.se/bug/?i=9737 + [133] = https://curl.se/bug/?i=9744 + [134] = https://curl.se/bug/?i=9707 + [135] = https://curl.se/bug/?i=9697 + [136] = https://curl.se/bug/?i=9700 + [137] = https://curl.se/bug/?i=9698 + [138] = https://curl.se/bug/?i=9701 + [139] = https://curl.se/bug/?i=7966 + [140] = https://curl.se/bug/?i=9791 + [141] = https://curl.se/bug/?i=9300 + [142] = https://curl.se/bug/?i=9680 + [143] = https://curl.se/bug/?i=9687 + [144] = https://github.com/curl/curl-for-win/blob/73a070d96fd906fdee929e2f1f00a9149fb39239/curl-autotools.sh#L44-L47 + [145] = https://curl.se/bug/?i=9689 + [146] = https://curl.se/bug/?i=9726 + [147] = https://curl.se/bug/?i=9727 + [148] = https://curl.se/bug/?i=9725 + [149] = https://curl.se/bug/?i=9731 + [150] = https://curl.se/bug/?i=9771 + [151] = https://curl.se/bug/?i=9732 + [152] = https://curl.se/bug/?i=9770 + [154] = https://curl.se/bug/?i=9763 + [155] = https://curl.se/bug/?i=9705 + [156] = https://curl.se/bug/?i=9451 + [157] = https://curl.se/bug/?i=9760 + [158] = https://curl.se/bug/?i=9762 + [159] = https://curl.se/bug/?i=9761 + [160] = https://curl.se/bug/?i=9759 + [161] = https://curl.se/bug/?i=9757 + [162] = https://curl.se/bug/?i=9754 + [163] = https://curl.se/bug/?i=9753 + [164] = https://curl.se/bug/?i=9414 + [165] = https://curl.se/bug/?i=9749 + [166] = https://curl.se/bug/?i=9751 + [167] = https://curl.se/bug/?i=9752 + [169] = https://curl.se/bug/?i=9417 + [170] = https://curl.se/bug/?i=9415 + [171] = https://curl.se/bug/?i=9419 + [172] = https://curl.se/bug/?i=9418 + [173] = https://curl.se/bug/?i=9394 + [174] = https://curl.se/bug/?i=9789 + [175] = https://curl.se/bug/?i=9389 + [176] = https://curl.se/bug/?i=8933 + [177] = https://curl.se/bug/?i=9214 + [179] = https://curl.se/bug/?i=9784 + [181] = https://curl.se/bug/?i=9766 + [182] = https://curl.se/bug/?i=9779 + [184] = https://curl.se/bug/?i=9773 + [186] = https://curl.se/bug/?i=9638 + [187] = https://curl.se/bug/?i=9755 diff --git a/contrib/libs/curl/include/curl/curl.h b/contrib/libs/curl/include/curl/curl.h index 7a1b561961..e28dd0b5a0 100644 --- a/contrib/libs/curl/include/curl/curl.h +++ b/contrib/libs/curl/include/curl/curl.h @@ -840,8 +840,8 @@ enum curl_khstat { CURLKHSTAT_FINE_ADD_TO_FILE, CURLKHSTAT_FINE, CURLKHSTAT_REJECT, /* reject the connection, return an error */ - CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so - this causes a CURLE_DEFER error but otherwise the + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now. + Causes a CURLE_PEER_FAILED_VERIFICATION error but the connection will be left intact etc */ CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key*/ CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ @@ -2154,6 +2154,9 @@ typedef enum { /* specify which protocols that libcurl is allowed to follow directs to */ CURLOPT(CURLOPT_REDIR_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 319), + /* websockets options */ + CURLOPT(CURLOPT_WS_OPTIONS, CURLOPTTYPE_LONG, 320), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -3109,6 +3112,7 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); #include "urlapi.h" #include "options.h" #include "header.h" +#include "websockets.h" /* the typechecker doesn't work in C++ (yet) */ #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ diff --git a/contrib/libs/curl/include/curl/curlver.h b/contrib/libs/curl/include/curl/curlver.h index 33753c72f5..2e7124e6ea 100644 --- a/contrib/libs/curl/include/curl/curlver.h +++ b/contrib/libs/curl/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 "7.85.0" +#define LIBCURL_VERSION "7.86.0" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 85 +#define LIBCURL_VERSION_MINOR 86 #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 0x075500 +#define LIBCURL_VERSION_NUM 0x075600 /* * This is the date and time when the full source package was created. The @@ -70,7 +70,7 @@ * * "2007-11-23" */ -#define LIBCURL_TIMESTAMP "2022-08-31" +#define LIBCURL_TIMESTAMP "2022-10-26" #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z)) #define CURL_AT_LEAST_VERSION(x,y,z) \ diff --git a/contrib/libs/curl/include/curl/header.h b/contrib/libs/curl/include/curl/header.h index 6af29c0c0a..1598c6f113 100644 --- a/contrib/libs/curl/include/curl/header.h +++ b/contrib/libs/curl/include/curl/header.h @@ -24,6 +24,10 @@ * ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + struct curl_header { char *name; /* this might not use the same case */ char *value; @@ -63,4 +67,8 @@ CURL_EXTERN struct curl_header *curl_easy_nextheader(CURL *easy, int request, struct curl_header *prev); +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + #endif /* CURLINC_HEADER_H */ diff --git a/contrib/libs/curl/include/curl/multi.h b/contrib/libs/curl/include/curl/multi.h index 30104925b7..2f3ec37a76 100644 --- a/contrib/libs/curl/include/curl/multi.h +++ b/contrib/libs/curl/include/curl/multi.h @@ -124,7 +124,7 @@ struct curl_waitfd { /* * Name: curl_multi_init() * - * Desc: inititalize multi-style curl usage + * Desc: initialize multi-style curl usage * * Returns: a new CURLM handle to use in all 'curl_multi' functions. */ diff --git a/contrib/libs/curl/include/curl/options.h b/contrib/libs/curl/include/curl/options.h index c8ac827c07..a792687cf4 100644 --- a/contrib/libs/curl/include/curl/options.h +++ b/contrib/libs/curl/include/curl/options.h @@ -33,7 +33,7 @@ typedef enum { CURLOT_VALUES, /* (a defined set or bitmask) */ CURLOT_OFF_T, /* curl_off_t (a range of values) */ CURLOT_OBJECT, /* pointer (void *) */ - CURLOT_STRING, /* (char * to zero terminated buffer) */ + CURLOT_STRING, /* (char * to null-terminated buffer) */ CURLOT_SLIST, /* (struct curl_slist *) */ CURLOT_CBPTR, /* (void * passed as-is to a callback) */ CURLOT_BLOB, /* blob (struct curl_blob *) */ diff --git a/contrib/libs/curl/include/curl/websockets.h b/contrib/libs/curl/include/curl/websockets.h new file mode 100644 index 0000000000..4d57f91e56 --- /dev/null +++ b/contrib/libs/curl/include/curl/websockets.h @@ -0,0 +1,83 @@ +#ifndef CURLINC_WEBSOCKETS_H +#define CURLINC_WEBSOCKETS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +struct curl_ws_frame { + int age; /* zero */ + int flags; /* See the CURLWS_* defines */ + curl_off_t offset; /* the offset of this data into the frame */ + curl_off_t bytesleft; /* number of pending bytes left of the payload */ +}; + +/* flag bits */ +#define CURLWS_TEXT (1<<0) +#define CURLWS_BINARY (1<<1) +#define CURLWS_CONT (1<<2) +#define CURLWS_CLOSE (1<<3) +#define CURLWS_PING (1<<4) +#define CURLWS_OFFSET (1<<5) + +/* + * NAME curl_ws_recv() + * + * DESCRIPTION + * + * Receives data from the websocket connection. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, + size_t *recv, + struct curl_ws_frame **metap); + +/* sendflags for curl_ws_send() */ +#define CURLWS_PONG (1<<6) + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the websocket connection. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, + size_t buflen, size_t *sent, + curl_off_t framesize, + unsigned int sendflags); + +/* bits for the CURLOPT_WS_OPTIONS bitmask: */ +#define CURLWS_RAW_MODE (1<<0) + +CURL_EXTERN struct curl_ws_frame *curl_ws_meta(CURL *curl); + +#ifdef __cplusplus +} +#endif + +#endif /* CURLINC_WEBSOCKETS_H */ diff --git a/contrib/libs/curl/lib/altsvc.c b/contrib/libs/curl/lib/altsvc.c index 2c0b3bdc43..7bca840151 100644 --- a/contrib/libs/curl/lib/altsvc.c +++ b/contrib/libs/curl/lib/altsvc.c @@ -52,15 +52,7 @@ #define MAX_ALTSVC_ALPNLENSTR "10" #define MAX_ALTSVC_ALPNLEN 10 -#if defined(USE_QUICHE) && !defined(UNITTESTS) -#define H3VERSION "h3-29" -#elif defined(USE_NGTCP2) && !defined(UNITTESTS) -#define H3VERSION "h3-29" -#elif defined(USE_MSH3) && !defined(UNITTESTS) -#define H3VERSION "h3-29" -#else #define H3VERSION "h3" -#endif static enum alpnid alpn2alpnid(char *name) { @@ -470,6 +462,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, struct altsvc *as; unsigned short dstport = srcport; /* the same by default */ CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); + size_t entries = 0; #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; #endif @@ -480,11 +473,10 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, DEBUGASSERT(asi); - /* Flush all cached alternatives for this source origin, if any */ - altsvc_flush(asi, srcalpnid, srchost, srcport); - /* "clear" is a magic keyword */ if(strcasecompare(alpnbuf, "clear")) { + /* Flush cached alternatives for this source origin */ + altsvc_flush(asi, srcalpnid, srchost, srcport); return CURLE_OK; } @@ -502,6 +494,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, bool quoted = FALSE; time_t maxage = 24 * 3600; /* default is 24 hours */ bool persist = FALSE; + bool valid = TRUE; p++; if(*p != ':') { /* host name starts here */ @@ -511,7 +504,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, len = p - hostp; if(!len || (len >= MAX_ALTSVC_HOSTLEN)) { infof(data, "Excessive alt-svc host name, ignoring."); - dstalpnid = ALPN_none; + valid = FALSE; } else { memcpy(namebuf, hostp, len); @@ -528,10 +521,11 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, unsigned long port = strtoul(++p, &end_ptr, 10); if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') { infof(data, "Unknown alt-svc port number, ignoring."); - dstalpnid = ALPN_none; + valid = FALSE; } + else + dstport = curlx_ultous(port); p = end_ptr; - dstport = curlx_ultous(port); } if(*p++ != '\"') break; @@ -583,7 +577,12 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, persist = TRUE; } } - if(dstalpnid) { + if(dstalpnid && valid) { + if(!entries++) + /* Flush cached alternatives for this source origin, if any - when + this is the first entry of the line. */ + altsvc_flush(asi, srcalpnid, srchost, srcport); + as = altsvc_createid(srchost, dsthost, srcalpnid, dstalpnid, srcport, dstport); @@ -597,10 +596,6 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, Curl_alpnid2str(dstalpnid)); } } - else { - infof(data, "Unknown alt-svc protocol \"%s\", skipping.", - alpnbuf); - } } else break; diff --git a/contrib/libs/curl/lib/amigaos.c b/contrib/libs/curl/lib/amigaos.c index c235a77f43..42b0c39b37 100644 --- a/contrib/libs/curl/lib/amigaos.c +++ b/contrib/libs/curl/lib/amigaos.c @@ -26,6 +26,8 @@ #ifdef __AMIGA__ +#include <curl/curl.h> + #include "hostip.h" #include "amigaos.h" diff --git a/contrib/libs/curl/lib/asyn-ares.c b/contrib/libs/curl/lib/asyn-ares.c index fb933b5edf..33edba1395 100644 --- a/contrib/libs/curl/lib/asyn-ares.c +++ b/contrib/libs/curl/lib/asyn-ares.c @@ -746,7 +746,7 @@ static void addrinfo_cb(void *arg, int status, int timeouts, * Curl_resolver_getaddrinfo() - when using ares * * Returns name information about the given hostname and port number. If - * successful, the 'hostent' is returned and the forth argument will point to + * successful, the 'hostent' is returned and the fourth argument will point to * memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. */ @@ -779,13 +779,17 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, int pf = PF_INET; memset(&hints, 0, sizeof(hints)); #ifdef CURLRES_IPV6 - if(Curl_ipv6works(data)) + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) /* The stack seems to be IPv6-enabled */ pf = PF_UNSPEC; #endif /* CURLRES_IPV6 */ hints.ai_family = pf; hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)? SOCK_STREAM : SOCK_DGRAM; + /* Since the service is a numerical one, set the hint flags + * accordingly to save a call to getservbyname in inside C-Ares + */ + hints.ai_flags = ARES_AI_NUMERICSERV; msnprintf(service, sizeof(service), "%d", port); res->num_pending = 1; ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname, @@ -794,7 +798,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, #else #ifdef HAVE_CARES_IPV6 - if(Curl_ipv6works(data)) { + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) { /* The stack seems to be IPv6-enabled */ res->num_pending = 2; diff --git a/contrib/libs/curl/lib/asyn-thread.c b/contrib/libs/curl/lib/asyn-thread.c index 248d63576e..0e4ebdc8b5 100644 --- a/contrib/libs/curl/lib/asyn-thread.c +++ b/contrib/libs/curl/lib/asyn-thread.c @@ -811,7 +811,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, *waitp = 0; /* default to synchronous response */ #ifdef CURLRES_IPV6 - if(Curl_ipv6works(data)) + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) /* The stack seems to be IPv6-enabled */ pf = PF_UNSPEC; #endif /* CURLRES_IPV6 */ diff --git a/contrib/libs/curl/lib/asyn.h b/contrib/libs/curl/lib/asyn.h index 80ca54d787..1aab21aaa7 100644 --- a/contrib/libs/curl/lib/asyn.h +++ b/contrib/libs/curl/lib/asyn.h @@ -148,7 +148,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, * Curl_resolver_getaddrinfo() - when using this resolver * * Returns name information about the given hostname and port number. If - * successful, the 'hostent' is returned and the forth argument will point to + * successful, the 'hostent' is returned and the fourth argument will point to * memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. * diff --git a/contrib/libs/curl/lib/base64.c b/contrib/libs/curl/lib/base64.c index 53ebc3db30..52654c2bc3 100644 --- a/contrib/libs/curl/lib/base64.c +++ b/contrib/libs/curl/lib/base64.c @@ -47,7 +47,7 @@ static const char base64[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; -/* The Base 64 encoding with an URL and filename safe alphabet, RFC 4648 +/* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648 section 5 */ static const char base64url[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; @@ -138,7 +138,7 @@ CURLcode Curl_base64_decode(const char *src, /* Calculate the size of the decoded string */ rawlen = (numQuantums * 3) - padding; - /* Allocate our buffer including room for a zero terminator */ + /* Allocate our buffer including room for a null-terminator */ newstr = malloc(rawlen + 1); if(!newstr) return CURLE_OUT_OF_MEMORY; diff --git a/contrib/libs/curl/lib/c-hyper.c b/contrib/libs/curl/lib/c-hyper.c index 3c9c163163..ab6740ca4a 100644 --- a/contrib/libs/curl/lib/c-hyper.c +++ b/contrib/libs/curl/lib/c-hyper.c @@ -54,6 +54,7 @@ #include "multiif.h" #include "progress.h" #include "content_encoding.h" +#include "ws.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -471,6 +472,24 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data, if(result) break; + k->deductheadercount = + (100 <= http_status && 199 >= http_status)?k->headerbytecount:0; +#ifdef USE_WEBSOCKETS + if(k->upgr101 == UPGR101_WS) { + if(http_status == 101) { + /* verify the response */ + result = Curl_ws_accept(data); + if(result) + return result; + } + else { + failf(data, "Expected 101, got %u", k->httpcode); + result = CURLE_HTTP_RETURNED_ERROR; + break; + } + } +#endif + /* Curl_http_auth_act() checks what authentication methods that are * available and decides which one (if any) to use. It will set 'newurl' * if an auth method was picked. */ @@ -918,7 +937,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) result = CURLE_OUT_OF_MEMORY; goto error; } - if(conn->negnpn == CURL_HTTP_VERSION_2) { + if(conn->alpn == CURL_HTTP_VERSION_2) { hyper_clientconn_options_http2(options, 1); h2 = TRUE; } @@ -1123,6 +1142,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(result) goto error; + if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) + result = Curl_ws_request(data, headers); + result = Curl_add_timecondition(data, headers); if(result) goto error; diff --git a/contrib/libs/curl/lib/conncache.c b/contrib/libs/curl/lib/conncache.c index 2a399c8814..a557ac6dc9 100644 --- a/contrib/libs/curl/lib/conncache.c +++ b/contrib/libs/curl/lib/conncache.c @@ -498,7 +498,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data) conn = curr->ptr; if(!CONN_INUSE(conn) && !conn->bits.close && - !conn->bits.connect_only) { + !conn->connect_only) { /* Set higher score for the age passed since the connection was used */ score = Curl_timediff(now, conn->lastused); diff --git a/contrib/libs/curl/lib/conncache.h b/contrib/libs/curl/lib/conncache.h index 6ec2757433..94664bc357 100644 --- a/contrib/libs/curl/lib/conncache.h +++ b/contrib/libs/curl/lib/conncache.h @@ -31,6 +31,7 @@ * be shared. */ +#include <curl/curl.h> #include "timeval.h" struct connectdata; diff --git a/contrib/libs/curl/lib/connect.c b/contrib/libs/curl/lib/connect.c index be9f72117c..ac007c61b0 100644 --- a/contrib/libs/curl/lib/connect.c +++ b/contrib/libs/curl/lib/connect.c @@ -625,7 +625,8 @@ void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn, else data->info.conn_local_ip[0] = 0; data->info.conn_scheme = conn->handler->scheme; - data->info.conn_protocol = conn->handler->protocol; + /* conn_protocol can only provide "old" protocols */ + data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK; data->info.conn_primary_port = conn->port; data->info.conn_remote_port = conn->remote_port; data->info.conn_local_port = local_port; @@ -761,18 +762,10 @@ void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn, char local_ip[MAX_IPADR_LEN] = ""; int local_port = -1; - if(conn->transport == TRNSPRT_TCP) { - if(!conn->bits.reuse && !conn->bits.tcp_fastopen) - Curl_conninfo_remote(data, conn, sockfd); - Curl_conninfo_local(data, sockfd, local_ip, &local_port); - } /* end of TCP-only section */ -#ifdef ENABLE_QUIC - else if(conn->transport == TRNSPRT_QUIC) { - if(!conn->bits.reuse) - Curl_conninfo_remote(data, conn, sockfd); - Curl_conninfo_local(data, sockfd, local_ip, &local_port); - } -#endif + if(!conn->bits.reuse && + (conn->transport != TRNSPRT_TCP || !conn->bits.tcp_fastopen)) + Curl_conninfo_remote(data, conn, sockfd); + Curl_conninfo_local(data, sockfd, local_ip, &local_port); /* persist connection info in session handle */ Curl_persistconninfo(data, conn, local_ip, local_port); @@ -1046,7 +1039,6 @@ CURLcode Curl_is_connected(struct Curl_easy *data, (conn->tempsock[1] == CURL_SOCKET_BAD)) { /* no more addresses to try */ const char *hostname; - char buffer[STRERROR_LEN]; CURLcode failreason = result; /* if the first address family runs out of addresses to try before the @@ -1073,11 +1065,7 @@ CURLcode Curl_is_connected(struct Curl_easy *data, "%" CURL_FORMAT_TIMEDIFF_T " ms: %s", hostname, conn->port, Curl_timediff(now, data->progress.t_startsingle), -#ifdef ENABLE_QUIC - (conn->transport == TRNSPRT_QUIC) ? - curl_easy_strerror(result) : -#endif - Curl_strerror(error, buffer, sizeof(buffer))); + curl_easy_strerror(result)); Curl_quic_disconnect(data, conn, 0); Curl_quic_disconnect(data, conn, 1); @@ -1209,6 +1197,7 @@ static CURLcode singleipconnect(struct Curl_easy *data, #ifdef TCP_FASTOPEN_CONNECT int optval = 1; #endif + const char *ipmsg; char buffer[STRERROR_LEN]; curl_socket_t *sockp = &conn->tempsock[tempindex]; *sockp = CURL_SOCKET_BAD; @@ -1226,7 +1215,13 @@ static CURLcode singleipconnect(struct Curl_easy *data, Curl_closesocket(data, conn, sockfd); return CURLE_OK; } - infof(data, " Trying %s:%d...", ipaddress, port); +#ifdef ENABLE_IPV6 + if(addr.family == AF_INET6) + ipmsg = " Trying [%s]:%d..."; + else +#endif + ipmsg = " Trying %s:%d..."; + infof(data, ipmsg, ipaddress, port); #ifdef ENABLE_IPV6 is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) && diff --git a/contrib/libs/curl/lib/content_encoding.c b/contrib/libs/curl/lib/content_encoding.c index e3c7ab9b1d..39bb9b5b13 100644 --- a/contrib/libs/curl/lib/content_encoding.c +++ b/contrib/libs/curl/lib/content_encoding.c @@ -28,7 +28,7 @@ #include <curl/curl.h> #include <stddef.h> -#ifdef HAVE_ZLIB_H +#ifdef HAVE_LIBZ #include <zlib.h> #endif @@ -82,8 +82,9 @@ typedef enum { ZLIB_INIT_GZIP /* initialized in transparent gzip mode */ } zlibInitState; -/* Writer parameters. */ -struct zlib_params { +/* Deflate and gzip writer. */ +struct zlib_writer { + struct contenc_writer super; zlibInitState zlib_init; /* zlib init state */ uInt trailerlen; /* Remaining trailer byte count. */ z_stream z; /* State structure for zlib. */ @@ -135,7 +136,7 @@ exit_zlib(struct Curl_easy *data, } static CURLcode process_trailer(struct Curl_easy *data, - struct zlib_params *zp) + struct zlib_writer *zp) { z_stream *z = &zp->z; CURLcode result = CURLE_OK; @@ -162,7 +163,7 @@ static CURLcode inflate_stream(struct Curl_easy *data, struct contenc_writer *writer, zlibInitState started) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ uInt nread = z->avail_in; Bytef *orig_in = z->next_in; @@ -265,7 +266,7 @@ static CURLcode inflate_stream(struct Curl_easy *data, static CURLcode deflate_init_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ if(!writer->downstream) @@ -285,7 +286,7 @@ static CURLcode deflate_unencode_write(struct Curl_easy *data, struct contenc_writer *writer, const char *buf, size_t nbytes) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ /* Set the compressed input when this function is called */ @@ -302,7 +303,7 @@ static CURLcode deflate_unencode_write(struct Curl_easy *data, static void deflate_close_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ exit_zlib(data, z, &zp->zlib_init, CURLE_OK); @@ -314,7 +315,7 @@ static const struct content_encoding deflate_encoding = { deflate_init_writer, deflate_unencode_write, deflate_close_writer, - sizeof(struct zlib_params) + sizeof(struct zlib_writer) }; @@ -322,7 +323,7 @@ static const struct content_encoding deflate_encoding = { static CURLcode gzip_init_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ if(!writer->downstream) @@ -439,7 +440,7 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data, struct contenc_writer *writer, const char *buf, size_t nbytes) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ if(zp->zlib_init == ZLIB_INIT_GZIP) { @@ -566,7 +567,7 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data, static void gzip_close_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ exit_zlib(data, z, &zp->zlib_init, CURLE_OK); @@ -578,15 +579,16 @@ static const struct content_encoding gzip_encoding = { gzip_init_writer, gzip_unencode_write, gzip_close_writer, - sizeof(struct zlib_params) + sizeof(struct zlib_writer) }; #endif /* HAVE_LIBZ */ #ifdef HAVE_BROTLI -/* Writer parameters. */ -struct brotli_params { +/* Brotli writer. */ +struct brotli_writer { + struct contenc_writer super; BrotliDecoderState *br; /* State structure for brotli. */ }; @@ -631,7 +633,7 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be) static CURLcode brotli_init_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct brotli_params *bp = (struct brotli_params *) &writer->params; + struct brotli_writer *bp = (struct brotli_writer *) writer; (void) data; if(!writer->downstream) @@ -645,7 +647,7 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data, struct contenc_writer *writer, const char *buf, size_t nbytes) { - struct brotli_params *bp = (struct brotli_params *) &writer->params; + struct brotli_writer *bp = (struct brotli_writer *) writer; const uint8_t *src = (const uint8_t *) buf; char *decomp; uint8_t *dst; @@ -692,7 +694,8 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data, static void brotli_close_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct brotli_params *bp = (struct brotli_params *) &writer->params; + struct brotli_writer *bp = (struct brotli_writer *) writer; + (void) data; if(bp->br) { @@ -707,14 +710,15 @@ static const struct content_encoding brotli_encoding = { brotli_init_writer, brotli_unencode_write, brotli_close_writer, - sizeof(struct brotli_params) + sizeof(struct brotli_writer) }; #endif #ifdef HAVE_ZSTD -/* Writer parameters. */ -struct zstd_params { +/* Zstd writer. */ +struct zstd_writer { + struct contenc_writer super; ZSTD_DStream *zds; /* State structure for zstd. */ void *decomp; }; @@ -722,7 +726,8 @@ struct zstd_params { static CURLcode zstd_init_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zstd_params *zp = (struct zstd_params *)&writer->params; + struct zstd_writer *zp = (struct zstd_writer *) writer; + (void)data; if(!writer->downstream) @@ -738,7 +743,7 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data, const char *buf, size_t nbytes) { CURLcode result = CURLE_OK; - struct zstd_params *zp = (struct zstd_params *)&writer->params; + struct zstd_writer *zp = (struct zstd_writer *) writer; ZSTD_inBuffer in; ZSTD_outBuffer out; size_t errorCode; @@ -777,7 +782,8 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data, static void zstd_close_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zstd_params *zp = (struct zstd_params *)&writer->params; + struct zstd_writer *zp = (struct zstd_writer *) writer; + (void)data; if(zp->decomp) { @@ -796,7 +802,7 @@ static const struct content_encoding zstd_encoding = { zstd_init_writer, zstd_unencode_write, zstd_close_writer, - sizeof(struct zstd_params) + sizeof(struct zstd_writer) }; #endif @@ -829,7 +835,7 @@ static const struct content_encoding identity_encoding = { identity_init_writer, identity_unencode_write, identity_close_writer, - 0 + sizeof(struct contenc_writer) }; @@ -921,7 +927,7 @@ static const struct content_encoding client_encoding = { client_init_writer, client_unencode_write, client_close_writer, - 0 + sizeof(struct contenc_writer) }; @@ -964,7 +970,7 @@ static const struct content_encoding error_encoding = { error_init_writer, error_unencode_write, error_close_writer, - 0 + sizeof(struct contenc_writer) }; /* Create an unencoding writer stage using the given handler. */ @@ -973,8 +979,10 @@ new_unencoding_writer(struct Curl_easy *data, const struct content_encoding *handler, struct contenc_writer *downstream) { - size_t sz = offsetof(struct contenc_writer, params) + handler->paramsize; - struct contenc_writer *writer = (struct contenc_writer *)calloc(1, sz); + struct contenc_writer *writer; + + DEBUGASSERT(handler->writersize >= sizeof(struct contenc_writer)); + writer = (struct contenc_writer *) calloc(1, handler->writersize); if(writer) { writer->handler = handler; @@ -1044,7 +1052,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, size_t namelen; /* Parse a single encoding name. */ - while(ISSPACE(*enclist) || *enclist == ',') + while(ISBLANK(*enclist) || *enclist == ',') enclist++; name = enclist; diff --git a/contrib/libs/curl/lib/content_encoding.h b/contrib/libs/curl/lib/content_encoding.h index 81bddd1be1..3c278cf727 100644 --- a/contrib/libs/curl/lib/content_encoding.h +++ b/contrib/libs/curl/lib/content_encoding.h @@ -28,7 +28,6 @@ struct contenc_writer { const struct content_encoding *handler; /* Encoding handler. */ struct contenc_writer *downstream; /* Downstream writer. */ - void *params; /* Encoding-specific storage (variable length). */ }; /* Content encoding writer. */ @@ -42,7 +41,7 @@ struct content_encoding { const char *buf, size_t nbytes); void (*close_writer)(struct Curl_easy *data, struct contenc_writer *writer); - size_t paramsize; + size_t writersize; }; diff --git a/contrib/libs/curl/lib/cookie.c b/contrib/libs/curl/lib/cookie.c index ab790a1cdb..8eaedeeb7f 100644 --- a/contrib/libs/curl/lib/cookie.c +++ b/contrib/libs/curl/lib/cookie.c @@ -458,11 +458,10 @@ static int invalid_octets(const char *p) "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" "\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f" }; - size_t vlen, len; + size_t len; /* scan for all the octets that are *not* in cookie-octet */ len = strcspn(p, badoctets); - vlen = strlen(p); - return (len != vlen); + return (p[len] != '\0'); } /* @@ -538,7 +537,7 @@ Curl_cookie_add(struct Curl_easy *data, do { /* we have a <what>=<this> pair or a stand-alone word here */ name[0] = what[0] = 0; /* init the buffers */ - if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%" + if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\t\r\n=] =%" MAX_NAME_TXT "[^;\r\n]", name, what)) { /* @@ -592,6 +591,13 @@ Curl_cookie_add(struct Curl_easy *data, while(*whatptr && ISBLANK(*whatptr)) whatptr++; + /* Reject cookies with a TAB inside the content */ + if(strchr(whatptr, '\t')) { + freecookie(co); + infof(data, "cookie contains TAB, dropping"); + return NULL; + } + /* * Check if we have a reserved prefix set before anything else, as we * otherwise have to test for the prefix in both the cookie name and diff --git a/contrib/libs/curl/lib/curl_addrinfo.c b/contrib/libs/curl/lib/curl_addrinfo.c index 34c594a162..a844101b92 100644 --- a/contrib/libs/curl/lib/curl_addrinfo.c +++ b/contrib/libs/curl/lib/curl_addrinfo.c @@ -279,7 +279,7 @@ Curl_he2ai(const struct hostent *he, int port) for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) { size_t ss_size; - size_t namelen = strlen(he->h_name) + 1; /* include zero termination */ + size_t namelen = strlen(he->h_name) + 1; /* include null-terminatior */ #ifdef ENABLE_IPV6 if(he->h_addrtype == AF_INET6) ss_size = sizeof(struct sockaddr_in6); diff --git a/contrib/libs/curl/lib/curl_config-linux.h b/contrib/libs/curl/lib/curl_config-linux.h index 8d065ebdd4..765dd67d61 100644 --- a/contrib/libs/curl/lib/curl_config-linux.h +++ b/contrib/libs/curl/lib/curl_config-linux.h @@ -390,12 +390,6 @@ /* Define to 1 if you have the `ssh2' library (-lssh2). */ /* #undef HAVE_LIBSSH2 */ -/* Define to 1 if you have the <libssh2.h> header file. */ -/* #undef HAVE_LIBSSH2_H */ - -/* Define to 1 if you have the <libssh/libssh.h> header file. */ -/* #undef HAVE_LIBSSH_LIBSSH_H */ - /* Define to 1 if you have the `ssl' library (-lssl). */ #define HAVE_LIBSSL 1 @@ -569,6 +563,9 @@ /* Define to 1 if you have the sigsetjmp function or macro. */ #define HAVE_SIGSETJMP 1 +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + /* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ #define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 @@ -746,9 +743,6 @@ /* Define to 1 if you have the <x509.h> header file. */ /* #undef HAVE_X509_H */ -/* if you have the zlib.h header file */ -#define HAVE_ZLIB_H 1 - /* if libzstd is in use */ /* #undef HAVE_ZSTD */ @@ -800,54 +794,6 @@ /* a suitable file to read random data from */ #define RANDOM_FILE "/dev/urandom" -/* Define to the type of arg 1 for recv. */ -#define RECV_TYPE_ARG1 int - -/* Define to the type of arg 2 for recv. */ -#define RECV_TYPE_ARG2 void * - -/* Define to the type of arg 3 for recv. */ -#define RECV_TYPE_ARG3 size_t - -/* Define to the type of arg 4 for recv. */ -#define RECV_TYPE_ARG4 int - -/* Define to the function return type for recv. */ -#define RECV_TYPE_RETV ssize_t - -/* Define to the type qualifier of arg 5 for select. */ -#define SELECT_QUAL_ARG5 - -/* Define to the type of arg 1 for select. */ -#define SELECT_TYPE_ARG1 int - -/* Define to the type of args 2, 3 and 4 for select. */ -#define SELECT_TYPE_ARG234 fd_set * - -/* Define to the type of arg 5 for select. */ -#define SELECT_TYPE_ARG5 struct timeval * - -/* Define to the function return type for select. */ -#define SELECT_TYPE_RETV int - -/* Define to the type qualifier of arg 2 for send. */ -#define SEND_QUAL_ARG2 const - -/* Define to the type of arg 1 for send. */ -#define SEND_TYPE_ARG1 int - -/* Define to the type of arg 2 for send. */ -#define SEND_TYPE_ARG2 void * - -/* Define to the type of arg 3 for send. */ -#define SEND_TYPE_ARG3 size_t - -/* Define to the type of arg 4 for send. */ -#define SEND_TYPE_ARG4 int - -/* Define to the function return type for send. */ -#define SEND_TYPE_RETV ssize_t - /* Size of curl_off_t in number of bytes */ #define SIZEOF_CURL_OFF_T 8 @@ -971,6 +917,9 @@ /* Use Unix domain sockets */ #define USE_UNIX_SOCKETS 1 +/* enable websockets support */ +/* #undef USE_WEBSOCKETS */ + /* Define to 1 if you are building a Windows target with crypto API support. */ /* #undef USE_WIN32_CRYPTO */ diff --git a/contrib/libs/curl/lib/curl_ctype.c b/contrib/libs/curl/lib/curl_ctype.c deleted file mode 100644 index e1a8445151..0000000000 --- a/contrib/libs/curl/lib/curl_ctype.c +++ /dev/null @@ -1,132 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ - -#include "curl_setup.h" - -#undef _U -#define _U (1<<0) /* upper case */ -#undef _L -#define _L (1<<1) /* lower case */ -#undef _N -#define _N (1<<2) /* decimal numerical digit */ -#undef _S -#define _S (1<<3) /* space */ -#undef _P -#define _P (1<<4) /* punctuation */ -#undef _C -#define _C (1<<5) /* control */ -#undef _X -#define _X (1<<6) /* hexadecimal letter */ -#undef _B -#define _B (1<<7) /* blank */ - -static const unsigned char ascii[128] = { - _C, _C, _C, _C, _C, _C, _C, _C, - _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, - _C, _C, _C, _C, _C, _C, _C, _C, - _C, _C, _C, _C, _C, _C, _C, _C, - _S|_B, _P, _P, _P, _P, _P, _P, _P, - _P, _P, _P, _P, _P, _P, _P, _P, - _N, _N, _N, _N, _N, _N, _N, _N, - _N, _N, _P, _P, _P, _P, _P, _P, - _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, - _U, _U, _U, _U, _U, _U, _U, _U, - _U, _U, _U, _U, _U, _U, _U, _U, - _U, _U, _U, _P, _P, _P, _P, _P, - _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, - _L, _L, _L, _L, _L, _L, _L, _L, - _L, _L, _L, _L, _L, _L, _L, _L, - _L, _L, _L, _P, _P, _P, _P, _C -}; - -int Curl_isspace(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & _S); -} - -int Curl_isdigit(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & _N); -} - -int Curl_isalnum(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_N|_U|_L)); -} - -int Curl_isxdigit(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_N|_X)); -} - -int Curl_isgraph(int c) -{ - if((c < 0) || (c >= 0x80) || (c == ' ')) - return FALSE; - return (ascii[c] & (_N|_X|_U|_L|_P|_S)); -} - -int Curl_isprint(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_N|_X|_U|_L|_P|_S)); -} - -int Curl_isalpha(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_U|_L)); -} - -int Curl_isupper(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_U)); -} - -int Curl_islower(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_L)); -} - -int Curl_iscntrl(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_C)); -} - diff --git a/contrib/libs/curl/lib/curl_ctype.h b/contrib/libs/curl/lib/curl_ctype.h index c70945a8d2..dc6b8cab86 100644 --- a/contrib/libs/curl/lib/curl_ctype.h +++ b/contrib/libs/curl/lib/curl_ctype.h @@ -24,32 +24,24 @@ * ***************************************************************************/ -#include "curl_setup.h" +#define ISLOWHEXALHA(x) (((x) >= 'a') && ((x) <= 'f')) +#define ISUPHEXALHA(x) (((x) >= 'A') && ((x) <= 'F')) -int Curl_isspace(int c); -int Curl_isdigit(int c); -int Curl_isalnum(int c); -int Curl_isxdigit(int c); -int Curl_isgraph(int c); -int Curl_isprint(int c); -int Curl_isalpha(int c); -int Curl_isupper(int c); -int Curl_islower(int c); -int Curl_iscntrl(int c); +#define ISLOWCNTRL(x) ((x) >= 0 && ((x) <= 0x1f)) +#define IS7F(x) ((x) == 0x7f) -#define ISSPACE(x) (Curl_isspace((int) ((unsigned char)x))) -#define ISDIGIT(x) (Curl_isdigit((int) ((unsigned char)x))) -#define ISALNUM(x) (Curl_isalnum((int) ((unsigned char)x))) -#define ISXDIGIT(x) (Curl_isxdigit((int) ((unsigned char)x))) -#define ISGRAPH(x) (Curl_isgraph((int) ((unsigned char)x))) -#define ISALPHA(x) (Curl_isalpha((int) ((unsigned char)x))) -#define ISPRINT(x) (Curl_isprint((int) ((unsigned char)x))) -#define ISUPPER(x) (Curl_isupper((int) ((unsigned char)x))) -#define ISLOWER(x) (Curl_islower((int) ((unsigned char)x))) -#define ISCNTRL(x) (Curl_iscntrl((int) ((unsigned char)x))) -#define ISASCII(x) (((x) >= 0) && ((x) <= 0x80)) +#define ISLOWPRINT(x) (((x) >= 9) && ((x) <= 0x0d)) -#define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \ - (((unsigned char)x) == '\t')) +#define ISPRINT(x) (ISLOWPRINT(x) || (((x) >= ' ') && ((x) <= 0x7e))) +#define ISGRAPH(x) (ISLOWPRINT(x) || (((x) > ' ') && ((x) <= 0x7e))) +#define ISCNTRL(x) (ISLOWCNTRL(x) || IS7F(x)) +#define ISALPHA(x) (ISLOWER(x) || ISUPPER(x)) +#define ISXDIGIT(x) (ISDIGIT(x) || ISLOWHEXALHA(x) || ISUPHEXALHA(x)) +#define ISALNUM(x) (ISDIGIT(x) || ISLOWER(x) || ISUPPER(x)) +#define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z')) +#define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z')) +#define ISDIGIT(x) (((x) >= '0') && ((x) <= '9')) +#define ISBLANK(x) (((x) == ' ') || ((x) == '\t')) +#define ISSPACE(x) (ISBLANK(x) || (((x) >= 0xa) && ((x) <= 0x0d))) #endif /* HEADER_CURL_CTYPE_H */ diff --git a/contrib/libs/curl/lib/curl_des.c b/contrib/libs/curl/lib/curl_des.c index 6d52cd3635..a2bf648c29 100644 --- a/contrib/libs/curl/lib/curl_des.c +++ b/contrib/libs/curl/lib/curl_des.c @@ -41,7 +41,7 @@ * * The function is a port of the Java based oddParity() function over at: * - * https://davenport.sourceforge.io/ntlm.html + * https://davenport.sourceforge.net/ntlm.html * * Parameters: * diff --git a/contrib/libs/curl/lib/curl_get_line.c b/contrib/libs/curl/lib/curl_get_line.c index 6a26bb254f..22e3705f4c 100644 --- a/contrib/libs/curl/lib/curl_get_line.c +++ b/contrib/libs/curl/lib/curl_get_line.c @@ -25,7 +25,7 @@ #include "curl_setup.h" #if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \ - !defined(CURL_DISABLE_HSTS) + !defined(CURL_DISABLE_HSTS) || !defined(CURL_DISABLE_NETRC) #include "curl_get_line.h" #include "curl_memory.h" @@ -33,8 +33,8 @@ #include "memdebug.h" /* - * get_line() makes sure to only return complete whole lines that fit in 'len' - * bytes and end with a newline. + * Curl_get_line() makes sure to only return complete whole lines that fit in + * 'len' bytes and end with a newline. */ char *Curl_get_line(char *buf, int len, FILE *input) { diff --git a/contrib/libs/curl/lib/curl_hmac.h b/contrib/libs/curl/lib/curl_hmac.h index 77dce0f165..36c0bd62e5 100644 --- a/contrib/libs/curl/lib/curl_hmac.h +++ b/contrib/libs/curl/lib/curl_hmac.h @@ -26,6 +26,8 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH +#include <curl/curl.h> + #define HMAC_MD5_LENGTH 16 typedef CURLcode (* HMAC_hinit_func)(void *context); diff --git a/contrib/libs/curl/lib/curl_ntlm_core.c b/contrib/libs/curl/lib/curl_ntlm_core.c index a977c2e0af..14c9f34d21 100644 --- a/contrib/libs/curl/lib/curl_ntlm_core.c +++ b/contrib/libs/curl/lib/curl_ntlm_core.c @@ -29,7 +29,7 @@ /* * NTLM details: * - * https://davenport.sourceforge.io/ntlm.html + * https://davenport.sourceforge.net/ntlm.html * https://www.innovation.ch/java/ntlm.html */ diff --git a/contrib/libs/curl/lib/curl_ntlm_wb.c b/contrib/libs/curl/lib/curl_ntlm_wb.c index f1eb9c6319..33dcf0ce25 100644 --- a/contrib/libs/curl/lib/curl_ntlm_wb.c +++ b/contrib/libs/curl/lib/curl_ntlm_wb.c @@ -30,7 +30,7 @@ /* * NTLM details: * - * https://davenport.sourceforge.io/ntlm.html + * https://davenport.sourceforge.net/ntlm.html * https://www.innovation.ch/java/ntlm.html */ diff --git a/contrib/libs/curl/lib/curl_path.c b/contrib/libs/curl/lib/curl_path.c index 92e3464956..67065809ba 100644 --- a/contrib/libs/curl/lib/curl_path.c +++ b/contrib/libs/curl/lib/curl_path.c @@ -122,7 +122,8 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir) bool relativePath = false; static const char WHITESPACE[] = " \t\r\n"; - if(!*cp) { + DEBUGASSERT(homedir); + if(!*cp || !homedir) { *cpp = NULL; *path = NULL; return CURLE_QUOTE_ERROR; diff --git a/contrib/libs/curl/lib/curl_range.c b/contrib/libs/curl/lib/curl_range.c index 9e03c3d4a6..dd92d05b39 100644 --- a/contrib/libs/curl/lib/curl_range.c +++ b/contrib/libs/curl/lib/curl_range.c @@ -47,7 +47,7 @@ CURLcode Curl_range(struct Curl_easy *data) from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from); if(from_t == CURL_OFFT_FLOW) return CURLE_RANGE_ERROR; - while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) + while(*ptr && (ISBLANK(*ptr) || (*ptr == '-'))) ptr++; to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); if(to_t == CURL_OFFT_FLOW) diff --git a/contrib/libs/curl/lib/curl_setup.h b/contrib/libs/curl/lib/curl_setup.h index 16a648ef32..5ad6f3b02e 100644 --- a/contrib/libs/curl/lib/curl_setup.h +++ b/contrib/libs/curl/lib/curl_setup.h @@ -158,8 +158,6 @@ /* please, do it beyond the point further indicated in this file. */ /* ================================================================ */ -#include <curl/curl.h> - /* * Disable other protocols when http is the only one desired. */ @@ -219,7 +217,7 @@ /* ================================================================ */ /* No system header file shall be included in this file before this */ -/* point. The only allowed ones are those included from curl/system.h */ +/* point. */ /* ================================================================ */ /* @@ -246,6 +244,8 @@ # include "setup-win32.h" #endif +#include <curl/system.h> + /* * Use getaddrinfo to resolve the IPv4 address literal. If the current network * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64, @@ -322,8 +322,10 @@ #include <assert.h> #endif -#ifdef __TANDEM /* for nsr-tandem-nsk systems */ -#include <floss.h> +#ifdef __TANDEM /* for ns*-tandem-nsk systems */ +# if ! defined __LP64 +# include <floss.h> /* FLOSS is only used for 32-bit builds. */ +# endif #endif #ifndef STDC_HEADERS /* no standard C headers! */ @@ -740,12 +742,12 @@ #define SHUT_RDWR 0x02 #endif -/* Define S_ISREG if not defined by system headers, f.e. MSVC */ +/* Define S_ISREG if not defined by system headers, e.g. MSVC */ #if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif -/* Define S_ISDIR if not defined by system headers, f.e. MSVC */ +/* Define S_ISDIR if not defined by system headers, e.g. MSVC */ #if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif diff --git a/contrib/libs/curl/lib/curl_setup_once.h b/contrib/libs/curl/lib/curl_setup_once.h index e9730c9282..f09b00f9f2 100644 --- a/contrib/libs/curl/lib/curl_setup_once.h +++ b/contrib/libs/curl/lib/curl_setup_once.h @@ -33,7 +33,6 @@ #include <stdlib.h> #include <string.h> #include <stdarg.h> -#include <ctype.h> #include <time.h> #ifdef HAVE_ERRNO_H @@ -88,6 +87,8 @@ #include <sys/socket.h> #endif +#include "functypes.h" + #ifdef __hpux # if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) # ifdef OLD_APP32_64BIT_OFF_T @@ -150,20 +151,10 @@ struct timeval { * SEND_TYPE_RETV must also be defined. */ -#if !defined(RECV_TYPE_ARG1) || \ - !defined(RECV_TYPE_ARG2) || \ - !defined(RECV_TYPE_ARG3) || \ - !defined(RECV_TYPE_ARG4) || \ - !defined(RECV_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_recv - /* */ -#else #define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \ (RECV_TYPE_ARG2)(y), \ (RECV_TYPE_ARG3)(z), \ (RECV_TYPE_ARG4)(0)) -#endif #else /* HAVE_RECV */ #ifndef sread /* */ @@ -180,21 +171,10 @@ struct timeval { (SEND_TYPE_ARG3)(z)) #elif defined(HAVE_SEND) -#if !defined(SEND_TYPE_ARG1) || \ - !defined(SEND_QUAL_ARG2) || \ - !defined(SEND_TYPE_ARG2) || \ - !defined(SEND_TYPE_ARG3) || \ - !defined(SEND_TYPE_ARG4) || \ - !defined(SEND_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_send - /* */ -#else #define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \ (SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \ (SEND_TYPE_ARG3)(z), \ (SEND_TYPE_ARG4)(SEND_4TH_ARG)) -#endif #else /* HAVE_SEND */ #ifndef swrite /* */ @@ -229,9 +209,6 @@ struct timeval { # define sfcntl fcntl #endif -#define TOLOWER(x) (tolower((int) ((unsigned char)x))) - - /* * 'bool' stuff compatible with HP-UX headers. */ diff --git a/contrib/libs/curl/lib/curl_sha256.h b/contrib/libs/curl/lib/curl_sha256.h index 9530b056da..7f296dc8f0 100644 --- a/contrib/libs/curl/lib/curl_sha256.h +++ b/contrib/libs/curl/lib/curl_sha256.h @@ -26,6 +26,7 @@ ***************************************************************************/ #ifndef CURL_DISABLE_CRYPTO_AUTH +#include <curl/curl.h> #include "curl_hmac.h" extern const struct HMAC_params Curl_HMAC_SHA256[1]; diff --git a/contrib/libs/curl/lib/doh.c b/contrib/libs/curl/lib/doh.c index a86e157fc0..3b1d5d60ef 100644 --- a/contrib/libs/curl/lib/doh.c +++ b/contrib/libs/curl/lib/doh.c @@ -396,7 +396,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, goto error; dohp->pending++; - if(Curl_ipv6works(data)) { + if((conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) { /* create IPv6 DoH request */ result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6], DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH], @@ -792,7 +792,7 @@ doh2ai(const struct dohentry *de, const char *hostname, int port) #endif CURLcode result = CURLE_OK; int i; - size_t hostlen = strlen(hostname) + 1; /* include zero terminator */ + size_t hostlen = strlen(hostname) + 1; /* include null-terminator */ if(!de) /* no input == no output! */ diff --git a/contrib/libs/curl/lib/dotdot.c b/contrib/libs/curl/lib/dotdot.c deleted file mode 100644 index 0b045315d0..0000000000 --- a/contrib/libs/curl/lib/dotdot.c +++ /dev/null @@ -1,184 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include <curl/curl.h> - -#include "dotdot.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * "Remove Dot Segments" - * https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 - */ - -/* - * Curl_dedotdotify() - * @unittest: 1395 - * - * This function gets a null-terminated path with dot and dotdot sequences - * passed in and strips them off according to the rules in RFC 3986 section - * 5.2.4. - * - * The function handles a query part ('?' + stuff) appended but it expects - * that fragments ('#' + stuff) have already been cut off. - * - * RETURNS - * - * an allocated dedotdotified output string - */ -char *Curl_dedotdotify(const char *input) -{ - size_t inlen = strlen(input); - char *clone; - size_t clen = inlen; /* the length of the cloned input */ - char *out = malloc(inlen + 1); - char *outptr; - char *orgclone; - char *queryp; - if(!out) - return NULL; /* out of memory */ - - *out = 0; /* null-terminates, for inputs like "./" */ - - /* get a cloned copy of the input */ - clone = strdup(input); - if(!clone) { - free(out); - return NULL; - } - orgclone = clone; - outptr = out; - - if(!*clone) { - /* zero length string, return that */ - free(out); - return clone; - } - - /* - * To handle query-parts properly, we must find it and remove it during the - * dotdot-operation and then append it again at the end to the output - * string. - */ - queryp = strchr(clone, '?'); - if(queryp) - *queryp = 0; - - do { - - /* A. If the input buffer begins with a prefix of "../" or "./", then - remove that prefix from the input buffer; otherwise, */ - - if(!strncmp("./", clone, 2)) { - clone += 2; - clen -= 2; - } - else if(!strncmp("../", clone, 3)) { - clone += 3; - clen -= 3; - } - - /* B. if the input buffer begins with a prefix of "/./" or "/.", where - "." is a complete path segment, then replace that prefix with "/" in - the input buffer; otherwise, */ - else if(!strncmp("/./", clone, 3)) { - clone += 2; - clen -= 2; - } - else if(!strcmp("/.", clone)) { - clone[1]='/'; - clone++; - clen -= 1; - } - - /* C. if the input buffer begins with a prefix of "/../" or "/..", where - ".." is a complete path segment, then replace that prefix with "/" in - the input buffer and remove the last segment and its preceding "/" (if - any) from the output buffer; otherwise, */ - - else if(!strncmp("/../", clone, 4)) { - clone += 3; - clen -= 3; - /* remove the last segment from the output buffer */ - while(outptr > out) { - outptr--; - if(*outptr == '/') - break; - } - *outptr = 0; /* null-terminate where it stops */ - } - else if(!strcmp("/..", clone)) { - clone[2]='/'; - clone += 2; - clen -= 2; - /* remove the last segment from the output buffer */ - while(outptr > out) { - outptr--; - if(*outptr == '/') - break; - } - *outptr = 0; /* null-terminate where it stops */ - } - - /* D. if the input buffer consists only of "." or "..", then remove - that from the input buffer; otherwise, */ - - else if(!strcmp(".", clone) || !strcmp("..", clone)) { - *clone = 0; - *out = 0; - } - - else { - /* E. move the first path segment in the input buffer to the end of - the output buffer, including the initial "/" character (if any) and - any subsequent characters up to, but not including, the next "/" - character or the end of the input buffer. */ - - do { - *outptr++ = *clone++; - clen--; - } while(*clone && (*clone != '/')); - *outptr = 0; - } - - } while(*clone); - - if(queryp) { - size_t qlen; - /* There was a query part, append that to the output. The 'clone' string - may now have been altered so we copy from the original input string - from the correct index. */ - size_t oindex = queryp - orgclone; - qlen = strlen(&input[oindex]); - memcpy(outptr, &input[oindex], qlen + 1); /* include the end zero byte */ - } - - free(orgclone); - return out; -} diff --git a/contrib/libs/curl/lib/dynbuf.c b/contrib/libs/curl/lib/dynbuf.c index 3b907dbe2e..0b1cf9afd8 100644 --- a/contrib/libs/curl/lib/dynbuf.c +++ b/contrib/libs/curl/lib/dynbuf.c @@ -128,7 +128,6 @@ void Curl_dyn_reset(struct dynbuf *s) s->leng = 0; } -#ifdef USE_NGTCP2 /* * Specify the size of the tail to keep (number of bytes from the end of the * buffer). The rest will be dropped. @@ -153,7 +152,6 @@ CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail) return CURLE_OK; } -#endif /* * Appends a buffer with length. @@ -255,3 +253,18 @@ size_t Curl_dyn_len(const struct dynbuf *s) DEBUGASSERT(!s->leng || s->bufr); return s->leng; } + +/* + * Set a new (smaller) length. + */ +CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + if(set > s->leng) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->leng = set; + s->bufr[s->leng] = 0; + return CURLE_OK; +} diff --git a/contrib/libs/curl/lib/dynbuf.h b/contrib/libs/curl/lib/dynbuf.h index c1e97235de..04a728c779 100644 --- a/contrib/libs/curl/lib/dynbuf.h +++ b/contrib/libs/curl/lib/dynbuf.h @@ -24,6 +24,8 @@ * ***************************************************************************/ +#include <curl/curl.h> + #ifndef BUILDING_LIBCURL /* this renames the functions so that the tool code can use the same code without getting symbol collisions */ @@ -38,12 +40,13 @@ #define Curl_dyn_len(a) curlx_dyn_len(a) #define Curl_dyn_reset(a) curlx_dyn_reset(a) #define Curl_dyn_tail(a,b) curlx_dyn_tail(a,b) +#define Curl_dyn_setlen(a,b) curlx_dyn_setlen(a,b) #define curlx_dynbuf dynbuf /* for the struct name */ #endif struct dynbuf { char *bufr; /* point to a null-terminated allocated buffer */ - size_t leng; /* number of bytes *EXCLUDING* the zero terminator */ + size_t leng; /* number of bytes *EXCLUDING* the null-terminator */ size_t allc; /* size of the current allocation */ size_t toobig; /* size limit for the buffer */ #ifdef DEBUGBUILD @@ -63,6 +66,7 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap) WARN_UNUSED_RESULT; 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); char *Curl_dyn_ptr(const struct dynbuf *s); unsigned char *Curl_dyn_uptr(const struct dynbuf *s); size_t Curl_dyn_len(const struct dynbuf *s); diff --git a/contrib/libs/curl/lib/easy.c b/contrib/libs/curl/lib/easy.c index 148b3615e3..b8ac1ef8a8 100644 --- a/contrib/libs/curl/lib/easy.c +++ b/contrib/libs/curl/lib/easy.c @@ -944,7 +944,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) goto fail; } -#ifdef USE_ALTSVC +#ifndef CURL_DISABLE_ALTSVC if(data->asi) { outcurl->asi = Curl_altsvc_init(); if(!outcurl->asi) @@ -1171,8 +1171,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) } -static CURLcode easy_connection(struct Curl_easy *data, - curl_socket_t *sfd, +static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd, struct connectdata **connp) { if(!data) @@ -1231,11 +1230,12 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, } /* - * Sends data over the connected socket. Use after successful - * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + * Sends data over the connected socket. + * + * This is the private internal version of curl_easy_send() */ -CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, - size_t buflen, size_t *n) +CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, + size_t buflen, ssize_t *n) { curl_socket_t sfd; CURLcode result; @@ -1243,9 +1243,6 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, struct connectdata *c = NULL; SIGPIPE_VARIABLE(pipe_st); - if(Curl_is_in_callback(data)) - return CURLE_RECURSIVE_API_CALL; - result = easy_connection(data, &sfd, &c); if(result) return result; @@ -1267,8 +1264,25 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, if(!result && !n1) return CURLE_AGAIN; - *n = (size_t)n1; + *n = n1; + + return result; +} + +/* + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, + size_t buflen, size_t *n) +{ + ssize_t written = 0; + CURLcode result; + if(Curl_is_in_callback(data)) + return CURLE_RECURSIVE_API_CALL; + result = Curl_senddata(data, buffer, buflen, &written); + *n = (size_t)written; return result; } diff --git a/contrib/libs/curl/lib/easy_lock.h b/contrib/libs/curl/lib/easy_lock.h index 4c22be5f8a..d96e56b8d8 100644 --- a/contrib/libs/curl/lib/easy_lock.h +++ b/contrib/libs/curl/lib/easy_lock.h @@ -47,7 +47,7 @@ typedef PVOID SRWLOCK, *PSRWLOCK; #define curl_simple_lock_lock(m) AcquireSRWLockExclusive(m) #define curl_simple_lock_unlock(m) ReleaseSRWLockExclusive(m) -#elif defined (HAVE_ATOMIC) +#elif defined(HAVE_ATOMIC) && defined(HAVE_STDATOMIC_H) #include <stdatomic.h> #if defined(HAVE_SCHED_YIELD) #include <sched.h> diff --git a/contrib/libs/curl/lib/easyif.h b/contrib/libs/curl/lib/easyif.h index 615df3f067..205382cd07 100644 --- a/contrib/libs/curl/lib/easyif.h +++ b/contrib/libs/curl/lib/easyif.h @@ -27,6 +27,9 @@ /* * Prototypes for library-wide functions provided by easy.c */ +CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, + size_t buflen, ssize_t *n); + #ifdef CURLDEBUG CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy); #endif diff --git a/contrib/libs/curl/lib/easyoptions.c b/contrib/libs/curl/lib/easyoptions.c index 412aefd990..e59b63af7a 100644 --- a/contrib/libs/curl/lib/easyoptions.c +++ b/contrib/libs/curl/lib/easyoptions.c @@ -354,6 +354,7 @@ struct curl_easyoption Curl_easyopts[] = { {"WRITEDATA", CURLOPT_WRITEDATA, CURLOT_CBPTR, 0}, {"WRITEFUNCTION", CURLOPT_WRITEFUNCTION, CURLOT_FUNCTION, 0}, {"WRITEHEADER", CURLOPT_HEADERDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS}, + {"WS_OPTIONS", CURLOPT_WS_OPTIONS, CURLOT_LONG, 0}, {"XFERINFODATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, 0}, {"XFERINFOFUNCTION", CURLOPT_XFERINFOFUNCTION, CURLOT_FUNCTION, 0}, {"XOAUTH2_BEARER", CURLOPT_XOAUTH2_BEARER, CURLOT_STRING, 0}, @@ -367,6 +368,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return ((CURLOPT_LASTENTRY%10000) != (319 + 1)); + return ((CURLOPT_LASTENTRY%10000) != (320 + 1)); } #endif diff --git a/contrib/libs/curl/lib/formdata.c b/contrib/libs/curl/lib/formdata.c index f5ed3653df..46542b4329 100644 --- a/contrib/libs/curl/lib/formdata.c +++ b/contrib/libs/curl/lib/formdata.c @@ -251,8 +251,10 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, } } else { - /* This is not array-state, get next option */ - option = va_arg(params, CURLformoption); + /* This is not array-state, get next option. This gets an 'int' with + va_arg() because CURLformoption might be a smaller type than int and + might cause compiler warnings and wrong behavior. */ + option = (CURLformoption)va_arg(params, int); if(CURLFORM_END == option) break; } diff --git a/contrib/libs/curl/lib/ftp.c b/contrib/libs/curl/lib/ftp.c index 0473a8af00..f1a25b23dc 100644 --- a/contrib/libs/curl/lib/ftp.c +++ b/contrib/libs/curl/lib/ftp.c @@ -516,11 +516,9 @@ static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected) } else { /* Add timeout to multi handle and break out of the loop */ - if(*connected == FALSE) { - Curl_expire(data, data->set.accepttimeout > 0 ? - data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, - EXPIRE_FTP_ACCEPT); - } + Curl_expire(data, data->set.accepttimeout ? + data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, + EXPIRE_FTP_ACCEPT); } return result; @@ -2131,9 +2129,11 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, default: infof(data, "unsupported MDTM reply format"); break; - case 550: /* "No such file or directory" */ - failf(data, "Given file does not exist"); - result = CURLE_REMOTE_FILE_NOT_FOUND; + case 550: /* 550 is used for several different problems, e.g. + "No such file or directory" or "Permission denied". + It does not mean that the file does not exist at all. */ + infof(data, "MDTM failed: file does not exist or permission problem," + " continuing"); break; } diff --git a/contrib/libs/curl/lib/ftplistparser.c b/contrib/libs/curl/lib/ftplistparser.c index 09476e55f4..40f5f3f189 100644 --- a/contrib/libs/curl/lib/ftplistparser.c +++ b/contrib/libs/curl/lib/ftplistparser.c @@ -422,7 +422,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, char *endptr = finfo->b_data + 6; /* here we can deal with directory size, pass the leading whitespace and then the digits */ - while(ISSPACE(*endptr)) + while(ISBLANK(*endptr)) endptr++; while(ISDIGIT(*endptr)) endptr++; @@ -894,7 +894,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, parser->item_length++; switch(parser->state.NT.sub.time) { case PL_WINNT_TIME_PRESPACE: - if(!ISSPACE(c)) { + if(!ISBLANK(c)) { parser->state.NT.sub.time = PL_WINNT_TIME_TIME; } break; diff --git a/contrib/libs/curl/lib/functypes.h b/contrib/libs/curl/lib/functypes.h new file mode 100644 index 0000000000..8891b1d5d6 --- /dev/null +++ b/contrib/libs/curl/lib/functypes.h @@ -0,0 +1,115 @@ +#ifndef HEADER_CURL_FUNCTYPES_H +#define HEADER_CURL_FUNCTYPES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +/* defaults: + + ssize_t recv(int, void *, size_t, int); + ssize_t send(int, const void *, size_t, int); + + If other argument or return types are needed: + + 1. For systems that run configure or cmake, the alternatives are provided + here. + 2. For systems with config-*.h files, define them there. +*/ + +#ifdef WIN32 +/* int recv(SOCKET, char *, int, int) */ +#define RECV_TYPE_ARG1 SOCKET +#define RECV_TYPE_ARG2 char * +#define RECV_TYPE_ARG3 int +#define RECV_TYPE_RETV int + +/* int send(SOCKET, const char *, int, int); */ +#define SEND_TYPE_ARG1 SOCKET +#define SEND_TYPE_ARG2 char * +#define SEND_TYPE_ARG3 int +#define SEND_TYPE_RETV int + +#elif defined(__AMIGA__) /* Any AmigaOS flavour */ + +/* long recv(long, char *, long, long); */ +#define RECV_TYPE_ARG1 long +#define RECV_TYPE_ARG2 char * +#define RECV_TYPE_ARG3 long +#define RECV_TYPE_ARG4 long +#define RECV_TYPE_RETV long + +/* int send(int, const char *, int, int); */ +#define SEND_TYPE_ARG1 int +#define SEND_TYPE_ARG2 char * +#define SEND_TYPE_ARG3 int +#define SEND_TYPE_RETV int +#endif + + +#ifndef RECV_TYPE_ARG1 +#define RECV_TYPE_ARG1 int +#endif + +#ifndef RECV_TYPE_ARG2 +#define RECV_TYPE_ARG2 void * +#endif + +#ifndef RECV_TYPE_ARG3 +#define RECV_TYPE_ARG3 size_t +#endif + +#ifndef RECV_TYPE_ARG4 +#define RECV_TYPE_ARG4 int +#endif + +#ifndef RECV_TYPE_RETV +#define RECV_TYPE_RETV ssize_t +#endif + +#ifndef SEND_QUAL_ARG2 +#define SEND_QUAL_ARG2 const +#endif + +#ifndef SEND_TYPE_ARG1 +#define SEND_TYPE_ARG1 int +#endif + +#ifndef SEND_TYPE_ARG2 +#define SEND_TYPE_ARG2 void * +#endif + +#ifndef SEND_TYPE_ARG3 +#define SEND_TYPE_ARG3 size_t +#endif + +#ifndef SEND_TYPE_ARG4 +#define SEND_TYPE_ARG4 int +#endif + +#ifndef SEND_TYPE_RETV +#define SEND_TYPE_RETV ssize_t +#endif + +#endif /* HEADER_CURL_FUNCTYPES_H */ diff --git a/contrib/libs/curl/lib/h2h3.c b/contrib/libs/curl/lib/h2h3.c index 5d26bf0f21..50254ad0fa 100644 --- a/contrib/libs/curl/lib/h2h3.c +++ b/contrib/libs/curl/lib/h2h3.c @@ -191,7 +191,7 @@ CURLcode Curl_pseudo_headers(struct Curl_easy *data, vptr = Curl_checkheaders(data, STRCONST(H2H3_PSEUDO_SCHEME)); if(vptr) { vptr += sizeof(H2H3_PSEUDO_SCHEME); - while(*vptr && ISSPACE(*vptr)) + while(*vptr && ISBLANK(*vptr)) vptr++; nva[2].value = vptr; infof(data, "set pseudo header %s to %s", H2H3_PSEUDO_SCHEME, vptr); diff --git a/contrib/libs/curl/lib/headers.c b/contrib/libs/curl/lib/headers.c index d1e0ed7544..978c918f4f 100644 --- a/contrib/libs/curl/lib/headers.c +++ b/contrib/libs/curl/lib/headers.c @@ -207,7 +207,7 @@ static CURLcode namevalue(char *header, size_t hlen, unsigned int type, return CURLE_BAD_FUNCTION_ARGUMENT; /* skip all leading space letters */ - while(*header && ISSPACE(*header)) + while(*header && ISBLANK(*header)) header++; *value = header; @@ -237,7 +237,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value, vlen--; /* save only one leading space */ - while((vlen > 1) && ISSPACE(value[0]) && ISSPACE(value[1])) { + while((vlen > 1) && ISBLANK(value[0]) && ISBLANK(value[1])) { vlen--; value++; } @@ -259,7 +259,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value, /* put the data at the end of the previous data, not the newline */ memcpy(&newhs->value[olen], value, vlen); - newhs->value[olen + vlen] = 0; /* zero terminate at newline */ + newhs->value[olen + vlen] = 0; /* null-terminate at newline */ /* insert this node into the list of headers */ Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail, diff --git a/contrib/libs/curl/lib/hostip.c b/contrib/libs/curl/lib/hostip.c index d5224bfd45..5d087b7ff1 100644 --- a/contrib/libs/curl/lib/hostip.c +++ b/contrib/libs/curl/lib/hostip.c @@ -181,7 +181,7 @@ create_hostcache_id(const char *name, int port, char *ptr, size_t buflen) len = buflen - 7; /* store and lower case the name */ while(len--) - *ptr++ = (char)TOLOWER(*name++); + *ptr++ = Curl_raw_tolower(*name++); msnprintf(ptr, 7, ":%u", port); } @@ -297,6 +297,31 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, } } + /* See if the returned entry matches the required resolve mode */ + if(dns && data->conn->ip_version != CURL_IPRESOLVE_WHATEVER) { + int pf = PF_INET; + bool found = false; + struct Curl_addrinfo *addr = dns->addr; + +#ifdef PF_INET6 + if(data->conn->ip_version == CURL_IPRESOLVE_V6) + pf = PF_INET6; +#endif + + while(addr) { + if(addr->ai_family == pf) { + found = true; + break; + } + addr = addr->ai_next; + } + + if(!found) { + infof(data, "Hostname in DNS cache doesn't have needed family, zapped"); + dns = NULL; /* the memory deallocation is being handled by the hash */ + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); + } + } return dns; } @@ -546,7 +571,11 @@ bool Curl_ipv6works(struct Curl_easy *data) have the info kept for fast re-use */ DEBUGASSERT(data); DEBUGASSERT(data->multi); - return data->multi->ipv6_works; + if(data->multi->ipv6_up == IPV6_UNKNOWN) { + bool works = Curl_ipv6works(NULL); + data->multi->ipv6_up = works ? IPV6_WORKS : IPV6_DEAD; + } + return data->multi->ipv6_up == IPV6_WORKS; } else { int ipv6_works = -1; @@ -584,7 +613,7 @@ bool Curl_host_is_ipnum(const char *hostname) } -/* return TRUE if 'part' is a case insentive tail of 'full' */ +/* return TRUE if 'part' is a case insensitive tail of 'full' */ static bool tailmatch(const char *full, const char *part) { size_t plen = strlen(part); diff --git a/contrib/libs/curl/lib/hostip6.c b/contrib/libs/curl/lib/hostip6.c index d9868628c3..c62c254c72 100644 --- a/contrib/libs/curl/lib/hostip6.c +++ b/contrib/libs/curl/lib/hostip6.c @@ -96,8 +96,8 @@ static void dump_addrinfo(struct connectdata *conn, * non-ares version). * * Returns name information about the given hostname and port number. If - * successful, the 'addrinfo' is returned and the forth argument will point to - * memory we need to free after use. That memory *MUST* be freed with + * successful, the 'addrinfo' is returned and the fourth argument will point + * to memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. */ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, @@ -117,7 +117,7 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, *waitp = 0; /* synchronous response only */ - if(Curl_ipv6works(data)) + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) /* The stack seems to be IPv6-enabled */ pf = PF_UNSPEC; diff --git a/contrib/libs/curl/lib/hsts.c b/contrib/libs/curl/lib/hsts.c index 4ba0f30726..e3b686ebfa 100644 --- a/contrib/libs/curl/lib/hsts.c +++ b/contrib/libs/curl/lib/hsts.c @@ -156,7 +156,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, return CURLE_OK; do { - while(*p && ISSPACE(*p)) + while(*p && ISBLANK(*p)) p++; if(Curl_strncasecompare("max-age=", p, 8)) { bool quoted = FALSE; @@ -167,7 +167,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, return CURLE_BAD_FUNCTION_ARGUMENT; p += 8; - while(*p && ISSPACE(*p)) + while(*p && ISBLANK(*p)) p++; if(*p == '\"') { p++; @@ -200,7 +200,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, p++; } - while(*p && ISSPACE(*p)) + while(*p && ISBLANK(*p)) p++; if(*p == ';') p++; diff --git a/contrib/libs/curl/lib/http.c b/contrib/libs/curl/lib/http.c index 48571ab52c..ea0a53632d 100644 --- a/contrib/libs/curl/lib/http.c +++ b/contrib/libs/curl/lib/http.c @@ -84,6 +84,7 @@ #include "strdup.h" #include "altsvc.h" #include "hsts.h" +#include "ws.h" #include "c-hyper.h" /* The last 3 #include files should be in this order */ @@ -114,6 +115,10 @@ static int https_getsock(struct Curl_easy *data, #endif 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. @@ -142,6 +147,32 @@ 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 */ + ZERO_NULL, /* 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. @@ -166,11 +197,38 @@ const struct Curl_handler Curl_handler_https = { PORT_HTTPS, /* defport */ CURLPROTO_HTTPS, /* protocol */ CURLPROTO_HTTP, /* family */ - PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN | /* flags */ + PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN | /* flags */ + 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 */ + https_connecting, /* connecting */ + ZERO_NULL, /* doing */ + https_getsock, /* proto_getsock */ + http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* 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) { @@ -205,6 +263,16 @@ 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 @@ -653,21 +721,6 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data) return result; } -/* - * Curl_allow_auth_to_host() tells if authentication, cookies or other - * "sensitive data" can (still) be sent to this host. - */ -bool Curl_allow_auth_to_host(struct Curl_easy *data) -{ - struct connectdata *conn = data->conn; - return (!data->state.this_is_a_follow || - data->set.allow_auth_to_other_hosts || - (data->state.first_host && - strcasecompare(data->state.first_host, conn->host.name) && - (data->state.first_remote_port == conn->remote_port) && - (data->state.first_remote_protocol == conn->handler->protocol))); -} - #ifndef CURL_DISABLE_HTTP_AUTH /* * Output the correct authentication header depending on the auth type @@ -866,7 +919,7 @@ Curl_http_output_auth(struct Curl_easy *data, /* To prevent the user+password to get sent to other than the original host due to a location-follow */ - if(Curl_allow_auth_to_host(data) + if(Curl_auth_allowed_to_host(data) #ifndef CURL_DISABLE_NETRC || conn->bits.netrc #endif @@ -1518,7 +1571,7 @@ CURLcode Curl_http_connect(struct Curl_easy *data, bool *done) } #endif - if(conn->given->protocol & CURLPROTO_HTTPS) { + if(conn->given->flags & PROTOPT_SSL) { /* perform SSL initialization */ result = https_connecting(data, done); if(result) @@ -1643,6 +1696,7 @@ CURLcode Curl_http_done(struct Curl_easy *data, Curl_mime_cleanpart(&http->form); Curl_dyn_reset(&data->state.headerb); Curl_hyper_done(data); + Curl_ws_done(data); if(status) return status; @@ -1919,7 +1973,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, checkprefix("Cookie:", compare)) && /* be careful of sending this potentially sensitive header to other hosts */ - !Curl_allow_auth_to_host(data)) + !Curl_auth_allowed_to_host(data)) ; else { #ifdef USE_HYPER @@ -2151,9 +2205,9 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn) [brackets] if the host name is a plain IPv6-address. RFC2732-style. */ const char *host = conn->host.name; - if(((conn->given->protocol&CURLPROTO_HTTPS) && + if(((conn->given->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS)) && (conn->remote_port == PORT_HTTPS)) || - ((conn->given->protocol&CURLPROTO_HTTP) && + ((conn->given->protocol&(CURLPROTO_HTTP|CURLPROTO_WS)) && (conn->remote_port == PORT_HTTP)) ) /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include the port number in the host string */ @@ -2702,6 +2756,13 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, FIRSTSOCKET); if(result) failf(data, "Failed sending HTTP request"); +#ifdef USE_WEBSOCKETS + else if((conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) && + !(data->set.connect_only)) + /* Set up the transfer for two-way since without CONNECT_ONLY set, this + request probably wants to send data too post upgrade */ + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET); +#endif else /* HTTP GET/HEAD download: */ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); @@ -2731,7 +2792,7 @@ CURLcode Curl_http_cookies(struct Curl_easy *data, const char *host = data->state.aptr.cookiehost ? data->state.aptr.cookiehost : conn->host.name; const bool secure_context = - conn->handler->protocol&CURLPROTO_HTTPS || + conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || strcasecompare("localhost", host) || !strcmp(host, "127.0.0.1") || !strcmp(host, "[::1]") ? TRUE : FALSE; @@ -3044,7 +3105,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(conn->transport != TRNSPRT_QUIC) { if(conn->httpversion < 20) { /* unless the connection is re-used and already http2 */ - switch(conn->negnpn) { + switch(conn->alpn) { case CURL_HTTP_VERSION_2: conn->httpversion = 20; /* we know we're on HTTP/2 now */ @@ -3256,6 +3317,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) } result = Curl_http_cookies(data, conn, &req); + if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) + result = Curl_ws_request(data, &req); if(!result) result = Curl_add_timecondition(data, &req); if(!result) @@ -3520,15 +3583,15 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, else if(checkprefix("Retry-After:", headp)) { /* Retry-After = HTTP-date / delay-seconds */ curl_off_t retry_after = 0; /* zero for unknown or "now" */ - time_t date = Curl_getdate_capped(headp + strlen("Retry-After:")); - if(-1 == date) { - /* not a date, try it as a decimal number */ - (void)curlx_strtoofft(headp + strlen("Retry-After:"), - NULL, 10, &retry_after); + /* Try it as a decimal number, if it works it is not a date */ + (void)curlx_strtoofft(headp + strlen("Retry-After:"), + NULL, 10, &retry_after); + if(!retry_after) { + time_t date = Curl_getdate_capped(headp + strlen("Retry-After:")); + if(-1 != date) + /* convert date to number of seconds into the future */ + retry_after = date - time(NULL); } - else - /* convert date to number of seconds into the future */ - retry_after = date - time(NULL); data->info.retry_after = retry_after; /* store it */ } else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) { @@ -3540,7 +3603,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, The second format was added since Sun's webserver JavaWebServer/1.1.1 obviously sends the header this way! The third added since some servers use that! - The forth means the requested range was unsatisfied. + The fourth means the requested range was unsatisfied. */ char *ptr = headp + strlen("Content-Range:"); @@ -3568,7 +3631,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, const char *host = data->state.aptr.cookiehost? data->state.aptr.cookiehost:conn->host.name; const bool secure_context = - conn->handler->protocol&CURLPROTO_HTTPS || + conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || strcasecompare("localhost", host) || !strcmp(host, "127.0.0.1") || !strcmp(host, "[::1]") ? TRUE : FALSE; @@ -3652,7 +3715,14 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, #ifndef CURL_DISABLE_HSTS /* If enabled, the header is incoming and this is over HTTPS */ else if(data->hsts && checkprefix("Strict-Transport-Security:", headp) && - (conn->handler->flags & PROTOPT_SSL)) { + ((conn->handler->flags & PROTOPT_SSL) || +#ifdef CURLDEBUG + /* allow debug builds to circumvent the HTTPS restriction */ + getenv("CURL_HSTS_HTTP") +#else + 0 +#endif + )) { CURLcode check = Curl_hsts_parse(data->hsts, data->state.up.hostname, headp + strlen("Strict-Transport-Security:")); @@ -3734,7 +3804,7 @@ CURLcode Curl_http_statusline(struct Curl_easy *data, connclose(conn, "HTTP/1.0 close after body"); } else if(conn->httpversion == 20 || - (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) { + (k->upgr101 == UPGR101_H2 && k->httpcode == 101)) { DEBUGF(infof(data, "HTTP/2 found, allow multiplexing")); /* HTTP/2 cannot avoid multiplexing since it is a core functionality of the protocol */ @@ -3960,9 +4030,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, break; case 101: /* Switching Protocols */ - if(k->upgr101 == UPGR101_REQUESTED) { + if(k->upgr101 == UPGR101_H2) { /* Switching to HTTP/2 */ - infof(data, "Received 101"); + infof(data, "Received 101, Switching to HTTP/2"); k->upgr101 = UPGR101_RECEIVED; /* we'll get more headers (HTTP/2 response) */ @@ -3976,8 +4046,21 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, return result; *nread = 0; } +#ifdef USE_WEBSOCKETS + else if(k->upgr101 == UPGR101_WS) { + /* verify the response */ + result = Curl_ws_accept(data); + 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 */ + *nread = 0; + } + } +#endif else { - /* Switching to another protocol (e.g. WebSocket) */ + /* Not switching to another protocol */ k->header = FALSE; /* no more header to parse! */ } break; @@ -4070,6 +4153,16 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, return CURLE_HTTP_RETURNED_ERROR; } +#ifdef USE_WEBSOCKETS + /* All non-101 HTTP status codes are bad when wanting to upgrade to + websockets */ + if(data->req.upgr101 == UPGR101_WS) { + failf(data, "Refused WebSockets upgrade: %d", k->httpcode); + return CURLE_HTTP_RETURNED_ERROR; + } +#endif + + data->req.deductheadercount = (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0; diff --git a/contrib/libs/curl/lib/http.h b/contrib/libs/curl/lib/http.h index 2ac287eca8..f7cbb34244 100644 --- a/contrib/libs/curl/lib/http.h +++ b/contrib/libs/curl/lib/http.h @@ -24,6 +24,7 @@ * ***************************************************************************/ #include "curl_setup.h" +#include "ws.h" typedef enum { HTTPREQ_GET, @@ -50,6 +51,15 @@ 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 */ + + /* Header specific functions */ bool Curl_compareheader(const char *headerline, /* line to check */ const char *header, /* header keyword _with_ colon */ @@ -218,6 +228,10 @@ struct HTTP { HTTPSEND_BODY /* sending body */ } sending; +#ifdef USE_WEBSOCKETS + struct websocket ws; +#endif + #ifndef CURL_DISABLE_HTTP struct dynbuf send_buffer; /* used if the request couldn't be sent in one chunk, points to an allocated send_buffer @@ -367,10 +381,4 @@ Curl_http_output_auth(struct Curl_easy *data, bool proxytunnel); /* TRUE if this is the request setting up the proxy tunnel */ -/* - * Curl_allow_auth_to_host() tells if authentication, cookies or other - * "sensitive data" can (still) be sent to this host. - */ -bool Curl_allow_auth_to_host(struct Curl_easy *data); - #endif /* HEADER_CURL_HTTP_H */ diff --git a/contrib/libs/curl/lib/http2.c b/contrib/libs/curl/lib/http2.c index 3a70528e4a..b7409b027d 100644 --- a/contrib/libs/curl/lib/http2.c +++ b/contrib/libs/curl/lib/http2.c @@ -1392,7 +1392,7 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req, NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); free(base64); - k->upgr101 = UPGR101_REQUESTED; + k->upgr101 = UPGR101_H2; return result; } diff --git a/contrib/libs/curl/lib/http_aws_sigv4.c b/contrib/libs/curl/lib/http_aws_sigv4.c index d144fb817a..440eb385f8 100644 --- a/contrib/libs/curl/lib/http_aws_sigv4.c +++ b/contrib/libs/curl/lib/http_aws_sigv4.c @@ -44,6 +44,8 @@ #include "curl_memory.h" #include "memdebug.h" +#include "slist.h" + #define HMAC_SHA256(k, kl, d, dl, o) \ do { \ ret = Curl_hmacit(Curl_HMAC_SHA256, \ @@ -51,49 +53,241 @@ (unsigned int)kl, \ (unsigned char *)d, \ (unsigned int)dl, o); \ - if(ret != CURLE_OK) { \ + if(ret) { \ goto fail; \ } \ } while(0) +#define TIMESTAMP_SIZE 17 + static void sha256_to_hex(char *dst, unsigned char *sha, size_t dst_l) { int i; DEBUGASSERT(dst_l >= 65); for(i = 0; i < 32; ++i) { - curl_msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]); + msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]); + } +} + +static char *find_date_hdr(struct Curl_easy *data, const char *sig_hdr) +{ + char *tmp = Curl_checkheaders(data, sig_hdr, strlen(sig_hdr)); + + if(tmp) + return tmp; + return Curl_checkheaders(data, STRCONST("Date")); +} + +/* remove whitespace, and lowercase all headers */ +static void trim_headers(struct curl_slist *head) +{ + struct curl_slist *l; + for(l = head; l; l = l->next) { + char *value; /* to read from */ + char *store; + size_t colon = strcspn(l->data, ":"); + Curl_strntolower(l->data, l->data, colon); + + value = &l->data[colon]; + if(!*value) + continue; + ++value; + store = value; + + /* skip leading whitespace */ + while(*value && ISBLANK(*value)) + value++; + + while(*value) { + int space = 0; + while(*value && ISBLANK(*value)) { + value++; + space++; + } + if(space) { + /* replace any number of consecutive whitespace with a single space, + unless at the end of the string, then nothing */ + if(*value) + *store++ = ' '; + } + else + *store++ = *value++; + } + *store = 0; /* null terminate */ } } +/* maximum lenth for the aws sivg4 parts */ +#define MAX_SIGV4_LEN 64 +#define MAX_SIGV4_LEN_TXT "64" + +#define DATE_HDR_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Date")) + +#define MAX_HOST_LEN 255 +/* FQDN + host: */ +#define FULL_HOST_LEN (MAX_HOST_LEN + sizeof("host:")) + +/* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */ +#define DATE_FULL_HDR_LEN (DATE_HDR_KEY_LEN + TIMESTAMP_SIZE + 1) + +/* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */ +static CURLcode make_headers(struct Curl_easy *data, + const char *hostname, + char *timestamp, + char *provider1, + char **date_header, + struct dynbuf *canonical_headers, + struct dynbuf *signed_headers) +{ + char date_hdr_key[DATE_HDR_KEY_LEN]; + char date_full_hdr[DATE_FULL_HDR_LEN]; + struct curl_slist *head = NULL; + struct curl_slist *tmp_head = NULL; + CURLcode ret = CURLE_OUT_OF_MEMORY; + struct curl_slist *l; + int again = 1; + + /* provider1 mid */ + Curl_strntolower(provider1, provider1, strlen(provider1)); + provider1[0] = Curl_raw_toupper(provider1[0]); + + msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%s-Date", provider1); + + /* provider1 lowercase */ + Curl_strntolower(provider1, provider1, 1); /* first byte only */ + msnprintf(date_full_hdr, DATE_FULL_HDR_LEN, + "x-%s-date:%s", provider1, timestamp); + + if(Curl_checkheaders(data, STRCONST("Host"))) { + head = NULL; + } + else { + char full_host[FULL_HOST_LEN + 1]; + + if(data->state.aptr.host) { + size_t pos; + + if(strlen(data->state.aptr.host) > FULL_HOST_LEN) { + ret = CURLE_URL_MALFORMAT; + goto fail; + } + strcpy(full_host, data->state.aptr.host); + /* remove /r/n as the separator for canonical request must be '\n' */ + pos = strcspn(full_host, "\n\r"); + full_host[pos] = 0; + } + else { + if(strlen(hostname) > MAX_HOST_LEN) { + ret = CURLE_URL_MALFORMAT; + goto fail; + } + msnprintf(full_host, FULL_HOST_LEN, "host:%s", hostname); + } + + head = curl_slist_append(NULL, full_host); + if(!head) + goto fail; + } + + + for(l = data->set.headers; l; l = l->next) { + tmp_head = curl_slist_append(head, l->data); + if(!tmp_head) + goto fail; + head = tmp_head; + } + + trim_headers(head); + + *date_header = find_date_hdr(data, date_hdr_key); + if(!*date_header) { + tmp_head = curl_slist_append(head, date_full_hdr); + if(!tmp_head) + goto fail; + head = tmp_head; + *date_header = curl_maprintf("%s: %s", date_hdr_key, timestamp); + } + else { + char *value; + + *date_header = strdup(*date_header); + if(!*date_header) + goto fail; + + value = strchr(*date_header, ':'); + if(!value) + goto fail; + ++value; + while(ISBLANK(*value)) + ++value; + strncpy(timestamp, value, TIMESTAMP_SIZE - 1); + timestamp[TIMESTAMP_SIZE - 1] = 0; + } + + /* alpha-sort in a case sensitive manner */ + do { + again = 0; + for(l = head; l; l = l->next) { + struct curl_slist *next = l->next; + + if(next && strcmp(l->data, next->data) > 0) { + char *tmp = l->data; + + l->data = next->data; + next->data = tmp; + again = 1; + } + } + } while(again); + + for(l = head; l; l = l->next) { + char *tmp; + + if(Curl_dyn_add(canonical_headers, l->data)) + goto fail; + if(Curl_dyn_add(canonical_headers, "\n")) + goto fail; + + tmp = strchr(l->data, ':'); + if(tmp) + *tmp = 0; + + if(l != head) { + if(Curl_dyn_add(signed_headers, ";")) + goto fail; + } + if(Curl_dyn_add(signed_headers, l->data)) + goto fail; + } + + ret = CURLE_OK; +fail: + curl_slist_free_all(head); + + return ret; +} + CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) { CURLcode ret = CURLE_OUT_OF_MEMORY; struct connectdata *conn = data->conn; size_t len; - const char *tmp0; - const char *tmp1; - char *provider0_low = NULL; - char *provider0_up = NULL; - char *provider1_low = NULL; - char *provider1_mid = NULL; - char *region = NULL; - char *service = NULL; + const char *arg; + char provider0[MAX_SIGV4_LEN + 1]=""; + char provider1[MAX_SIGV4_LEN + 1]=""; + char region[MAX_SIGV4_LEN + 1]=""; + char service[MAX_SIGV4_LEN + 1]=""; const char *hostname = conn->host.name; -#ifdef DEBUGBUILD - char *force_timestamp; -#endif time_t clock; struct tm tm; - char timestamp[17]; + char timestamp[TIMESTAMP_SIZE]; char date[9]; - const char *content_type = Curl_checkheaders(data, STRCONST("Content-Type")); - char *canonical_headers = NULL; - char *signed_headers = NULL; - Curl_HttpReq httpreq; - const char *method; - size_t post_data_len; - const char *post_data = data->set.postfields ? data->set.postfields : ""; + struct dynbuf canonical_headers; + struct dynbuf signed_headers; + char *date_header = NULL; + const char *post_data = data->set.postfields; + size_t post_data_len = 0; unsigned char sha_hash[32]; char sha_hex[65]; char *canonical_request = NULL; @@ -101,10 +295,9 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) char *credential_scope = NULL; char *str_to_sign = NULL; const char *user = data->state.aptr.user ? data->state.aptr.user : ""; - const char *passwd = data->state.aptr.passwd ? data->state.aptr.passwd : ""; char *secret = NULL; - unsigned char tmp_sign0[32] = {0}; - unsigned char tmp_sign1[32] = {0}; + unsigned char sign0[32] = {0}; + unsigned char sign1[32] = {0}; char *auth_headers = NULL; DEBUGASSERT(!proxy); @@ -115,6 +308,10 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) return CURLE_OK; } + /* we init thoses buffers here, so goto fail will free initialized dynbuf */ + Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER); + Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER); + /* * Parameters parsing * Google and Outscale use the same OSC or GOOG, @@ -122,223 +319,154 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) * AWS is the default because most of non-amazon providers * are still using aws:amz as a prefix. */ - tmp0 = data->set.str[STRING_AWS_SIGV4] ? + arg = data->set.str[STRING_AWS_SIGV4] ? data->set.str[STRING_AWS_SIGV4] : "aws:amz"; - tmp1 = strchr(tmp0, ':'); - len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0); - if(len < 1) { - infof(data, "first provider can't be empty"); + + /* provider1[:provider2[:region[:service]]] + + No string can be longer than N bytes of non-whitespace + */ + (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]" + ":%" MAX_SIGV4_LEN_TXT "[^:]" + ":%" MAX_SIGV4_LEN_TXT "[^:]" + ":%" MAX_SIGV4_LEN_TXT "s", + provider0, provider1, region, service); + if(!provider0[0]) { + failf(data, "first provider can't be empty"); ret = CURLE_BAD_FUNCTION_ARGUMENT; goto fail; } - provider0_low = malloc(len + 1); - provider0_up = malloc(len + 1); - if(!provider0_low || !provider0_up) { - goto fail; - } - Curl_strntolower(provider0_low, tmp0, len); - provider0_low[len] = '\0'; - Curl_strntoupper(provider0_up, tmp0, len); - provider0_up[len] = '\0'; - - if(tmp1) { - tmp0 = tmp1 + 1; - tmp1 = strchr(tmp0, ':'); - len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0); - if(len < 1) { - infof(data, "second provider can't be empty"); - ret = CURLE_BAD_FUNCTION_ARGUMENT; - goto fail; - } - provider1_low = malloc(len + 1); - provider1_mid = malloc(len + 1); - if(!provider1_low || !provider1_mid) { - goto fail; - } - Curl_strntolower(provider1_low, tmp0, len); - provider1_low[len] = '\0'; - Curl_strntolower(provider1_mid, tmp0, len); - provider1_mid[0] = Curl_raw_toupper(provider1_mid[0]); - provider1_mid[len] = '\0'; - - if(tmp1) { - tmp0 = tmp1 + 1; - tmp1 = strchr(tmp0, ':'); - len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0); - if(len < 1) { - infof(data, "region can't be empty"); - ret = CURLE_BAD_FUNCTION_ARGUMENT; - goto fail; - } - region = Curl_memdup(tmp0, len + 1); - if(!region) { - goto fail; - } - region[len] = '\0'; - - if(tmp1) { - tmp0 = tmp1 + 1; - service = strdup(tmp0); - if(!service) { - goto fail; - } - if(strlen(service) < 1) { - infof(data, "service can't be empty"); - ret = CURLE_BAD_FUNCTION_ARGUMENT; - goto fail; - } - } - } - } - else { - provider1_low = Curl_memdup(provider0_low, len + 1); - provider1_mid = Curl_memdup(provider0_low, len + 1); - if(!provider1_low || !provider1_mid) { - goto fail; - } - provider1_mid[0] = Curl_raw_toupper(provider1_mid[0]); - } + else if(!provider1[0]) + strcpy(provider1, provider0); - if(!service) { - tmp0 = hostname; - tmp1 = strchr(tmp0, '.'); - if(!tmp1) { - infof(data, "service missing in parameters or hostname"); + if(!service[0]) { + char *hostdot = strchr(hostname, '.'); + if(!hostdot) { + failf(data, "service missing in parameters and hostname"); ret = CURLE_URL_MALFORMAT; goto fail; } - len = tmp1 - tmp0; - service = Curl_memdup(tmp0, len + 1); - if(!service) { + len = hostdot - hostname; + if(len > MAX_SIGV4_LEN) { + failf(data, "service too long in hostname"); + ret = CURLE_URL_MALFORMAT; goto fail; } + strncpy(service, hostname, len); service[len] = '\0'; - if(!region) { - tmp0 = tmp1 + 1; - tmp1 = strchr(tmp0, '.'); - if(!tmp1) { - infof(data, "region missing in parameters or hostname"); + if(!region[0]) { + const char *reg = hostdot + 1; + const char *hostreg = strchr(reg, '.'); + if(!hostreg) { + failf(data, "region missing in parameters and hostname"); ret = CURLE_URL_MALFORMAT; goto fail; } - len = tmp1 - tmp0; - region = Curl_memdup(tmp0, len + 1); - if(!region) { + len = hostreg - reg; + if(len > MAX_SIGV4_LEN) { + failf(data, "region too long in hostname"); + ret = CURLE_URL_MALFORMAT; goto fail; } + strncpy(region, reg, len); region[len] = '\0'; } } #ifdef DEBUGBUILD - force_timestamp = getenv("CURL_FORCETIME"); - if(force_timestamp) - clock = 0; - else - time(&clock); + { + char *force_timestamp = getenv("CURL_FORCETIME"); + if(force_timestamp) + clock = 0; + else + time(&clock); + } #else time(&clock); #endif ret = Curl_gmtime(clock, &tm); - if(ret != CURLE_OK) { + if(ret) { goto fail; } if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) { + ret = CURLE_OUT_OF_MEMORY; goto fail; } + + ret = make_headers(data, hostname, timestamp, provider1, + &date_header, &canonical_headers, &signed_headers); + if(ret) + goto fail; + ret = CURLE_OUT_OF_MEMORY; + memcpy(date, timestamp, sizeof(date)); date[sizeof(date) - 1] = 0; - if(content_type) { - content_type = strchr(content_type, ':'); - if(!content_type) { - ret = CURLE_FAILED_INIT; - goto fail; - } - content_type++; - /* Skip whitespace now */ - while(*content_type == ' ' || *content_type == '\t') - ++content_type; - - canonical_headers = curl_maprintf("content-type:%s\n" - "host:%s\n" - "x-%s-date:%s\n", - content_type, - hostname, - provider1_low, timestamp); - signed_headers = curl_maprintf("content-type;host;x-%s-date", - provider1_low); - } - else { - canonical_headers = curl_maprintf("host:%s\n" - "x-%s-date:%s\n", - hostname, - provider1_low, timestamp); - signed_headers = curl_maprintf("host;x-%s-date", provider1_low); - } - - if(!canonical_headers || !signed_headers) { - goto fail; + if(post_data) { + if(data->set.postfieldsize < 0) + post_data_len = strlen(post_data); + else + post_data_len = (size_t)data->set.postfieldsize; } - - if(data->set.postfieldsize < 0) - post_data_len = strlen(post_data); - else - post_data_len = (size_t)data->set.postfieldsize; if(Curl_sha256it(sha_hash, (const unsigned char *) post_data, - post_data_len)) { + post_data_len)) goto fail; - } sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex)); - Curl_http_method(data, conn, &method, &httpreq); - - canonical_request = - curl_maprintf("%s\n" /* HTTPRequestMethod */ - "%s\n" /* CanonicalURI */ - "%s\n" /* CanonicalQueryString */ - "%s\n" /* CanonicalHeaders */ - "%s\n" /* SignedHeaders */ - "%s", /* HashedRequestPayload in hex */ - method, - data->state.up.path, - data->state.up.query ? data->state.up.query : "", - canonical_headers, - signed_headers, - sha_hex); - if(!canonical_request) { - goto fail; + { + Curl_HttpReq httpreq; + const char *method; + + Curl_http_method(data, conn, &method, &httpreq); + + canonical_request = + curl_maprintf("%s\n" /* HTTPRequestMethod */ + "%s\n" /* CanonicalURI */ + "%s\n" /* CanonicalQueryString */ + "%s\n" /* CanonicalHeaders */ + "%s\n" /* SignedHeaders */ + "%s", /* HashedRequestPayload in hex */ + method, + data->state.up.path, + data->state.up.query ? data->state.up.query : "", + Curl_dyn_ptr(&canonical_headers), + Curl_dyn_ptr(&signed_headers), + sha_hex); + if(!canonical_request) + goto fail; } - request_type = curl_maprintf("%s4_request", provider0_low); - if(!request_type) { + /* provider 0 lowercase */ + Curl_strntolower(provider0, provider0, strlen(provider0)); + request_type = curl_maprintf("%s4_request", provider0); + if(!request_type) goto fail; - } credential_scope = curl_maprintf("%s/%s/%s/%s", date, region, service, request_type); - if(!credential_scope) { + if(!credential_scope) goto fail; - } if(Curl_sha256it(sha_hash, (unsigned char *) canonical_request, - strlen(canonical_request))) { + strlen(canonical_request))) goto fail; - } sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex)); + /* provider 0 uppercase */ + Curl_strntoupper(provider0, provider0, strlen(provider0)); + /* - * Google allow to use rsa key instead of HMAC, so this code might change - * In the future, but for now we support only HMAC version + * Google allows using RSA key instead of HMAC, so this code might change + * in the future. For now we ony support HMAC. */ str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */ "%s\n" /* RequestDateTime */ "%s\n" /* CredentialScope */ "%s", /* HashedCanonicalRequest in hex */ - provider0_up, + provider0, timestamp, credential_scope, sha_hex); @@ -346,36 +474,33 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) goto fail; } - secret = curl_maprintf("%s4%s", provider0_up, passwd); - if(!secret) { + /* provider 0 uppercase */ + secret = curl_maprintf("%s4%s", provider0, + data->state.aptr.passwd ? + data->state.aptr.passwd : ""); + if(!secret) goto fail; - } - HMAC_SHA256(secret, strlen(secret), - date, strlen(date), tmp_sign0); - HMAC_SHA256(tmp_sign0, sizeof(tmp_sign0), - region, strlen(region), tmp_sign1); - HMAC_SHA256(tmp_sign1, sizeof(tmp_sign1), - service, strlen(service), tmp_sign0); - HMAC_SHA256(tmp_sign0, sizeof(tmp_sign0), - request_type, strlen(request_type), tmp_sign1); - HMAC_SHA256(tmp_sign1, sizeof(tmp_sign1), - str_to_sign, strlen(str_to_sign), tmp_sign0); + HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0); + HMAC_SHA256(sign0, sizeof(sign0), region, strlen(region), sign1); + HMAC_SHA256(sign1, sizeof(sign1), service, strlen(service), sign0); + HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1); + HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0); - sha256_to_hex(sha_hex, tmp_sign0, sizeof(sha_hex)); + sha256_to_hex(sha_hex, sign0, sizeof(sha_hex)); + /* provider 0 uppercase */ auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 " "Credential=%s/%s, " "SignedHeaders=%s, " "Signature=%s\r\n" - "X-%s-Date: %s\r\n", - provider0_up, + "%s\r\n", + provider0, user, credential_scope, - signed_headers, + Curl_dyn_ptr(&signed_headers), sha_hex, - provider1_mid, - timestamp); + date_header); if(!auth_headers) { goto fail; } @@ -386,19 +511,14 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) ret = CURLE_OK; fail: - free(provider0_low); - free(provider0_up); - free(provider1_low); - free(provider1_mid); - free(region); - free(service); - free(canonical_headers); - free(signed_headers); + Curl_dyn_free(&canonical_headers); + Curl_dyn_free(&signed_headers); free(canonical_request); free(request_type); free(credential_scope); free(str_to_sign); free(secret); + free(date_header); return ret; } diff --git a/contrib/libs/curl/lib/http_chunks.c b/contrib/libs/curl/lib/http_chunks.c index 290dbe8faa..0b836851ac 100644 --- a/contrib/libs/curl/lib/http_chunks.c +++ b/contrib/libs/curl/lib/http_chunks.c @@ -125,7 +125,7 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, while(length) { switch(ch->state) { case CHUNK_HEX: - if(isxdigit_ascii(*datap)) { + if(ISXDIGIT(*datap)) { if(ch->hexindex < CHUNK_MAXNUM_LEN) { ch->hexbuffer[ch->hexindex] = *datap; datap++; diff --git a/contrib/libs/curl/lib/http_digest.c b/contrib/libs/curl/lib/http_digest.c index c2472e103b..a71c6b7cfb 100644 --- a/contrib/libs/curl/lib/http_digest.c +++ b/contrib/libs/curl/lib/http_digest.c @@ -58,11 +58,11 @@ CURLcode Curl_input_digest(struct Curl_easy *data, digest = &data->state.digest; } - if(!checkprefix("Digest", header) || !ISSPACE(header[6])) + if(!checkprefix("Digest", header) || !ISBLANK(header[6])) return CURLE_BAD_CONTENT_ENCODING; header += strlen("Digest"); - while(*header && ISSPACE(*header)) + while(*header && ISBLANK(*header)) header++; return Curl_auth_decode_digest_http_message(header, digest); diff --git a/contrib/libs/curl/lib/http_negotiate.c b/contrib/libs/curl/lib/http_negotiate.c index 0ac4ead097..5909f85b0d 100644 --- a/contrib/libs/curl/lib/http_negotiate.c +++ b/contrib/libs/curl/lib/http_negotiate.c @@ -84,7 +84,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, /* Obtain the input token, if any */ header += strlen("Negotiate"); - while(*header && ISSPACE(*header)) + while(*header && ISBLANK(*header)) header++; len = strlen(header); diff --git a/contrib/libs/curl/lib/http_ntlm.c b/contrib/libs/curl/lib/http_ntlm.c index a1f0f20cbb..5a6a977905 100644 --- a/contrib/libs/curl/lib/http_ntlm.c +++ b/contrib/libs/curl/lib/http_ntlm.c @@ -29,7 +29,7 @@ /* * NTLM details: * - * https://davenport.sourceforge.io/ntlm.html + * https://davenport.sourceforge.net/ntlm.html * https://www.innovation.ch/java/ntlm.html */ diff --git a/contrib/libs/curl/lib/http_proxy.c b/contrib/libs/curl/lib/http_proxy.c index 64b2dfe08a..d1933df0e3 100644 --- a/contrib/libs/curl/lib/http_proxy.c +++ b/contrib/libs/curl/lib/http_proxy.c @@ -212,10 +212,8 @@ void Curl_connect_done(struct Curl_easy *data) Curl_dyn_free(&s->rcvbuf); Curl_dyn_free(&s->req); - /* restore the protocol pointer, if not already done */ - if(s->prot_save) - data->req.p.http = s->prot_save; - s->prot_save = NULL; + /* restore the protocol pointer */ + data->req.p.http = s->prot_save; data->info.httpcode = 0; /* clear it as it might've been used for the proxy */ data->req.ignorebody = FALSE; diff --git a/contrib/libs/curl/lib/idn_win32.c b/contrib/libs/curl/lib/idn_win32.c index dacba01d7a..2433d927ee 100644 --- a/contrib/libs/curl/lib/idn_win32.c +++ b/contrib/libs/curl/lib/idn_win32.c @@ -67,10 +67,10 @@ WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags, #define IDN_MAX_LENGTH 255 -bool curl_win32_idn_to_ascii(const char *in, char **out); -bool curl_win32_ascii_to_idn(const char *in, char **out); +bool Curl_win32_idn_to_ascii(const char *in, char **out); +bool Curl_win32_ascii_to_idn(const char *in, char **out); -bool curl_win32_idn_to_ascii(const char *in, char **out) +bool Curl_win32_idn_to_ascii(const char *in, char **out) { bool success = FALSE; @@ -93,7 +93,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out) return success; } -bool curl_win32_ascii_to_idn(const char *in, char **out) +bool Curl_win32_ascii_to_idn(const char *in, char **out) { bool success = FALSE; diff --git a/contrib/libs/curl/lib/imap.c b/contrib/libs/curl/lib/imap.c index 12ee2a47eb..ffa08bf7a4 100644 --- a/contrib/libs/curl/lib/imap.c +++ b/contrib/libs/curl/lib/imap.c @@ -1886,8 +1886,8 @@ static char *imap_atom(const char *str, bool escape_only) */ static bool imap_is_bchar(char ch) { - /* Peforming the alnum check with this macro is faster because of ASCII - artihmetic */ + /* Performing the alnum check with this macro is faster because of ASCII + arithmetic */ if(ISALNUM(ch)) return true; diff --git a/contrib/libs/curl/lib/memdebug.h b/contrib/libs/curl/lib/memdebug.h index 7a99e9c58a..7fc90e83a0 100644 --- a/contrib/libs/curl/lib/memdebug.h +++ b/contrib/libs/curl/lib/memdebug.h @@ -30,6 +30,9 @@ * as well as the library. Do not mix with library internals! */ +#include <curl/curl.h> +#include "functypes.h" + #if defined(__GNUC__) && __GNUC__ >= 3 # define ALLOC_FUNC __attribute__((malloc)) # define ALLOC_SIZE(s) __attribute__((alloc_size(s))) diff --git a/contrib/libs/curl/lib/mime.c b/contrib/libs/curl/lib/mime.c index 11e614dc32..042141fc80 100644 --- a/contrib/libs/curl/lib/mime.c +++ b/contrib/libs/curl/lib/mime.c @@ -31,8 +31,9 @@ #include "urldata.h" #include "sendf.h" -#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \ - !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP) +#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \ + !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP)) #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) #include <libgen.h> @@ -1924,8 +1925,8 @@ void Curl_mime_unpause(curl_mimepart *part) } -#else /* !CURL_DISABLE_HTTP && !CURL_DISABLE_MIME || - !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ +#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP || + !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */ /* Mime not compiled in: define stubs for externally-referenced functions. */ curl_mime *curl_mime_init(CURL *easy) diff --git a/contrib/libs/curl/lib/mime.h b/contrib/libs/curl/lib/mime.h index fe1a61c060..bafde29f40 100644 --- a/contrib/libs/curl/lib/mime.h +++ b/contrib/libs/curl/lib/mime.h @@ -134,8 +134,9 @@ struct curl_mimepart { CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...); -#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \ - !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP) +#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \ + !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP)) /* Prototypes. */ void Curl_mime_initpart(struct curl_mimepart *part, struct Curl_easy *easy); diff --git a/contrib/libs/curl/lib/mprintf.c b/contrib/libs/curl/lib/mprintf.c index 30347de250..8a7c17a7ff 100644 --- a/contrib/libs/curl/lib/mprintf.c +++ b/contrib/libs/curl/lib/mprintf.c @@ -318,6 +318,11 @@ static int dprintf_Pass1(const char *format, struct va_stack *vto, flags |= FLAGS_PREC; precision = strtol(fmt, &fmt, 10); } + 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; break; case 'h': flags |= FLAGS_SHORT; @@ -956,7 +961,7 @@ static int dprintf_formatf( else *fptr++ = 'f'; - *fptr = 0; /* and a final zero termination */ + *fptr = 0; /* and a final null-termination */ #ifdef __clang__ #pragma clang diagnostic push @@ -964,7 +969,11 @@ static int dprintf_formatf( #endif /* NOTE NOTE NOTE!! Not all sprintf implementations return number of output characters */ +#ifdef HAVE_SNPRINTF + (snprintf)(work, sizeof(work), formatbuf, p->data.dnum); +#else (sprintf)(work, formatbuf, p->data.dnum); +#endif #ifdef __clang__ #pragma clang diagnostic pop #endif diff --git a/contrib/libs/curl/lib/mqtt.c b/contrib/libs/curl/lib/mqtt.c index 7320747af0..4f3d14386f 100644 --- a/contrib/libs/curl/lib/mqtt.c +++ b/contrib/libs/curl/lib/mqtt.c @@ -186,7 +186,7 @@ static int add_passwd(const char *passwd, const size_t plen, return 0; } -/* add user to the CONN packet */ +/* add user to the CONNECT packet */ static int add_user(const char *username, const size_t ulen, unsigned char *pkt, const size_t start, int remain_pos) { @@ -204,7 +204,7 @@ static int add_user(const char *username, const size_t ulen, return 0; } -/* add client ID to the CONN packet */ +/* add client ID to the CONNECT packet */ static int add_client_id(const char *client_id, const size_t client_id_len, char *pkt, const size_t start) { @@ -216,7 +216,7 @@ static int add_client_id(const char *client_id, const size_t client_id_len, return 0; } -/* Set initial values of CONN packet */ +/* Set initial values of CONNECT packet */ static int init_connpack(char *packet, char *remain, int remain_pos) { /* Fixed header starts */ @@ -293,7 +293,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data) return CURLE_OUT_OF_MEMORY; memset(packet, 0, packetlen); - /* set initial values for CONN pack */ + /* set initial values for the CONNECT packet */ pos = init_connpack(packet, remain, remain_pos); result = Curl_rand_hex(data, (unsigned char *)&client_id[clen], @@ -389,10 +389,18 @@ static CURLcode mqtt_get_topic(struct Curl_easy *data, char **topic, size_t *topiclen) { char *path = data->state.up.path; - if(strlen(path) > 1) - return Curl_urldecode(path + 1, 0, topic, topiclen, REJECT_NADA); - failf(data, "No MQTT topic found. Forgot to URL encode it?"); - return CURLE_URL_MALFORMAT; + CURLcode result = CURLE_URL_MALFORMAT; + if(strlen(path) > 1) { + result = Curl_urldecode(path + 1, 0, topic, topiclen, REJECT_NADA); + if(!result && (*topiclen > 0xffff)) { + failf(data, "Too long MQTT topic"); + result = CURLE_URL_MALFORMAT; + } + } + else + failf(data, "No MQTT topic found. Forgot to URL encode it?"); + + return result; } static CURLcode mqtt_subscribe(struct Curl_easy *data) @@ -690,7 +698,7 @@ static CURLcode mqtt_do(struct Curl_easy *data, bool *done) result = mqtt_connect(data); if(result) { - failf(data, "Error %d sending MQTT CONN request", result); + failf(data, "Error %d sending MQTT CONNECT request", result); return result; } mqstate(data, MQTT_FIRST, MQTT_CONNACK); diff --git a/contrib/libs/curl/lib/multi.c b/contrib/libs/curl/lib/multi.c index f78ff72c42..7a54387253 100644 --- a/contrib/libs/curl/lib/multi.c +++ b/contrib/libs/curl/lib/multi.c @@ -45,7 +45,6 @@ #include "multihandle.h" #include "sigpipe.h" #include "vtls/vtls.h" -#include "connect.h" #include "http_proxy.h" #include "http2.h" #include "socketpair.h" @@ -417,7 +416,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ /* -1 means it not set by user, use the default value */ multi->maxconnects = -1; multi->max_concurrent_streams = 100; - multi->ipv6_works = Curl_ipv6works(NULL); #ifdef USE_WINSOCK multi->wsa_event = WSACreateEvent(); @@ -755,7 +753,7 @@ static int close_connect_only(struct Curl_easy *data, if(data->state.lastconnect_id != conn->connection_id) return 0; - if(!conn->bits.connect_only) + if(!conn->connect_only) return 1; connclose(conn, "Removing connect-only easy handle"); @@ -853,7 +851,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, Curl_detach_connection(data); if(data->set.connect_only && !data->multi_easy) { - /* This removes a handle that was part the multi inteface that used + /* This removes a handle that was part the multi interface that used CONNECT_ONLY, that connection is now left alive but since this handle has bits.close set nothing can use that transfer anymore and it is forbidden from reuse. And this easy handle cannot find the connection @@ -2146,7 +2144,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } } - if(data->set.connect_only) { + if(data->set.connect_only == 1) { /* keep connection open for application to use the socket */ connkeep(data->conn, "CONNECT_ONLY"); multistate(data, MSTATE_DONE); diff --git a/contrib/libs/curl/lib/multihandle.h b/contrib/libs/curl/lib/multihandle.h index 76a67a89a0..a997784ea3 100644 --- a/contrib/libs/curl/lib/multihandle.h +++ b/contrib/libs/curl/lib/multihandle.h @@ -150,11 +150,13 @@ struct Curl_multi { 0 is used for read, 1 is used for write */ #endif #endif - /* multiplexing wanted */ - bool multiplexing; - bool recheckstate; /* see Curl_multi_connchanged */ +#define IPV6_UNKNOWN 0 +#define IPV6_DEAD 1 +#define IPV6_WORKS 2 + unsigned char ipv6_up; /* IPV6_* defined */ + bool multiplexing; /* multiplexing wanted */ + bool recheckstate; /* see Curl_multi_connchanged */ bool in_callback; /* true while executing a callback */ - bool ipv6_works; #ifdef USE_OPENSSL bool ssl_seeded; #endif diff --git a/contrib/libs/curl/lib/netrc.c b/contrib/libs/curl/lib/netrc.c index 62a6a10df8..4461b8492f 100644 --- a/contrib/libs/curl/lib/netrc.c +++ b/contrib/libs/curl/lib/netrc.c @@ -33,6 +33,7 @@ #include "netrc.h" #include "strtok.h" #include "strcase.h" +#include "curl_get_line.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -58,8 +59,6 @@ enum host_lookup_state { static int parsenetrc(const char *host, char **loginp, char **passwordp, - bool *login_changed, - bool *password_changed, char *netrcfile) { FILE *file; @@ -84,7 +83,7 @@ static int parsenetrc(const char *host, char netrcbuffer[4096]; int netrcbuffsize = (int)sizeof(netrcbuffer); - while(!done && fgets(netrcbuffer, netrcbuffsize, file)) { + while(!done && Curl_get_line(netrcbuffer, netrcbuffsize, file)) { char *tok; char *tok_end; bool quoted; @@ -96,7 +95,7 @@ static int parsenetrc(const char *host, } tok = netrcbuffer; while(tok) { - while(ISSPACE(*tok)) + while(ISBLANK(*tok)) tok++; /* tok is first non-space letter */ if(!*tok || (*tok == '#')) @@ -198,9 +197,9 @@ static int parsenetrc(const char *host, /* we are now parsing sub-keywords concerning "our" host */ if(state_login) { if(specific_login) { - state_our_login = strcasecompare(login, tok); + state_our_login = !Curl_timestrcmp(login, tok); } - else if(!login || strcmp(login, tok)) { + else if(!login || Curl_timestrcmp(login, tok)) { if(login_alloc) { free(login); login_alloc = FALSE; @@ -216,7 +215,7 @@ static int parsenetrc(const char *host, } else if(state_password) { if((state_our_login || !specific_login) - && (!password || strcmp(password, tok))) { + && (!password || Curl_timestrcmp(password, tok))) { if(password_alloc) { free(password); password_alloc = FALSE; @@ -243,24 +242,20 @@ static int parsenetrc(const char *host, } /* switch (state) */ tok = ++tok_end; } - } /* while fgets() */ + } /* while Curl_get_line() */ out: if(!retcode) { /* success */ - *login_changed = FALSE; - *password_changed = FALSE; if(login_alloc) { if(*loginp) free(*loginp); *loginp = login; - *login_changed = TRUE; } if(password_alloc) { if(*passwordp) free(*passwordp); *passwordp = password; - *password_changed = TRUE; } } else { @@ -281,11 +276,7 @@ static int parsenetrc(const char *host, * *loginp and *passwordp MUST be allocated if they aren't NULL when passed * in. */ -int Curl_parsenetrc(const char *host, - char **loginp, - char **passwordp, - bool *login_changed, - bool *password_changed, +int Curl_parsenetrc(const char *host, char **loginp, char **passwordp, char *netrcfile) { int retcode = 1; @@ -334,8 +325,7 @@ int Curl_parsenetrc(const char *host, free(homea); return -1; } - retcode = parsenetrc(host, loginp, passwordp, login_changed, - password_changed, filealloc); + retcode = parsenetrc(host, loginp, passwordp, filealloc); free(filealloc); #ifdef WIN32 if(retcode == NETRC_FILE_MISSING) { @@ -345,16 +335,14 @@ int Curl_parsenetrc(const char *host, free(homea); return -1; } - retcode = parsenetrc(host, loginp, passwordp, login_changed, - password_changed, filealloc); + retcode = parsenetrc(host, loginp, passwordp, filealloc); free(filealloc); } #endif free(homea); } else - retcode = parsenetrc(host, loginp, passwordp, login_changed, - password_changed, netrcfile); + retcode = parsenetrc(host, loginp, passwordp, netrcfile); return retcode; } diff --git a/contrib/libs/curl/lib/netrc.h b/contrib/libs/curl/lib/netrc.h index 53e315b61a..53d0056721 100644 --- a/contrib/libs/curl/lib/netrc.h +++ b/contrib/libs/curl/lib/netrc.h @@ -28,12 +28,8 @@ #ifndef CURL_DISABLE_NETRC /* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */ -int Curl_parsenetrc(const char *host, - char **loginp, - char **passwordp, - bool *login_changed, - bool *password_changed, - char *filename); +int Curl_parsenetrc(const char *host, char **loginp, + char **passwordp, char *filename); /* Assume: (*passwordp)[0]=0, host[0] != 0. * If (*loginp)[0] = 0, search for login and password within a machine * section in the netrc. diff --git a/contrib/libs/curl/lib/noproxy.c b/contrib/libs/curl/lib/noproxy.c new file mode 100644 index 0000000000..81f1e09934 --- /dev/null +++ b/contrib/libs/curl/lib/noproxy.c @@ -0,0 +1,222 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_PROXY + +#include "inet_pton.h" +#include "strcase.h" +#include "noproxy.h" + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +/* + * Curl_cidr4_match() returns TRUE if the given IPv4 address is within the + * specified CIDR address range. + */ +UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */ + const char *network, /* 1.2.3.4 address */ + unsigned int bits) +{ + unsigned int address = 0; + unsigned int check = 0; + + if(bits > 32) + /* strange input */ + return FALSE; + + if(1 != Curl_inet_pton(AF_INET, ipv4, &address)) + return FALSE; + if(1 != Curl_inet_pton(AF_INET, network, &check)) + return FALSE; + + if(bits && (bits != 32)) { + unsigned int mask = 0xffffffff << (32 - bits); + unsigned int haddr = htonl(address); + unsigned int hcheck = htonl(check); +#if 0 + fprintf(stderr, "Host %s (%x) network %s (%x) bits %u mask %x => %x\n", + ipv4, haddr, network, hcheck, bits, mask, + (haddr ^ hcheck) & mask); +#endif + if((haddr ^ hcheck) & mask) + return FALSE; + return TRUE; + } + return (address == check); +} + +UNITTEST bool Curl_cidr6_match(const char *ipv6, + const char *network, + unsigned int bits) +{ +#ifdef ENABLE_IPV6 + int bytes; + int rest; + unsigned char address[16]; + unsigned char check[16]; + + if(!bits) + bits = 128; + + bytes = bits/8; + rest = bits & 0x07; + if(1 != Curl_inet_pton(AF_INET6, ipv6, address)) + return FALSE; + if(1 != Curl_inet_pton(AF_INET6, network, check)) + return FALSE; + if((bytes > 16) || ((bytes == 16) && rest)) + return FALSE; + if(bytes && memcmp(address, check, bytes)) + return FALSE; + if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest)))) + return FALSE; + + return TRUE; +#else + (void)ipv6; + (void)network; + (void)bits; + return FALSE; +#endif +} + +enum nametype { + TYPE_HOST, + TYPE_IPV4, + TYPE_IPV6 +}; + +/**************************************************************** +* Checks if the host is in the noproxy list. returns TRUE if it matches and +* therefore the proxy should NOT be used. +****************************************************************/ +bool Curl_check_noproxy(const char *name, const char *no_proxy) +{ + /* no_proxy=domain1.dom,host.domain2.dom + * (a comma-separated list of hosts which should + * not be proxied, or an asterisk to override + * all proxy variables) + */ + if(no_proxy && no_proxy[0]) { + const char *p = no_proxy; + size_t namelen; + enum nametype type = TYPE_HOST; + char hostip[128]; + if(!strcmp("*", no_proxy)) + return TRUE; + + /* NO_PROXY was specified and it wasn't just an asterisk */ + + if(name[0] == '[') { + char *endptr; + /* IPv6 numerical address */ + endptr = strchr(name, ']'); + if(!endptr) + return FALSE; + name++; + namelen = endptr - name; + if(namelen >= sizeof(hostip)) + return FALSE; + memcpy(hostip, name, namelen); + hostip[namelen] = 0; + name = hostip; + type = TYPE_IPV6; + } + else { + unsigned int address; + if(1 == Curl_inet_pton(AF_INET, name, &address)) + type = TYPE_IPV4; + namelen = strlen(name); + } + + while(*p) { + const char *token; + size_t tokenlen = 0; + bool match = FALSE; + + /* pass blanks */ + while(*p && ISBLANK(*p)) + p++; + + token = p; + /* pass over the pattern */ + while(*p && !ISBLANK(*p) && (*p != ',')) { + p++; + tokenlen++; + } + + if(tokenlen) { + switch(type) { + case TYPE_HOST: + if(*token == '.') { + ++token; + --tokenlen; + /* tailmatch */ + match = (tokenlen <= namelen) && + strncasecompare(token, name + (namelen - tokenlen), namelen); + } + else + match = (tokenlen == namelen) && + strncasecompare(token, name, namelen); + break; + case TYPE_IPV4: + /* FALLTHROUGH */ + case TYPE_IPV6: { + const char *check = token; + char *slash = strchr(check, '/'); + unsigned int bits = 0; + char checkip[128]; + /* if the slash is part of this token, use it */ + if(slash && (slash < &check[tokenlen])) { + bits = atoi(slash + 1); + /* copy the check name to a temp buffer */ + if(tokenlen >= sizeof(checkip)) + break; + memcpy(checkip, check, tokenlen); + checkip[ slash - check ] = 0; + check = checkip; + } + if(type == TYPE_IPV6) + match = Curl_cidr6_match(name, check, bits); + else + match = Curl_cidr4_match(name, check, bits); + break; + } + } + if(match) + return TRUE; + } /* if(tokenlen) */ + while(*p == ',') + p++; + } /* while(*p) */ + } /* NO_PROXY was specified and it wasn't just an asterisk */ + + return FALSE; +} + +#endif /* CURL_DISABLE_PROXY */ diff --git a/contrib/libs/curl/lib/dotdot.h b/contrib/libs/curl/lib/noproxy.h index 4ffe72de83..8800a21276 100644 --- a/contrib/libs/curl/lib/dotdot.h +++ b/contrib/libs/curl/lib/noproxy.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_DOTDOT_H -#define HEADER_CURL_DOTDOT_H +#ifndef HEADER_CURL_NOPROXY_H +#define HEADER_CURL_NOPROXY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -23,5 +23,22 @@ * SPDX-License-Identifier: curl * ***************************************************************************/ -char *Curl_dedotdotify(const char *input); -#endif /* HEADER_CURL_DOTDOT_H */ +#include "curl_setup.h" + +#ifndef CURL_DISABLE_PROXY + +#ifdef DEBUGBUILD + +UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */ + const char *network, /* 1.2.3.4 address */ + unsigned int bits); +UNITTEST bool Curl_cidr6_match(const char *ipv6, + const char *network, + unsigned int bits); +#endif + +bool Curl_check_noproxy(const char *name, const char *no_proxy); + +#endif + +#endif /* HEADER_CURL_NOPROXY_H */ diff --git a/contrib/libs/curl/lib/openldap.c b/contrib/libs/curl/lib/openldap.c index d1adf27c86..7027c88054 100644 --- a/contrib/libs/curl/lib/openldap.c +++ b/contrib/libs/curl/lib/openldap.c @@ -1068,8 +1068,8 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf, if(!binary) { /* check for leading or trailing whitespace */ - if(ISSPACE(bvals[i].bv_val[0]) || - ISSPACE(bvals[i].bv_val[bvals[i].bv_len - 1])) + if(ISBLANK(bvals[i].bv_val[0]) || + ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1])) binval = 1; else { /* check for unprintable characters */ diff --git a/contrib/libs/curl/lib/pingpong.c b/contrib/libs/curl/lib/pingpong.c index 74a678a1a4..d4e6be98c4 100644 --- a/contrib/libs/curl/lib/pingpong.c +++ b/contrib/libs/curl/lib/pingpong.c @@ -330,7 +330,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data, else if(gotbytes <= 0) { keepon = FALSE; result = CURLE_RECV_ERROR; - failf(data, "response reading failed"); + failf(data, "response reading failed (errno: %d)", SOCKERRNO); } else { /* we got a whole chunk of data, which can be anything from one diff --git a/contrib/libs/curl/lib/rand.c b/contrib/libs/curl/lib/rand.c index c6fd47e7f6..2e7e7e8238 100644 --- a/contrib/libs/curl/lib/rand.c +++ b/contrib/libs/curl/lib/rand.c @@ -212,7 +212,7 @@ CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num) /* * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random - * hexadecimal digits PLUS a zero terminating byte. It must be an odd number + * hexadecimal digits PLUS a null-terminating byte. It must be an odd number * size. */ @@ -235,7 +235,7 @@ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, /* make sure it fits in the local buffer and that it is an odd number! */ return CURLE_BAD_FUNCTION_ARGUMENT; - num--; /* save one for zero termination */ + num--; /* save one for null-termination */ result = Curl_rand(data, buffer, num/2); if(result) diff --git a/contrib/libs/curl/lib/rand.h b/contrib/libs/curl/lib/rand.h index 99f25b94e1..30fc29615a 100644 --- a/contrib/libs/curl/lib/rand.h +++ b/contrib/libs/curl/lib/rand.h @@ -42,7 +42,7 @@ CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num); /* * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random - * hexadecimal digits PLUS a zero terminating byte. It must be an odd number + * hexadecimal digits PLUS a null-terminating byte. It must be an odd number * size. */ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, diff --git a/contrib/libs/curl/lib/rtsp.c b/contrib/libs/curl/lib/rtsp.c index 5a6644b26c..6d3bf97e6c 100644 --- a/contrib/libs/curl/lib/rtsp.c +++ b/contrib/libs/curl/lib/rtsp.c @@ -794,7 +794,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header) /* Find the first non-space letter */ start = header + 8; - while(*start && ISSPACE(*start)) + while(*start && ISBLANK(*start)) start++; if(!*start) { diff --git a/contrib/libs/curl/lib/select.h b/contrib/libs/curl/lib/select.h index eaff7d9b1c..f2cf8bbd9f 100644 --- a/contrib/libs/curl/lib/select.h +++ b/contrib/libs/curl/lib/select.h @@ -36,8 +36,7 @@ * Definition of pollfd struct and constants for platforms lacking them. */ -#if !defined(HAVE_STRUCT_POLLFD) && \ - !defined(HAVE_SYS_POLL_H) && \ +#if !defined(HAVE_SYS_POLL_H) && \ !defined(HAVE_POLL_H) && \ !defined(POLLIN) diff --git a/contrib/libs/curl/lib/sendf.c b/contrib/libs/curl/lib/sendf.c index 2fe7169dd2..d26b7e7cd7 100644 --- a/contrib/libs/curl/lib/sendf.c +++ b/contrib/libs/curl/lib/sendf.c @@ -48,6 +48,7 @@ #include "strdup.h" #include "http2.h" #include "headers.h" +#include "ws.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -534,6 +535,7 @@ static CURLcode chop_write(struct Curl_easy *data, curl_write_callback writebody = NULL; char *ptr = optr; size_t len = olen; + void *writebody_ptr = data->set.out; if(!len) return CURLE_OK; @@ -544,8 +546,18 @@ static CURLcode chop_write(struct Curl_easy *data, return pausewrite(data, type, ptr, len); /* Determine the callback(s) to use. */ - if(type & CLIENTWRITE_BODY) + if(type & CLIENTWRITE_BODY) { +#ifdef USE_WEBSOCKETS + if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) { + struct HTTP *ws = data->req.p.http; + writebody = Curl_ws_writecb; + ws->ws.data = data; + writebody_ptr = ws; + } + else +#endif writebody = data->set.fwrite_func; + } if((type & CLIENTWRITE_HEADER) && (data->set.fwrite_header || data->set.writeheader)) { /* @@ -563,7 +575,7 @@ static CURLcode chop_write(struct Curl_easy *data, if(writebody) { size_t wrote; Curl_set_in_callback(data, true); - wrote = writebody(ptr, 1, chunklen, data->set.out); + wrote = writebody(ptr, 1, chunklen, writebody_ptr); Curl_set_in_callback(data, false); if(CURL_WRITEFUNC_PAUSE == wrote) { @@ -723,9 +735,10 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type, static const char s_infotype[CURLINFO_END][3] = { "* ", "< ", "> ", "{ ", "} ", "{ ", "} " }; if(data->set.fdebug) { + bool inCallback = Curl_is_in_callback(data); Curl_set_in_callback(data, true); (void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata); - Curl_set_in_callback(data, false); + Curl_set_in_callback(data, inCallback); } else { switch(type) { diff --git a/contrib/libs/curl/lib/setopt.c b/contrib/libs/curl/lib/setopt.c index d5e3b50c82..5b5975485c 100644 --- a/contrib/libs/curl/lib/setopt.c +++ b/contrib/libs/curl/lib/setopt.c @@ -148,81 +148,36 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) #define C_SSLVERSION_VALUE(x) (x & 0xffff) #define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000) -static CURLcode protocol2num(char *str, curl_off_t *val) +static CURLcode protocol2num(const char *str, curl_prot_t *val) { - bool found_comma = FALSE; - static struct scheme { - const char *name; - long bit; - } const protos[] = { - { "dict", CURLPROTO_DICT }, - { "file", CURLPROTO_FILE }, - { "ftp", CURLPROTO_FTP }, - { "ftps", CURLPROTO_FTPS }, - { "gopher", CURLPROTO_GOPHER }, - { "gophers", CURLPROTO_GOPHERS }, - { "http", CURLPROTO_HTTP }, - { "https", CURLPROTO_HTTPS }, - { "imap", CURLPROTO_IMAP }, - { "imaps", CURLPROTO_IMAPS }, - { "ldap", CURLPROTO_LDAP }, - { "ldaps", CURLPROTO_LDAPS }, - { "mqtt", CURLPROTO_MQTT }, - { "pop3", CURLPROTO_POP3 }, - { "pop3s", CURLPROTO_POP3S }, - { "rtmp", CURLPROTO_RTMP }, - { "rtmpe", CURLPROTO_RTMPE }, - { "rtmps", CURLPROTO_RTMPS }, - { "rtmpt", CURLPROTO_RTMPT }, - { "rtmpte", CURLPROTO_RTMPTE }, - { "rtmpts", CURLPROTO_RTMPTS }, - { "rtsp", CURLPROTO_RTSP }, - { "scp", CURLPROTO_SCP }, - { "sftp", CURLPROTO_SFTP }, - { "smb", CURLPROTO_SMB }, - { "smbs", CURLPROTO_SMBS }, - { "smtp", CURLPROTO_SMTP }, - { "smtps", CURLPROTO_SMTPS }, - { "telnet", CURLPROTO_TELNET }, - { "tftp", CURLPROTO_TFTP }, - { NULL, 0 } - }; - if(!str) return CURLE_BAD_FUNCTION_ARGUMENT; - else if(curl_strequal(str, "all")) { - *val = ~0; + + if(curl_strequal(str, "all")) { + *val = ~(curl_prot_t) 0; return CURLE_OK; } *val = 0; do { + const char *token = str; size_t tlen; - struct scheme const *pp; - char *token; - token = strchr(str, ','); - found_comma = token ? TRUE : FALSE; - if(!token) - token = strchr(str, '\0'); - tlen = token - str; + + str = strchr(str, ','); + tlen = str? (size_t) (str - token): strlen(token); if(tlen) { - for(pp = protos; pp->name; pp++) { - if((strlen(pp->name) == tlen) && - curl_strnequal(str, pp->name, tlen)) { - *val |= pp->bit; - break; - } - } - if(!(pp->name)) - /* protocol name didn't match */ - return CURLE_BAD_FUNCTION_ARGUMENT; + const struct Curl_handler *h = Curl_builtin_scheme(token, tlen); + + if(!h) + return CURLE_UNSUPPORTED_PROTOCOL; + + *val |= h->protocol; } - if(found_comma) - str = token + 1; - } while(found_comma); + } while(str++); + if(!*val) - /* no matching protocol */ + /* no protocol listed */ return CURLE_BAD_FUNCTION_ARGUMENT; return CURLE_OK; } @@ -696,8 +651,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) } else data->set.method = HTTPREQ_GET; + data->set.upload = FALSE; break; +#ifndef CURL_DISABLE_MIME case CURLOPT_HTTPPOST: /* * Set to make us do HTTP POST @@ -706,6 +663,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.method = HTTPREQ_POST_FORM; data->set.opt_no_body = FALSE; /* this is implied */ break; +#endif case CURLOPT_AWS_SIGV4: /* @@ -721,18 +679,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.httpauth = CURLAUTH_AWS_SIGV4; break; - case CURLOPT_MIMEPOST: - /* - * Set to make us do MIME/form POST - */ - result = Curl_mime_set_subparts(&data->set.mimepost, - va_arg(param, curl_mime *), FALSE); - if(!result) { - data->set.method = HTTPREQ_POST_MIME; - data->set.opt_no_body = FALSE; /* this is implied */ - } - break; - case CURLOPT_REFERER: /* * String to set in the HTTP Referer: field. @@ -754,13 +700,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) va_arg(param, char *)); break; - case CURLOPT_HTTPHEADER: - /* - * Set a list with HTTP headers to use (or replace internals with) - */ - data->set.headers = va_arg(param, struct curl_slist *); - break; - #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXYHEADER: /* @@ -998,6 +937,36 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; #endif /* CURL_DISABLE_HTTP */ +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP) +# if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MIME) + case CURLOPT_HTTPHEADER: + /* + * Set a list with HTTP headers to use (or replace internals with) + */ + data->set.headers = va_arg(param, struct curl_slist *); + break; +# endif + +# ifndef CURL_DISABLE_MIME + case CURLOPT_MIMEPOST: + /* + * Set to make us do MIME POST + */ + result = Curl_mime_set_subparts(&data->set.mimepost, + va_arg(param, curl_mime *), FALSE); + if(!result) { + data->set.method = HTTPREQ_POST_MIME; + data->set.opt_no_body = FALSE; /* this is implied */ + } + break; + + case CURLOPT_MIME_OPTIONS: + data->set.mime_options = (unsigned int)va_arg(param, long); + break; +# endif +#endif + case CURLOPT_HTTPAUTH: /* * Set HTTP Authentication type BITMASK. @@ -2430,9 +2399,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURLOPT_CONNECT_ONLY: /* - * No data transfer, set up connection and let application use the socket + * No data transfer. + * (1) - only do connection + * (2) - do first get request but get no content */ - data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE; + arg = va_arg(param, long); + if(arg > 2) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.connect_only = (unsigned char)arg; break; case CURLOPT_SOCKOPTFUNCTION: @@ -2640,31 +2614,35 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) transfer, which thus helps the app which takes URLs from users or other external inputs and want to restrict what protocol(s) to deal with. Defaults to CURLPROTO_ALL. */ - data->set.allowed_protocols = (curl_off_t)va_arg(param, long); + data->set.allowed_protocols = (curl_prot_t)va_arg(param, long); break; case CURLOPT_REDIR_PROTOCOLS: /* set the bitmask for the protocols that libcurl is allowed to follow to, as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs to be set in both bitmasks to be allowed to get redirected to. */ - data->set.redir_protocols = (curl_off_t)va_arg(param, long); + data->set.redir_protocols = (curl_prot_t)va_arg(param, long); break; - case CURLOPT_PROTOCOLS_STR: + case CURLOPT_PROTOCOLS_STR: { + curl_prot_t prot; argptr = va_arg(param, char *); - result = protocol2num(argptr, &bigsize); + result = protocol2num(argptr, &prot); if(result) return result; - data->set.allowed_protocols = bigsize; + data->set.allowed_protocols = prot; break; + } - case CURLOPT_REDIR_PROTOCOLS_STR: + case CURLOPT_REDIR_PROTOCOLS_STR: { + curl_prot_t prot; argptr = va_arg(param, char *); - result = protocol2num(argptr, &bigsize); + result = protocol2num(argptr, &prot); if(result) return result; - data->set.redir_protocols = bigsize; + data->set.redir_protocols = prot; break; + } case CURLOPT_DEFAULT_PROTOCOL: /* Set the protocol to use when the URL doesn't include any protocol */ @@ -2694,13 +2672,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; #endif -#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \ - !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP) - case CURLOPT_MIME_OPTIONS: - data->set.mime_options = (unsigned int)va_arg(param, long); - break; -#endif - case CURLOPT_SASL_AUTHZID: /* Authorization identity (identity to act as) */ result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID], @@ -2952,7 +2923,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) #endif break; case CURLOPT_SSL_ENABLE_NPN: - data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SSL_ENABLE_ALPN: data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE; @@ -3128,6 +3098,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURLOPT_PREREQDATA: data->set.prereq_userp = va_arg(param, void *); break; +#ifdef USE_WEBSOCKETS + case CURLOPT_WS_OPTIONS: { + bool raw; + arg = va_arg(param, long); + raw = (arg & CURLWS_RAW_MODE); + data->set.ws_raw_mode = raw; + break; + } +#endif default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; diff --git a/contrib/libs/curl/lib/setup-win32.h b/contrib/libs/curl/lib/setup-win32.h index c16928db90..bc5f8efc3c 100644 --- a/contrib/libs/curl/lib/setup-win32.h +++ b/contrib/libs/curl/lib/setup-win32.h @@ -37,10 +37,21 @@ #ifdef HAVE_WINDOWS_H # if defined(UNICODE) && !defined(_UNICODE) -# define _UNICODE +# error "UNICODE is defined but _UNICODE is not defined" # endif # if defined(_UNICODE) && !defined(UNICODE) -# define UNICODE +# error "_UNICODE is defined but UNICODE is not defined" +# endif +/* + * Don't include unneeded stuff in Windows headers to avoid compiler + * warnings and macro clashes. + * Make sure to define this macro before including any Windows headers. + */ +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# ifndef NOGDI +# define NOGDI # endif # include <winerror.h> # include <windows.h> diff --git a/contrib/libs/curl/lib/smb.c b/contrib/libs/curl/lib/smb.c index 039d680041..a62e858143 100644 --- a/contrib/libs/curl/lib/smb.c +++ b/contrib/libs/curl/lib/smb.c @@ -34,7 +34,7 @@ #include <process.h> #ifdef CURL_WINDOWS_APP #define getpid GetCurrentProcessId -#elif !defined(MSDOS) +#elif defined(WIN32) #define getpid _getpid #endif #endif diff --git a/contrib/libs/curl/lib/socketpair.h b/contrib/libs/curl/lib/socketpair.h index f91a3c6511..de70df673a 100644 --- a/contrib/libs/curl/lib/socketpair.h +++ b/contrib/libs/curl/lib/socketpair.h @@ -26,6 +26,8 @@ #include "curl_setup.h" #ifndef HAVE_SOCKETPAIR +#include <curl/curl.h> + int Curl_socketpair(int domain, int type, int protocol, curl_socket_t socks[2]); #else diff --git a/contrib/libs/curl/lib/strcase.c b/contrib/libs/curl/lib/strcase.c index f932485204..09d2a8a961 100644 --- a/contrib/libs/curl/lib/strcase.c +++ b/contrib/libs/curl/lib/strcase.c @@ -28,8 +28,6 @@ #include "strcase.h" -static char raw_tolower(char in); - /* Mapping table to go from lowercase to uppercase for plain ASCII.*/ static const unsigned char touppermap[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, @@ -79,7 +77,7 @@ char Curl_raw_toupper(char in) /* Portable, consistent tolower. Do not use tolower() because its behavior is altered by the current locale. */ -static char raw_tolower(char in) +char Curl_raw_tolower(char in) { return tolowermap[(unsigned char) in]; } @@ -165,7 +163,7 @@ void Curl_strntolower(char *dest, const char *src, size_t n) return; do { - *dest++ = raw_tolower(*src); + *dest++ = Curl_raw_tolower(*src); } while(*src++ && --n); } @@ -179,6 +177,28 @@ bool Curl_safecmp(char *a, char *b) return !a && !b; } +/* + * Curl_timestrcmp() returns 0 if the two strings are identical. The time this + * function spends is a function of the shortest string, not of the contents. + */ +int Curl_timestrcmp(const char *a, const char *b) +{ + int match = 0; + int i = 0; + + if(a && b) { + while(1) { + match |= a[i]^b[i]; + if(!a[i] || !b[i]) + break; + i++; + } + } + else + return a || b; + return match; +} + /* --- public functions --- */ int curl_strequal(const char *first, const char *second) diff --git a/contrib/libs/curl/lib/strcase.h b/contrib/libs/curl/lib/strcase.h index d245929227..65a575385d 100644 --- a/contrib/libs/curl/lib/strcase.h +++ b/contrib/libs/curl/lib/strcase.h @@ -43,6 +43,7 @@ int Curl_safe_strcasecompare(const char *first, const char *second); int Curl_strncasecompare(const char *first, const char *second, size_t max); char Curl_raw_toupper(char in); +char Curl_raw_tolower(char in); /* checkprefix() is a shorter version of the above, used when the first argument is the string literal */ @@ -52,5 +53,6 @@ void Curl_strntoupper(char *dest, const char *src, size_t n); void Curl_strntolower(char *dest, const char *src, size_t n); bool Curl_safecmp(char *a, char *b); +int Curl_timestrcmp(const char *first, const char *second); #endif /* HEADER_CURL_STRCASE_H */ diff --git a/contrib/libs/curl/lib/strerror.c b/contrib/libs/curl/lib/strerror.c index 02f8986d18..4889097775 100644 --- a/contrib/libs/curl/lib/strerror.c +++ b/contrib/libs/curl/lib/strerror.c @@ -476,7 +476,7 @@ curl_url_strerror(CURLUcode error) return "Port number was not a decimal number between 0 and 65535"; case CURLUE_UNSUPPORTED_SCHEME: - return "This libcurl build doesn't support the given URL scheme"; + return "Unsupported URL scheme"; case CURLUE_URLDECODE: return "URL decode error, most likely because of rubbish in the input"; @@ -530,7 +530,7 @@ curl_url_strerror(CURLUcode error) return "Bad file:// URL"; case CURLUE_BAD_SLASHES: - return "Unsupported number of slashes"; + return "Unsupported number of slashes following scheme"; case CURLUE_BAD_SCHEME: return "Bad scheme"; diff --git a/contrib/libs/curl/lib/strtoofft.c b/contrib/libs/curl/lib/strtoofft.c index 30908fdd92..30deb8c05b 100644 --- a/contrib/libs/curl/lib/strtoofft.c +++ b/contrib/libs/curl/lib/strtoofft.c @@ -87,7 +87,7 @@ static curl_off_t strtooff(const char *nptr, char **endptr, int base) /* Skip leading whitespace. */ end = (char *)nptr; - while(ISSPACE(end[0])) { + while(ISBLANK(end[0])) { end++; } @@ -222,9 +222,9 @@ CURLofft curlx_strtoofft(const char *str, char **endp, int base, errno = 0; *num = 0; /* clear by default */ - while(*str && ISSPACE(*str)) + while(*str && ISBLANK(*str)) str++; - if('-' == *str) { + if(('-' == *str) || (ISSPACE(*str))) { if(endp) *endp = (char *)str; /* didn't actually move */ return CURL_OFFT_INVAL; /* nothing parsed */ diff --git a/contrib/libs/curl/lib/timediff.c b/contrib/libs/curl/lib/timediff.c index 27fd911638..c5893187dd 100644 --- a/contrib/libs/curl/lib/timediff.c +++ b/contrib/libs/curl/lib/timediff.c @@ -24,6 +24,8 @@ #include "timediff.h" +#include <limits.h> + /* * Converts number of milliseconds into a timeval structure. * diff --git a/contrib/libs/curl/lib/transfer.c b/contrib/libs/curl/lib/transfer.c index 6560d9607d..441da73429 100644 --- a/contrib/libs/curl/lib/transfer.c +++ b/contrib/libs/curl/lib/transfer.c @@ -1439,6 +1439,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) if(result) return result; + data->state.requests = 0; data->state.followlocation = 0; /* reset the location-follow counter */ data->state.this_is_a_follow = FALSE; /* reset this */ data->state.errorbuf = FALSE; /* no error has occurred */ @@ -1636,7 +1637,7 @@ CURLcode Curl_follow(struct Curl_easy *data, if((type != FOLLOW_RETRY) && (data->req.httpcode != 401) && (data->req.httpcode != 407) && - Curl_is_absolute_url(newurl, NULL, 0)) + Curl_is_absolute_url(newurl, NULL, 0, FALSE)) /* If this is not redirect due to a 401 or 407 response and an absolute URL: don't allow a custom port number */ disallowport = TRUE; @@ -1648,8 +1649,11 @@ CURLcode Curl_follow(struct Curl_easy *data, CURLU_ALLOW_SPACE | (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)); if(uc) { - if(type != FOLLOW_FAKE) + if(type != FOLLOW_FAKE) { + failf(data, "The redirect target URL could not be parsed: %s", + curl_url_strerror(uc)); return Curl_uc_to_curlcode(uc); + } /* the URL could not be parsed for some reason, but since this is FAKE mode, just duplicate the field as-is */ @@ -1696,7 +1700,7 @@ CURLcode Curl_follow(struct Curl_easy *data, return Curl_uc_to_curlcode(uc); } - p = Curl_builtin_scheme(scheme); + p = Curl_builtin_scheme(scheme, CURL_ZERO_TERMINATED); if(p && (p->protocol != data->info.conn_protocol)) { infof(data, "Clear auth, redirects scheme from %s to %s", data->info.conn_scheme, scheme); diff --git a/contrib/libs/curl/lib/url.c b/contrib/libs/curl/lib/url.c index ec3fb77b01..7b6d694449 100644 --- a/contrib/libs/curl/lib/url.c +++ b/contrib/libs/curl/lib/url.c @@ -73,8 +73,8 @@ #endif #elif defined(USE_WIN32_IDN) -/* prototype for curl_win32_idn_to_ascii() */ -bool curl_win32_idn_to_ascii(const char *in, char **out); +/* prototype for Curl_win32_idn_to_ascii() */ +bool Curl_win32_idn_to_ascii(const char *in, char **out); #endif /* USE_LIBIDN2 */ #include "doh.h" @@ -106,6 +106,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "urlapi-int.h" #include "system_win32.h" #include "hsts.h" +#include "noproxy.h" /* And now for the protocols */ #include "ftp.h" @@ -128,7 +129,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "http_proxy.h" #include "conncache.h" #include "multihandle.h" -#include "dotdot.h" #include "strdup.h" #include "setopt.h" #include "altsvc.h" @@ -168,7 +168,7 @@ static void conn_free(struct connectdata *conn); * * Returns the family as a single bit protocol identifier. */ -static unsigned int get_protocol_family(const struct Curl_handler *h) +static curl_prot_t get_protocol_family(const struct Curl_handler *h) { DEBUGASSERT(h); DEBUGASSERT(h->family); @@ -192,6 +192,16 @@ static const struct Curl_handler * const protocols[] = { &Curl_handler_http, #endif +#ifdef USE_WEBSOCKETS +#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) + &Curl_handler_wss, +#endif + +#ifndef CURL_DISABLE_HTTP + &Curl_handler_ws, +#endif +#endif + #ifndef CURL_DISABLE_FTP &Curl_handler_ftp, #endif @@ -568,11 +578,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->new_file_perms = 0644; /* Default permissions */ set->new_directory_perms = 0755; /* Default permissions */ - - /* for the *protocols fields we don't use the CURLPROTO_ALL convenience - define since we internally only use the lower 16 bits for the passed - in bitmask to not conflict with the private bits */ - set->allowed_protocols = (unsigned int)CURLPROTO_ALL; + set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL; set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | CURLPROTO_FTPS; @@ -623,7 +629,6 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->tcp_keepidle = 60; set->tcp_fastopen = FALSE; set->tcp_nodelay = TRUE; - set->ssl_enable_npn = TRUE; set->ssl_enable_alpn = TRUE; set->expect_100_timeout = 1000L; /* Wait for a second by default. */ set->sep_headers = TRUE; /* separated header lists by default */ @@ -746,15 +751,6 @@ static void conn_shutdown(struct Curl_easy *data, struct connectdata *conn) DEBUGASSERT(data); infof(data, "Closing connection %ld", conn->connection_id); -#ifndef USE_HYPER - if(conn->connect_state && conn->connect_state->prot_save) { - /* If this was closed with a CONNECT in progress, cleanup this temporary - struct arrangement */ - data->req.p.http = NULL; - Curl_safefree(conn->connect_state->prot_save); - } -#endif - /* possible left-overs from the async name resolvers */ Curl_resolver_cancel(data); @@ -869,7 +865,7 @@ void Curl_disconnect(struct Curl_easy *data, /* Cleanup NEGOTIATE connection-related data */ Curl_http_auth_cleanup_negotiate(conn); - if(conn->bits.connect_only) + if(conn->connect_only) /* treat the connection as dead in CONNECT_ONLY situations */ dead_connection = TRUE; @@ -953,19 +949,11 @@ socks_proxy_info_matches(const struct proxy_info *data, /* the user information is case-sensitive or at least it is not defined as case-insensitive see https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1 */ - if(!data->user != !needle->user) - return FALSE; - /* curl_strequal does a case insentive comparison, so do not use it here! */ - if(data->user && - needle->user && - strcmp(data->user, needle->user) != 0) - return FALSE; - if(!data->passwd != !needle->passwd) - return FALSE; - /* curl_strequal does a case insentive comparison, so do not use it here! */ - if(data->passwd && - needle->passwd && - strcmp(data->passwd, needle->passwd) != 0) + + /* curl_strequal does a case insensitive comparison, + so do not use it here! */ + if(Curl_timestrcmp(data->user, needle->user) || + Curl_timestrcmp(data->passwd, needle->passwd)) return FALSE; return TRUE; } @@ -1215,7 +1203,7 @@ ConnectionExists(struct Curl_easy *data, check = curr->ptr; curr = curr->next; - if(check->bits.connect_only || check->bits.close) + if(check->connect_only || check->bits.close) /* connect-only or to-be-closed connections will not be reused */ continue; @@ -1367,10 +1355,10 @@ ConnectionExists(struct Curl_easy *data, if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { /* This protocol requires credentials per connection, so verify that we're using the same name and password as well */ - if(strcmp(needle->user, check->user) || - strcmp(needle->passwd, check->passwd) || - !Curl_safecmp(needle->sasl_authzid, check->sasl_authzid) || - !Curl_safecmp(needle->oauth_bearer, check->oauth_bearer)) { + if(Curl_timestrcmp(needle->user, check->user) || + Curl_timestrcmp(needle->passwd, check->passwd) || + Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) || + Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) { /* one of them was different */ continue; } @@ -1446,8 +1434,8 @@ ConnectionExists(struct Curl_easy *data, possible. (Especially we must not reuse the same connection if partway through a handshake!) */ if(wantNTLMhttp) { - if(strcmp(needle->user, check->user) || - strcmp(needle->passwd, check->passwd)) { + if(Curl_timestrcmp(needle->user, check->user) || + Curl_timestrcmp(needle->passwd, check->passwd)) { /* we prefer a credential match, but this is at least a connection that can be reused and "upgraded" to NTLM */ @@ -1469,8 +1457,10 @@ ConnectionExists(struct Curl_easy *data, if(!check->http_proxy.user || !check->http_proxy.passwd) continue; - if(strcmp(needle->http_proxy.user, check->http_proxy.user) || - strcmp(needle->http_proxy.passwd, check->http_proxy.passwd)) + if(Curl_timestrcmp(needle->http_proxy.user, + check->http_proxy.user) || + Curl_timestrcmp(needle->http_proxy.passwd, + check->http_proxy.passwd)) continue; } else if(check->proxy_ntlm_state != NTLMSTATE_NONE) { @@ -1642,7 +1632,7 @@ CURLcode Curl_idnconvert_hostname(struct Curl_easy *data, #elif defined(USE_WIN32_IDN) char *ace_hostname = NULL; - if(curl_win32_idn_to_ascii(host->name, &ace_hostname)) { + if(Curl_win32_idn_to_ascii(host->name, &ace_hostname)) { host->encalloc = ace_hostname; /* change the name pointer to point to the encoded hostname */ host->name = host->encalloc; @@ -1673,7 +1663,7 @@ void Curl_free_idnconverted_hostname(struct hostname *host) } #elif defined(USE_WIN32_IDN) free(host->encalloc); /* must be freed with free() since this was - allocated by curl_win32_idn_to_ascii */ + allocated by Curl_win32_idn_to_ascii */ host->encalloc = NULL; #else (void)host; @@ -1799,7 +1789,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->proxy_ssl_config.ssl_options = data->set.proxy_ssl.primary.ssl_options; #endif conn->ip_version = data->set.ipver; - conn->bits.connect_only = data->set.connect_only; + conn->connect_only = data->set.connect_only; conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */ #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ @@ -1843,15 +1833,18 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) } /* returns the handler if the given scheme is built-in */ -const struct Curl_handler *Curl_builtin_scheme(const char *scheme) +const struct Curl_handler *Curl_builtin_scheme(const char *scheme, + size_t schemelen) { const struct Curl_handler * const *pp; const struct Curl_handler *p; /* Scan protocol handler table and match against 'scheme'. The handler may be changed later when the protocol specific setup function is called. */ + if(schemelen == CURL_ZERO_TERMINATED) + schemelen = strlen(scheme); for(pp = protocols; (p = *pp) != NULL; pp++) - if(strcasecompare(p->scheme, scheme)) - /* Protocol found in table. Check if allowed */ + if(strncasecompare(p->scheme, scheme, schemelen) && !p->scheme[schemelen]) + /* Protocol found in table. */ return p; return NULL; /* not found */ } @@ -1861,7 +1854,8 @@ static CURLcode findprotocol(struct Curl_easy *data, struct connectdata *conn, const char *protostr) { - const struct Curl_handler *p = Curl_builtin_scheme(protostr); + const struct Curl_handler *p = Curl_builtin_scheme(protostr, + CURL_ZERO_TERMINATED); if(p && /* Protocol found in table. Check if allowed */ (data->set.allowed_protocols & p->protocol)) { @@ -1985,7 +1979,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; if(data->set.str[STRING_DEFAULT_PROTOCOL] && - !Curl_is_absolute_url(data->state.url, NULL, 0)) { + !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) { char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL], data->state.url); if(!url) @@ -2033,10 +2027,56 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, failf(data, "Too long host name (maximum is %d)", MAX_URL_LEN); return CURLE_URL_MALFORMAT; } + hostname = data->state.up.hostname; + + if(hostname && hostname[0] == '[') { + /* This looks like an IPv6 address literal. See if there is an address + scope. */ + size_t hlen; + conn->bits.ipv6_ip = TRUE; + /* cut off the brackets! */ + hostname++; + hlen = strlen(hostname); + hostname[hlen - 1] = 0; + + zonefrom_url(uh, data, conn); + } + + /* make sure the connect struct gets its own copy of the host name */ + conn->host.rawalloc = strdup(hostname ? hostname : ""); + if(!conn->host.rawalloc) + return CURLE_OUT_OF_MEMORY; + conn->host.name = conn->host.rawalloc; + + /************************************************************* + * IDN-convert the hostnames + *************************************************************/ + result = Curl_idnconvert_hostname(data, &conn->host); + if(result) + return result; + if(conn->bits.conn_to_host) { + result = Curl_idnconvert_hostname(data, &conn->conn_to_host); + if(result) + return result; + } +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy) { + result = Curl_idnconvert_hostname(data, &conn->http_proxy.host); + if(result) + return result; + } + if(conn->bits.socksproxy) { + result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host); + if(result) + return result; + } +#endif #ifndef CURL_DISABLE_HSTS + /* HSTS upgrade */ if(data->hsts && strcasecompare("http", data->state.up.scheme)) { - if(Curl_hsts(data->hsts, data->state.up.hostname, TRUE)) { + /* This MUST use the IDN decoded name */ + if(Curl_hsts(data->hsts, conn->host.name, TRUE)) { char *url; Curl_safefree(data->state.up.scheme); uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0); @@ -2087,7 +2127,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, return Curl_uc_to_curlcode(uc); } - if(!data->state.aptr.user) { + if(!data->set.str[STRING_USERNAME]) { /* we don't use the URL API's URL decoder option here since it rejects control codes and we want to allow them for some schemes in the user and password fields */ @@ -2142,26 +2182,6 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0); - hostname = data->state.up.hostname; - if(hostname && hostname[0] == '[') { - /* This looks like an IPv6 address literal. See if there is an address - scope. */ - size_t hlen; - conn->bits.ipv6_ip = TRUE; - /* cut off the brackets! */ - hostname++; - hlen = strlen(hostname); - hostname[hlen - 1] = 0; - - zonefrom_url(uh, data, conn); - } - - /* make sure the connect struct gets its own copy of the host name */ - conn->host.rawalloc = strdup(hostname ? hostname : ""); - if(!conn->host.rawalloc) - return CURLE_OUT_OF_MEMORY; - conn->host.name = conn->host.rawalloc; - #ifdef ENABLE_IPV6 if(data->set.scope_id) /* Override any scope that was set above. */ @@ -2259,83 +2279,6 @@ void Curl_free_request_state(struct Curl_easy *data) #ifndef CURL_DISABLE_PROXY -/**************************************************************** -* Checks if the host is in the noproxy list. returns true if it matches -* and therefore the proxy should NOT be used. -****************************************************************/ -static bool check_noproxy(const char *name, const char *no_proxy) -{ - /* no_proxy=domain1.dom,host.domain2.dom - * (a comma-separated list of hosts which should - * not be proxied, or an asterisk to override - * all proxy variables) - */ - if(no_proxy && no_proxy[0]) { - size_t tok_start; - size_t tok_end; - const char *separator = ", "; - size_t no_proxy_len; - size_t namelen; - char *endptr; - if(strcasecompare("*", no_proxy)) { - return TRUE; - } - - /* NO_PROXY was specified and it wasn't just an asterisk */ - - no_proxy_len = strlen(no_proxy); - if(name[0] == '[') { - /* IPv6 numerical address */ - endptr = strchr(name, ']'); - if(!endptr) - return FALSE; - name++; - namelen = endptr - name; - } - else - namelen = strlen(name); - - for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) { - while(tok_start < no_proxy_len && - strchr(separator, no_proxy[tok_start]) != NULL) { - /* Look for the beginning of the token. */ - ++tok_start; - } - - if(tok_start == no_proxy_len) - break; /* It was all trailing separator chars, no more tokens. */ - - for(tok_end = tok_start; tok_end < no_proxy_len && - strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end) - /* Look for the end of the token. */ - ; - - /* To match previous behavior, where it was necessary to specify - * ".local.com" to prevent matching "notlocal.com", we will leave - * the '.' off. - */ - if(no_proxy[tok_start] == '.') - ++tok_start; - - if((tok_end - tok_start) <= namelen) { - /* Match the last part of the name to the domain we are checking. */ - const char *checkn = name + namelen - (tok_end - tok_start); - if(strncasecompare(no_proxy + tok_start, checkn, - tok_end - tok_start)) { - if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') { - /* We either have an exact match, or the previous character is a . - * so it is within the same domain, so no proxy for this host. - */ - return TRUE; - } - } - } /* if((tok_end - tok_start) <= namelen) */ - } /* for(tok_start = 0; tok_start < no_proxy_len; - tok_start = tok_end + 1) */ - } /* NO_PROXY was specified and it wasn't just an asterisk */ - - return FALSE; -} #ifndef CURL_DISABLE_HTTP /**************************************************************** @@ -2375,7 +2318,7 @@ static char *detect_proxy(struct Curl_easy *data, /* Now, build <protocol>_proxy and check for such a one to use */ while(*protop) - *envp++ = (char)tolower((int)*protop++); + *envp++ = Curl_raw_tolower(*protop++); /* append _proxy */ strcpy(envp, "_proxy"); @@ -2704,8 +2647,8 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data, } } - if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ? - data->set.str[STRING_NOPROXY] : no_proxy)) { + if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ? + data->set.str[STRING_NOPROXY] : no_proxy)) { Curl_safefree(proxy); Curl_safefree(socksproxy); } @@ -2902,15 +2845,15 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len, (psep && psep > osep ? (size_t)(psep - osep) : (size_t)(login + len - osep)) - 1 : 0); - /* Allocate the user portion buffer */ - if(userp && ulen) { + /* Allocate the user portion buffer, which can be zero length */ + if(userp) { ubuf = malloc(ulen + 1); if(!ubuf) result = CURLE_OUT_OF_MEMORY; } /* Allocate the password portion buffer */ - if(!result && passwdp && plen) { + if(!result && passwdp && psep) { pbuf = malloc(plen + 1); if(!pbuf) { free(ubuf); @@ -2995,14 +2938,6 @@ static CURLcode override_login(struct Curl_easy *data, char **passwdp = &conn->passwd; char **optionsp = &conn->options; -#ifndef CURL_DISABLE_NETRC - if(data->set.use_netrc == CURL_NETRC_REQUIRED && data->state.aptr.user) { - Curl_safefree(*userp); - Curl_safefree(*passwdp); - Curl_safefree(data->state.aptr.user); /* disable user+password */ - } -#endif - if(data->set.str[STRING_OPTIONS]) { free(*optionsp); *optionsp = strdup(data->set.str[STRING_OPTIONS]); @@ -3011,22 +2946,23 @@ static CURLcode override_login(struct Curl_easy *data, } #ifndef CURL_DISABLE_NETRC + if(data->set.use_netrc == CURL_NETRC_REQUIRED) { + Curl_safefree(*userp); + Curl_safefree(*passwdp); + } conn->bits.netrc = FALSE; if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) { - bool netrc_user_changed = FALSE; - bool netrc_passwd_changed = FALSE; int ret; bool url_provided = FALSE; - if(data->state.up.user) { - /* there was a user name in the URL */ - userp = &data->state.up.user; + if(data->state.aptr.user) { + /* there was a user name in the URL. Use the URL decoded version */ + userp = &data->state.aptr.user; url_provided = TRUE; } ret = Curl_parsenetrc(conn->host.name, userp, passwdp, - &netrc_user_changed, &netrc_passwd_changed, data->set.str[STRING_NETRC_FILE]); if(ret > 0) { infof(data, "Couldn't find host %s in the %s file; using defaults", @@ -3059,9 +2995,13 @@ static CURLcode override_login(struct Curl_easy *data, /* for updated strings, we update them in the URL */ if(*userp) { - CURLcode result = Curl_setstropt(&data->state.aptr.user, *userp); - if(result) - return result; + CURLcode result; + if(data->state.aptr.user != *userp) { + /* nothing to do then */ + result = Curl_setstropt(&data->state.aptr.user, *userp); + if(result) + return result; + } } if(data->state.aptr.user) { uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user, @@ -3493,9 +3433,9 @@ static CURLcode resolve_proxy(struct Curl_easy *data, } #endif -static CURLcode resolve_ip(struct Curl_easy *data, - struct connectdata *conn, - bool *async) +static CURLcode resolve_host(struct Curl_easy *data, + struct connectdata *conn, + bool *async) { struct Curl_dns_entry *hostaddr = NULL; struct hostname *connhost; @@ -3561,7 +3501,7 @@ static CURLcode resolve_fresh(struct Curl_easy *data, return resolve_proxy(data, conn, async); #endif - return resolve_ip(data, conn, async); + return resolve_host(data, conn, async); } /************************************************************* @@ -3790,29 +3730,6 @@ static CURLcode create_conn(struct Curl_easy *data, if(result) goto out; - /************************************************************* - * IDN-convert the hostnames - *************************************************************/ - result = Curl_idnconvert_hostname(data, &conn->host); - if(result) - goto out; - if(conn->bits.conn_to_host) { - result = Curl_idnconvert_hostname(data, &conn->conn_to_host); - if(result) - goto out; - } -#ifndef CURL_DISABLE_PROXY - if(conn->bits.httpproxy) { - result = Curl_idnconvert_hostname(data, &conn->http_proxy.host); - if(result) - goto out; - } - if(conn->bits.socksproxy) { - result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host); - if(result) - goto out; - } -#endif /************************************************************* * Check whether the host and the "connect to host" are equal. @@ -4025,13 +3942,11 @@ static CURLcode create_conn(struct Curl_easy *data, be able to do that if we have reached the limit of how many connections we are allowed to open. */ - if(conn->handler->flags & PROTOPT_ALPN_NPN) { + if(conn->handler->flags & PROTOPT_ALPN) { /* The protocol wants it, so set the bits if enabled in the easy handle (default) */ if(data->set.ssl_enable_alpn) conn->bits.tls_enable_alpn = TRUE; - if(data->set.ssl_enable_npn) - conn->bits.tls_enable_npn = TRUE; } if(waitpipe) diff --git a/contrib/libs/curl/lib/url.h b/contrib/libs/curl/lib/url.h index e3b2940305..ba4270d523 100644 --- a/contrib/libs/curl/lib/url.h +++ b/contrib/libs/curl/lib/url.h @@ -46,7 +46,8 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len, char **userptr, char **passwdptr, char **optionsptr); -const struct Curl_handler *Curl_builtin_scheme(const char *scheme); +const struct Curl_handler *Curl_builtin_scheme(const char *scheme, + size_t schemelen); bool Curl_is_ASCII_name(const char *hostname); CURLcode Curl_idnconvert_hostname(struct Curl_easy *data, diff --git a/contrib/libs/curl/lib/urlapi-int.h b/contrib/libs/curl/lib/urlapi-int.h index a03aa888af..43a83ef6e4 100644 --- a/contrib/libs/curl/lib/urlapi-int.h +++ b/contrib/libs/curl/lib/urlapi-int.h @@ -25,10 +25,12 @@ ***************************************************************************/ #include "curl_setup.h" -bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen); +size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen, + bool guess_scheme); #ifdef DEBUGBUILD -CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, bool); +CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, + bool has_scheme); #endif #endif /* HEADER_CURL_URLAPI_INT_H */ diff --git a/contrib/libs/curl/lib/urlapi.c b/contrib/libs/curl/lib/urlapi.c index dee4b5aa09..7dac81c85c 100644 --- a/contrib/libs/curl/lib/urlapi.c +++ b/contrib/libs/curl/lib/urlapi.c @@ -27,12 +27,12 @@ #include "urldata.h" #include "urlapi-int.h" #include "strcase.h" -#include "dotdot.h" #include "url.h" #include "escape.h" #include "curl_ctype.h" #include "inet_pton.h" #include "inet_ntop.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -68,9 +68,6 @@ struct Curl_URL { char *path; char *query; char *fragment; - - char *scratch; /* temporary scratch area */ - char *temppath; /* temporary path pointer */ long portnum; /* the numerical version */ }; @@ -88,8 +85,6 @@ static void free_urlhandle(struct Curl_URL *u) free(u->path); free(u->query); free(u->fragment); - free(u->scratch); - free(u->temppath); } /* @@ -121,95 +116,50 @@ static const char *find_host_sep(const char *url) } /* - * Decide in an encoding-independent manner whether a character in an - * URL must be escaped. The same criterion must be used in strlen_url() - * and strcpy_url(). + * Decide in an encoding-independent manner whether a character in a URL must + * be escaped. This is used in urlencode_str(). */ static bool urlchar_needs_escaping(int c) { return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c)); } -/* - * strlen_url() returns the length of the given URL if the spaces within the - * URL were properly URL encoded. - * URL encoding should be skipped for host names, otherwise IDN resolution - * will fail. - */ -static size_t strlen_url(const char *url, bool relative) -{ - const unsigned char *ptr; - size_t newlen = 0; - bool left = TRUE; /* left side of the ? */ - const unsigned char *host_sep = (const unsigned char *) url; - - if(!relative) - host_sep = (const unsigned char *) find_host_sep(url); - - for(ptr = (unsigned char *)url; *ptr; ptr++) { - - if(ptr < host_sep) { - ++newlen; - continue; - } - - if(*ptr == ' ') { - if(left) - newlen += 3; - else - newlen++; - continue; - } - - if (*ptr == '?') - left = FALSE; - - if(urlchar_needs_escaping(*ptr)) - newlen += 2; - - newlen++; - } - - return newlen; -} - -/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in - * the source URL accordingly. +/* urlencode_str() writes data into an output dynbuf and URL-encodes the + * spaces in the source URL accordingly. + * * URL encoding should be skipped for host names, otherwise IDN resolution * will fail. - * - * Returns TRUE if something was updated. */ -static bool strcpy_url(char *output, const char *url, bool relative) +static CURLUcode urlencode_str(struct dynbuf *o, const char *url, + size_t len, bool relative, + bool query) { /* we must add this with whitespace-replacing */ - bool left = TRUE; + bool left = !query; const unsigned char *iptr; - char *optr = output; const unsigned char *host_sep = (const unsigned char *) url; - bool changed = FALSE; if(!relative) host_sep = (const unsigned char *) find_host_sep(url); for(iptr = (unsigned char *)url; /* read from here */ - *iptr; /* until zero byte */ - iptr++) { + len; iptr++, len--) { if(iptr < host_sep) { - *optr++ = *iptr; + if(Curl_dyn_addn(o, iptr, 1)) + return CURLUE_OUT_OF_MEMORY; continue; } if(*iptr == ' ') { if(left) { - *optr++='%'; /* add a '%' */ - *optr++='2'; /* add a '2' */ - *optr++='0'; /* add a '0' */ + if(Curl_dyn_addn(o, "%20", 3)) + return CURLUE_OUT_OF_MEMORY; + } + else { + if(Curl_dyn_addn(o, "+", 1)) + return CURLUE_OUT_OF_MEMORY; } - else - *optr++='+'; /* add a '+' here */ - changed = TRUE; continue; } @@ -217,24 +167,28 @@ static bool strcpy_url(char *output, const char *url, bool relative) left = FALSE; if(urlchar_needs_escaping(*iptr)) { - msnprintf(optr, 4, "%%%02x", *iptr); - changed = TRUE; - optr += 3; + if(Curl_dyn_addf(o, "%%%02x", *iptr)) + return CURLUE_OUT_OF_MEMORY; + } + else { + if(Curl_dyn_addn(o, iptr, 1)) + return CURLUE_OUT_OF_MEMORY; } - else - *optr++ = *iptr; } - *optr = 0; /* null-terminate output buffer */ - return changed; + return CURLUE_OK; } /* - * Returns true if the given URL is absolute (as opposed to relative). Returns - * the scheme in the buffer if TRUE and 'buf' is non-NULL. The buflen must - * be larger than MAX_SCHEME_LEN if buf is set. + * Returns the length of the scheme if the given URL is absolute (as opposed + * to relative). Stores the scheme in the buffer if TRUE and 'buf' is + * non-NULL. The buflen must be larger than MAX_SCHEME_LEN if buf is set. + * + * If 'guess_scheme' is TRUE, it means the URL might be provided without + * scheme. */ -bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) +size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen, + bool guess_scheme) { int i; DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN)); @@ -242,8 +196,8 @@ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) if(buf) buf[0] = 0; /* always leave a defined value in buf */ #ifdef WIN32 - if(STARTS_WITH_DRIVE_PREFIX(url)) - return FALSE; + if(guess_scheme && STARTS_WITH_DRIVE_PREFIX(url)) + return 0; #endif for(i = 0; i < MAX_SCHEME_LEN; ++i) { char s = url[i]; @@ -256,16 +210,22 @@ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) break; } } - if(i && (url[i] == ':') && (url[i + 1] == '/')) { + if(i && (url[i] == ':') && ((url[i + 1] == '/') || !guess_scheme)) { + /* If this does not guess scheme, the scheme always ends with the colon so + that this also detects data: URLs etc. In guessing mode, data: could + be the host name "data" with a specified port number. */ + + /* the length of the scheme is the name part only */ + size_t len = i; if(buf) { buf[i] = 0; while(i--) { - buf[i] = (char)TOLOWER(url[i]); + buf[i] = Curl_raw_tolower(url[i]); } } - return TRUE; + return len; } - return FALSE; + return 0; } /* @@ -273,34 +233,26 @@ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) * URL-encodes any spaces. * The returned pointer must be freed by the caller unless NULL * (returns NULL on out of memory). + * + * Note that this function destroys the 'base' string. */ -static char *concat_url(const char *base, const char *relurl) +static char *concat_url(char *base, const char *relurl) { /*** TRY to append this new path to the old URL to the right of the host part. Oh crap, this is doomed to cause problems in the future... */ - char *newest; + struct dynbuf newest; char *protsep; char *pathsep; - size_t newlen; bool host_changed = FALSE; - const char *useurl = relurl; - size_t urllen; - - /* we must make our own copy of the URL to play with, as it may - point to read-only data */ - char *url_clone = strdup(base); - - if(!url_clone) - return NULL; /* skip out of this NOW */ /* protsep points to the start of the host name */ - protsep = strstr(url_clone, "//"); + protsep = strstr(base, "//"); if(!protsep) - protsep = url_clone; + protsep = base; else protsep += 2; /* pass the slashes */ @@ -393,38 +345,24 @@ static char *concat_url(const char *base, const char *relurl) } } - /* If the new part contains a space, this is a mighty stupid redirect - but we still make an effort to do "right". To the left of a '?' - letter we replace each space with %20 while it is replaced with '+' - on the right side of the '?' letter. - */ - newlen = strlen_url(useurl, !host_changed); - - urllen = strlen(url_clone); - - newest = malloc(urllen + 1 + /* possible slash */ - newlen + 1 /* zero byte */); - - if(!newest) { - free(url_clone); /* don't leak this */ - return NULL; - } + Curl_dyn_init(&newest, CURL_MAX_INPUT_LENGTH); /* copy over the root url part */ - memcpy(newest, url_clone, urllen); + if(Curl_dyn_add(&newest, base)) + return NULL; /* check if we need to append a slash */ if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0])) ; - else - newest[urllen++]='/'; + else { + if(Curl_dyn_addn(&newest, "/", 1)) + return NULL; + } /* then append the new piece on the right side */ - strcpy_url(&newest[urllen], useurl, !host_changed); + urlencode_str(&newest, useurl, strlen(useurl), !host_changed, FALSE); - free(url_clone); - - return newest; + return Curl_dyn_ptr(&newest); } /* scan for byte values < 31 or 127 */ @@ -458,7 +396,7 @@ static bool junkscan(const char *part, unsigned int flags) * */ static CURLUcode parse_hostname_login(struct Curl_URL *u, - char **hostname, + struct dynbuf *host, unsigned int flags) { CURLUcode result = CURLUE_OK; @@ -468,27 +406,31 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, char *optionsp = NULL; const struct Curl_handler *h = NULL; - /* At this point, we're hoping all the other special cases have - * been taken care of, so conn->host.name is at most - * [user[:password][;options]]@]hostname + /* At this point, we assume all the other special cases have been taken + * care of, so the host is at most + * + * [user[:password][;options]]@]hostname * * We need somewhere to put the embedded details, so do that first. */ - char *ptr = strchr(*hostname, '@'); - char *login = *hostname; + char *login = Curl_dyn_ptr(host); + char *ptr; + + DEBUGASSERT(login); + ptr = strchr(login, '@'); if(!ptr) goto out; /* We will now try to extract the * possible login information in a string like: * ftp://user:password@ftp.my.site:8021/README */ - *hostname = ++ptr; + ptr++; /* if this is a known scheme, get some details */ if(u->scheme) - h = Curl_builtin_scheme(u->scheme); + h = Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED); /* We could use the login information in the URL so extract it. Only parse options if the handler says we should. Note that 'h' might be NULL! */ @@ -530,6 +472,10 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, u->options = optionsp; } + /* move the name to the start of the host buffer */ + if(Curl_dyn_tail(host, strlen(ptr))) + return CURLUE_OUT_OF_MEMORY; + return CURLUE_OK; out: @@ -543,13 +489,13 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, return result; } -UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, +UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, bool has_scheme) { char *portptr = NULL; char endbracket; int len; - + char *hostname = Curl_dyn_ptr(host); /* * Find the end of an IPv6 address, either on the ']' ending bracket or * a percent-encoded zone index. @@ -586,6 +532,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, char *rest; long port; char portbuf[7]; + size_t keep = portptr - hostname; /* Browser behavior adaptation. If there's a colon with no digits after, just cut off the name there which makes us ignore the colon and just @@ -594,15 +541,15 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, Don't do it if the URL has no scheme, to make something that looks like a scheme not work! */ - if(!portptr[1]) { - *portptr = '\0'; + Curl_dyn_setlen(host, keep); + portptr++; + if(!*portptr) return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER; - } - if(!ISDIGIT(portptr[1])) + if(!ISDIGIT(*portptr)) return CURLUE_BAD_PORT_NUMBER; - port = strtol(portptr + 1, &rest, 10); /* Port number must be decimal */ + port = strtol(portptr, &rest, 10); /* Port number must be decimal */ if(port > 0xffff) return CURLUE_BAD_PORT_NUMBER; @@ -610,7 +557,6 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, if(rest[0]) return CURLUE_BAD_PORT_NUMBER; - *portptr++ = '\0'; /* cut off the name there */ *rest = 0; /* generate a new port number string to get rid of leading zeroes etc */ msnprintf(portbuf, sizeof(portbuf), "%ld", port); @@ -623,12 +569,15 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, return CURLUE_OK; } -static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) +static CURLUcode hostname_check(struct Curl_URL *u, char *hostname, + size_t hlen) /* length of hostname */ { size_t len; - size_t hlen = strlen(hostname); + DEBUGASSERT(hostname); - if(hostname[0] == '[') { + if(!hostname[0]) + return CURLUE_NO_HOST; + else if(hostname[0] == '[') { const char *l = "0123456789abcdefABCDEF:."; if(hlen < 4) /* '[::]' is the shortest possible valid string */ return CURLUE_BAD_IPV6; @@ -687,13 +636,11 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) } else { /* letters from the second string are not ok */ - len = strcspn(hostname, " \r\n\t/:#?!@"); + len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,"); if(hlen != len) /* hostname with bad content */ return CURLUE_BAD_HOSTNAME; } - if(!hostname[0]) - return CURLUE_NO_HOST; return CURLUE_OK; } @@ -787,79 +734,230 @@ static bool ipv4_normalize(const char *hostname, char *outp, size_t olen) return TRUE; } -/* return strdup'ed version in 'outp', possibly percent decoded */ -static CURLUcode decode_host(char *hostname, char **outp) +/* if necessary, replace the host content with a URL decoded version */ +static CURLUcode decode_host(struct dynbuf *host) { char *per = NULL; - if(hostname[0] != '[') + const char *hostname = Curl_dyn_ptr(host); + if(hostname[0] == '[') /* only decode if not an ipv6 numerical */ - per = strchr(hostname, '%'); - if(!per) { - *outp = strdup(hostname); - if(!*outp) - return CURLUE_OUT_OF_MEMORY; - } + return CURLUE_OK; + per = strchr(hostname, '%'); + if(!per) + /* nothing to decode */ + return CURLUE_OK; else { - /* might be encoded */ + /* encoded */ size_t dlen; - CURLcode result = Curl_urldecode(hostname, 0, outp, &dlen, REJECT_CTRL); + char *decoded; + CURLcode result = Curl_urldecode(hostname, 0, &decoded, &dlen, + REJECT_CTRL); if(result) return CURLUE_BAD_HOSTNAME; + Curl_dyn_reset(host); + result = Curl_dyn_addn(host, decoded, dlen); + free(decoded); + if(result) + return CURLUE_OUT_OF_MEMORY; } return CURLUE_OK; } -static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) +/* + * "Remove Dot Segments" + * https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 + */ + +/* + * dedotdotify() + * @unittest: 1395 + * + * This function gets a null-terminated path with dot and dotdot sequences + * passed in and strips them off according to the rules in RFC 3986 section + * 5.2.4. + * + * The function handles a query part ('?' + stuff) appended but it expects + * that fragments ('#' + stuff) have already been cut off. + * + * RETURNS + * + * an allocated dedotdotified output string + */ +UNITTEST char *dedotdotify(const char *input, size_t clen); +UNITTEST char *dedotdotify(const char *input, size_t clen) { - char *path; - bool path_alloced = FALSE; + char *out = malloc(clen + 1); + char *outptr; + const char *orginput = input; + char *queryp; + if(!out) + return NULL; /* out of memory */ + + *out = 0; /* null-terminates, for inputs like "./" */ + outptr = out; + + if(!*input) + /* zero length input string, return that */ + return out; + + /* + * To handle query-parts properly, we must find it and remove it during the + * dotdot-operation and then append it again at the end to the output + * string. + */ + queryp = strchr(input, '?'); + + do { + bool dotdot = TRUE; + if(*input == '.') { + /* A. If the input buffer begins with a prefix of "../" or "./", then + remove that prefix from the input buffer; otherwise, */ + + if(!strncmp("./", input, 2)) { + input += 2; + clen -= 2; + } + else if(!strncmp("../", input, 3)) { + input += 3; + clen -= 3; + } + /* D. if the input buffer consists only of "." or "..", then remove + that from the input buffer; otherwise, */ + + else if(!strcmp(".", input) || !strcmp("..", input) || + !strncmp(".?", input, 2) || !strncmp("..?", input, 3)) { + *out = 0; + break; + } + else + dotdot = FALSE; + } + else if(*input == '/') { + /* B. if the input buffer begins with a prefix of "/./" or "/.", where + "." is a complete path segment, then replace that prefix with "/" in + the input buffer; otherwise, */ + if(!strncmp("/./", input, 3)) { + input += 2; + clen -= 2; + } + else if(!strcmp("/.", input) || !strncmp("/.?", input, 3)) { + *outptr++ = '/'; + *outptr = 0; + break; + } + + /* C. if the input buffer begins with a prefix of "/../" or "/..", + where ".." is a complete path segment, then replace that prefix with + "/" in the input buffer and remove the last segment and its + preceding "/" (if any) from the output buffer; otherwise, */ + + else if(!strncmp("/../", input, 4)) { + input += 3; + clen -= 3; + /* remove the last segment from the output buffer */ + while(outptr > out) { + outptr--; + if(*outptr == '/') + break; + } + *outptr = 0; /* null-terminate where it stops */ + } + else if(!strcmp("/..", input) || !strncmp("/..?", input, 4)) { + /* remove the last segment from the output buffer */ + while(outptr > out) { + outptr--; + if(*outptr == '/') + break; + } + *outptr++ = '/'; + *outptr = 0; /* null-terminate where it stops */ + break; + } + else + dotdot = FALSE; + } + else + dotdot = FALSE; + + if(!dotdot) { + /* E. move the first path segment in the input buffer to the end of + the output buffer, including the initial "/" character (if any) and + any subsequent characters up to, but not including, the next "/" + character or the end of the input buffer. */ + + do { + *outptr++ = *input++; + clen--; + } while(*input && (*input != '/') && (*input != '?')); + *outptr = 0; + } + + /* continue until end of input string OR, if there is a terminating + query part, stop there */ + } while(*input && (!queryp || (input < queryp))); + + if(queryp) { + size_t qlen; + /* There was a query part, append that to the output. */ + size_t oindex = queryp - orginput; + qlen = strlen(&orginput[oindex]); + memcpy(outptr, &orginput[oindex], qlen + 1); /* include zero byte */ + } + + return out; +} + +static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) +{ + const char *path; + size_t pathlen; bool uncpath = FALSE; - char *hostname; char *query = NULL; char *fragment = NULL; - CURLUcode result; - bool url_has_scheme = FALSE; char schemebuf[MAX_SCHEME_LEN + 1]; const char *schemep = NULL; size_t schemelen = 0; size_t urllen; + CURLUcode result = CURLUE_OK; + size_t fraglen = 0; + struct dynbuf host; DEBUGASSERT(url); + Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH); + /************************************************************* * Parse the URL. ************************************************************/ /* allocate scratch area */ urllen = strlen(url); - if(urllen > CURL_MAX_INPUT_LENGTH) + if(urllen > CURL_MAX_INPUT_LENGTH) { /* excessive input length */ - return CURLUE_MALFORMED_INPUT; - - path = u->scratch = malloc(urllen * 2 + 2); - if(!path) - return CURLUE_OUT_OF_MEMORY; - - hostname = &path[urllen + 1]; - hostname[0] = 0; - - if(Curl_is_absolute_url(url, schemebuf, sizeof(schemebuf))) { - url_has_scheme = TRUE; - schemelen = strlen(schemebuf); + result = CURLUE_MALFORMED_INPUT; + goto fail; } + schemelen = Curl_is_absolute_url(url, schemebuf, sizeof(schemebuf), + flags & (CURLU_GUESS_SCHEME| + CURLU_DEFAULT_SCHEME)); + /* handle the file: scheme */ - if(url_has_scheme && !strcmp(schemebuf, "file")) { - if(urllen <= 6) + if(schemelen && !strcmp(schemebuf, "file")) { + if(urllen <= 6) { /* file:/ is not enough to actually be a complete file: URL */ - return CURLUE_BAD_FILE_URL; + result = CURLUE_BAD_FILE_URL; + goto fail; + } /* path has been allocated large enough to hold this */ - strcpy(path, &url[5]); + path = (char *)&url[5]; - u->scheme = strdup("file"); - if(!u->scheme) - return CURLUE_OUT_OF_MEMORY; + schemep = u->scheme = strdup("file"); + if(!u->scheme) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } /* Extra handling URLs with an authority component (i.e. that start with * "file://") @@ -869,7 +967,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) */ if(path[0] == '/' && path[1] == '/') { /* swallow the two slashes */ - char *ptr = &path[2]; + const char *ptr = &path[2]; /* * According to RFC 8089, a file: URL can be reliably dereferenced if: @@ -905,13 +1003,17 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) chars, and the delimiting slash character must be appended to the host name */ path = strpbrk(ptr, "/\\:*?\"<>|"); - if(!path || *path != '/') - return CURLUE_BAD_FILE_URL; + if(!path || *path != '/') { + result = CURLUE_BAD_FILE_URL; + goto fail; + } len = path - ptr; if(len) { - memcpy(hostname, ptr, len); - hostname[len] = 0; + if(Curl_dyn_addn(&host, ptr, len)) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } uncpath = TRUE; } @@ -919,7 +1021,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) #else /* Invalid file://hostname/, expected localhost or 127.0.0.1 or none */ - return CURLUE_BAD_FILE_URL; + result = CURLUE_BAD_FILE_URL; + goto fail; #endif } } @@ -928,7 +1031,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } if(!uncpath) - hostname = NULL; /* no host for file: URLs by default */ + /* no host for file: URLs by default */ + Curl_dyn_reset(&host); #if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__) /* Don't allow Windows drive letters when not in Windows. @@ -936,13 +1040,14 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) || STARTS_WITH_URL_DRIVE_PREFIX(path)) { /* File drive letters are only accepted in MSDOS/Windows */ - return CURLUE_BAD_FILE_URL; + result = CURLUE_BAD_FILE_URL; + goto fail; } #else /* If the path starts with a slash and a drive letter, ditch the slash */ if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) { /* This cannot be done with strcpy, as the memory chunks overlap! */ - memmove(path, &path[1], strlen(&path[1]) + 1); + path++; } #endif @@ -952,32 +1057,39 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) const char *p; const char *hostp; size_t len; - path[0] = 0; - if(url_has_scheme) { + if(schemelen) { int i = 0; p = &url[schemelen + 1]; while(p && (*p == '/') && (i < 4)) { p++; i++; } - if((i < 1) || (i>3)) - /* less than one or more than three slashes */ - return CURLUE_BAD_SLASHES; schemep = schemebuf; - if(!Curl_builtin_scheme(schemep) && - !(flags & CURLU_NON_SUPPORT_SCHEME)) - return CURLUE_UNSUPPORTED_SCHEME; + if(!Curl_builtin_scheme(schemep, CURL_ZERO_TERMINATED) && + !(flags & CURLU_NON_SUPPORT_SCHEME)) { + result = CURLUE_UNSUPPORTED_SCHEME; + goto fail; + } - if(junkscan(schemep, flags)) - return CURLUE_BAD_SCHEME; + if((i < 1) || (i>3)) { + /* less than one or more than three slashes */ + result = CURLUE_BAD_SLASHES; + goto fail; + } + if(junkscan(schemep, flags)) { + result = CURLUE_BAD_SCHEME; + goto fail; + } } else { /* no scheme! */ - if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) - return CURLUE_BAD_SCHEME; + if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) { + result = CURLUE_BAD_SCHEME; + goto fail; + } if(flags & CURLU_DEFAULT_SCHEME) schemep = DEFAULT_SCHEME; @@ -994,122 +1106,169 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) len = p - hostp; if(len) { - memcpy(hostname, hostp, len); - hostname[len] = 0; + if(Curl_dyn_addn(&host, hostp, len)) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } } else { - if(!(flags & CURLU_NO_AUTHORITY)) - return CURLUE_NO_HOST; + if(!(flags & CURLU_NO_AUTHORITY)) { + result = CURLUE_NO_HOST; + goto fail; + } } - strcpy(path, p); + path = (char *)p; if(schemep) { u->scheme = strdup(schemep); - if(!u->scheme) - return CURLUE_OUT_OF_MEMORY; + if(!u->scheme) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } } } - if((flags & CURLU_URLENCODE) && path[0]) { - /* worst case output length is 3x the original! */ - char *newp = malloc(strlen(path) * 3); - if(!newp) - return CURLUE_OUT_OF_MEMORY; - path_alloced = TRUE; - strcpy_url(newp, path, TRUE); /* consider it relative */ - u->temppath = path = newp; - } - fragment = strchr(path, '#'); if(fragment) { - *fragment++ = 0; - if(junkscan(fragment, flags)) - return CURLUE_BAD_FRAGMENT; - if(fragment[0]) { - u->fragment = strdup(fragment); - if(!u->fragment) - return CURLUE_OUT_OF_MEMORY; + fraglen = strlen(fragment); + if(fraglen > 1) { + /* skip the leading '#' in the copy but include the terminating null */ + u->fragment = Curl_memdup(fragment + 1, fraglen); + if(!u->fragment) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + + if(junkscan(u->fragment, flags)) { + result = CURLUE_BAD_FRAGMENT; + goto fail; + } } } query = strchr(path, '?'); - if(query) { - *query++ = 0; - if(junkscan(query, flags)) - return CURLUE_BAD_QUERY; - /* done even if the query part is a blank string */ - u->query = strdup(query); - if(!u->query) - return CURLUE_OUT_OF_MEMORY; - } + if(query && (!fragment || (query < fragment))) { + size_t qlen = strlen(query) - fraglen; /* includes '?' */ + pathlen = strlen(path) - qlen - fraglen; + if(qlen > 1) { + if(qlen && (flags & CURLU_URLENCODE)) { + 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; + goto fail; + } + u->query = Curl_dyn_ptr(&enc); + } + else { + u->query = Curl_memdup(query + 1, qlen); + if(!u->query) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + u->query[qlen - 1] = 0; + } - if(junkscan(path, flags)) - return CURLUE_BAD_PATH; + if(junkscan(u->query, flags)) { + result = CURLUE_BAD_QUERY; + goto fail; + } + } + else { + /* single byte query */ + u->query = strdup(""); + if(!u->query) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + } + } + else + pathlen = strlen(path) - fraglen; + + 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; + goto fail; + } + pathlen = Curl_dyn_len(&enc); + path = u->path = Curl_dyn_ptr(&enc); + } - if(!path[0]) - /* if there's no path left set, unset */ + if(!pathlen) { + /* there is no path left, unset */ path = NULL; + } else { + if(!u->path) { + u->path = Curl_memdup(path, pathlen + 1); + if(!u->path) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + u->path[pathlen] = 0; + path = u->path; + } + else if(flags & CURLU_URLENCODE) + /* it might have encoded more than just the path so cut it */ + u->path[pathlen] = 0; + + if(junkscan(u->path, flags)) { + result = CURLUE_BAD_PATH; + goto fail; + } + if(!(flags & CURLU_PATH_AS_IS)) { /* remove ../ and ./ sequences according to RFC3986 */ - char *newp = Curl_dedotdotify(path); - if(!newp) - return CURLUE_OUT_OF_MEMORY; - - if(strcmp(newp, path)) { - /* if we got a new version */ - if(path_alloced) - Curl_safefree(u->temppath); - u->temppath = path = newp; - path_alloced = TRUE; + char *newp = dedotdotify((char *)path, pathlen); + if(!newp) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; } - else - free(newp); + free(u->path); + u->path = newp; } - - u->path = path_alloced?path:strdup(path); - if(!u->path) - return CURLUE_OUT_OF_MEMORY; - u->temppath = NULL; /* used now */ } - if(hostname) { + if(Curl_dyn_len(&host)) { char normalized_ipv4[sizeof("255.255.255.255") + 1]; /* * Parse the login details and strip them out of the host name. */ - result = parse_hostname_login(u, &hostname, flags); - if(result) - return result; - - result = Curl_parse_port(u, hostname, url_has_scheme); + result = parse_hostname_login(u, &host, flags); + if(!result) + result = Curl_parse_port(u, &host, schemelen); if(result) - return result; + goto fail; - if(junkscan(hostname, flags)) - return CURLUE_BAD_HOSTNAME; + if(junkscan(Curl_dyn_ptr(&host), flags)) { + result = CURLUE_BAD_HOSTNAME; + goto fail; + } - if(0 == strlen(hostname) && (flags & CURLU_NO_AUTHORITY)) { - /* Skip hostname check, it's allowed to be empty. */ - u->host = strdup(""); + if(ipv4_normalize(Curl_dyn_ptr(&host), + normalized_ipv4, sizeof(normalized_ipv4))) { + Curl_dyn_reset(&host); + if(Curl_dyn_add(&host, normalized_ipv4)) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } } else { - if(ipv4_normalize(hostname, normalized_ipv4, sizeof(normalized_ipv4))) - u->host = strdup(normalized_ipv4); - else { - result = decode_host(hostname, &u->host); - if(result) - return result; - result = hostname_check(u, u->host); - if(result) - return result; - } + result = decode_host(&host); + if(!result) + result = hostname_check(u, Curl_dyn_ptr(&host), Curl_dyn_len(&host)); + if(result) + goto fail; } - if(!u->host) - return CURLUE_OUT_OF_MEMORY; + if((flags & CURLU_GUESS_SCHEME) && !schemep) { + const char *hostname = Curl_dyn_ptr(&host); /* legacy curl-style guess based on host name */ if(checkprefix("ftp.", hostname)) schemep = "ftp"; @@ -1127,27 +1286,26 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) schemep = "http"; u->scheme = strdup(schemep); - if(!u->scheme) - return CURLUE_OUT_OF_MEMORY; + if(!u->scheme) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + } + } + else if(flags & CURLU_NO_AUTHORITY) { + /* allowed to be empty. */ + if(Curl_dyn_add(&host, "")) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; } } - Curl_safefree(u->scratch); - Curl_safefree(u->temppath); - - return CURLUE_OK; -} + u->host = Curl_dyn_ptr(&host); -/* - * Parse the URL and set the relevant members of the Curl_URL struct. - */ -static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) -{ - CURLUcode result = seturl(url, u, flags); - if(result) { - free_urlhandle(u); - memset(u, 0, sizeof(struct Curl_URL)); - } + return result; + fail: + Curl_dyn_free(&host); + free_urlhandle(u); return result; } @@ -1165,8 +1323,6 @@ static CURLUcode parseurl_and_replace(const char *url, CURLU *u, free_urlhandle(u); *u = tmpurl; } - else - free_urlhandle(&tmpurl); return result; } @@ -1265,7 +1421,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, /* there's no stored port number, but asked to deliver a default one for the scheme */ const struct Curl_handler *h = - Curl_builtin_scheme(u->scheme); + Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED); if(h) { msnprintf(portbuf, sizeof(portbuf), "%u", h->defport); ptr = portbuf; @@ -1275,7 +1431,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, /* there is a stored port number, but ask to inhibit if it matches the default one for the scheme */ const struct Curl_handler *h = - Curl_builtin_scheme(u->scheme); + Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED); if(h && (h->defport == u->portnum) && (flags & CURLU_NO_DEFAULT_PORT)) ptr = NULL; @@ -1321,7 +1477,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, else return CURLUE_NO_SCHEME; - h = Curl_builtin_scheme(scheme); + h = Curl_builtin_scheme(scheme, CURL_ZERO_TERMINATED); if(!port && (flags & CURLU_DEFAULT_PORT)) { /* there's no stored port number, but asked to deliver a default one for the scheme */ @@ -1344,14 +1500,13 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, if(u->host[0] == '[') { if(u->zoneid) { /* make it '[ host %25 zoneid ]' */ + struct dynbuf enc; size_t hostlen = strlen(u->host); - size_t alen = hostlen + 3 + strlen(u->zoneid) + 1; - allochost = malloc(alen); - if(!allochost) + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + if(Curl_dyn_addf(&enc, "%.*s%%25%s]", (int)hostlen - 1, u->host, + u->zoneid)) return CURLUE_OUT_OF_MEMORY; - memcpy(allochost, u->host, hostlen - 1); - msnprintf(&allochost[hostlen - 1], alen - hostlen + 1, - "%%25%s]", u->zoneid); + allochost = Curl_dyn_ptr(&enc); } } else if(urlencode) { @@ -1362,32 +1517,32 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, else { /* only encode '%' in output host name */ char *host = u->host; - size_t pcount = 0; + bool percent = FALSE; /* first, count number of percents present in the name */ while(*host) { - if(*host == '%') - pcount++; + if(*host == '%') { + percent = TRUE; + break; + } host++; } - /* if there were percents, encode the host name */ - if(pcount) { - size_t hostlen = strlen(u->host); - size_t alen = hostlen + 2 * pcount + 1; - char *o = allochost = malloc(alen); - if(!allochost) - return CURLUE_OUT_OF_MEMORY; - + /* if there were percent(s), encode the host name */ + if(percent) { + struct dynbuf enc; + CURLcode result; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); host = u->host; while(*host) { - if(*host == '%') { - memcpy(o, "%25", 3); - o += 3; - host++; - continue; - } - *o++ = *host++; + if(*host == '%') + result = Curl_dyn_addn(&enc, "%25", 3); + else + result = Curl_dyn_addn(&enc, host, 1); + if(result) + return CURLUE_OUT_OF_MEMORY; + host++; } - *o = '\0'; + free(u->host); + u->host = Curl_dyn_ptr(&enc); } } @@ -1420,13 +1575,15 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, break; } if(ptr) { - *part = strdup(ptr); + size_t partlen = strlen(ptr); + size_t i = 0; + *part = Curl_memdup(ptr, partlen + 1); if(!*part) return CURLUE_OUT_OF_MEMORY; if(plusdecode) { /* convert + to space */ - char *plus; - for(plus = *part; *plus; ++plus) { + char *plus = *part; + for(i = 0; i < partlen; ++plus, i++) { if(*plus == '+') *plus = ' '; } @@ -1443,18 +1600,16 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, return CURLUE_URLDECODE; } *part = decoded; + partlen = dlen; } if(urlencode) { - /* worst case output length is 3x the original! */ - char *newp = malloc(strlen(*part) * 3); - if(!newp) + struct dynbuf enc; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + if(urlencode_str(&enc, *part, partlen, TRUE, + what == CURLUPART_QUERY)) return CURLUE_OUT_OF_MEMORY; - if(strcpy_url(newp, *part, TRUE)) { /* consider it relative */ - free(*part); - *part = newp; - } - else - free(newp); + free(*part); + *part = Curl_dyn_ptr(&enc); } return CURLUE_OK; @@ -1532,7 +1687,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, return CURLUE_BAD_SCHEME; if(!(flags & CURLU_NON_SUPPORT_SCHEME) && /* verify that it is a fine scheme */ - !Curl_builtin_scheme(part)) + !Curl_builtin_scheme(part, CURL_ZERO_TERMINATED)) return CURLUE_UNSUPPORTED_SCHEME; storep = &u->scheme; urlencode = FALSE; /* never */ @@ -1598,7 +1753,9 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, /* if the new thing is absolute or the old one is not * (we could not get an absolute url in 'oldurl'), * then replace the existing with the new. */ - if(Curl_is_absolute_url(part, NULL, 0) + if(Curl_is_absolute_url(part, NULL, 0, + flags & (CURLU_GUESS_SCHEME| + CURLU_DEFAULT_SCHEME)) || curl_url_get(u, CURLUPART_URL, &oldurl, flags)) { return parseurl_and_replace(part, u, flags); } @@ -1628,14 +1785,16 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, if(urlencode) { const unsigned char *i; - char *o; - char *enc = malloc(nalloc * 3 + 1); /* for worst case! */ - if(!enc) - return CURLUE_OUT_OF_MEMORY; - for(i = (const unsigned char *)part, o = enc; *i; i++) { + struct dynbuf enc; + + Curl_dyn_init(&enc, nalloc * 3 + 1); + + for(i = (const unsigned char *)part; *i; i++) { + CURLcode result; if((*i == ' ') && plusencode) { - *o = '+'; - o++; + result = Curl_dyn_addn(&enc, "+", 1); + if(result) + return CURLUE_OUT_OF_MEMORY; } else if(Curl_isunreserved(*i) || ((*i == '/') && urlskipslash) || @@ -1643,16 +1802,17 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, if((*i == '=') && equalsencode) /* only skip the first equals sign */ equalsencode = FALSE; - *o = *i; - o++; + result = Curl_dyn_addn(&enc, i, 1); + if(result) + return CURLUE_OUT_OF_MEMORY; } else { - msnprintf(o, 4, "%%%02x", *i); - o += 3; + result = Curl_dyn_addf(&enc, "%%%02x", *i); + if(result) + return CURLUE_OUT_OF_MEMORY; } } - *o = 0; /* null-terminate */ - newp = enc; + newp = Curl_dyn_ptr(&enc); } else { char *p; @@ -1664,8 +1824,8 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, /* make sure percent encoded are lower case */ if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) && (ISUPPER(p[1]) || ISUPPER(p[2]))) { - p[1] = (char)TOLOWER(p[1]); - p[2] = (char)TOLOWER(p[2]); + p[1] = Curl_raw_tolower(p[1]); + p[2] = Curl_raw_tolower(p[2]); p += 3; } else @@ -1674,34 +1834,41 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, } if(appendquery) { - /* Append the string onto the old query. Add a '&' separator if none is - present at the end of the exsting query already */ + /* Append the 'newp' string onto the old query. Add a '&' separator if + none is present at the end of the existing query already */ + size_t querylen = u->query ? strlen(u->query) : 0; bool addamperand = querylen && (u->query[querylen -1] != '&'); if(querylen) { - size_t newplen = strlen(newp); - char *p = malloc(querylen + addamperand + newplen + 1); - if(!p) { - free((char *)newp); - return CURLUE_OUT_OF_MEMORY; + struct dynbuf enc; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + + if(Curl_dyn_addn(&enc, u->query, querylen)) /* add original query */ + goto nomem; + + if(addamperand) { + if(Curl_dyn_addn(&enc, "&", 1)) + goto nomem; } - strcpy(p, u->query); /* original query */ - if(addamperand) - p[querylen] = '&'; /* ampersand */ - strcpy(&p[querylen + addamperand], newp); /* new suffix */ + if(Curl_dyn_add(&enc, newp)) + goto nomem; free((char *)newp); free(*storep); - *storep = p; + *storep = Curl_dyn_ptr(&enc); return CURLUE_OK; + nomem: + free((char *)newp); + return CURLUE_OUT_OF_MEMORY; } } if(what == CURLUPART_HOST) { - if(0 == strlen(newp) && (flags & CURLU_NO_AUTHORITY)) { + size_t n = strlen(newp); + if(!n && (flags & CURLU_NO_AUTHORITY)) { /* Skip hostname check, it's allowed to be empty. */ } else { - if(hostname_check(u, (char *)newp)) { + if(hostname_check(u, (char *)newp, n)) { free((char *)newp); return CURLUE_BAD_HOSTNAME; } diff --git a/contrib/libs/curl/lib/urldata.h b/contrib/libs/curl/lib/urldata.h index a9aee8f303..323a53a0d0 100644 --- a/contrib/libs/curl/lib/urldata.h +++ b/contrib/libs/curl/lib/urldata.h @@ -53,6 +53,33 @@ #define PORT_GOPHER 70 #define PORT_MQTT 1883 +#ifdef USE_WEBSOCKETS +/* CURLPROTO_GOPHERS (29) is the highest publicly used protocol bit number, + * the rest are internal information. If we use higher bits we only do this on + * platforms that have a >= 64 bit type and then we use such a type for the + * protocol fields in the protocol handler. + */ +#define CURLPROTO_WS (1<<30) +#define CURLPROTO_WSS ((curl_prot_t)1<<31) +#else +#define CURLPROTO_WS 0 +#define CURLPROTO_WSS 0 +#endif + +/* This should be undefined once we need bit 32 or higher */ +#define PROTO_TYPE_SMALL + +#ifndef PROTO_TYPE_SMALL +typedef curl_off_t curl_prot_t; +#else +typedef unsigned int curl_prot_t; +#endif + +/* This mask is for all the old protocols that are provided and defined in the + public header and shall exclude protocols added since which are not exposed + in the API */ +#define CURLPROTO_MASK (0x3ffffff) + #define DICT_MATCH "/MATCH:" #define DICT_MATCH2 "/M:" #define DICT_MATCH3 "/FIND:" @@ -66,7 +93,8 @@ /* Convenience defines for checking protocols or their SSL based version. Each protocol handler should only ever have a single CURLPROTO_ in its protocol field. */ -#define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS) +#define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_WS| \ + CURLPROTO_WSS) #define PROTO_FAMILY_FTP (CURLPROTO_FTP|CURLPROTO_FTPS) #define PROTO_FAMILY_POP3 (CURLPROTO_POP3|CURLPROTO_POP3S) #define PROTO_FAMILY_SMB (CURLPROTO_SMB|CURLPROTO_SMBS) @@ -157,10 +185,10 @@ typedef CURLcode (*Curl_datastream)(struct Curl_easy *data, # endif #endif -#ifdef HAVE_LIBSSH2_H +#ifdef USE_LIBSSH2 #error #include <libssh2.h> #error #include <libssh2_sftp.h> -#endif /* HAVE_LIBSSH2_H */ +#endif /* USE_LIBSSH2 */ #define READBUFFER_SIZE CURL_MAX_WRITE_SIZE #define READBUFFER_MAX CURL_MAX_READ_SIZE @@ -507,9 +535,7 @@ struct ConnectBits { connection */ BIT(multiplex); /* connection is multiplexed */ BIT(tcp_fastopen); /* use TCP Fast Open */ - BIT(tls_enable_npn); /* TLS NPN extension? */ BIT(tls_enable_alpn); /* TLS ALPN extension? */ - BIT(connect_only); #ifndef CURL_DISABLE_DOH BIT(doh); #endif @@ -554,7 +580,7 @@ struct Curl_async { struct Curl_dns_entry *dns; struct thread_data *tdata; void *resolver; /* resolver state, if it is used in the URL state - - ares_channel f.e. */ + ares_channel e.g. */ int port; int status; /* if done is TRUE, this is the status from the callback */ BIT(done); /* set TRUE when the lookup is complete */ @@ -575,8 +601,9 @@ enum expect100 { enum upgrade101 { UPGR101_INIT, /* default state */ - UPGR101_REQUESTED, /* upgrade requested */ - UPGR101_RECEIVED, /* response received */ + UPGR101_WS, /* upgrade to WebSockets requested */ + UPGR101_H2, /* upgrade to HTTP/2 requested */ + UPGR101_RECEIVED, /* 101 response received */ UPGR101_WORKING /* talking upgraded protocol */ }; @@ -779,10 +806,10 @@ struct Curl_handler { void (*attach)(struct Curl_easy *data, struct connectdata *conn); int defport; /* Default port. */ - unsigned int protocol; /* See CURLPROTO_* - this needs to be the single - specific protocol bit */ - unsigned int family; /* single bit for protocol family; basically the - non-TLS name of the protocol this is */ + curl_prot_t protocol; /* See CURLPROTO_* - this needs to be the single + specific protocol bit */ + curl_prot_t family; /* single bit for protocol family; basically the + non-TLS name of the protocol this is */ unsigned int flags; /* Extra particular characteristics, see PROTOPT_* */ }; @@ -803,7 +830,7 @@ struct Curl_handler { url query strings (?foo=bar) ! */ #define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per request instead of per connection */ -#define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */ +#define PROTOPT_ALPN (1<<8) /* set ALPN for this */ #define PROTOPT_STREAM (1<<9) /* a protocol with individual logical streams */ #define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field of the URL */ @@ -1118,11 +1145,12 @@ struct connectdata { unsigned short localport; unsigned short secondary_port; /* secondary socket remote port to connect to (ftp) */ - unsigned char negnpn; /* APLN or NPN TLS negotiated protocol, - a CURL_HTTP_VERSION* value */ + unsigned char alpn; /* APLN TLS negotiated protocol, a CURL_HTTP_VERSION* + value */ unsigned char transport; /* one of the TRNSPRT_* defines */ unsigned char ip_version; /* copied from the Curl_easy at creation time */ unsigned char httpversion; /* the HTTP version*10 reported by the server */ + unsigned char connect_only; }; /* The end of connectdata. */ @@ -1336,7 +1364,7 @@ struct UrlState { This is strdup()ed data. */ char *first_host; int first_remote_port; - unsigned int first_remote_protocol; + curl_prot_t first_remote_protocol; int retrycount; /* number of retries on a new connection */ struct Curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ @@ -1767,8 +1795,8 @@ struct UserDefined { #ifdef ENABLE_IPV6 unsigned int scope_id; /* Scope id for IPv6 */ #endif - curl_off_t allowed_protocols; - curl_off_t redir_protocols; + curl_prot_t allowed_protocols; + curl_prot_t redir_protocols; unsigned int mime_options; /* Mime option flags. */ #ifndef CURL_DISABLE_RTSP @@ -1817,6 +1845,8 @@ struct UserDefined { BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some recipients */ #endif + unsigned char connect_only; /* make connection/request, then let + application use the socket */ BIT(is_fread_set); /* has read callback been set to non-NULL? */ #ifndef CURL_DISABLE_TFTP BIT(tftp_no_options); /* do not send TFTP options requests */ @@ -1862,7 +1892,6 @@ struct UserDefined { BIT(no_signal); /* do not use any signal/alarm handler */ BIT(tcp_nodelay); /* whether to enable TCP_NODELAY or not */ BIT(ignorecl); /* ignore content length */ - BIT(connect_only); /* make connection, let application use the socket */ BIT(http_te_skip); /* pass the raw body data to the user, even when transfer-encoded (chunked, compressed) */ BIT(http_ce_skip); /* pass the raw body data to the user, even when @@ -1875,7 +1904,6 @@ struct UserDefined { BIT(sasl_ir); /* Enable/disable SASL initial response */ BIT(tcp_keepalive); /* use TCP keepalives */ BIT(tcp_fastopen); /* use TCP Fast Open */ - BIT(ssl_enable_npn); /* TLS NPN extension? */ BIT(ssl_enable_alpn);/* TLS ALPN extension? */ BIT(path_as_is); /* allow dotdots? */ BIT(pipewait); /* wait for multiplex status before starting a new @@ -1895,6 +1923,9 @@ struct UserDefined { BIT(doh_verifystatus); /* DoH certificate status verification */ #endif BIT(http09_allowed); /* allow HTTP/0.9 responses */ +#ifdef USE_WEBSOCKETS + BIT(ws_raw_mode); +#endif }; struct Names { diff --git a/contrib/libs/curl/lib/vauth/digest.c b/contrib/libs/curl/lib/vauth/digest.c index 962aa624a3..f945e8b6c9 100644 --- a/contrib/libs/curl/lib/vauth/digest.c +++ b/contrib/libs/curl/lib/vauth/digest.c @@ -382,7 +382,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) return CURLE_BAD_CONTENT_ENCODING; - /* Generate 32 random hex chars, 32 bytes + 1 zero termination */ + /* Generate 32 random hex chars, 32 bytes + 1 null-termination */ result = Curl_rand_hex(data, (unsigned char *)cnonce, sizeof(cnonce)); if(result) return result; @@ -521,7 +521,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, char content[DIGEST_MAX_CONTENT_LENGTH]; /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) + while(*chlg && ISBLANK(*chlg)) chlg++; /* Extract a value=content pair */ @@ -561,7 +561,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, token = strtok_r(tmp, ",", &tok_buf); while(token) { /* Pass additional spaces here */ - while(*token && ISSPACE(*token)) + while(*token && ISBLANK(*token)) token++; if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) { foundAuth = TRUE; @@ -622,7 +622,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, break; /* We're done here */ /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) + while(*chlg && ISBLANK(*chlg)) chlg++; /* Allow the list to be comma-separated */ diff --git a/contrib/libs/curl/lib/vauth/digest_sspi.c b/contrib/libs/curl/lib/vauth/digest_sspi.c index af463848a6..89a9db52c7 100644 --- a/contrib/libs/curl/lib/vauth/digest_sspi.c +++ b/contrib/libs/curl/lib/vauth/digest_sspi.c @@ -259,7 +259,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, char content[DIGEST_MAX_CONTENT_LENGTH]; /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) + while(*chlg && ISBLANK(*chlg)) chlg++; /* Extract a value=content pair */ @@ -292,7 +292,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, break; /* We're done here */ /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) + while(*chlg && ISBLANK(*chlg)) chlg++; /* Allow the list to be comma-separated */ @@ -333,7 +333,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, char value[DIGEST_MAX_VALUE_LENGTH]; char content[DIGEST_MAX_CONTENT_LENGTH]; - while(*p && ISSPACE(*p)) + while(*p && ISBLANK(*p)) p++; if(!Curl_auth_digest_get_pair(p, value, content, &p)) @@ -345,7 +345,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, break; } - while(*p && ISSPACE(*p)) + while(*p && ISBLANK(*p)) p++; if(',' == *p) @@ -431,8 +431,8 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, has changed then delete that context. */ if((userp && !digest->user) || (!userp && digest->user) || (passwdp && !digest->passwd) || (!passwdp && digest->passwd) || - (userp && digest->user && strcmp(userp, digest->user)) || - (passwdp && digest->passwd && strcmp(passwdp, digest->passwd))) { + (userp && digest->user && Curl_timestrcmp(userp, digest->user)) || + (passwdp && digest->passwd && Curl_timestrcmp(passwdp, digest->passwd))) { if(digest->http_context) { s_pSecFn->DeleteSecurityContext(digest->http_context); Curl_safefree(digest->http_context); diff --git a/contrib/libs/curl/lib/vauth/gsasl.c b/contrib/libs/curl/lib/vauth/gsasl.c index 7219400eab..f96a6dca29 100644 --- a/contrib/libs/curl/lib/vauth/gsasl.c +++ b/contrib/libs/curl/lib/vauth/gsasl.c @@ -36,7 +36,8 @@ #error #include <gsasl.h> -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" diff --git a/contrib/libs/curl/lib/vauth/ntlm.c b/contrib/libs/curl/lib/vauth/ntlm.c index edaacbb9ed..c10fa6caaf 100644 --- a/contrib/libs/curl/lib/vauth/ntlm.c +++ b/contrib/libs/curl/lib/vauth/ntlm.c @@ -29,7 +29,7 @@ /* * NTLM details: * - * https://davenport.sourceforge.io/ntlm.html + * https://davenport.sourceforge.net/ntlm.html * https://www.innovation.ch/java/ntlm.html */ @@ -600,7 +600,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, /* A safer but less compatible alternative is: * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); - * See https://davenport.sourceforge.io/ntlm.html#ntlmVersion2 */ + * See https://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ } if(unicode) { @@ -658,7 +658,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, /* LanManager response */ /* NT response */ - 0, /* zero termination */ + 0, /* null-termination */ 0, 0, 0, /* type-3 long, the 24 upper bits */ SHORTPAIR(0x18), /* LanManager response length, twice */ diff --git a/contrib/libs/curl/lib/vauth/ntlm.h b/contrib/libs/curl/lib/vauth/ntlm.h index 97325d975c..4dfda55453 100644 --- a/contrib/libs/curl/lib/vauth/ntlm.h +++ b/contrib/libs/curl/lib/vauth/ntlm.h @@ -34,7 +34,8 @@ /* Stuff only required for curl_ntlm_msgs.c */ #ifdef BUILDING_CURL_NTLM_MSGS_C -/* Flag bits definitions based on https://davenport.sourceforge.io/ntlm.html */ +/* Flag bits definitions based on + https://davenport.sourceforge.net/ntlm.html */ #define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) /* Indicates that Unicode strings are supported for use in security buffer diff --git a/contrib/libs/curl/lib/vauth/vauth.c b/contrib/libs/curl/lib/vauth/vauth.c index 9d6363df07..58fe05139d 100644 --- a/contrib/libs/curl/lib/vauth/vauth.c +++ b/contrib/libs/curl/lib/vauth/vauth.c @@ -27,6 +27,8 @@ #include <curl/curl.h> #include "vauth.h" +#include "urldata.h" +#include "strcase.h" #include "curl_multibyte.h" #include "curl_printf.h" @@ -144,3 +146,18 @@ bool Curl_auth_user_contains_domain(const char *user) return valid; } + +/* + * Curl_auth_ollowed_to_host() tells if authentication, cookies or other + * "sensitive data" can (still) be sent to this host. + */ +bool Curl_auth_allowed_to_host(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + return (!data->state.this_is_a_follow || + data->set.allow_auth_to_other_hosts || + (data->state.first_host && + strcasecompare(data->state.first_host, conn->host.name) && + (data->state.first_remote_port == conn->remote_port) && + (data->state.first_remote_protocol == conn->handler->protocol))); +} diff --git a/contrib/libs/curl/lib/vauth/vauth.h b/contrib/libs/curl/lib/vauth/vauth.h index 1c4b5b5dc6..af27f01dfb 100644 --- a/contrib/libs/curl/lib/vauth/vauth.h +++ b/contrib/libs/curl/lib/vauth/vauth.h @@ -54,6 +54,12 @@ struct gsasldata; #define GSS_ERROR(status) ((status) & 0x80000000) #endif +/* + * Curl_auth_allowed_to_host() tells if authentication, cookies or other + * "sensitive data" can (still) be sent to this host. + */ +bool Curl_auth_allowed_to_host(struct Curl_easy *data); + /* This is used to build a SPN string */ #if !defined(USE_WINDOWS_SSPI) char *Curl_auth_build_spn(const char *service, const char *host, @@ -224,7 +230,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, CURLcode Curl_auth_create_spnego_message(struct negotiatedata *nego, char **outptr, size_t *outlen); -/* This is used to clean up the SPNEGO specifiec data */ +/* This is used to clean up the SPNEGO specific data */ void Curl_auth_cleanup_spnego(struct negotiatedata *nego); #endif /* USE_SPNEGO */ diff --git a/contrib/libs/curl/lib/version.c b/contrib/libs/curl/lib/version.c index 1f74e177d5..8d7be114f4 100644 --- a/contrib/libs/curl/lib/version.c +++ b/contrib/libs/curl/lib/version.c @@ -53,7 +53,7 @@ #include <librtmp/rtmp.h> #endif -#ifdef HAVE_ZLIB_H +#ifdef HAVE_LIBZ #include <zlib.h> #endif @@ -338,6 +338,11 @@ static const char * const protocols[] = { #endif #ifdef USE_LIBRTMP "rtmp", + "rtmpe", + "rtmps", + "rtmpt", + "rtmpte", + "rtmpts", #endif #ifndef CURL_DISABLE_RTSP "rtsp", @@ -367,6 +372,12 @@ static const char * const protocols[] = { #ifndef CURL_DISABLE_TFTP "tftp", #endif +#ifdef USE_WEBSOCKETS + "ws", +#endif +#if defined(USE_SSL) && defined(USE_WEBSOCKETS) + "wss", +#endif NULL }; diff --git a/contrib/libs/curl/lib/vquic/msh3.c b/contrib/libs/curl/lib/vquic/msh3.c index 8f66bcf493..7a70ee57d4 100644 --- a/contrib/libs/curl/lib/vquic/msh3.c +++ b/contrib/libs/curl/lib/vquic/msh3.c @@ -114,7 +114,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, socklen_t addrlen) { struct quicsocket *qs = &conn->hequic[sockindex]; - bool unsecure = !conn->ssl_config.verifypeer; + bool insecure = !conn->ssl_config.verifypeer; memset(qs, 0, sizeof(*qs)); (void)sockfd; @@ -132,7 +132,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, qs->conn = MsH3ConnectionOpen(qs->api, conn->host.name, (uint16_t)conn->remote_port, - unsecure); + insecure); if(!qs->conn) { failf(data, "can't create msh3 connection"); if(qs->api) { @@ -381,9 +381,6 @@ static void MSH3_CALL msh3_shutdown(MSH3_REQUEST *Request, void *IfContext) (void)stream; } -static_assert(sizeof(MSH3_HEADER) == sizeof(struct h2h3pseudo), - "Sizes must match for cast below to work"); - static ssize_t msh3_stream_send(struct Curl_easy *data, int sockindex, const void *mem, @@ -396,6 +393,9 @@ static ssize_t msh3_stream_send(struct Curl_easy *data, struct h2h3req *hreq; (void)sockindex; + /* Sizes must match for cast below to work" */ + DEBUGASSERT(sizeof(MSH3_HEADER) == sizeof(struct h2h3pseudo)); + H3BUGF(infof(data, "msh3_stream_send %zu", len)); if(!stream->req) { diff --git a/contrib/libs/curl/lib/vquic/ngtcp2.c b/contrib/libs/curl/lib/vquic/ngtcp2.c index 11787cee5f..feabd5fa89 100644 --- a/contrib/libs/curl/lib/vquic/ngtcp2.c +++ b/contrib/libs/curl/lib/vquic/ngtcp2.c @@ -760,6 +760,7 @@ static ngtcp2_callbacks ng_callbacks = { NULL, /* version_negotiation */ cb_recv_rx_key, NULL, /* recv_tx_key */ + NULL, /* early_data_rejected */ }; /* @@ -1703,6 +1704,11 @@ static CURLcode ng_has_connected(struct Curl_easy *data, } else infof(data, "Skipped certificate verification"); +#ifdef USE_OPENSSL + if(data->set.ssl.certinfo) + /* asked to gather certificate info */ + (void)Curl_ossl_certchain(data, conn->quic->ssl); +#endif return result; } @@ -1828,15 +1834,17 @@ static CURLcode do_sendmsg(size_t *psent, struct Curl_easy *data, int sockfd, size_t pktlen, size_t gsolen) { #ifdef HAVE_SENDMSG - struct iovec msg_iov = {(void *)pkt, pktlen}; + struct iovec msg_iov; struct msghdr msg = {0}; - uint8_t msg_ctrl[32]; ssize_t sent; #if defined(__linux__) && defined(UDP_SEGMENT) + uint8_t msg_ctrl[32]; struct cmsghdr *cm; #endif *psent = 0; + msg_iov.iov_base = (uint8_t *)pkt; + msg_iov.iov_len = pktlen; msg.msg_iov = &msg_iov; msg.msg_iovlen = 1; @@ -1981,9 +1989,9 @@ static CURLcode ng_flush_egress(struct Curl_easy *data, ngtcp2_ssize outlen; uint8_t *outpos = qs->pktbuf; size_t max_udp_payload_size = - ngtcp2_conn_get_max_udp_payload_size(qs->qconn); + ngtcp2_conn_get_max_tx_udp_payload_size(qs->qconn); size_t path_max_udp_payload_size = - ngtcp2_conn_get_path_max_udp_payload_size(qs->qconn); + ngtcp2_conn_get_path_max_tx_udp_payload_size(qs->qconn); size_t max_pktcnt = CURLMIN(MAX_PKT_BURST, qs->pktbuflen / max_udp_payload_size); size_t pktcnt = 0; diff --git a/contrib/libs/curl/lib/vquic/quiche.c b/contrib/libs/curl/lib/vquic/quiche.c index 034794f8e7..5a3d6fe378 100644 --- a/contrib/libs/curl/lib/vquic/quiche.c +++ b/contrib/libs/curl/lib/vquic/quiche.c @@ -416,6 +416,10 @@ static CURLcode quiche_has_connected(struct Curl_easy *data, qs->cfg = NULL; qs->conn = NULL; } + if(data->set.ssl.certinfo) + /* asked to gather certificate info */ + (void)Curl_ossl_certchain(data, qs->ssl); + return CURLE_OK; fail: quiche_h3_config_free(qs->h3config); diff --git a/contrib/libs/curl/lib/vssh/libssh.c b/contrib/libs/curl/lib/vssh/libssh.c index 331aef366b..dc98aa0413 100644 --- a/contrib/libs/curl/lib/vssh/libssh.c +++ b/contrib/libs/curl/lib/vssh/libssh.c @@ -963,10 +963,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) rc = sftp_init(sshc->sftp_session); if(rc != SSH_OK) { - rc = sftp_get_error(sshc->sftp_session); failf(data, "Failure initializing sftp session: %s", ssh_get_error(sshc->ssh_session)); - MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(rc)); + MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE)); break; } state(data, SSH_SFTP_REALPATH); @@ -1667,7 +1666,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(from_t == CURL_OFFT_FLOW) { return CURLE_RANGE_ERROR; } - while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) + while(*ptr && (ISBLANK(*ptr) || (*ptr == '-'))) ptr++; to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); if(to_t == CURL_OFFT_FLOW) { diff --git a/contrib/libs/curl/lib/vssh/libssh2.c b/contrib/libs/curl/lib/vssh/libssh2.c index 7632888b9f..0536f5a09e 100644 --- a/contrib/libs/curl/lib/vssh/libssh2.c +++ b/contrib/libs/curl/lib/vssh/libssh2.c @@ -2506,7 +2506,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from); if(from_t == CURL_OFFT_FLOW) return CURLE_RANGE_ERROR; - while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) + while(*ptr && (ISBLANK(*ptr) || (*ptr == '-'))) ptr++; to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); if(to_t == CURL_OFFT_FLOW) diff --git a/contrib/libs/curl/lib/vssh/ssh.h b/contrib/libs/curl/lib/vssh/ssh.h index 88ac106134..33f369bf42 100644 --- a/contrib/libs/curl/lib/vssh/ssh.h +++ b/contrib/libs/curl/lib/vssh/ssh.h @@ -26,10 +26,10 @@ #include "curl_setup.h" -#if defined(HAVE_LIBSSH2_H) +#if defined(USE_LIBSSH2) #error #include <libssh2.h> #error #include <libssh2_sftp.h> -#elif defined(HAVE_LIBSSH_LIBSSH_H) +#elif defined(USE_LIBSSH) #error #include <libssh/libssh.h> #error #include <libssh/sftp.h> #elif defined(USE_WOLFSSH) diff --git a/contrib/libs/curl/lib/vtls/bearssl.c b/contrib/libs/curl/lib/vtls/bearssl.c index f14eb66a20..1221ce8c84 100644 --- a/contrib/libs/curl/lib/vtls/bearssl.c +++ b/contrib/libs/curl/lib/vtls/bearssl.c @@ -76,9 +76,9 @@ struct cafile_parser { #define CAFILE_SOURCE_PATH 1 #define CAFILE_SOURCE_BLOB 2 struct cafile_source { - const int type; - const char * const data; - const size_t len; + int type; + const char *data; + size_t len; }; static void append_dn(void *ctx, const void *buf, size_t len) @@ -618,11 +618,11 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, } if(ca_info_blob) { - struct cafile_source source = { - CAFILE_SOURCE_BLOB, - ca_info_blob->data, - ca_info_blob->len, - }; + struct cafile_source source; + source.type = CAFILE_SOURCE_BLOB; + source.data = ca_info_blob->data; + source.len = ca_info_blob->len; + ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); if(ret != CURLE_OK) { if(verifypeer) { @@ -635,11 +635,11 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, } if(ssl_cafile) { - struct cafile_source source = { - CAFILE_SOURCE_PATH, - ssl_cafile, - 0, - }; + struct cafile_source source; + source.type = CAFILE_SOURCE_PATH; + source.data = ssl_cafile; + source.len = 0; + ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); if(ret != CURLE_OK) { if(verifypeer) { @@ -875,14 +875,14 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data, #ifdef USE_HTTP2 if(!strcmp(protocol, ALPN_H2)) - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; else #endif if(!strcmp(protocol, ALPN_HTTP_1_1)) - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; else infof(data, "ALPN, unrecognized protocol %s", protocol); - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } else diff --git a/contrib/libs/curl/lib/vtls/keylog.c b/contrib/libs/curl/lib/vtls/keylog.c index 7471217921..1952a690ca 100644 --- a/contrib/libs/curl/lib/vtls/keylog.c +++ b/contrib/libs/curl/lib/vtls/keylog.c @@ -24,6 +24,7 @@ #include "curl_setup.h" #include "keylog.h" +#include <curl/curl.h> /* The last #include files should be: */ #include "curl_memory.h" diff --git a/contrib/libs/curl/lib/vtls/openssl.c b/contrib/libs/curl/lib/vtls/openssl.c index 4daae3788e..fe55490309 100644 --- a/contrib/libs/curl/lib/vtls/openssl.c +++ b/contrib/libs/curl/lib/vtls/openssl.c @@ -29,7 +29,7 @@ #include "curl_setup.h" -#ifdef USE_OPENSSL +#if defined(USE_QUICHE) || defined(USE_OPENSSL) #include <limits.h> @@ -55,6 +55,7 @@ #include "slist.h" #include "select.h" #include "vtls.h" +#include "vauth/vauth.h" #include "keylog.h" #include "strcase.h" #include "hostcheck.h" @@ -271,6 +272,344 @@ struct ssl_backend_data { #endif }; +#define push_certinfo(_label, _num) \ +do { \ + long info_len = BIO_get_mem_data(mem, &ptr); \ + Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ + if(1 != BIO_reset(mem)) \ + break; \ +} while(0) + +static void pubkey_show(struct Curl_easy *data, + BIO *mem, + int num, + const char *type, + const char *name, + const BIGNUM *bn) +{ + char *ptr; + char namebuf[32]; + + msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); + + if(bn) + BN_print(mem, bn); + push_certinfo(namebuf, num); +} + +#ifdef HAVE_OPAQUE_RSA_DSA_DH +#define print_pubkey_BN(_type, _name, _num) \ + pubkey_show(data, mem, _num, #_type, #_name, _name) + +#else +#define print_pubkey_BN(_type, _name, _num) \ +do { \ + if(_type->_name) { \ + pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ + } \ +} while(0) +#endif + +static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) +{ + int i, ilen; + + ilen = (int)len; + if(ilen < 0) + return 1; /* buffer too big */ + + i = i2t_ASN1_OBJECT(buf, ilen, a); + + if(i >= ilen) + return 1; /* buffer too small */ + + return 0; +} + +static void X509V3_ext(struct Curl_easy *data, + int certnum, + CONST_EXTS STACK_OF(X509_EXTENSION) *exts) +{ + int i; + + if((int)sk_X509_EXTENSION_num(exts) <= 0) + /* no extensions, bail out */ + return; + + for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) { + ASN1_OBJECT *obj; + X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); + BUF_MEM *biomem; + char namebuf[128]; + BIO *bio_out = BIO_new(BIO_s_mem()); + + if(!bio_out) + return; + + obj = X509_EXTENSION_get_object(ext); + + asn1_object_dump(obj, namebuf, sizeof(namebuf)); + + if(!X509V3_EXT_print(bio_out, ext, 0, 0)) + ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); + + BIO_get_mem_ptr(bio_out, &biomem); + Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data, + biomem->length); + BIO_free(bio_out); + } +} + +#ifdef OPENSSL_IS_BORINGSSL +typedef size_t numcert_t; +#else +typedef int numcert_t; +#endif + +CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl) +{ + CURLcode result; + STACK_OF(X509) *sk; + int i; + numcert_t numcerts; + BIO *mem; + + DEBUGASSERT(ssl); + + sk = SSL_get_peer_cert_chain(ssl); + if(!sk) { + return CURLE_OUT_OF_MEMORY; + } + + numcerts = sk_X509_num(sk); + + result = Curl_ssl_init_certinfo(data, (int)numcerts); + if(result) { + return result; + } + + mem = BIO_new(BIO_s_mem()); + if(!mem) { + return CURLE_OUT_OF_MEMORY; + } + + for(i = 0; i < (int)numcerts; i++) { + ASN1_INTEGER *num; + X509 *x = sk_X509_value(sk, i); + EVP_PKEY *pubkey = NULL; + int j; + char *ptr; + const ASN1_BIT_STRING *psig = NULL; + + X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); + push_certinfo("Subject", i); + + X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); + push_certinfo("Issuer", i); + + BIO_printf(mem, "%lx", X509_get_version(x)); + push_certinfo("Version", i); + + num = X509_get_serialNumber(x); + if(num->type == V_ASN1_NEG_INTEGER) + BIO_puts(mem, "-"); + for(j = 0; j < num->length; j++) + BIO_printf(mem, "%02x", num->data[j]); + push_certinfo("Serial Number", i); + +#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) + { + const X509_ALGOR *sigalg = NULL; + X509_PUBKEY *xpubkey = NULL; + ASN1_OBJECT *pubkeyoid = NULL; + + X509_get0_signature(&psig, &sigalg, x); + if(sigalg) { + i2a_ASN1_OBJECT(mem, sigalg->algorithm); + push_certinfo("Signature Algorithm", i); + } + + xpubkey = X509_get_X509_PUBKEY(x); + if(xpubkey) { + X509_PUBKEY_get0_param(&pubkeyoid, NULL, NULL, NULL, xpubkey); + if(pubkeyoid) { + i2a_ASN1_OBJECT(mem, pubkeyoid); + push_certinfo("Public Key Algorithm", i); + } + } + + X509V3_ext(data, i, X509_get0_extensions(x)); + } +#else + { + /* before OpenSSL 1.0.2 */ + X509_CINF *cinf = x->cert_info; + + i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); + push_certinfo("Signature Algorithm", i); + + i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); + push_certinfo("Public Key Algorithm", i); + + X509V3_ext(data, i, cinf->extensions); + + psig = x->signature; + } +#endif + + ASN1_TIME_print(mem, X509_get0_notBefore(x)); + push_certinfo("Start date", i); + + ASN1_TIME_print(mem, X509_get0_notAfter(x)); + push_certinfo("Expire date", i); + + pubkey = X509_get_pubkey(x); + if(!pubkey) + infof(data, " Unable to load public key"); + else { + int pktype; +#ifdef HAVE_OPAQUE_EVP_PKEY + pktype = EVP_PKEY_id(pubkey); +#else + pktype = pubkey->type; +#endif + switch(pktype) { + case EVP_PKEY_RSA: + { +#ifndef HAVE_EVP_PKEY_GET_PARAMS + RSA *rsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + rsa = EVP_PKEY_get0_RSA(pubkey); +#else + rsa = pubkey->pkey.rsa; +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ + + { +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(n); + DECLARE_PKEY_PARAM_BIGNUM(e); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &n); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &e); +#else + RSA_get0_key(rsa, &n, &e, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ + BIO_printf(mem, "%d", BN_num_bits(n)); +#else + BIO_printf(mem, "%d", BN_num_bits(rsa->n)); +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ + push_certinfo("RSA Public Key", i); + print_pubkey_BN(rsa, n, i); + print_pubkey_BN(rsa, e, i); + FREE_PKEY_PARAM_BIGNUM(n); + FREE_PKEY_PARAM_BIGNUM(e); + } + + break; + } + case EVP_PKEY_DSA: + { +#ifndef OPENSSL_NO_DSA +#ifndef HAVE_EVP_PKEY_GET_PARAMS + DSA *dsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + dsa = EVP_PKEY_get0_DSA(pubkey); +#else + dsa = pubkey->pkey.dsa; +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ + { +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(p); + DECLARE_PKEY_PARAM_BIGNUM(q); + DECLARE_PKEY_PARAM_BIGNUM(g); + DECLARE_PKEY_PARAM_BIGNUM(pub_key); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else + DSA_get0_pqg(dsa, &p, &q, &g); + DSA_get0_key(dsa, &pub_key, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ + print_pubkey_BN(dsa, p, i); + print_pubkey_BN(dsa, q, i); + print_pubkey_BN(dsa, g, i); + print_pubkey_BN(dsa, pub_key, i); + FREE_PKEY_PARAM_BIGNUM(p); + FREE_PKEY_PARAM_BIGNUM(q); + FREE_PKEY_PARAM_BIGNUM(g); + FREE_PKEY_PARAM_BIGNUM(pub_key); + } +#endif /* !OPENSSL_NO_DSA */ + break; + } + case EVP_PKEY_DH: + { +#ifndef HAVE_EVP_PKEY_GET_PARAMS + DH *dh; +#ifdef HAVE_OPAQUE_EVP_PKEY + dh = EVP_PKEY_get0_DH(pubkey); +#else + dh = pubkey->pkey.dh; +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ + { +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(p); + DECLARE_PKEY_PARAM_BIGNUM(q); + DECLARE_PKEY_PARAM_BIGNUM(g); + DECLARE_PKEY_PARAM_BIGNUM(pub_key); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else + DH_get0_pqg(dh, &p, &q, &g); + DH_get0_key(dh, &pub_key, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, q, i); + print_pubkey_BN(dh, g, i); +#else + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, g, i); +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ + print_pubkey_BN(dh, pub_key, i); + FREE_PKEY_PARAM_BIGNUM(p); + FREE_PKEY_PARAM_BIGNUM(q); + FREE_PKEY_PARAM_BIGNUM(g); + FREE_PKEY_PARAM_BIGNUM(pub_key); + } + break; + } + } + EVP_PKEY_free(pubkey); + } + + if(psig) { + for(j = 0; j < psig->length; j++) + BIO_printf(mem, "%02x:", psig->data[j]); + push_certinfo("Signature", i); + } + + PEM_write_bio_X509(mem, x); + push_certinfo("Cert", i); + } + + BIO_free(mem); + + return CURLE_OK; +} + +#endif /* quiche or OpenSSL */ + +#ifdef USE_OPENSSL + static bool ossl_associate_connection(struct Curl_easy *data, struct connectdata *conn, int sockindex); @@ -2254,72 +2593,6 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, # define HAS_ALPN 1 #endif -/* Check for OpenSSL 1.0.1 which has NPN support. */ -#undef HAS_NPN -#if OPENSSL_VERSION_NUMBER >= 0x10001000L \ - && !defined(OPENSSL_NO_TLSEXT) \ - && !defined(OPENSSL_NO_NEXTPROTONEG) -# define HAS_NPN 1 -#endif - -#ifdef HAS_NPN - -/* - * in is a list of length prefixed strings. this function has to select - * the protocol we want to use from the list and write its string into out. - */ - -static int -select_next_protocol(unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, - const char *key, unsigned int keylen) -{ - unsigned int i; - for(i = 0; i + keylen <= inlen; i += in[i] + 1) { - if(memcmp(&in[i + 1], key, keylen) == 0) { - *out = (unsigned char *) &in[i + 1]; - *outlen = in[i]; - return 0; - } - } - return -1; -} - -static int -select_next_proto_cb(SSL *ssl, - unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, - void *arg) -{ - struct Curl_easy *data = (struct Curl_easy *)arg; - struct connectdata *conn = data->conn; - (void)ssl; - -#ifdef USE_HTTP2 - if(data->state.httpwant >= CURL_HTTP_VERSION_2 && - !select_next_protocol(out, outlen, in, inlen, ALPN_H2, ALPN_H2_LENGTH)) { - infof(data, "NPN, negotiated HTTP2 (%s)", ALPN_H2); - conn->negnpn = CURL_HTTP_VERSION_2; - return SSL_TLSEXT_ERR_OK; - } -#endif - - if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1, - ALPN_HTTP_1_1_LENGTH)) { - infof(data, "NPN, negotiated HTTP1.1"); - conn->negnpn = CURL_HTTP_VERSION_1_1; - return SSL_TLSEXT_ERR_OK; - } - - infof(data, "NPN, no overlap, use HTTP1.1"); - *out = (unsigned char *)ALPN_HTTP_1_1; - *outlen = ALPN_HTTP_1_1_LENGTH; - conn->negnpn = CURL_HTTP_VERSION_1_1; - - return SSL_TLSEXT_ERR_OK; -} -#endif /* HAS_NPN */ - #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ static CURLcode set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn) @@ -2810,11 +3083,6 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, SSL_CTX_set_options(backend->ctx, ctx_options); -#ifdef HAS_NPN - if(conn->bits.tls_enable_npn) - SSL_CTX_set_next_proto_select_cb(backend->ctx, select_next_proto_cb, data); -#endif - #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { int cur = 0; @@ -2904,7 +3172,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #ifdef USE_OPENSSL_SRP if((ssl_authtype == CURL_TLSAUTH_SRP) && - Curl_allow_auth_to_host(data)) { + Curl_auth_allowed_to_host(data)) { char * const ssl_username = SSL_SET_OPTION(primary.username); char * const ssl_password = SSL_SET_OPTION(primary.password); infof(data, "Using TLS-SRP username: %s", ssl_username); @@ -3442,19 +3710,19 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, #ifdef USE_HTTP2 if(len == ALPN_H2_LENGTH && !memcmp(ALPN_H2, neg_protocol, len)) { - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; } else #endif if(len == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; } } else infof(data, VTLS_INFOF_NO_ALPN); - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } #endif @@ -3463,342 +3731,6 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, } } -static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) -{ - int i, ilen; - - ilen = (int)len; - if(ilen < 0) - return 1; /* buffer too big */ - - i = i2t_ASN1_OBJECT(buf, ilen, a); - - if(i >= ilen) - return 1; /* buffer too small */ - - return 0; -} - -#define push_certinfo(_label, _num) \ -do { \ - long info_len = BIO_get_mem_data(mem, &ptr); \ - Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ - if(1 != BIO_reset(mem)) \ - break; \ -} while(0) - -static void pubkey_show(struct Curl_easy *data, - BIO *mem, - int num, - const char *type, - const char *name, - const BIGNUM *bn) -{ - char *ptr; - char namebuf[32]; - - msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); - - if(bn) - BN_print(mem, bn); - push_certinfo(namebuf, num); -} - -#ifdef HAVE_OPAQUE_RSA_DSA_DH -#define print_pubkey_BN(_type, _name, _num) \ - pubkey_show(data, mem, _num, #_type, #_name, _name) - -#else -#define print_pubkey_BN(_type, _name, _num) \ -do { \ - if(_type->_name) { \ - pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ - } \ -} while(0) -#endif - -static void X509V3_ext(struct Curl_easy *data, - int certnum, - CONST_EXTS STACK_OF(X509_EXTENSION) *exts) -{ - int i; - - if((int)sk_X509_EXTENSION_num(exts) <= 0) - /* no extensions, bail out */ - return; - - for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) { - ASN1_OBJECT *obj; - X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); - BUF_MEM *biomem; - char namebuf[128]; - BIO *bio_out = BIO_new(BIO_s_mem()); - - if(!bio_out) - return; - - obj = X509_EXTENSION_get_object(ext); - - asn1_object_dump(obj, namebuf, sizeof(namebuf)); - - if(!X509V3_EXT_print(bio_out, ext, 0, 0)) - ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); - - BIO_get_mem_ptr(bio_out, &biomem); - Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data, - biomem->length); - BIO_free(bio_out); - } -} - -#ifdef OPENSSL_IS_BORINGSSL -typedef size_t numcert_t; -#else -typedef int numcert_t; -#endif - -static CURLcode get_cert_chain(struct Curl_easy *data, - struct ssl_connect_data *connssl) -{ - CURLcode result; - STACK_OF(X509) *sk; - int i; - numcert_t numcerts; - BIO *mem; - struct ssl_backend_data *backend = connssl->backend; - - DEBUGASSERT(backend); - - sk = SSL_get_peer_cert_chain(backend->handle); - if(!sk) { - return CURLE_OUT_OF_MEMORY; - } - - numcerts = sk_X509_num(sk); - - result = Curl_ssl_init_certinfo(data, (int)numcerts); - if(result) { - return result; - } - - mem = BIO_new(BIO_s_mem()); - if(!mem) { - return CURLE_OUT_OF_MEMORY; - } - - for(i = 0; i < (int)numcerts; i++) { - ASN1_INTEGER *num; - X509 *x = sk_X509_value(sk, i); - EVP_PKEY *pubkey = NULL; - int j; - char *ptr; - const ASN1_BIT_STRING *psig = NULL; - - X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); - push_certinfo("Subject", i); - - X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); - push_certinfo("Issuer", i); - - BIO_printf(mem, "%lx", X509_get_version(x)); - push_certinfo("Version", i); - - num = X509_get_serialNumber(x); - if(num->type == V_ASN1_NEG_INTEGER) - BIO_puts(mem, "-"); - for(j = 0; j < num->length; j++) - BIO_printf(mem, "%02x", num->data[j]); - push_certinfo("Serial Number", i); - -#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) - { - const X509_ALGOR *sigalg = NULL; - X509_PUBKEY *xpubkey = NULL; - ASN1_OBJECT *pubkeyoid = NULL; - - X509_get0_signature(&psig, &sigalg, x); - if(sigalg) { - i2a_ASN1_OBJECT(mem, sigalg->algorithm); - push_certinfo("Signature Algorithm", i); - } - - xpubkey = X509_get_X509_PUBKEY(x); - if(xpubkey) { - X509_PUBKEY_get0_param(&pubkeyoid, NULL, NULL, NULL, xpubkey); - if(pubkeyoid) { - i2a_ASN1_OBJECT(mem, pubkeyoid); - push_certinfo("Public Key Algorithm", i); - } - } - - X509V3_ext(data, i, X509_get0_extensions(x)); - } -#else - { - /* before OpenSSL 1.0.2 */ - X509_CINF *cinf = x->cert_info; - - i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); - push_certinfo("Signature Algorithm", i); - - i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); - push_certinfo("Public Key Algorithm", i); - - X509V3_ext(data, i, cinf->extensions); - - psig = x->signature; - } -#endif - - ASN1_TIME_print(mem, X509_get0_notBefore(x)); - push_certinfo("Start date", i); - - ASN1_TIME_print(mem, X509_get0_notAfter(x)); - push_certinfo("Expire date", i); - - pubkey = X509_get_pubkey(x); - if(!pubkey) - infof(data, " Unable to load public key"); - else { - int pktype; -#ifdef HAVE_OPAQUE_EVP_PKEY - pktype = EVP_PKEY_id(pubkey); -#else - pktype = pubkey->type; -#endif - switch(pktype) { - case EVP_PKEY_RSA: - { -#ifndef HAVE_EVP_PKEY_GET_PARAMS - RSA *rsa; -#ifdef HAVE_OPAQUE_EVP_PKEY - rsa = EVP_PKEY_get0_RSA(pubkey); -#else - rsa = pubkey->pkey.rsa; -#endif /* HAVE_OPAQUE_EVP_PKEY */ -#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ - - { -#ifdef HAVE_OPAQUE_RSA_DSA_DH - DECLARE_PKEY_PARAM_BIGNUM(n); - DECLARE_PKEY_PARAM_BIGNUM(e); -#ifdef HAVE_EVP_PKEY_GET_PARAMS - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &n); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &e); -#else - RSA_get0_key(rsa, &n, &e, NULL); -#endif /* HAVE_EVP_PKEY_GET_PARAMS */ - BIO_printf(mem, "%d", BN_num_bits(n)); -#else - BIO_printf(mem, "%d", BN_num_bits(rsa->n)); -#endif /* HAVE_OPAQUE_RSA_DSA_DH */ - push_certinfo("RSA Public Key", i); - print_pubkey_BN(rsa, n, i); - print_pubkey_BN(rsa, e, i); - FREE_PKEY_PARAM_BIGNUM(n); - FREE_PKEY_PARAM_BIGNUM(e); - } - - break; - } - case EVP_PKEY_DSA: - { -#ifndef OPENSSL_NO_DSA -#ifndef HAVE_EVP_PKEY_GET_PARAMS - DSA *dsa; -#ifdef HAVE_OPAQUE_EVP_PKEY - dsa = EVP_PKEY_get0_DSA(pubkey); -#else - dsa = pubkey->pkey.dsa; -#endif /* HAVE_OPAQUE_EVP_PKEY */ -#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ - { -#ifdef HAVE_OPAQUE_RSA_DSA_DH - DECLARE_PKEY_PARAM_BIGNUM(p); - DECLARE_PKEY_PARAM_BIGNUM(q); - DECLARE_PKEY_PARAM_BIGNUM(g); - DECLARE_PKEY_PARAM_BIGNUM(pub_key); -#ifdef HAVE_EVP_PKEY_GET_PARAMS - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); -#else - DSA_get0_pqg(dsa, &p, &q, &g); - DSA_get0_key(dsa, &pub_key, NULL); -#endif /* HAVE_EVP_PKEY_GET_PARAMS */ -#endif /* HAVE_OPAQUE_RSA_DSA_DH */ - print_pubkey_BN(dsa, p, i); - print_pubkey_BN(dsa, q, i); - print_pubkey_BN(dsa, g, i); - print_pubkey_BN(dsa, pub_key, i); - FREE_PKEY_PARAM_BIGNUM(p); - FREE_PKEY_PARAM_BIGNUM(q); - FREE_PKEY_PARAM_BIGNUM(g); - FREE_PKEY_PARAM_BIGNUM(pub_key); - } -#endif /* !OPENSSL_NO_DSA */ - break; - } - case EVP_PKEY_DH: - { -#ifndef HAVE_EVP_PKEY_GET_PARAMS - DH *dh; -#ifdef HAVE_OPAQUE_EVP_PKEY - dh = EVP_PKEY_get0_DH(pubkey); -#else - dh = pubkey->pkey.dh; -#endif /* HAVE_OPAQUE_EVP_PKEY */ -#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ - { -#ifdef HAVE_OPAQUE_RSA_DSA_DH - DECLARE_PKEY_PARAM_BIGNUM(p); - DECLARE_PKEY_PARAM_BIGNUM(q); - DECLARE_PKEY_PARAM_BIGNUM(g); - DECLARE_PKEY_PARAM_BIGNUM(pub_key); -#ifdef HAVE_EVP_PKEY_GET_PARAMS - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); -#else - DH_get0_pqg(dh, &p, &q, &g); - DH_get0_key(dh, &pub_key, NULL); -#endif /* HAVE_EVP_PKEY_GET_PARAMS */ - print_pubkey_BN(dh, p, i); - print_pubkey_BN(dh, q, i); - print_pubkey_BN(dh, g, i); -#else - print_pubkey_BN(dh, p, i); - print_pubkey_BN(dh, g, i); -#endif /* HAVE_OPAQUE_RSA_DSA_DH */ - print_pubkey_BN(dh, pub_key, i); - FREE_PKEY_PARAM_BIGNUM(p); - FREE_PKEY_PARAM_BIGNUM(q); - FREE_PKEY_PARAM_BIGNUM(g); - FREE_PKEY_PARAM_BIGNUM(pub_key); - } - break; - } - } - EVP_PKEY_free(pubkey); - } - - if(psig) { - for(j = 0; j < psig->length; j++) - BIO_printf(mem, "%02x:", psig->data[j]); - push_certinfo("Signature", i); - } - - PEM_write_bio_X509(mem, x); - push_certinfo("Cert", i); - } - - BIO_free(mem); - - return CURLE_OK; -} - /* * Heavily modified from: * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL @@ -3893,8 +3825,8 @@ static CURLcode servercert(struct Curl_easy *data, } if(data->set.ssl.certinfo) - /* we've been asked to gather certificate info! */ - (void)get_cert_chain(data, connssl); + /* asked to gather certificate info */ + (void)Curl_ossl_certchain(data, connssl->backend->handle); backend->server_cert = SSL_get1_peer_certificate(backend->handle); if(!backend->server_cert) { @@ -4437,7 +4369,7 @@ static size_t ossl_version(char *buffer, size_t size) } count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver); for(p = buffer; *p; ++p) { - if(ISSPACE(*p)) + if(ISBLANK(*p)) *p = '_'; } return count; diff --git a/contrib/libs/curl/lib/vtls/openssl.h b/contrib/libs/curl/lib/vtls/openssl.h index cb47f4ea81..9df4ecddba 100644 --- a/contrib/libs/curl/lib/vtls/openssl.h +++ b/contrib/libs/curl/lib/vtls/openssl.h @@ -31,6 +31,7 @@ * This header should only be needed to get included by vtls.c, openssl.c * and ngtcp2.c */ +#include <openssl/ssl.h> #include "urldata.h" @@ -53,5 +54,7 @@ CURLcode Curl_ossl_set_client_cert(struct Curl_easy *data, const struct curl_blob *key_blob, const char *key_type, char *key_passwd); +CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl); + #endif /* USE_OPENSSL */ #endif /* HEADER_CURL_SSLUSE_H */ diff --git a/contrib/libs/curl/lib/vtls/rustls.c b/contrib/libs/curl/lib/vtls/rustls.c index be4af98502..77a49f1ab4 100644 --- a/contrib/libs/curl/lib/vtls/rustls.c +++ b/contrib/libs/curl/lib/vtls/rustls.c @@ -415,20 +415,20 @@ cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn, #ifdef USE_HTTP2 if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) { infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, ALPN_H2); - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; } else #endif if(len == ALPN_HTTP_1_1_LENGTH && 0 == memcmp(ALPN_HTTP_1_1, protocol, len)) { infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, ALPN_HTTP_1_1); - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; } else { infof(data, "ALPN, negotiated an unrecognized protocol"); } - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } diff --git a/contrib/libs/curl/lib/vtls/schannel.h b/contrib/libs/curl/lib/vtls/schannel.h index e6dc0e9359..2acf4dc8ce 100644 --- a/contrib/libs/curl/lib/vtls/schannel.h +++ b/contrib/libs/curl/lib/vtls/schannel.h @@ -83,17 +83,23 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data, /* structs to expose only in schannel.c and schannel_verify.c */ #ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS +#include <wincrypt.h> + #ifdef __MINGW32__ #ifdef __MINGW64_VERSION_MAJOR #define HAS_MANUAL_VERIFY_API #endif #else -#include <wincrypt.h> #ifdef CERT_CHAIN_REVOCATION_CHECK_CHAIN #define HAS_MANUAL_VERIFY_API #endif #endif +#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \ + && !defined(DISABLE_SCHANNEL_CLIENT_CERT) +#define HAS_CLIENT_CERT_PATH +#endif + #ifndef SCH_CREDENTIALS_VERSION #define SCH_CREDENTIALS_VERSION 0x00000005 @@ -155,6 +161,9 @@ struct Curl_schannel_cred { CredHandle cred_handle; TimeStamp time_stamp; TCHAR *sni_hostname; +#ifdef HAS_CLIENT_CERT_PATH + HCERTSTORE client_cert_store; +#endif int refcount; }; @@ -179,6 +188,7 @@ struct ssl_backend_data { CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ bool recv_sspi_close_notify; /* true if connection closed by close_notify */ bool recv_connection_closed; /* true if connection closed, regardless how */ + bool recv_renegotiating; /* true if recv is doing renegotiation */ bool use_alpn; /* true if ALPN is used for this connection */ #ifdef HAS_MANUAL_VERIFY_API bool use_manual_cred_validation; /* true if manual cred validation is used */ diff --git a/contrib/libs/curl/lib/vtls/sectransp.c b/contrib/libs/curl/lib/vtls/sectransp.c index a18ca4ee9d..c764e3631b 100644 --- a/contrib/libs/curl/lib/vtls/sectransp.c +++ b/contrib/libs/curl/lib/vtls/sectransp.c @@ -2847,18 +2847,18 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn, #ifdef USE_HTTP2 if(chosenProtocol && !CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) { - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; } else #endif if(chosenProtocol && !CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; } else infof(data, VTLS_INFOF_NO_ALPN); - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); /* chosenProtocol is a reference to the string within alpnArr diff --git a/contrib/libs/curl/lib/vtls/vtls.c b/contrib/libs/curl/lib/vtls/vtls.c index 8048ba7a41..9dee5aa3b3 100644 --- a/contrib/libs/curl/lib/vtls/vtls.c +++ b/contrib/libs/curl/lib/vtls/vtls.c @@ -146,8 +146,8 @@ Curl_ssl_config_matches(struct ssl_primary_config *data, Curl_safecmp(data->issuercert, needle->issuercert) && Curl_safecmp(data->clientcert, needle->clientcert) && #ifdef USE_TLS_SRP - Curl_safecmp(data->username, needle->username) && - Curl_safecmp(data->password, needle->password) && + !Curl_timestrcmp(data->username, needle->username) && + !Curl_timestrcmp(data->password, needle->password) && (data->authtype == needle->authtype) && #endif Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && diff --git a/contrib/libs/curl/lib/vtls/wolfssl.c b/contrib/libs/curl/lib/vtls/wolfssl.c index b4f07971e6..b068639c80 100644 --- a/contrib/libs/curl/lib/vtls/wolfssl.c +++ b/contrib/libs/curl/lib/vtls/wolfssl.c @@ -763,17 +763,17 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, if(protocol_len == ALPN_HTTP_1_1_LENGTH && !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; #ifdef USE_HTTP2 else if(data->state.httpwant >= CURL_HTTP_VERSION_2 && protocol_len == ALPN_H2_LENGTH && !memcmp(protocol, ALPN_H2, ALPN_H2_LENGTH)) - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; #endif else infof(data, "ALPN, unrecognized protocol %.*s", protocol_len, protocol); - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } else if(rc == SSL_ALPN_NOT_FOUND) @@ -811,8 +811,10 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(SSL_SET_OPTION(primary.sessionid)) { bool incache; + bool added = FALSE; void *old_ssl_sessionid = NULL; - SSL_SESSION *our_ssl_sessionid = SSL_get_session(backend->handle); + /* SSL_get1_session allocates memory that has to be freed. */ + SSL_SESSION *our_ssl_sessionid = SSL_get1_session(backend->handle); bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; if(our_ssl_sessionid) { @@ -832,11 +834,20 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, 0, sockindex, NULL); if(result) { Curl_ssl_sessionid_unlock(data); + SSL_SESSION_free(our_ssl_sessionid); failf(data, "failed to store ssl session"); return result; } + else { + added = TRUE; + } } Curl_ssl_sessionid_unlock(data); + + if(!added) { + /* If the session info wasn't added to the cache, free our copy. */ + SSL_SESSION_free(our_ssl_sessionid); + } } } @@ -956,8 +967,7 @@ static ssize_t wolfssl_recv(struct Curl_easy *data, static void wolfssl_session_free(void *ptr) { - (void)ptr; - /* wolfSSL reuses sessions on own, no free */ + SSL_SESSION_free(ptr); } diff --git a/contrib/libs/curl/lib/vtls/x509asn1.c b/contrib/libs/curl/lib/vtls/x509asn1.c index d5661b0976..0cfcbe87da 100644 --- a/contrib/libs/curl/lib/vtls/x509asn1.c +++ b/contrib/libs/curl/lib/vtls/x509asn1.c @@ -45,6 +45,7 @@ #include <curl/curl.h> #include "urldata.h" #include "strcase.h" +#include "curl_ctype.h" #include "hostcheck.h" #include "vtls/vtls.h" #include "sendf.h" @@ -716,7 +717,7 @@ static ssize_t encodeDN(char *buf, size_t buflen, struct Curl_asn1Element *dn) /* Encode delimiter. If attribute has a short uppercase name, delimiter is ", ". */ if(l) { - for(p3 = str; isupper(*p3); p3++) + for(p3 = str; ISUPPER(*p3); p3++) ; for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) { if(l < buflen) diff --git a/contrib/libs/curl/lib/warnless.c b/contrib/libs/curl/lib/warnless.c index 51187aa52e..b00d7a5a26 100644 --- a/contrib/libs/curl/lib/warnless.c +++ b/contrib/libs/curl/lib/warnless.c @@ -39,6 +39,8 @@ #include "warnless.h" +#include <limits.h> + #define CURL_MASK_UCHAR ((unsigned char)~0) #define CURL_MASK_SCHAR (CURL_MASK_UCHAR >> 1) diff --git a/contrib/libs/curl/lib/wildcard.h b/contrib/libs/curl/lib/wildcard.h index f9d2167bf2..21e933b9a4 100644 --- a/contrib/libs/curl/lib/wildcard.h +++ b/contrib/libs/curl/lib/wildcard.h @@ -27,6 +27,7 @@ #include "curl_setup.h" #ifndef CURL_DISABLE_FTP +#include <curl/curl.h> #include "llist.h" /* list of wildcard process states */ diff --git a/contrib/libs/curl/lib/ws.c b/contrib/libs/curl/lib/ws.c new file mode 100644 index 0000000000..a673446625 --- /dev/null +++ b/contrib/libs/curl/lib/ws.c @@ -0,0 +1,757 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" +#include <curl/curl.h> + +#ifdef USE_WEBSOCKETS + +#include "urldata.h" +#include "dynbuf.h" +#include "rand.h" +#include "curl_base64.h" +#include "sendf.h" +#include "multiif.h" +#include "ws.h" +#include "easyif.h" +#include "transfer.h" +#include "nonblock.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +struct wsfield { + const char *name; + const char *val; +}; + +CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req) +{ + unsigned int i; + CURLcode result = CURLE_OK; + unsigned char rand[16]; + char *randstr; + size_t randlen; + char keyval[40]; + struct SingleRequest *k = &data->req; + struct wsfield heads[]= { + { + /* The request MUST contain an |Upgrade| header field whose value + MUST include the "websocket" keyword. */ + "Upgrade:", "websocket" + }, + { + /* The request MUST contain a |Connection| header field whose value + MUST include the "Upgrade" token. */ + "Connection:", "Upgrade", + }, + { + /* The request MUST include a header field with the name + |Sec-WebSocket-Version|. The value of this header field MUST be + 13. */ + "Sec-WebSocket-Version:", "13", + }, + { + /* The request MUST include a header field with the name + |Sec-WebSocket-Key|. The value of this header field MUST be a nonce + consisting of a randomly selected 16-byte value that has been + base64-encoded (see Section 4 of [RFC4648]). The nonce MUST be + selected randomly for each connection. */ + "Sec-WebSocket-Key:", NULL, + } + }; + heads[3].val = &keyval[0]; + + /* 16 bytes random */ + result = Curl_rand(data, (unsigned char *)rand, sizeof(rand)); + if(result) + return result; + result = Curl_base64_encode((char *)rand, sizeof(rand), &randstr, &randlen); + if(result) + return result; + DEBUGASSERT(randlen < sizeof(keyval)); + if(randlen >= sizeof(keyval)) + return CURLE_FAILED_INIT; + strcpy(keyval, randstr); + free(randstr); + for(i = 0; !result && (i < sizeof(heads)/sizeof(heads[0])); i++) { + if(!Curl_checkheaders(data, STRCONST(heads[i].name))) { +#ifdef USE_HYPER + char field[128]; + msnprintf(field, sizeof(field), "%s %s", heads[i].name, + heads[i].val); + result = Curl_hyper_header(data, req, field); +#else + (void)data; + result = Curl_dyn_addf(req, "%s %s\r\n", heads[i].name, + heads[i].val); +#endif + } + } + k->upgr101 = UPGR101_WS; + Curl_dyn_init(&data->req.p.http->ws.buf, MAX_WS_SIZE * 2); + return result; +} + +CURLcode Curl_ws_accept(struct Curl_easy *data) +{ + struct SingleRequest *k = &data->req; + struct HTTP *ws = data->req.p.http; + struct connectdata *conn = data->conn; + struct websocket *wsp = &data->req.p.http->ws; + CURLcode result; + + /* Verify the Sec-WebSocket-Accept response. + + The sent value is the base64 encoded version of a SHA-1 hash done on the + |Sec-WebSocket-Key| header field concatenated with + the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11". + */ + + /* If the response includes a |Sec-WebSocket-Extensions| header field and + this header field indicates the use of an extension that was not present + in the client's handshake (the server has indicated an extension not + requested by the client), the client MUST Fail the WebSocket Connection. + */ + + /* If the response includes a |Sec-WebSocket-Protocol| header field + and this header field indicates the use of a subprotocol that was + not present in the client's handshake (the server has indicated a + subprotocol not requested by the client), the client MUST Fail + the WebSocket Connection. */ + + /* 4 bytes random */ + result = Curl_rand(data, (unsigned char *)&ws->ws.mask, sizeof(ws->ws.mask)); + if(result) + return result; + + infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x", + ws->ws.mask[0], ws->ws.mask[1], ws->ws.mask[2], ws->ws.mask[3]); + k->upgr101 = UPGR101_RECEIVED; + + if(data->set.connect_only) + /* switch off non-blocking sockets */ + (void)curlx_nonblock(conn->sock[FIRSTSOCKET], FALSE); + + wsp->oleft = 0; + return result; +} + +#define WSBIT_FIN 0x80 +#define WSBIT_OPCODE_CONT 0 +#define WSBIT_OPCODE_TEXT (1) +#define WSBIT_OPCODE_BIN (2) +#define WSBIT_OPCODE_CLOSE (8) +#define WSBIT_OPCODE_PING (9) +#define WSBIT_OPCODE_PONG (0xa) +#define WSBIT_OPCODE_MASK (0xf) + +#define WSBIT_MASK 0x80 + +/* remove the spent bytes from the beginning of the buffer as that part has + now been delivered to the application */ +static void ws_decode_clear(struct Curl_easy *data) +{ + struct websocket *wsp = &data->req.p.http->ws; + size_t spent = wsp->usedbuf; + size_t len = Curl_dyn_len(&wsp->buf); + size_t keep = len - spent; + DEBUGASSERT(len >= spent); + Curl_dyn_tail(&wsp->buf, keep); +} + +/* ws_decode() decodes a binary frame into structured WebSocket data, + + wpkt - the incoming raw data. If NULL, work on the already buffered data. + ilen - the size of the provided data, perhaps too little, perhaps too much + out - stored pointed to extracted data + olen - stored length of the extracted data + oleft - number of unread bytes pending to that belongs to this frame + more - if there is more data in there + flags - stored bitmask about the frame + + Returns CURLE_AGAIN if there is only a partial frame in the buffer. Then it + stores the first part in the ->extra buffer to be used in the next call + when more data is provided. +*/ + +static CURLcode ws_decode(struct Curl_easy *data, + unsigned char *wpkt, size_t ilen, + unsigned char **out, size_t *olen, + curl_off_t *oleft, + bool *more, + unsigned int *flags) +{ + bool fin; + unsigned char opcode; + curl_off_t total; + size_t dataindex = 2; + curl_off_t plen; /* size of data in the buffer */ + curl_off_t payloadsize; + struct websocket *wsp = &data->req.p.http->ws; + unsigned char *p; + CURLcode result; + + *olen = 0; + + /* add the incoming bytes, if any */ + if(wpkt) { + result = Curl_dyn_addn(&wsp->buf, wpkt, ilen); + if(result) + return result; + } + + plen = Curl_dyn_len(&wsp->buf); + if(plen < 2) { + /* the smallest possible frame is two bytes */ + infof(data, "WS: plen == %u, EAGAIN", (int)plen); + return CURLE_AGAIN; + } + + p = Curl_dyn_uptr(&wsp->buf); + + fin = p[0] & WSBIT_FIN; + opcode = p[0] & WSBIT_OPCODE_MASK; + infof(data, "WS:%d received FIN bit %u", __LINE__, (int)fin); + *flags = 0; + switch(opcode) { + case WSBIT_OPCODE_CONT: + if(!fin) + *flags |= CURLWS_CONT; + infof(data, "WS: received OPCODE CONT"); + break; + case WSBIT_OPCODE_TEXT: + infof(data, "WS: received OPCODE TEXT"); + *flags |= CURLWS_TEXT; + break; + case WSBIT_OPCODE_BIN: + infof(data, "WS: received OPCODE BINARY"); + *flags |= CURLWS_BINARY; + break; + case WSBIT_OPCODE_CLOSE: + infof(data, "WS: received OPCODE CLOSE"); + *flags |= CURLWS_CLOSE; + break; + case WSBIT_OPCODE_PING: + infof(data, "WS: received OPCODE PING"); + *flags |= CURLWS_PING; + break; + case WSBIT_OPCODE_PONG: + infof(data, "WS: received OPCODE PONG"); + *flags |= CURLWS_PONG; + break; + } + + if(p[1] & WSBIT_MASK) { + /* A client MUST close a connection if it detects a masked frame. */ + failf(data, "WS: masked input frame"); + return CURLE_RECV_ERROR; + } + payloadsize = p[1]; + if(payloadsize == 126) { + if(plen < 4) { + infof(data, "WS:%d plen == %u, EAGAIN", __LINE__, (int)plen); + return CURLE_AGAIN; /* not enough data available */ + } + payloadsize = (p[2] << 8) | p[3]; + dataindex += 2; + } + else if(payloadsize == 127) { + /* 64 bit payload size */ + if(plen < 10) + return CURLE_AGAIN; + if(p[2] & 80) { + failf(data, "WS: too large frame"); + return CURLE_RECV_ERROR; + } + dataindex += 8; + payloadsize = ((curl_off_t)p[2] << 56) | + (curl_off_t)p[3] << 48 | + (curl_off_t)p[4] << 40 | + (curl_off_t)p[5] << 32 | + (curl_off_t)p[6] << 24 | + (curl_off_t)p[7] << 16 | + (curl_off_t)p[8] << 8 | + p[9]; + } + + total = dataindex + payloadsize; + if(total > plen) { + /* deliver a partial frame */ + *oleft = total - dataindex; + payloadsize = total - dataindex; + } + else { + *oleft = 0; + if(plen > total) + /* there is another fragment after */ + *more = TRUE; + } + + /* point to the payload */ + *out = &p[dataindex]; + + /* return the payload length */ + *olen = payloadsize; + + /* number of bytes "used" from the buffer */ + wsp->usedbuf = dataindex + payloadsize; + infof(data, "WS: received %zu bytes payload (%zu left)", + payloadsize, *oleft); + return CURLE_OK; +} + +/* 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 HTTP *ws = (struct HTTP *)userp; + struct Curl_easy *data = ws->ws.data; + void *writebody_ptr = data->set.out; + if(data->set.ws_raw_mode) + return data->set.fwrite_func(buffer, size, nitems, writebody_ptr); + else if(nitems) { + unsigned char *frame = NULL; + size_t flen = 0; + size_t wrote = 0; + CURLcode result; + bool more; /* there's is more to parse in the buffer */ + curl_off_t oleft; + + decode: + more = FALSE; + oleft = ws->ws.frame.bytesleft; + if(!oleft) { + unsigned int recvflags; + result = ws_decode(data, (unsigned char *)buffer, nitems, + &frame, &flen, &oleft, &more, &recvflags); + if(result == CURLE_AGAIN) + /* insufficient amount of data, keep it for later */ + return nitems; + else if(result) { + infof(data, "WS: decode error %d", (int)result); + return nitems - 1; + } + /* Store details about the frame to be reachable with curl_ws_meta() + from within the write callback */ + ws->ws.frame.age = 0; + ws->ws.frame.offset = 0; + ws->ws.frame.flags = recvflags; + ws->ws.frame.bytesleft = oleft; + } + else { + if(nitems > (size_t)ws->ws.frame.bytesleft) { + nitems = ws->ws.frame.bytesleft; + more = TRUE; + } + else + more = FALSE; + ws->ws.frame.offset += nitems; + ws->ws.frame.bytesleft -= nitems; + frame = (unsigned char *)buffer; + flen = nitems; + } + if((ws->ws.frame.flags & CURLWS_PING) && !oleft) { + /* auto-respond to PINGs, only works for single-frame payloads atm */ + size_t bytes; + infof(data, "WS: auto-respond to PING with a PONG"); + DEBUGASSERT(frame); + /* send back the exact same content as a PONG */ + result = curl_ws_send(data, frame, flen, &bytes, 0, CURLWS_PONG); + if(result) + return result; + } + else { + /* deliver the decoded frame to the user callback */ + Curl_set_in_callback(data, true); + wrote = data->set.fwrite_func((char *)frame, 1, flen, writebody_ptr); + Curl_set_in_callback(data, false); + if(wrote != flen) + return 0; + } + if(oleft) + ws->ws.frame.offset += flen; + /* the websocket frame has been delivered */ + ws_decode_clear(data); + if(more) { + /* there's more websocket data to deal with in the buffer */ + buffer = NULL; /* the buffer as been drained already */ + goto decode; + } + } + return nitems; +} + + +CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer, + size_t buflen, size_t *nread, + struct curl_ws_frame **metap) +{ + size_t bytes; + CURLcode result; + struct websocket *wsp = &data->req.p.http->ws; + + *nread = 0; + *metap = NULL; + /* get a download buffer */ + result = Curl_preconnect(data); + if(result) + return result; + + do { + bool drain = FALSE; /* if there is pending buffered data to drain */ + char *inbuf = data->state.buffer; + bytes = wsp->stillbuffer; + if(!bytes) { + result = curl_easy_recv(data, data->state.buffer, + data->set.buffer_size, &bytes); + if(result) + return result; + } + else { + /* the pending bytes can be found here */ + inbuf = wsp->stillb; + drain = TRUE; + } + if(bytes) { + unsigned char *out; + size_t olen; + bool more; + unsigned int recvflags; + curl_off_t oleft = wsp->frame.bytesleft; + + infof(data, "WS: got %u websocket bytes to decode", (int)bytes); + if(!oleft && !drain) { + result = ws_decode(data, (unsigned char *)inbuf, bytes, + &out, &olen, &oleft, &more, &recvflags); + if(result == CURLE_AGAIN) + /* a packet fragment only */ + break; + else if(result) + return result; + wsp->frame.offset = 0; + wsp->frame.bytesleft = oleft; + wsp->frame.flags = recvflags; + } + else { + olen = oleft; + out = (unsigned char *)wsp->stillb; + recvflags = wsp->frame.flags; + if((curl_off_t)buflen < oleft) + /* there is still data left after this */ + wsp->frame.bytesleft -= buflen; + else + wsp->frame.bytesleft = 0; + } + + /* auto-respond to PINGs */ + if((recvflags & CURLWS_PING) && !oleft) { + infof(data, "WS: auto-respond to PING with a PONG"); + /* send back the exact same content as a PONG */ + result = curl_ws_send(data, out, olen, &bytes, 0, CURLWS_PONG); + if(result) + return result; + } + else { + if(olen < buflen) { + /* copy the payload to the user buffer */ + memcpy(buffer, out, olen); + *nread = olen; + if(!oleft) + /* websocket frame has been delivered */ + ws_decode_clear(data); + } + else { + /* copy a partial payload */ + memcpy(buffer, out, buflen); + *nread = buflen; + /* remember what is left and where */ + wsp->stillbuffer = olen - buflen; + wsp->stillb = (char *)buffer + buflen; + } + wsp->frame.offset += *nread; + } + } + else + *nread = bytes; + break; + } while(1); + *metap = &wsp->frame; + return CURLE_OK; +} + +static void ws_xor(struct Curl_easy *data, + const unsigned char *source, + unsigned char *dest, + size_t len) +{ + struct websocket *wsp = &data->req.p.http->ws; + size_t i; + /* append payload after the mask, XOR appropriately */ + for(i = 0; i < len; i++) { + dest[i] = source[i] ^ wsp->mask[wsp->xori]; + wsp->xori++; + wsp->xori &= 3; + } +} + +/*** + RFC 6455 Section 5.2 + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-------+-+-------------+-------------------------------+ + |F|R|R|R| opcode|M| Payload len | Extended payload length | + |I|S|S|S| (4) |A| (7) | (16/64) | + |N|V|V|V| |S| | (if payload len==126/127) | + | |1|2|3| |K| | | + +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + | Extended payload length continued, if payload len == 127 | + + - - - - - - - - - - - - - - - +-------------------------------+ + | |Masking-key, if MASK set to 1 | + +-------------------------------+-------------------------------+ + | Masking-key (continued) | Payload Data | + +-------------------------------- - - - - - - - - - - - - - - - + + : Payload Data continued ... : + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | Payload Data continued ... | + +---------------------------------------------------------------+ +*/ + +static size_t ws_packethead(struct Curl_easy *data, + size_t len, unsigned int flags) +{ + struct HTTP *ws = data->req.p.http; + unsigned char *out = (unsigned char *)data->state.ulbuf; + unsigned char firstbyte = 0; + int outi; + unsigned char opcode; + if(flags & CURLWS_TEXT) { + opcode = WSBIT_OPCODE_TEXT; + infof(data, "WS: send OPCODE TEXT"); + } + else if(flags & CURLWS_CLOSE) { + opcode = WSBIT_OPCODE_CLOSE; + infof(data, "WS: send OPCODE CLOSE"); + } + else if(flags & CURLWS_PING) { + opcode = WSBIT_OPCODE_PING; + infof(data, "WS: send OPCODE PING"); + } + else if(flags & CURLWS_PONG) { + opcode = WSBIT_OPCODE_PONG; + infof(data, "WS: send OPCODE PONG"); + } + else { + opcode = WSBIT_OPCODE_BIN; + infof(data, "WS: send OPCODE BINARY"); + } + + if(!(flags & CURLWS_CONT)) { + /* if not marked as continuing, assume this is the final fragment */ + firstbyte |= WSBIT_FIN | opcode; + ws->ws.contfragment = FALSE; + } + else if(ws->ws.contfragment) { + /* the previous fragment was not a final one and this isn't either, keep a + CONT opcode and no FIN bit */ + firstbyte |= WSBIT_OPCODE_CONT; + } + else { + ws->ws.contfragment = TRUE; + } + out[0] = firstbyte; + if(len > 65535) { + out[1] = 127 | WSBIT_MASK; + out[2] = (len >> 8) & 0xff; + out[3] = len & 0xff; + outi = 10; + } + else if(len > 126) { + out[1] = 126 | WSBIT_MASK; + out[2] = (len >> 8) & 0xff; + out[3] = len & 0xff; + outi = 4; + } + else { + out[1] = (unsigned char)len | WSBIT_MASK; + outi = 2; + } + + infof(data, "WS: send FIN bit %u (byte %02x)", + firstbyte & WSBIT_FIN ? 1 : 0, + firstbyte); + infof(data, "WS: send payload len %u", (int)len); + + /* 4 bytes mask */ + memcpy(&out[outi], &ws->ws.mask, 4); + + if(data->set.upload_buffer_size < (len + 10)) + return 0; + + /* pass over the mask */ + outi += 4; + + ws->ws.xori = 0; + /* return packet size */ + return outi; +} + +CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer, + size_t buflen, size_t *sent, + curl_off_t totalsize, + unsigned int sendflags) +{ + CURLcode result; + size_t headlen; + char *out; + ssize_t written; + struct websocket *wsp = &data->req.p.http->ws; + + if(!data->set.ws_raw_mode) { + result = Curl_get_upload_buffer(data); + if(result) + return result; + } + else { + if(totalsize || sendflags) + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + if(data->set.ws_raw_mode) { + if(!buflen) + /* nothing to do */ + return CURLE_OK; + /* raw mode sends exactly what was requested, and this is from within + the write callback */ + if(Curl_is_in_callback(data)) + result = Curl_write(data, data->conn->writesockfd, buffer, buflen, + &written); + else + result = Curl_senddata(data, buffer, buflen, &written); + + infof(data, "WS: wanted to send %zu bytes, sent %zu bytes", + buflen, written); + *sent = written; + return result; + } + + if(buflen > (data->set.upload_buffer_size - 10)) + /* don't do more than this in one go */ + buflen = data->set.upload_buffer_size - 10; + + if(sendflags & CURLWS_OFFSET) { + if(totalsize) { + /* a frame series 'totalsize' bytes big, this is the first */ + headlen = ws_packethead(data, totalsize, sendflags); + wsp->sleft = totalsize - buflen; + } + else { + headlen = 0; + if((curl_off_t)buflen > wsp->sleft) { + infof(data, "WS: unaligned frame size (sending %zu instead of %zu)", + buflen, wsp->sleft); + wsp->sleft = 0; + } + else + wsp->sleft -= buflen; + } + } + else + headlen = ws_packethead(data, buflen, sendflags); + + /* headlen is the size of the frame header */ + out = data->state.ulbuf; + if(buflen) + /* for PING and PONG etc there might not be a payload */ + ws_xor(data, buffer, (unsigned char *)out + headlen, buflen); + + if(data->set.connect_only) + result = Curl_senddata(data, out, buflen + headlen, &written); + else + result = Curl_write(data, data->conn->writesockfd, out, + buflen + headlen, &written); + + infof(data, "WS: wanted to send %zu bytes, sent %zu bytes", + headlen + buflen, written); + *sent = written; + + return result; +} + +void Curl_ws_done(struct Curl_easy *data) +{ + struct websocket *wsp = &data->req.p.http->ws; + DEBUGASSERT(wsp); + Curl_dyn_free(&wsp->buf); +} + +CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) +{ + /* we only return something for websocket, called from within the callback + when not using raw mode */ + if(GOOD_EASY_HANDLE(data) && Curl_is_in_callback(data) && data->req.p.http && + !data->set.ws_raw_mode) + return &data->req.p.http->ws.frame; + return NULL; +} + +#else + +CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, + size_t *nread, + struct curl_ws_frame **metap) +{ + (void)curl; + (void)buffer; + (void)buflen; + (void)nread; + (void)metap; + return CURLE_OK; +} + +CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, + size_t buflen, size_t *sent, + curl_off_t framesize, + unsigned int sendflags) +{ + (void)curl; + (void)buffer; + (void)buflen; + (void)sent; + (void)framesize; + (void)sendflags; + return CURLE_OK; +} + +CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) +{ + (void)data; + return NULL; +} +#endif /* USE_WEBSOCKETS */ diff --git a/contrib/libs/curl/lib/ws.h b/contrib/libs/curl/lib/ws.h new file mode 100644 index 0000000000..341242e50e --- /dev/null +++ b/contrib/libs/curl/lib/ws.h @@ -0,0 +1,69 @@ +#ifndef HEADER_CURL_WS_H +#define HEADER_CURL_WS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_WEBSOCKETS + +#ifdef USE_HYPER +#define REQTYPE void +#else +#define REQTYPE struct dynbuf +#endif + +/* this is the largest single fragment size we support */ +#define MAX_WS_SIZE 65535 + +/* part of 'struct HTTP', when used in the 'struct SingleRequest' in the + Curl_easy struct */ +struct websocket { + bool contfragment; /* set TRUE if the previous fragment sent was not final */ + unsigned char mask[4]; /* 32 bit mask for this connection */ + struct Curl_easy *data; /* used for write callback handling */ + struct dynbuf buf; + size_t usedbuf; /* number of leading bytes in 'buf' the most recent complete + websocket frame uses */ + struct curl_ws_frame frame; /* the struct used for frame state */ + curl_off_t oleft; /* outstanding number of payload bytes left from the + server */ + curl_off_t stillbuffer; /* number of bytes left in the buffer to deliver in + the next curl_ws_recv() call */ + char *stillb; /* the stillbuffer pending bytes are here */ + curl_off_t sleft; /* outstanding number of payload bytes left to send */ + unsigned int xori; /* xor index */ +}; + +CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req); +CURLcode Curl_ws_accept(struct Curl_easy *data); + +size_t Curl_ws_writecb(char *buffer, size_t size, size_t nitems, void *userp); +void Curl_ws_done(struct Curl_easy *data); + +#else +#define Curl_ws_request(x,y) CURLE_OK +#define Curl_ws_done(x) Curl_nop_stmt +#endif + +#endif /* HEADER_CURL_WS_H */ diff --git a/contrib/libs/curl/src/tool_cb_hdr.c b/contrib/libs/curl/src/tool_cb_hdr.c index 64b2bb212f..23700de222 100644 --- a/contrib/libs/curl/src/tool_cb_hdr.c +++ b/contrib/libs/curl/src/tool_cb_hdr.c @@ -35,6 +35,7 @@ #include "tool_cb_hdr.h" #include "tool_cb_wrt.h" #include "tool_operate.h" +#include "tool_libinfo.h" #include "memdebug.h" /* keep this as LAST include */ @@ -74,7 +75,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) const char *str = ptr; const size_t cb = size * nmemb; const char *end = (char *)ptr + cb; - long protocol = 0; + const char *scheme = NULL; /* * Once that libcurl has called back tool_header_cb() the returned value @@ -116,7 +117,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) const char *etag_h = &str[5]; const char *eot = end - 1; if(*eot == '\n') { - while(ISSPACE(*etag_h) && (etag_h < eot)) + while(ISBLANK(*etag_h) && (etag_h < eot)) etag_h++; while(ISSPACE(*eot)) eot--; @@ -139,10 +140,11 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) * Content-Disposition header specifying a filename property. */ - curl_easy_getinfo(per->curl, CURLINFO_PROTOCOL, &protocol); + curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme); + scheme = proto_token(scheme); if(hdrcbdata->honor_cd_filename && (cb > 20) && checkprefix("Content-disposition:", str) && - (protocol & (CURLPROTO_HTTPS|CURLPROTO_HTTP))) { + (scheme == proto_http || scheme == proto_https)) { const char *p = str + 20; /* look for the 'filename=' parameter @@ -202,8 +204,8 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) per->was_last_header_empty = TRUE; } if(hdrcbdata->config->show_headers && - (protocol & - (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_RTSP|CURLPROTO_FILE))) { + (scheme == proto_http || scheme == proto_https || + scheme == proto_rtsp || scheme == proto_file)) { /* bold headers only for selected protocols */ char *value = NULL; diff --git a/contrib/libs/curl/src/tool_cfgable.h b/contrib/libs/curl/src/tool_cfgable.h index ec26eebf60..c26cddd5e0 100644 --- a/contrib/libs/curl/src/tool_cfgable.h +++ b/contrib/libs/curl/src/tool_cfgable.h @@ -267,7 +267,6 @@ struct OperationConfig { certificate for authentication (Schannel) */ bool proxy_ssl_auto_client_cert; /* proxy version of ssl_auto_client_cert */ char *oauth_bearer; /* OAuth 2.0 bearer token */ - bool nonpn; /* enable/disable TLS NPN extension */ bool noalpn; /* enable/disable TLS ALPN extension */ char *unix_socket_path; /* path to Unix domain socket */ bool abstract_unix_socket; /* path to an abstract Unix domain socket */ diff --git a/contrib/libs/curl/src/tool_easysrc.h b/contrib/libs/curl/src/tool_easysrc.h index d7a629aca7..ec2fdd23f0 100644 --- a/contrib/libs/curl/src/tool_easysrc.h +++ b/contrib/libs/curl/src/tool_easysrc.h @@ -46,6 +46,13 @@ extern CURLcode easysrc_cleanup(void); void dumpeasysrc(struct GlobalConfig *config); +#else /* CURL_DISABLE_LIBCURL_OPTION is defined */ + +#define easysrc_init() CURLE_OK +#define easysrc_cleanup() +#define dumpeasysrc(x) +#define easysrc_perform(x) CURLE_OK + #endif /* CURL_DISABLE_LIBCURL_OPTION */ #endif /* HEADER_CURL_TOOL_EASYSRC_H */ diff --git a/contrib/libs/curl/src/tool_formparse.c b/contrib/libs/curl/src/tool_formparse.c index 927d3c1492..d4fc651e25 100644 --- a/contrib/libs/curl/src/tool_formparse.c +++ b/contrib/libs/curl/src/tool_formparse.c @@ -38,10 +38,6 @@ #include "memdebug.h" /* keep this as LAST include */ -/* Macros to free const pointers. */ -#define CONST_FREE(x) free((void *) (x)) -#define CONST_SAFEFREE(x) Curl_safefree(*((void **) &(x))) - /* tool_mime functions. */ static struct tool_mime *tool_mime_new(struct tool_mime *parent, toolmimekind kind) @@ -65,7 +61,7 @@ static struct tool_mime *tool_mime_new_parts(struct tool_mime *parent) } static struct tool_mime *tool_mime_new_data(struct tool_mime *parent, - const char *data) + char *data) { struct tool_mime *m = NULL; @@ -73,7 +69,7 @@ static struct tool_mime *tool_mime_new_data(struct tool_mime *parent, if(data) { m = tool_mime_new(parent, TOOLMIME_DATA); if(!m) - CONST_FREE(data); + free(data); else m->data = data; } @@ -91,13 +87,13 @@ static struct tool_mime *tool_mime_new_filedata(struct tool_mime *parent, *errcode = CURLE_OUT_OF_MEMORY; if(strcmp(filename, "-")) { /* This is a normal file. */ - filename = strdup(filename); - if(filename) { + char *filedup = strdup(filename); + if(filedup) { m = tool_mime_new(parent, TOOLMIME_FILE); if(!m) - CONST_FREE(filename); + free(filedup); else { - m->data = filename; + m->data = filedup; if(!isremotefile) m->kind = TOOLMIME_FILEDATA; *errcode = CURLE_OK; @@ -168,11 +164,11 @@ void tool_mime_free(struct tool_mime *mime) tool_mime_free(mime->subparts); if(mime->prev) tool_mime_free(mime->prev); - CONST_SAFEFREE(mime->name); - CONST_SAFEFREE(mime->filename); - CONST_SAFEFREE(mime->type); - CONST_SAFEFREE(mime->encoder); - CONST_SAFEFREE(mime->data); + Curl_safefree(mime->name); + Curl_safefree(mime->filename); + Curl_safefree(mime->type); + Curl_safefree(mime->encoder); + Curl_safefree(mime->data); curl_slist_free_all(mime->headers); free(mime); } @@ -499,7 +495,7 @@ static int get_param_part(struct OperationConfig *config, char endchar, sep = *p; *endpos = '\0'; while(sep == ';') { - while(ISSPACE(*++p)) + while(p++ && ISSPACE(*p)) ; if(!endct && checkprefix("type=", p)) { @@ -709,24 +705,15 @@ static int get_param_part(struct OperationConfig *config, char endchar, * ***************************************************************************/ -/* Convenience macros for null pointer check. */ -#define NULL_CHECK(ptr, init, retcode) \ +#define SET_TOOL_MIME_PTR(m, field) \ do { \ - (ptr) = (init); \ - if(!(ptr)) { \ - warnf(config->global, "out of memory!\n"); \ - curl_slist_free_all(headers); \ - Curl_safefree(contents); \ - return retcode; \ + if(field) { \ + (m)->field = strdup(field); \ + if(!(m)->field) \ + goto fail; \ } \ } while(0) -#define SET_TOOL_MIME_PTR(m, field, retcode) \ - do { \ - if(field) \ - NULL_CHECK((m)->field, strdup(field), retcode); \ - } while(0) - int formparse(struct OperationConfig *config, const char *input, struct tool_mime **mimeroot, @@ -745,15 +732,20 @@ int formparse(struct OperationConfig *config, struct curl_slist *headers = NULL; struct tool_mime *part = NULL; CURLcode res; + int err = 1; /* Allocate the main mime structure if needed. */ if(!*mimecurrent) { - NULL_CHECK(*mimeroot, tool_mime_new_parts(NULL), 1); + *mimeroot = tool_mime_new_parts(NULL); + if(!*mimeroot) + goto fail; *mimecurrent = *mimeroot; } /* Make a copy we can overwrite. */ - NULL_CHECK(contents, strdup(input), 2); + contents = strdup(input); + if(!contents) + goto fail; /* Scan for the end of the name. */ contp = strchr(contents, '='); @@ -767,23 +759,22 @@ int formparse(struct OperationConfig *config, /* Starting a multipart. */ sep = get_param_part(config, '\0', &contp, &data, &type, NULL, NULL, &headers); - if(sep < 0) { - Curl_safefree(contents); - return 3; - } - NULL_CHECK(part, tool_mime_new_parts(*mimecurrent), 4); + if(sep < 0) + goto fail; + part = tool_mime_new_parts(*mimecurrent); + if(!part) + goto fail; *mimecurrent = part; part->headers = headers; headers = NULL; - SET_TOOL_MIME_PTR(part, type, 5); + SET_TOOL_MIME_PTR(part, type); } else if(!name && !strcmp(contp, ")") && !literal_value) { /* Ending a multipart. */ if(*mimecurrent == *mimeroot) { warnf(config->global, "no multipart to terminate!\n"); - Curl_safefree(contents); - return 6; - } + goto fail; + } *mimecurrent = (*mimecurrent)->parent; } else if('@' == contp[0] && !literal_value) { @@ -799,8 +790,7 @@ int formparse(struct OperationConfig *config, sep = get_param_part(config, ',', &contp, &data, &type, &filename, &encoder, &headers); if(sep < 0) { - Curl_safefree(contents); - return 7; + goto fail; } /* now contp point to comma or string end. @@ -808,13 +798,17 @@ int formparse(struct OperationConfig *config, if(!subparts) { if(sep != ',') /* If there is a single file. */ subparts = *mimecurrent; - else - NULL_CHECK(subparts, tool_mime_new_parts(*mimecurrent), 8); + else { + subparts = tool_mime_new_parts(*mimecurrent); + if(!subparts) + goto fail; + } } /* Store that file in a part. */ - NULL_CHECK(part, - tool_mime_new_filedata(subparts, data, TRUE, &res), 9); + part = tool_mime_new_filedata(subparts, data, TRUE, &res); + if(!part) + goto fail; part->headers = headers; headers = NULL; part->config = config->global; @@ -825,17 +819,16 @@ int formparse(struct OperationConfig *config, if(part->size > 0) { warnf(config->global, "error while reading standard input\n"); - Curl_safefree(contents); - return 10; + goto fail; } - CONST_SAFEFREE(part->data); + Curl_safefree(part->data); part->data = NULL; part->size = -1; res = CURLE_OK; } - SET_TOOL_MIME_PTR(part, filename, 11); - SET_TOOL_MIME_PTR(part, type, 12); - SET_TOOL_MIME_PTR(part, encoder, 13); + SET_TOOL_MIME_PTR(part, filename); + SET_TOOL_MIME_PTR(part, type); + SET_TOOL_MIME_PTR(part, encoder); /* *contp could be '\0', so we just check with the delimiter */ } while(sep); /* loop if there's another file name */ @@ -846,13 +839,13 @@ int formparse(struct OperationConfig *config, ++contp; sep = get_param_part(config, '\0', &contp, &data, &type, NULL, &encoder, &headers); - if(sep < 0) { - Curl_safefree(contents); - return 14; - } + if(sep < 0) + goto fail; - NULL_CHECK(part, tool_mime_new_filedata(*mimecurrent, data, FALSE, - &res), 15); + part = tool_mime_new_filedata(*mimecurrent, data, FALSE, + &res); + if(!part) + goto fail; part->headers = headers; headers = NULL; part->config = config->global; @@ -863,10 +856,9 @@ int formparse(struct OperationConfig *config, if(part->size > 0) { warnf(config->global, "error while reading standard input\n"); - Curl_safefree(contents); - return 16; + goto fail; } - CONST_SAFEFREE(part->data); + Curl_safefree(part->data); part->data = NULL; part->size = -1; res = CURLE_OK; @@ -878,20 +870,20 @@ int formparse(struct OperationConfig *config, else { sep = get_param_part(config, '\0', &contp, &data, &type, &filename, &encoder, &headers); - if(sep < 0) { - Curl_safefree(contents); - return 17; - } + if(sep < 0) + goto fail; } - NULL_CHECK(part, tool_mime_new_data(*mimecurrent, data), 18); + part = tool_mime_new_data(*mimecurrent, data); + if(!part) + goto fail; part->headers = headers; headers = NULL; } - SET_TOOL_MIME_PTR(part, filename, 19); - SET_TOOL_MIME_PTR(part, type, 20); - SET_TOOL_MIME_PTR(part, encoder, 21); + SET_TOOL_MIME_PTR(part, filename); + SET_TOOL_MIME_PTR(part, type); + SET_TOOL_MIME_PTR(part, encoder); if(sep) { *contp = (char) sep; @@ -901,13 +893,15 @@ int formparse(struct OperationConfig *config, } /* Set part name. */ - SET_TOOL_MIME_PTR(part, name, 22); + SET_TOOL_MIME_PTR(part, name); } else { warnf(config->global, "Illegally formatted input field!\n"); - Curl_safefree(contents); - return 23; + goto fail; } + err = 0; + fail: Curl_safefree(contents); - return 0; + curl_slist_free_all(headers); + return err; } diff --git a/contrib/libs/curl/src/tool_formparse.h b/contrib/libs/curl/src/tool_formparse.h index 260bcf48f0..8c0461c69e 100644 --- a/contrib/libs/curl/src/tool_formparse.h +++ b/contrib/libs/curl/src/tool_formparse.h @@ -43,11 +43,11 @@ struct tool_mime { struct tool_mime *parent; /* Parent item. */ struct tool_mime *prev; /* Previous sibling (reverse order link). */ /* Common fields. */ - const char *data; /* Actual data or data filename. */ - const char *name; /* Part name. */ - const char *filename; /* Part's filename. */ - const char *type; /* Part's mime type. */ - const char *encoder; /* Part's requested encoding. */ + char *data; /* Actual data or data filename. */ + char *name; /* Part name. */ + char *filename; /* Part's filename. */ + char *type; /* Part's mime type. */ + char *encoder; /* Part's requested encoding. */ struct curl_slist *headers; /* User-defined headers. */ /* TOOLMIME_PARTS fields. */ struct tool_mime *subparts; /* Part's subparts. */ diff --git a/contrib/libs/curl/src/tool_getparam.c b/contrib/libs/curl/src/tool_getparam.c index e6c6a273da..af4b3a6984 100644 --- a/contrib/libs/curl/src/tool_getparam.c +++ b/contrib/libs/curl/src/tool_getparam.c @@ -556,6 +556,106 @@ static void cleanarg(argv_item_t str) #define cleanarg(x) #endif +/* --data-urlencode */ +static ParameterError data_urlencode(struct GlobalConfig *global, + char *nextarg, + char **postp, + size_t *lenp) +{ + /* [name]=[content], we encode the content part only + * [name]@[file name] + * + * Case 2: we first load the file using that name and then encode + * the content. + */ + ParameterError err; + const char *p = strchr(nextarg, '='); + size_t nlen; + char is_file; + char *postdata = NULL; + size_t size = 0; + if(!p) + /* there was no '=' letter, check for a '@' instead */ + p = strchr(nextarg, '@'); + if(p) { + nlen = p - nextarg; /* length of the name part */ + is_file = *p++; /* pass the separator */ + } + else { + /* neither @ nor =, so no name and it isn't a file */ + nlen = is_file = 0; + p = nextarg; + } + if('@' == is_file) { + FILE *file; + /* a '@' letter, it means that a file name or - (stdin) follows */ + if(!strcmp("-", p)) { + file = stdin; + set_binmode(stdin); + } + else { + file = fopen(p, "rb"); + if(!file) + warnf(global, + "Couldn't read data from file \"%s\", this makes " + "an empty POST.\n", nextarg); + } + + err = file2memory(&postdata, &size, file); + + if(file && (file != stdin)) + fclose(file); + if(err) + return err; + } + else { + GetStr(&postdata, p); + if(postdata) + size = strlen(postdata); + } + + if(!postdata) { + /* no data from the file, point to a zero byte string to make this + get sent as a POST anyway */ + postdata = strdup(""); + if(!postdata) + return PARAM_NO_MEM; + size = 0; + } + else { + char *enc = curl_easy_escape(NULL, postdata, (int)size); + Curl_safefree(postdata); /* no matter if it worked or not */ + if(enc) { + /* replace (in-place) '%20' by '+' according to RFC1866 */ + size_t enclen = replace_url_encoded_space_by_plus(enc); + /* now make a string with the name from above and append the + encoded string */ + size_t outlen = nlen + enclen + 2; + char *n = malloc(outlen); + if(!n) { + curl_free(enc); + return PARAM_NO_MEM; + } + if(nlen > 0) { /* only append '=' if we have a name */ + msnprintf(n, outlen, "%.*s=%s", (int)nlen, nextarg, enc); + size = outlen-1; + } + else { + strcpy(n, enc); + size = outlen-2; /* since no '=' was inserted */ + } + curl_free(enc); + postdata = n; + } + else + return PARAM_NO_MEM; + } + *postp = postdata; + *lenp = size; + return PARAM_OK; +} + + ParameterError getparameter(const char *flag, /* f or -long-flag */ char *nextarg, /* NULL if unset */ bool *usedarg, /* set to TRUE if the arg @@ -578,6 +678,15 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ #ifdef HAVE_WRITABLE_ARGV argv_item_t clearthis = NULL; #endif + + static const char *redir_protos[] = { + "http", + "https", + "ftp", + "ftps", + NULL + }; + *usedarg = FALSE; /* default is that we don't use the arg */ if(('-' != flag[0]) || ('-' == flag[1])) { @@ -699,7 +808,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ break; case 'c': /* connect-timeout */ err = str2udouble(&config->connecttimeout, nextarg, - LONG_MAX/1000); + (double)LONG_MAX/1000); if(err) return err; break; @@ -740,7 +849,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ global->tracetype = TRACE_BIN; break; case 'G': /* --npn */ - config->nonpn = (!toggle)?TRUE:FALSE; + warnf(global, "--npn is no longer supported\n"); break; case 'h': /* --trace-ascii */ GetStr(&global->trace_dump, nextarg); @@ -1007,6 +1116,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) return PARAM_LIBCURL_DOESNT_SUPPORT; config->ftp_ssl = toggle; + if(config->ftp_ssl) + warnf(global, + "--ssl is an insecure option, consider --ssl-reqd instead\n"); break; case 'b': /* --ftp-pasv */ Curl_safefree(config->ftpport); @@ -1206,16 +1318,13 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ break; case 'D': /* --proto */ config->proto_present = TRUE; - err = proto2num(config, (unsigned int)CURLPROTO_ALL, - &config->proto_str, nextarg); + err = proto2num(config, built_in_protos, &config->proto_str, nextarg); if(err) return err; break; case 'E': /* --proto-redir */ config->proto_redir_present = TRUE; - if(proto2num(config, CURLPROTO_HTTP|CURLPROTO_HTTPS| - CURLPROTO_FTP|CURLPROTO_FTPS, - &config->proto_redir_str, nextarg)) + if(proto2num(config, redir_protos, &config->proto_redir_str, nextarg)) return PARAM_BAD_USE; break; case 'F': /* --resolve */ @@ -1265,7 +1374,8 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ return err; break; case 'R': /* --expect100-timeout */ - err = str2udouble(&config->expect100timeout, nextarg, LONG_MAX/1000); + err = str2udouble(&config->expect100timeout, nextarg, + (double)LONG_MAX/1000); if(err) return err; break; @@ -1460,90 +1570,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ bool raw_mode = (subletter == 'r'); if(subletter == 'e') { /* --data-urlencode */ - /* [name]=[content], we encode the content part only - * [name]@[file name] - * - * Case 2: we first load the file using that name and then encode - * the content. - */ - const char *p = strchr(nextarg, '='); - size_t nlen; - char is_file; - if(!p) - /* there was no '=' letter, check for a '@' instead */ - p = strchr(nextarg, '@'); - if(p) { - nlen = p - nextarg; /* length of the name part */ - is_file = *p++; /* pass the separator */ - } - else { - /* neither @ nor =, so no name and it isn't a file */ - nlen = is_file = 0; - p = nextarg; - } - if('@' == is_file) { - /* a '@' letter, it means that a file name or - (stdin) follows */ - if(!strcmp("-", p)) { - file = stdin; - set_binmode(stdin); - } - else { - file = fopen(p, "rb"); - if(!file) - warnf(global, - "Couldn't read data from file \"%s\", this makes " - "an empty POST.\n", nextarg); - } - - err = file2memory(&postdata, &size, file); - - if(file && (file != stdin)) - fclose(file); - if(err) - return err; - } - else { - GetStr(&postdata, p); - if(postdata) - size = strlen(postdata); - } - - if(!postdata) { - /* no data from the file, point to a zero byte string to make this - get sent as a POST anyway */ - postdata = strdup(""); - if(!postdata) - return PARAM_NO_MEM; - size = 0; - } - else { - char *enc = curl_easy_escape(NULL, postdata, (int)size); - Curl_safefree(postdata); /* no matter if it worked or not */ - if(enc) { - /* replace (in-place) '%20' by '+' according to RFC1866 */ - size_t enclen = replace_url_encoded_space_by_plus(enc); - /* now make a string with the name from above and append the - encoded string */ - size_t outlen = nlen + enclen + 2; - char *n = malloc(outlen); - if(!n) { - curl_free(enc); - return PARAM_NO_MEM; - } - if(nlen > 0) { /* only append '=' if we have a name */ - msnprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc); - size = outlen-1; - } - else { - strcpy(n, enc); - size = outlen-2; /* since no '=' was inserted */ - } - curl_free(enc); - postdata = n; - } - else - return PARAM_NO_MEM; - } + err = data_urlencode(global, nextarg, &postdata, &size); + if(err) + return err; } else if('@' == *nextarg && !raw_mode) { /* the data begins with a '@' letter, it means that a file name @@ -2039,19 +2068,17 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ break; case 'm': /* specified max time */ - err = str2udouble(&config->timeout, nextarg, LONG_MAX/1000); + err = str2udouble(&config->timeout, nextarg, (double)LONG_MAX/1000); if(err) return err; break; case 'M': /* M for manual, huge help */ if(toggle) { /* --no-manual shows no manual... */ -#ifdef USE_MANUAL - return PARAM_MANUAL_REQUESTED; -#else +#ifndef USE_MANUAL warnf(global, "built-in manual was disabled at build-time!\n"); - return PARAM_OPTION_UNKNOWN; #endif + return PARAM_MANUAL_REQUESTED; } break; case 'n': diff --git a/contrib/libs/curl/src/tool_help.c b/contrib/libs/curl/src/tool_help.c index 75400d94c1..65a1f43dfa 100644 --- a/contrib/libs/curl/src/tool_help.c +++ b/contrib/libs/curl/src/tool_help.c @@ -22,9 +22,6 @@ * ***************************************************************************/ #include "tool_setup.h" -#if defined(HAVE_STRCASECMP) && defined(HAVE_STRINGS_H) -#include <strings.h> -#endif #define ENABLE_CURLX_PRINTF /* use our own printf() functions */ #include "curlx.h" @@ -32,6 +29,7 @@ #include "tool_panykey.h" #include "tool_help.h" #include "tool_libinfo.h" +#include "tool_util.h" #include "tool_version.h" #include "memdebug.h" /* keep this as LAST include */ @@ -190,22 +188,6 @@ void tool_help(char *category) free(category); } -static int -featcomp(const void *p1, const void *p2) -{ - /* The arguments to this function are "pointers to pointers to char", but - the comparison arguments are "pointers to char", hence the following cast - plus dereference */ -#ifdef HAVE_STRCASECMP - return strcasecmp(* (char * const *) p1, * (char * const *) p2); -#elif defined(HAVE_STRCMPI) - return strcmpi(* (char * const *) p1, * (char * const *) p2); -#elif defined(HAVE_STRICMP) - return stricmp(* (char * const *) p1, * (char * const *) p2); -#else - return strcmp(* (char * const *) p1, * (char * const *) p2); -#endif -} void tool_version_info(void) { @@ -221,7 +203,10 @@ void tool_version_info(void) if(curlinfo->protocols) { printf("Protocols: "); for(proto = curlinfo->protocols; *proto; ++proto) { - printf("%s ", *proto); + /* Special case: do not list rtmp?* protocols. + They may only appear together with "rtmp" */ + if(!curl_strnequal(*proto, "rtmp", 4) || !proto[0][4]) + printf("%s ", *proto); } puts(""); /* newline */ } @@ -234,7 +219,7 @@ void tool_version_info(void) if(curlinfo->features & feats[i].bitmask) featp[numfeat++] = (char *)feats[i].name; } - qsort(&featp[0], numfeat, sizeof(char *), featcomp); + qsort(&featp[0], numfeat, sizeof(char *), struplocompare4sort); for(i = 0; i< numfeat; i++) printf(" %s", featp[i]); puts(""); /* newline */ diff --git a/contrib/libs/curl/src/tool_hugehelp.c b/contrib/libs/curl/src/tool_hugehelp.c index bc33e2f143..578968b8cb 100644 --- a/contrib/libs/curl/src/tool_hugehelp.c +++ b/contrib/libs/curl/src/tool_hugehelp.c @@ -1,3 +1 @@ -/* built-in manual is disabled, blank function */ #include "tool_hugehelp.h" -void hugehelp(void) {} diff --git a/contrib/libs/curl/src/tool_hugehelp.h b/contrib/libs/curl/src/tool_hugehelp.h index 9d1028094f..d5880ac251 100644 --- a/contrib/libs/curl/src/tool_hugehelp.h +++ b/contrib/libs/curl/src/tool_hugehelp.h @@ -25,6 +25,11 @@ ***************************************************************************/ #include "tool_setup.h" +#ifdef USE_MANUAL void hugehelp(void); +#else +/* do nothing if not there */ +#define hugehelp() +#endif #endif /* HEADER_CURL_TOOL_HUGEHELP_H */ diff --git a/contrib/libs/curl/src/tool_libinfo.c b/contrib/libs/curl/src/tool_libinfo.c index 039443e239..801fd579f3 100644 --- a/contrib/libs/curl/src/tool_libinfo.c +++ b/contrib/libs/curl/src/tool_libinfo.c @@ -35,85 +35,90 @@ /* global variable definitions, for libcurl run-time info */ +static const char *no_protos = NULL; + curl_version_info_data *curlinfo = NULL; -long built_in_protos = 0; +const char * const *built_in_protos = &no_protos; + +size_t proto_count = 0; + +const char *proto_file = NULL; +const char *proto_ftp = NULL; +const char *proto_ftps = NULL; +const char *proto_http = NULL; +const char *proto_https = NULL; +const char *proto_rtsp = NULL; +const char *proto_scp = NULL; +const char *proto_sftp = NULL; +const char *proto_tftp = NULL; -static struct proto_name_pattern { - const char *proto_name; - long proto_pattern; +static struct proto_name_tokenp { + const char *proto_name; + const char **proto_tokenp; } const possibly_built_in[] = { - { "dict", CURLPROTO_DICT }, - { "file", CURLPROTO_FILE }, - { "ftp", CURLPROTO_FTP }, - { "ftps", CURLPROTO_FTPS }, - { "gopher", CURLPROTO_GOPHER }, - { "gophers",CURLPROTO_GOPHERS}, - { "http", CURLPROTO_HTTP }, - { "https", CURLPROTO_HTTPS }, - { "imap", CURLPROTO_IMAP }, - { "imaps", CURLPROTO_IMAPS }, - { "ldap", CURLPROTO_LDAP }, - { "ldaps", CURLPROTO_LDAPS }, - { "mqtt", CURLPROTO_MQTT }, - { "pop3", CURLPROTO_POP3 }, - { "pop3s", CURLPROTO_POP3S }, - { "rtmp", CURLPROTO_RTMP }, - { "rtmps", CURLPROTO_RTMPS }, - { "rtsp", CURLPROTO_RTSP }, - { "scp", CURLPROTO_SCP }, - { "sftp", CURLPROTO_SFTP }, - { "smb", CURLPROTO_SMB }, - { "smbs", CURLPROTO_SMBS }, - { "smtp", CURLPROTO_SMTP }, - { "smtps", CURLPROTO_SMTPS }, - { "telnet", CURLPROTO_TELNET }, - { "tftp", CURLPROTO_TFTP }, - { NULL, 0 } + { "file", &proto_file }, + { "ftp", &proto_ftp }, + { "ftps", &proto_ftps }, + { "http", &proto_http }, + { "https", &proto_https }, + { "rtsp", &proto_rtsp }, + { "scp", &proto_scp }, + { "sftp", &proto_sftp }, + { "tftp", &proto_tftp }, + { NULL, NULL } }; /* * libcurl_info_init: retrieves run-time information about libcurl, * setting a global pointer 'curlinfo' to libcurl's run-time info - * struct, and a global bit pattern 'built_in_protos' composed of - * CURLPROTO_* bits indicating which protocols are actually built - * into library being used. + * struct, count protocols and flag those we are interested in. */ CURLcode get_libcurl_info(void) { - const char *const *proto; + CURLcode result = CURLE_OK; /* Pointer to libcurl's run-time version information */ curlinfo = curl_version_info(CURLVERSION_NOW); if(!curlinfo) return CURLE_FAILED_INIT; - /* Build CURLPROTO_* bit pattern with libcurl's built-in protocols */ - built_in_protos = 0; if(curlinfo->protocols) { - for(proto = curlinfo->protocols; *proto; proto++) { - struct proto_name_pattern const *p; - for(p = possibly_built_in; p->proto_name; p++) { - if(curl_strequal(*proto, p->proto_name)) { - built_in_protos |= p->proto_pattern; + const char *const *builtin; + const struct proto_name_tokenp *p; + + built_in_protos = curlinfo->protocols; + + for(builtin = built_in_protos; !result && *builtin; builtin++) { + /* Identify protocols we are interested in. */ + for(p = possibly_built_in; p->proto_name; p++) + if(curl_strequal(p->proto_name, *builtin)) { + *p->proto_tokenp = *builtin; break; } - } } + proto_count = builtin - built_in_protos; } return CURLE_OK; } -/* - * scheme2protocol() returns the protocol bit for the specified URL scheme +/* Tokenize a protocol name. + * Return the address of the protocol name listed by the library, or NULL if + * not found. + * Although this may seem useless, this always returns the same address for + * a given protocol and thus allows comparing pointers rather than strings. + * In addition, the returned pointer is not deallocated until the program ends. */ -long scheme2protocol(const char *scheme) + +const char *proto_token(const char *proto) { - struct proto_name_pattern const *p; - for(p = possibly_built_in; p->proto_name; p++) { - if(curl_strequal(scheme, p->proto_name)) - return p->proto_pattern; - } - return 0; + const char * const *builtin; + + if(!proto) + return NULL; + for(builtin = built_in_protos; *builtin; builtin++) + if(curl_strequal(*builtin, proto)) + break; + return *builtin; } diff --git a/contrib/libs/curl/src/tool_libinfo.h b/contrib/libs/curl/src/tool_libinfo.h index ba6fc0ec1b..40e5aff3ee 100644 --- a/contrib/libs/curl/src/tool_libinfo.h +++ b/contrib/libs/curl/src/tool_libinfo.h @@ -27,10 +27,22 @@ /* global variable declarations, for libcurl run-time info */ + extern curl_version_info_data *curlinfo; -extern long built_in_protos; +extern const char * const *built_in_protos; +extern size_t proto_count; + +extern const char *proto_file; +extern const char *proto_ftp; +extern const char *proto_ftps; +extern const char *proto_http; +extern const char *proto_https; +extern const char *proto_rtsp; +extern const char *proto_scp; +extern const char *proto_sftp; +extern const char *proto_tftp; CURLcode get_libcurl_info(void); -long scheme2protocol(const char *scheme); +const char *proto_token(const char *proto); #endif /* HEADER_CURL_TOOL_LIBINFO_H */ diff --git a/contrib/libs/curl/src/tool_listhelp.c b/contrib/libs/curl/src/tool_listhelp.c index f3217be619..6a2d10fb69 100644 --- a/contrib/libs/curl/src/tool_listhelp.c +++ b/contrib/libs/curl/src/tool_listhelp.c @@ -251,7 +251,7 @@ const struct helptxt helptext[] = { CURLHELP_HTTP | CURLHELP_FTP | CURLHELP_FILE}, {"-H, --header <header/@file>", "Pass custom header(s) to server", - CURLHELP_HTTP}, + CURLHELP_HTTP | CURLHELP_IMAP | CURLHELP_SMTP}, {"-h, --help <category>", "Get help for commands", CURLHELP_IMPORTANT | CURLHELP_CURL}, diff --git a/contrib/libs/curl/src/tool_main.c b/contrib/libs/curl/src/tool_main.c index 7b6815f635..84bc679b53 100644 --- a/contrib/libs/curl/src/tool_main.c +++ b/contrib/libs/curl/src/tool_main.c @@ -33,6 +33,10 @@ #include <signal.h> #endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + #ifdef USE_NSS #include <nspr.h> #error #include <plarenas.h> @@ -80,29 +84,30 @@ int _CRT_glob = 0; /* if we build a static library for unit tests, there is no main() function */ #ifndef UNITTESTS +#if defined(HAVE_PIPE) && defined(HAVE_FCNTL) /* * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are * open before starting to run. Otherwise, the first three network * sockets opened by curl could be used for input sources, downloaded data * or error logs as they will effectively be stdin, stdout and/or stderr. + * + * fcntl's F_GETFD instruction returns -1 if the file descriptor is closed, + * otherwise it returns "the file descriptor flags (which typically can only + * be FD_CLOEXEC, which is not set here). */ -static void main_checkfds(void) +static int main_checkfds(void) { -#ifdef HAVE_PIPE - int fd[2] = { STDIN_FILENO, STDIN_FILENO }; - while(fd[0] == STDIN_FILENO || - fd[0] == STDOUT_FILENO || - fd[0] == STDERR_FILENO || - fd[1] == STDIN_FILENO || - fd[1] == STDOUT_FILENO || - fd[1] == STDERR_FILENO) - if(pipe(fd) < 0) - return; /* Out of handles. This isn't really a big problem now, but - will be when we try to create a socket later. */ - close(fd[0]); - close(fd[1]); -#endif + int fd[2]; + while((fcntl(STDIN_FILENO, F_GETFD) == -1) || + (fcntl(STDOUT_FILENO, F_GETFD) == -1) || + (fcntl(STDERR_FILENO, F_GETFD) == -1)) + if(pipe(fd)) + return 1; + return 0; } +#else +#define main_checkfds() 0 +#endif #ifdef CURLDEBUG static void memory_tracking_init(void) @@ -259,7 +264,10 @@ int main(int argc, char *argv[]) } #endif - main_checkfds(); + if(main_checkfds()) { + fprintf(stderr, "curl: out of file descriptors\n"); + return CURLE_FAILED_INIT; + } #if defined(HAVE_SIGNAL) && defined(SIGPIPE) (void)signal(SIGPIPE, SIG_IGN); diff --git a/contrib/libs/curl/src/tool_msgs.c b/contrib/libs/curl/src/tool_msgs.c index 4900333ff9..a880a667eb 100644 --- a/contrib/libs/curl/src/tool_msgs.c +++ b/contrib/libs/curl/src/tool_msgs.c @@ -59,7 +59,7 @@ static void voutf(struct GlobalConfig *config, if(len > width) { size_t cut = width-1; - while(!ISSPACE(ptr[cut]) && cut) { + while(!ISBLANK(ptr[cut]) && cut) { cut--; } if(0 == cut) diff --git a/contrib/libs/curl/src/tool_operate.c b/contrib/libs/curl/src/tool_operate.c index 87981d21ea..43c1c5e6c4 100644 --- a/contrib/libs/curl/src/tool_operate.c +++ b/contrib/libs/curl/src/tool_operate.c @@ -205,6 +205,7 @@ static curl_off_t VmsSpecialSize(const char *name, struct per_transfer *transfers; /* first node */ static struct per_transfer *transfersl; /* last node */ +static long all_pers; /* add_per_transfer creates a new 'per_transfer' node in the linked list of transfers */ @@ -227,6 +228,8 @@ static CURLcode add_per_transfer(struct per_transfer **per) } *per = p; all_xfers++; /* count total number of transfers added */ + all_pers++; + return CURLE_OK; } @@ -254,6 +257,7 @@ static struct per_transfer *del_per_transfer(struct per_transfer *per) transfersl = p; free(per); + all_pers--; return n; } @@ -269,11 +273,11 @@ static CURLcode pre_transfer(struct GlobalConfig *global, /* VMS Note: * * Reading binary from files can be a problem... Only FIXED, VAR - * etc WITHOUT implied CC will work Others need a \n appended to a - * line + * etc WITHOUT implied CC will work. Others need a \n appended to + * a line * - * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a - * fixed file with implied CC needs to have a byte added for every + * - Stat gives a size but this is UNRELIABLE in VMS. E.g. + * a fixed file with implied CC needs to have a byte added for every * record processed, this can be derived from Filesize & recordsize * for VARiable record files the records need to be counted! for * every record add 1 for linefeed and subtract 2 for the record @@ -343,6 +347,29 @@ static void AmigaSetComment(struct per_transfer *per, #define AmigaSetComment(x,y) Curl_nop_stmt #endif +/* When doing serial transfers, we use a single fixed error area */ +static char global_errorbuffer[CURL_ERROR_SIZE]; + +void single_transfer_cleanup(struct OperationConfig *config) +{ + if(config) { + struct State *state = &config->state; + if(state->urls) { + /* Free list of remaining URLs */ + glob_cleanup(state->urls); + state->urls = NULL; + } + Curl_safefree(state->outfiles); + Curl_safefree(state->httpgetfields); + Curl_safefree(state->uploadfile); + if(state->inglob) { + /* Free list of globbed upload files */ + glob_cleanup(state->inglob); + state->inglob = NULL; + } + } +} + /* * Call this after a transfer has completed. */ @@ -374,9 +401,9 @@ static CURLcode post_per_transfer(struct GlobalConfig *global, else #endif if(!config->synthetic_error && result && global->showerror) { + const char *msg = per->errorbuffer; fprintf(global->errors, "curl: (%d) %s\n", result, - (per->errorbuffer[0]) ? per->errorbuffer : - curl_easy_strerror(result)); + (msg && msg[0]) ? msg : curl_easy_strerror(result)); if(result == CURLE_PEER_FAILED_VERIFICATION) fputs(CURL_CA_CERT_ERRORMSG, global->errors); } @@ -394,7 +421,7 @@ static CURLcode post_per_transfer(struct GlobalConfig *global, } /* Set file extended attributes */ if(!result && config->xattr && outs->fopened && outs->stream) { - int rc = fwrite_xattr(curl, fileno(outs->stream)); + int rc = fwrite_xattr(curl, per->this_url, fileno(outs->stream)); if(rc) warnf(config->global, "Error setting extended attributes on '%s': %s\n", outs->filename, strerror(errno)); @@ -458,9 +485,10 @@ static CURLcode post_per_transfer(struct GlobalConfig *global, /* If it returned OK. _or_ failonerror was enabled and it returned due to such an error, check for HTTP transient errors to retry on. */ - long protocol = 0; - curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); - if((protocol == CURLPROTO_HTTP) || (protocol == CURLPROTO_HTTPS)) { + const char *scheme; + curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme); + scheme = proto_token(scheme); + if(scheme == proto_http || scheme == proto_https) { /* This was HTTP(S) */ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); @@ -487,13 +515,13 @@ static CURLcode post_per_transfer(struct GlobalConfig *global, } } /* if CURLE_OK */ else if(result) { - long protocol = 0; + const char *scheme; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); - curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); + curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme); + scheme = proto_token(scheme); - if((protocol == CURLPROTO_FTP || protocol == CURLPROTO_FTPS) && - response / 100 == 4) + if((scheme == proto_ftp || scheme == proto_ftps) && response / 100 == 4) /* * This is typically when the FTP server only allows a certain * amount of users and we are not one of them. All 4xx codes @@ -652,37 +680,20 @@ static CURLcode post_per_transfer(struct GlobalConfig *global, free(per->this_url); free(per->outfile); free(per->uploadfile); + if(global->parallel) + free(per->errorbuffer); return result; } -static void single_transfer_cleanup(struct OperationConfig *config) -{ - if(config) { - struct State *state = &config->state; - if(state->urls) { - /* Free list of remaining URLs */ - glob_cleanup(state->urls); - state->urls = NULL; - } - Curl_safefree(state->outfiles); - Curl_safefree(state->httpgetfields); - Curl_safefree(state->uploadfile); - if(state->inglob) { - /* Free list of globbed upload files */ - glob_cleanup(state->inglob); - state->inglob = NULL; - } - } -} - /* - * Return the proto bit for the scheme used in the given URL + * Return the protocol token for the scheme used in the given URL */ -static long url_proto(char *url) +static const char *url_proto(char *url) { CURLU *uh = curl_url(); - long proto = 0; + const char *proto = NULL; + if(uh) { if(url) { if(!curl_url_set(uh, CURLUPART_URL, url, @@ -691,18 +702,17 @@ static long url_proto(char *url) if(!curl_url_get(uh, CURLUPART_SCHEME, &schemep, CURLU_DEFAULT_SCHEME) && schemep) { - proto = scheme2protocol(schemep); + proto = proto_token(schemep); curl_free(schemep); } } } curl_url_cleanup(uh); } - return proto; + return proto? proto: "???"; /* Never match if not found. */ } /* create the next (singular) transfer */ - static CURLcode single_transfer(struct GlobalConfig *global, struct OperationConfig *config, CURLSH *share, @@ -842,7 +852,7 @@ static CURLcode single_transfer(struct GlobalConfig *global, struct OutStruct *etag_save; struct HdrCbData *hdrcbdata = NULL; struct OutStruct etag_first; - long use_proto; + const char *use_proto; CURL *curl; /* --etag-save */ @@ -1121,12 +1131,10 @@ static CURLcode single_transfer(struct GlobalConfig *global, /* * We have specified a file to upload and it isn't "-". */ - char *nurl = add_file_name_to_url(per->this_url, per->uploadfile); - if(!nurl) { - result = CURLE_OUT_OF_MEMORY; + result = add_file_name_to_url(per->curl, &per->this_url, + per->uploadfile); + if(result) break; - } - per->this_url = nurl; } else if(per->uploadfile && stdin_upload(per->uploadfile)) { /* count to see if there are more than one auth bit set @@ -1181,43 +1189,22 @@ static CURLcode single_transfer(struct GlobalConfig *global, } if(httpgetfields) { - char *urlbuffer; - /* Find out whether the url contains a file name */ - const char *pc = strstr(per->this_url, "://"); - char sep = '?'; - if(pc) - pc += 3; - else - pc = per->this_url; - - pc = strrchr(pc, '/'); /* check for a slash */ - - if(pc) { - /* there is a slash present in the URL */ - - if(strchr(pc, '?')) - /* Ouch, there's already a question mark in the URL string, we - then append the data with an ampersand separator instead! */ - sep = '&'; - } - /* - * Then append ? followed by the get fields to the url. - */ - if(pc) - urlbuffer = aprintf("%s%c%s", per->this_url, sep, httpgetfields); - else - /* Append / before the ? to create a well-formed url - if the url contains a hostname only - */ - urlbuffer = aprintf("%s/?%s", per->this_url, httpgetfields); - - if(!urlbuffer) { - result = CURLE_OUT_OF_MEMORY; - break; + CURLU *uh = curl_url(); + if(uh) { + char *updated; + if(curl_url_set(uh, CURLUPART_URL, per->this_url, + CURLU_GUESS_SCHEME) || + curl_url_set(uh, CURLUPART_QUERY, httpgetfields, + CURLU_APPENDQUERY) || + curl_url_get(uh, CURLUPART_URL, &updated, CURLU_GUESS_SCHEME)) { + curl_url_cleanup(uh); + result = CURLE_OUT_OF_MEMORY; + break; + } + Curl_safefree(per->this_url); /* free previous URL */ + per->this_url = updated; /* use our new URL instead! */ + curl_url_cleanup(uh); } - - Curl_safefree(per->this_url); /* free previous URL */ - per->this_url = urlbuffer; /* use our new URL instead! */ } if(!global->errors) @@ -1239,14 +1226,7 @@ static CURLcode single_transfer(struct GlobalConfig *global, if(result) break; - /* here */ use_proto = url_proto(per->this_url); -#if 0 - if(!(use_proto & built_in_protos)) { - warnf(global, "URL is '%s' but no support for the scheme\n", - per->this_url); - } -#endif if(!config->tcp_nodelay) my_setopt(curl, CURLOPT_TCP_NODELAY, 0L); @@ -1360,7 +1340,10 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt_str(curl, CURLOPT_LOGIN_OPTIONS, config->login_options); my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd); my_setopt_str(curl, CURLOPT_RANGE, config->range); - my_setopt(curl, CURLOPT_ERRORBUFFER, per->errorbuffer); + if(!global->parallel) { + per->errorbuffer = global_errorbuffer; + my_setopt(curl, CURLOPT_ERRORBUFFER, global_errorbuffer); + } my_setopt(curl, CURLOPT_TIMEOUT_MS, (long)(config->timeout * 1000)); switch(config->httpreq) { @@ -1395,13 +1378,12 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers); - if(built_in_protos & (CURLPROTO_HTTP | CURLPROTO_RTSP)) { + if(proto_http || proto_rtsp) { my_setopt_str(curl, CURLOPT_REFERER, config->referer); my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent); } - if(built_in_protos & CURLPROTO_HTTP) { - + if(proto_http) { long postRedir = 0; my_setopt(curl, CURLOPT_FOLLOWLOCATION, @@ -1451,9 +1433,10 @@ static CURLcode single_transfer(struct GlobalConfig *global, return result; } - } /* (built_in_protos & CURLPROTO_HTTP) */ + } /* (proto_http) */ - my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport); + if(proto_ftp) + my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport); my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, config->low_speed_limit); my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time); @@ -1470,7 +1453,7 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd); my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd); - if(use_proto & (CURLPROTO_SCP|CURLPROTO_SFTP)) { + if(use_proto == proto_scp || use_proto == proto_sftp) { /* SSH and SSL private key uses same command-line option */ /* new in libcurl 7.16.1 */ @@ -1741,7 +1724,7 @@ static CURLcode single_transfer(struct GlobalConfig *global, if(config->path_as_is) my_setopt(curl, CURLOPT_PATH_AS_IS, 1L); - if((use_proto & (CURLPROTO_SCP|CURLPROTO_SFTP)) && + if((use_proto == proto_scp || use_proto == proto_sftp) && !config->insecure_ok) { char *known = findfile(".ssh/known_hosts", FALSE); if(known) { @@ -1951,7 +1934,9 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L); /* curl 7.15.1 */ - my_setopt(curl, CURLOPT_FTP_FILEMETHOD, (long)config->ftp_filemethod); + if(proto_ftp) + my_setopt(curl, CURLOPT_FTP_FILEMETHOD, + (long)config->ftp_filemethod); /* curl 7.15.2 */ if(config->localport) { @@ -1986,7 +1971,7 @@ static CURLcode single_transfer(struct GlobalConfig *global, my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L); /* curl 7.20.0 */ - if(config->tftp_blksize) + if(config->tftp_blksize && proto_tftp) my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize); if(config->mail_from) @@ -2073,10 +2058,6 @@ static CURLcode single_transfer(struct GlobalConfig *global, if(config->sasl_ir) my_setopt(curl, CURLOPT_SASL_IR, 1L); - if(config->nonpn) { - my_setopt(curl, CURLOPT_SSL_ENABLE_NPN, 0L); - } - if(config->noalpn) { my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L); } @@ -2103,7 +2084,7 @@ static CURLcode single_transfer(struct GlobalConfig *global, (long)(config->expect100timeout*1000)); /* new in 7.48.0 */ - if(config->tftp_no_options) + if(config->tftp_no_options && proto_tftp) my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L); /* new in 7.59.0 */ @@ -2192,11 +2173,14 @@ static CURLcode add_parallel_transfers(struct GlobalConfig *global, CURLcode result = CURLE_OK; CURLMcode mcode; bool sleeping = FALSE; + char *errorbuf; *addedp = FALSE; *morep = FALSE; - result = create_transfer(global, share, addedp); - if(result) - return result; + if(all_pers < (global->parallel_max*2)) { + result = create_transfer(global, share, addedp); + if(result) + return result; + } for(per = transfers; per && (all_added < global->parallel_max); per = per->next) { bool getadded = FALSE; @@ -2208,11 +2192,16 @@ static CURLcode add_parallel_transfers(struct GlobalConfig *global, sleeping = TRUE; continue; } + per->added = TRUE; result = pre_transfer(global, per); if(result) return result; + errorbuf = malloc(CURL_ERROR_SIZE); + if(!errorbuf) + return CURLE_OUT_OF_MEMORY; + /* parallel connect means that we don't set PIPEWAIT since pipewait will make libcurl prefer multiplexing */ (void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT, @@ -2223,12 +2212,20 @@ static CURLcode add_parallel_transfers(struct GlobalConfig *global, (void)curl_easy_setopt(per->curl, CURLOPT_NOPROGRESS, 0L); mcode = curl_multi_add_handle(multi, per->curl); - if(mcode) - return CURLE_OUT_OF_MEMORY; + if(mcode) { + DEBUGASSERT(mcode == CURLM_OUT_OF_MEMORY); + result = CURLE_OUT_OF_MEMORY; + } - result = create_transfer(global, share, &getadded); - if(result) + if(!result) + result = create_transfer(global, share, &getadded); + if(result) { + free(errorbuf); return result; + } + errorbuf[0] = 0; + (void)curl_easy_setopt(per->curl, CURLOPT_ERRORBUFFER, errorbuf); + per->errorbuffer = errorbuf; per->added = TRUE; all_added++; *addedp = TRUE; @@ -2302,8 +2299,9 @@ static CURLcode parallel_transfers(struct GlobalConfig *global, curl_multi_remove_handle(multi, easy); if(ended->abort && tres == CURLE_ABORTED_BY_CALLBACK) { - msnprintf(ended->errorbuffer, sizeof(ended->errorbuffer), - "Transfer aborted due to critical error in another transfer"); + msnprintf(ended->errorbuffer, CURL_ERROR_SIZE, + "Transfer aborted due to critical error " + "in another transfer"); } tres = post_per_transfer(global, ended, tres, &retry, &delay); progress_finalize(ended); /* before it goes away */ @@ -2393,13 +2391,12 @@ static CURLcode serial_transfers(struct GlobalConfig *global, if(result) break; -#ifndef CURL_DISABLE_LIBCURL_OPTION if(global->libcurl) { result = easysrc_perform(); if(result) break; } -#endif + start = tvnow(); #ifdef CURLDEBUG if(global->test_event_based) @@ -2671,12 +2668,10 @@ CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[]) result = CURLE_FAILED_INIT; } else { -#ifndef CURL_DISABLE_LIBCURL_OPTION if(global->libcurl) { /* Initialise the libcurl source output */ result = easysrc_init(); } -#endif /* Perform the main operations */ if(!result) { @@ -2684,12 +2679,10 @@ CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[]) struct OperationConfig *operation = global->first; CURLSH *share = curl_share_init(); if(!share) { -#ifndef CURL_DISABLE_LIBCURL_OPTION if(global->libcurl) { /* Cleanup the libcurl source output */ easysrc_cleanup(); } -#endif return CURLE_OUT_OF_MEMORY; } @@ -2713,7 +2706,6 @@ CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[]) result = run_all_transfers(global, share, result); curl_share_cleanup(share); -#ifndef CURL_DISABLE_LIBCURL_OPTION if(global->libcurl) { /* Cleanup the libcurl source output */ easysrc_cleanup(); @@ -2721,7 +2713,6 @@ CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[]) /* Dump the libcurl code if previously enabled */ dumpeasysrc(global); } -#endif } else errorf(global, "out of memory\n"); diff --git a/contrib/libs/curl/src/tool_operate.h b/contrib/libs/curl/src/tool_operate.h index a779239478..c714da1bc2 100644 --- a/contrib/libs/curl/src/tool_operate.h +++ b/contrib/libs/curl/src/tool_operate.h @@ -52,7 +52,6 @@ struct per_transfer { struct HdrCbData hdrcbdata; long num_headers; bool was_last_header_empty; - char errorbuffer[CURL_ERROR_SIZE]; bool added; /* set TRUE when added to the multi handle */ time_t startat; /* when doing parallel transfers, this is a retry transfer @@ -72,9 +71,12 @@ struct per_transfer { /* NULL or malloced */ char *uploadfile; + char *errorbuffer; /* alloced and assigned while this is used for a + transfer */ }; CURLcode operate(struct GlobalConfig *config, int argc, argv_item_t argv[]); +void single_transfer_cleanup(struct OperationConfig *config); extern struct per_transfer *transfers; /* first node */ diff --git a/contrib/libs/curl/src/tool_operhlp.c b/contrib/libs/curl/src/tool_operhlp.c index 014444219c..eb58772fb9 100644 --- a/contrib/libs/curl/src/tool_operhlp.c +++ b/contrib/libs/curl/src/tool_operhlp.c @@ -22,6 +22,7 @@ * ***************************************************************************/ #include "tool_setup.h" +#include "tool_operate.h" #include "strcase.h" @@ -51,6 +52,7 @@ void clean_getout(struct OperationConfig *config) } config->url_list = NULL; } + single_transfer_cleanup(config); } bool output_expected(const char *url, const char *uploadfile) @@ -73,61 +75,73 @@ bool stdin_upload(const char *uploadfile) * Adds the file name to the URL if it doesn't already have one. * url will be freed before return if the returned pointer is different */ -char *add_file_name_to_url(char *url, const char *filename) +CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename) { - /* If no file name part is given in the URL, we add this file name */ - char *ptr = strstr(url, "://"); - CURL *curl = curl_easy_init(); /* for url escaping */ - if(!curl) - return NULL; /* error! */ - if(ptr) - ptr += 3; - else - ptr = url; - ptr = strrchr(ptr, '/'); - if(!ptr || !*++ptr) { - /* The URL has no file name part, add the local file name. In order - to be able to do so, we have to create a new URL in another - buffer.*/ - - /* We only want the part of the local path that is on the right - side of the rightmost slash and backslash. */ - const char *filep = strrchr(filename, '/'); - char *file2 = strrchr(filep?filep:filename, '\\'); - char *encfile; - - if(file2) - filep = file2 + 1; - else if(filep) - filep++; - else - filep = filename; - - /* URL encode the file name */ - encfile = curl_easy_escape(curl, filep, 0 /* use strlen */); - if(encfile) { - char *urlbuffer; - if(ptr) - /* there is a trailing slash on the URL */ - urlbuffer = aprintf("%s%s", url, encfile); + CURLcode result = CURLE_OUT_OF_MEMORY; + CURLU *uh = curl_url(); + char *path = NULL; + if(uh) { + char *ptr; + if(curl_url_set(uh, CURLUPART_URL, *inurlp, + CURLU_GUESS_SCHEME|CURLU_NON_SUPPORT_SCHEME)) + goto fail; + if(curl_url_get(uh, CURLUPART_PATH, &path, 0)) + goto fail; + + ptr = strrchr(path, '/'); + if(!ptr || !*++ptr) { + /* The URL path has no file name part, add the local file name. In order + to be able to do so, we have to create a new URL in another buffer.*/ + + /* We only want the part of the local path that is on the right + side of the rightmost slash and backslash. */ + const char *filep = strrchr(filename, '/'); + char *file2 = strrchr(filep?filep:filename, '\\'); + char *encfile; + + if(file2) + filep = file2 + 1; + else if(filep) + filep++; else - /* there is no trailing slash on the URL */ - urlbuffer = aprintf("%s/%s", url, encfile); - - curl_free(encfile); - - if(!urlbuffer) { - url = NULL; - goto end; + filep = filename; + + /* URL encode the file name */ + encfile = curl_easy_escape(curl, filep, 0 /* use strlen */); + if(encfile) { + char *newpath; + char *newurl; + CURLUcode uerr; + if(ptr) + /* there is a trailing slash on the path */ + newpath = aprintf("%s%s", path, encfile); + else + /* there is no trailing slash on the path */ + newpath = aprintf("%s/%s", path, encfile); + + curl_free(encfile); + + if(!newpath) + goto fail; + uerr = curl_url_set(uh, CURLUPART_PATH, newpath, 0); + free(newpath); + if(uerr) + goto fail; + if(curl_url_get(uh, CURLUPART_URL, &newurl, CURLU_DEFAULT_SCHEME)) + goto fail; + free(*inurlp); + *inurlp = newurl; + result = CURLE_OK; } - - Curl_safefree(url); - url = urlbuffer; /* use our new URL instead! */ } + else + /* nothing to do */ + result = CURLE_OK; } - end: - curl_easy_cleanup(curl); - return url; + fail: + curl_url_cleanup(uh); + curl_free(path); + return result; } /* Extracts the name portion of the URL. @@ -137,61 +151,65 @@ char *add_file_name_to_url(char *url, const char *filename) CURLcode get_url_file_name(char **filename, const char *url) { const char *pc, *pc2; + CURLU *uh = curl_url(); + char *path = NULL; + + if(!uh) + return CURLE_OUT_OF_MEMORY; *filename = NULL; - /* Find and get the remote file name */ - pc = strstr(url, "://"); - if(pc) - pc += 3; - else - pc = url; - - pc2 = strrchr(pc, '\\'); - pc = strrchr(pc, '/'); - if(pc2 && (!pc || pc < pc2)) - pc = pc2; - - if(pc) - /* duplicate the string beyond the slash */ - pc++; - else - /* no slash => empty string */ - pc = ""; - - *filename = strdup(pc); - if(!*filename) - return CURLE_OUT_OF_MEMORY; + if(!curl_url_set(uh, CURLUPART_URL, url, CURLU_GUESS_SCHEME) && + !curl_url_get(uh, CURLUPART_PATH, &path, 0)) { + curl_url_cleanup(uh); + + pc = strrchr(path, '/'); + pc2 = strrchr(pc ? pc + 1 : path, '\\'); + if(pc2) + pc = pc2; + + if(pc) + /* duplicate the string beyond the slash */ + pc++; + else + /* no slash => empty string */ + pc = ""; + + *filename = strdup(pc); + curl_free(path); + if(!*filename) + return CURLE_OUT_OF_MEMORY; #if defined(MSDOS) || defined(WIN32) - { - char *sanitized; - SANITIZEcode sc = sanitize_file_name(&sanitized, *filename, 0); - Curl_safefree(*filename); - if(sc) - return CURLE_URL_MALFORMAT; - *filename = sanitized; - } + { + char *sanitized; + SANITIZEcode sc = sanitize_file_name(&sanitized, *filename, 0); + Curl_safefree(*filename); + if(sc) + return CURLE_URL_MALFORMAT; + *filename = sanitized; + } #endif /* MSDOS || WIN32 */ - /* in case we built debug enabled, we allow an environment variable - * named CURL_TESTDIR to prefix the given file name to put it into a - * specific directory - */ + /* in case we built debug enabled, we allow an environment variable + * named CURL_TESTDIR to prefix the given file name to put it into a + * specific directory + */ #ifdef DEBUGBUILD - { - char *tdir = curlx_getenv("CURL_TESTDIR"); - if(tdir) { - char buffer[512]; /* suitably large */ - msnprintf(buffer, sizeof(buffer), "%s/%s", tdir, *filename); - Curl_safefree(*filename); - *filename = strdup(buffer); /* clone the buffer */ - curl_free(tdir); - if(!*filename) - return CURLE_OUT_OF_MEMORY; + { + char *tdir = curlx_getenv("CURL_TESTDIR"); + if(tdir) { + char *alt = aprintf("%s/%s", tdir, *filename); + Curl_safefree(*filename); + *filename = alt; + curl_free(tdir); + if(!*filename) + return CURLE_OUT_OF_MEMORY; + } } - } #endif - - return CURLE_OK; + return CURLE_OK; + } + curl_url_cleanup(uh); + return CURLE_URL_MALFORMAT; } diff --git a/contrib/libs/curl/src/tool_operhlp.h b/contrib/libs/curl/src/tool_operhlp.h index c48d7eca64..8018d1a67c 100644 --- a/contrib/libs/curl/src/tool_operhlp.h +++ b/contrib/libs/curl/src/tool_operhlp.h @@ -33,7 +33,7 @@ bool output_expected(const char *url, const char *uploadfile); bool stdin_upload(const char *uploadfile); -char *add_file_name_to_url(char *url, const char *filename); +CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename); CURLcode get_url_file_name(char **filename, const char *url); diff --git a/contrib/libs/curl/src/tool_paramhlp.c b/contrib/libs/curl/src/tool_paramhlp.c index 9306498e23..05afb8d3a4 100644 --- a/contrib/libs/curl/src/tool_paramhlp.c +++ b/contrib/libs/curl/src/tool_paramhlp.c @@ -34,6 +34,8 @@ #include "tool_getpass.h" #include "tool_msgs.h" #include "tool_paramhlp.h" +#include "tool_libinfo.h" +#include "tool_util.h" #include "tool_version.h" #include "dynbuf.h" @@ -66,6 +68,7 @@ struct getout *new_getout(struct OperationConfig *config) ParameterError file2string(char **bufp, FILE *file) { struct curlx_dynbuf dyn; + DEBUGASSERT(MAX_FILE2STRING < INT_MAX); /* needs to fit in an int later */ curlx_dyn_init(&dyn, MAX_FILE2STRING); if(file) { char buffer[256]; @@ -92,6 +95,8 @@ ParameterError file2memory(char **bufp, size_t *size, FILE *file) if(file) { size_t nread; struct curlx_dynbuf dyn; + /* The size needs to fit in an int later */ + DEBUGASSERT(MAX_FILE2MEMORY < INT_MAX); curlx_dyn_init(&dyn, MAX_FILE2MEMORY); do { char buffer[4096]; @@ -213,7 +218,7 @@ ParameterError str2unummax(long *val, const char *str, long max) * data. */ -static ParameterError str2double(double *val, const char *str, long max) +static ParameterError str2double(double *val, const char *str, double max) { if(str) { char *endptr; @@ -246,7 +251,7 @@ static ParameterError str2double(double *val, const char *str, long max) * data. */ -ParameterError str2udouble(double *valp, const char *str, long max) +ParameterError str2udouble(double *valp, const char *str, double max) { double value; ParameterError result = str2double(&value, str, max); @@ -260,6 +265,53 @@ ParameterError str2udouble(double *valp, const char *str, long max) } /* + * Implement protocol sets in null-terminated array of protocol name pointers. + */ + +/* Return index of prototype token in set, card(set) if not found. + Can be called with proto == NULL to get card(set). */ +static size_t protoset_index(const char * const *protoset, const char *proto) +{ + const char * const *p = protoset; + + DEBUGASSERT(proto == proto_token(proto)); /* Ensure it is tokenized. */ + + for(; *p; p++) + if(proto == *p) + break; + return p - protoset; +} + +/* Include protocol token in set. */ +static void protoset_set(const char **protoset, const char *proto) +{ + if(proto) { + size_t n = protoset_index(protoset, proto); + + if(!protoset[n]) { + DEBUGASSERT(n < proto_count); + protoset[n] = proto; + protoset[n + 1] = NULL; + } + } +} + +/* Exclude protocol token from set. */ +static void protoset_clear(const char **protoset, const char *proto) +{ + if(proto) { + size_t n = protoset_index(protoset, proto); + + if(protoset[n]) { + size_t m = protoset_index(protoset, NULL) - 1; + + protoset[n] = protoset[m]; + protoset[m] = NULL; + } + } +} + +/* * Parse the string and provide an allocated libcurl compatible protocol * string output. Return non-zero on failure, zero on success. * @@ -270,48 +322,20 @@ ParameterError str2udouble(double *valp, const char *str, long max) * data. */ +#define MAX_PROTOSTRING (64*11) /* Enough room for 64 10-chars proto names. */ + ParameterError proto2num(struct OperationConfig *config, - unsigned int val, char **ostr, const char *str) + const char * const *val, char **ostr, const char *str) { char *buffer; const char *sep = ","; char *token; - char obuf[256] = ""; - size_t olen = sizeof(obuf); - char *optr; - struct sprotos const *pp; - - static struct sprotos { - const char *name; - unsigned int bit; - } const protos[] = { - { "all", (unsigned int)CURLPROTO_ALL }, - { "http", CURLPROTO_HTTP }, - { "https", CURLPROTO_HTTPS }, - { "ftp", CURLPROTO_FTP }, - { "ftps", CURLPROTO_FTPS }, - { "scp", CURLPROTO_SCP }, - { "sftp", CURLPROTO_SFTP }, - { "telnet", CURLPROTO_TELNET }, - { "ldap", CURLPROTO_LDAP }, - { "ldaps", CURLPROTO_LDAPS }, - { "mqtt", CURLPROTO_MQTT }, - { "dict", CURLPROTO_DICT }, - { "file", CURLPROTO_FILE }, - { "tftp", CURLPROTO_TFTP }, - { "imap", CURLPROTO_IMAP }, - { "imaps", CURLPROTO_IMAPS }, - { "pop3", CURLPROTO_POP3 }, - { "pop3s", CURLPROTO_POP3S }, - { "smtp", CURLPROTO_SMTP }, - { "smtps", CURLPROTO_SMTPS }, - { "rtsp", CURLPROTO_RTSP }, - { "gopher", CURLPROTO_GOPHER }, - { "gophers", CURLPROTO_GOPHERS }, - { "smb", CURLPROTO_SMB }, - { "smbs", CURLPROTO_SMBS }, - { NULL, 0 } - }; + const char **protoset; + struct curlx_dynbuf obuf; + size_t proto; + CURLcode result; + + curlx_dyn_init(&obuf, MAX_PROTOSTRING); if(!str) return PARAM_OPTION_AMBIGUOUS; @@ -320,6 +344,21 @@ ParameterError proto2num(struct OperationConfig *config, if(!buffer) return PARAM_NO_MEM; + protoset = malloc((proto_count + 1) * sizeof(*protoset)); + if(!protoset) { + free(buffer); + return PARAM_NO_MEM; + } + + /* Preset protocol set with default values. */ + protoset[0] = NULL; + for(; *val; val++) { + const char *p = proto_token(*val); + + if(p) + protoset_set(protoset, p); + } + /* Allow strtok() here since this isn't used threaded */ /* !checksrc! disable BANNEDFUNC 2 */ for(token = strtok(buffer, sep); @@ -340,49 +379,60 @@ ParameterError proto2num(struct OperationConfig *config, action = allow; break; default: /* Includes case of terminating NULL */ - Curl_safefree(buffer); + free(buffer); + free((char *) protoset); return PARAM_BAD_USE; } } - for(pp = protos; pp->name; pp++) { - if(curl_strequal(token, pp->name)) { + if(curl_strequal(token, "all")) { + switch(action) { + case deny: + protoset[0] = NULL; + break; + case allow: + case set: + memcpy((char *) protoset, + built_in_protos, (proto_count + 1) * sizeof(*protoset)); + break; + } + } + else { + const char *p = proto_token(token); + + if(p) switch(action) { case deny: - val &= ~(pp->bit); - break; - case allow: - val |= pp->bit; + protoset_clear(protoset, p); break; case set: - val = pp->bit; + protoset[0] = NULL; + /* FALLTHROUGH */ + case allow: + protoset_set(protoset, p); break; } - break; + else { /* unknown protocol */ + /* If they have specified only this protocol, we say treat it as + if no protocols are allowed */ + if(action == set) + protoset[0] = NULL; + warnf(config->global, "unrecognized protocol '%s'\n", token); } } - - if(!(pp->name)) { /* unknown protocol */ - /* If they have specified only this protocol, we say treat it as - if no protocols are allowed */ - if(action == set) - val = 0; - warnf(config->global, "unrecognized protocol '%s'\n", token); - } - } - Curl_safefree(buffer); - - optr = obuf; - for(pp = &protos[1]; pp->name; pp++) { - if(val & pp->bit) { - size_t n = msnprintf(optr, olen, "%s%s", - olen != sizeof(obuf) ? "," : "", - pp->name); - olen -= n; - optr += n; - } } - *ostr = strdup(obuf); + free(buffer); + + /* We need the protocols in alphabetic order for CI tests requirements. */ + qsort((char *) protoset, protoset_index(protoset, NULL), sizeof(*protoset), + struplocompare4sort); + + result = curlx_dyn_addn(&obuf, "", 0); + for(proto = 0; protoset[proto] && !result; proto++) + result = curlx_dyn_addf(&obuf, "%s,", protoset[proto]); + free((char *) protoset); + curlx_dyn_setlen(&obuf, curlx_dyn_len(&obuf) - 1); + *ostr = curlx_dyn_ptr(&obuf); return *ostr ? PARAM_OK : PARAM_NO_MEM; } @@ -397,14 +447,11 @@ ParameterError proto2num(struct OperationConfig *config, */ ParameterError check_protocol(const char *str) { - const char * const *pp; - const curl_version_info_data *curlinfo = curl_version_info(CURLVERSION_NOW); if(!str) return PARAM_REQUIRES_PARAMETER; - for(pp = curlinfo->protocols; *pp; pp++) { - if(curl_strequal(*pp, str)) - return PARAM_OK; - } + + if(proto_token(str)) + return PARAM_OK; return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL; } diff --git a/contrib/libs/curl/src/tool_paramhlp.h b/contrib/libs/curl/src/tool_paramhlp.h index 6d9451f1d9..7d68583e67 100644 --- a/contrib/libs/curl/src/tool_paramhlp.h +++ b/contrib/libs/curl/src/tool_paramhlp.h @@ -24,6 +24,7 @@ * ***************************************************************************/ #include "tool_setup.h" +#include "tool_libinfo.h" struct getout *new_getout(struct OperationConfig *config); @@ -35,10 +36,10 @@ ParameterError str2num(long *val, const char *str); ParameterError str2unum(long *val, const char *str); ParameterError oct2nummax(long *val, const char *str, long max); ParameterError str2unummax(long *val, const char *str, long max); -ParameterError str2udouble(double *val, const char *str, long max); +ParameterError str2udouble(double *val, const char *str, double max); ParameterError proto2num(struct OperationConfig *config, - unsigned int val, char **obuf, + const char * const *val, char **obuf, const char *str); ParameterError check_protocol(const char *str); diff --git a/contrib/libs/curl/src/tool_progress.c b/contrib/libs/curl/src/tool_progress.c index 46185c0d3c..266177b6ec 100644 --- a/contrib/libs/curl/src/tool_progress.c +++ b/contrib/libs/curl/src/tool_progress.c @@ -161,8 +161,8 @@ static bool indexwrapped; static struct speedcount speedstore[SPEEDCNT]; /* - |DL% UL% Dled Uled Xfers Live Qd Total Current Left Speed - | 6 -- 9.9G 0 2 2 0 0:00:40 0:00:02 0:00:37 4087M + |DL% UL% Dled Uled Xfers Live Total Current Left Speed + | 6 -- 9.9G 0 2 2 0:00:40 0:00:02 0:00:37 4087M */ bool progress_meter(struct GlobalConfig *global, struct timeval *start, @@ -181,7 +181,7 @@ bool progress_meter(struct GlobalConfig *global, if(!header) { header = TRUE; - fputs("DL% UL% Dled Uled Xfers Live Qd " + fputs("DL% UL% Dled Uled Xfers Live " "Total Current Left Speed\n", global->errors); } @@ -199,7 +199,6 @@ bool progress_meter(struct GlobalConfig *global, bool dlknown = TRUE; bool ulknown = TRUE; curl_off_t all_running = 0; /* in progress */ - curl_off_t all_queued = 0; /* pending */ curl_off_t speed = 0; unsigned int i; stamp = now; @@ -225,9 +224,7 @@ bool progress_meter(struct GlobalConfig *global, all_ultotal += per->ultotal; per->ultotal_added = TRUE; } - if(!per->added) - all_queued++; - else + if(per->added) all_running++; } if(dlknown && all_dltotal) @@ -296,8 +293,7 @@ bool progress_meter(struct GlobalConfig *global, "%s " /* Uled */ "%5" CURL_FORMAT_CURL_OFF_T " " /* Xfers */ "%5" CURL_FORMAT_CURL_OFF_T " " /* Live */ - "%5" CURL_FORMAT_CURL_OFF_T " " /* Queued */ - "%s " /* Total time */ + " %s " /* Total time */ "%s " /* Current time */ "%s " /* Time left */ "%s " /* Speed */ @@ -309,7 +305,6 @@ bool progress_meter(struct GlobalConfig *global, max5data(all_ulnow, buffer[1]), all_xfers, all_running, - all_queued, time_total, time_spent, time_left, diff --git a/contrib/libs/curl/src/tool_setopt.c b/contrib/libs/curl/src/tool_setopt.c index 5ff86c7f5b..3db2fe3c68 100644 --- a/contrib/libs/curl/src/tool_setopt.c +++ b/contrib/libs/curl/src/tool_setopt.c @@ -33,6 +33,7 @@ #include "tool_easysrc.h" #include "tool_setopt.h" #include "tool_msgs.h" +#include "dynbuf.h" #include "memdebug.h" /* keep this as LAST include */ @@ -145,35 +146,6 @@ const struct NameValue setopt_nv_CURL_NETRC[] = { NVEND, }; -/* These mappings essentially triplicated - see - * tool_libinfo.c and tool_paramhlp.c */ -const struct NameValue setopt_nv_CURLPROTO[] = { - NV(CURLPROTO_ALL), /* combination */ - NV(CURLPROTO_DICT), - NV(CURLPROTO_FILE), - NV(CURLPROTO_FTP), - NV(CURLPROTO_FTPS), - NV(CURLPROTO_GOPHER), - NV(CURLPROTO_HTTP), - NV(CURLPROTO_HTTPS), - NV(CURLPROTO_IMAP), - NV(CURLPROTO_IMAPS), - NV(CURLPROTO_LDAP), - NV(CURLPROTO_LDAPS), - NV(CURLPROTO_POP3), - NV(CURLPROTO_POP3S), - NV(CURLPROTO_RTSP), - NV(CURLPROTO_SCP), - NV(CURLPROTO_SFTP), - NV(CURLPROTO_SMB), - NV(CURLPROTO_SMBS), - NV(CURLPROTO_SMTP), - NV(CURLPROTO_SMTPS), - NV(CURLPROTO_TELNET), - NV(CURLPROTO_TFTP), - NVEND, -}; - /* These options have non-zero default values. */ static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = { NV1(CURLOPT_SSL_VERIFYPEER, 1), @@ -223,7 +195,7 @@ static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = { #define REM0(s) ADD((&easysrc_toohard, s)) #define REM1(f,a) ADDF((&easysrc_toohard, f,a)) -#define REM2(f,a,b) ADDF((&easysrc_toohard, f,a,b)) +#define REM3(f,a,b,c) ADDF((&easysrc_toohard, f,a,b,c)) /* Escape string to C string syntax. Return NULL if out of memory. * Is this correct for those wacky EBCDIC guys? */ @@ -234,9 +206,11 @@ static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = { static char *c_escape(const char *str, curl_off_t len) { const char *s; - unsigned char c; - char *escaped, *e; unsigned int cutoff = 0; + CURLcode result; + struct curlx_dynbuf escaped; + + curlx_dyn_init(&escaped, 4 * MAX_STRING_LENGTH_OUTPUT + 3); if(len == ZERO_TERMINATED) len = strlen(str); @@ -247,51 +221,44 @@ static char *c_escape(const char *str, curl_off_t len) cutoff = 3; } - /* Allocate space based on worst-case */ - escaped = malloc(4 * (size_t)len + 1 + cutoff); - if(!escaped) - return NULL; - - e = escaped; - for(s = str; len; s++, len--) { - c = *s; - if(c == '\n') { - strcpy(e, "\\n"); - e += 2; - } - else if(c == '\r') { - strcpy(e, "\\r"); - e += 2; - } - else if(c == '\t') { - strcpy(e, "\\t"); - e += 2; - } - else if(c == '\\') { - strcpy(e, "\\\\"); - e += 2; - } - else if(c == '"') { - strcpy(e, "\\\""); - e += 2; - } - else if(c == '?') { - /* escape question marks as well, to prevent generating accidental - trigraphs */ - strcpy(e, "\\?"); - e += 2; - } - else if(!isprint(c)) { - msnprintf(e, 5, "\\x%02x", (unsigned)c); - e += 4; + result = curlx_dyn_addn(&escaped, STRCONST("")); + for(s = str; !result && len; s++, len--) { + /* escape question marks as well, to prevent generating accidental + trigraphs */ + static const char from[] = "\t\r\n?\"\\"; + static const char to[] = "\\t\\r\\n\\?\\\"\\\\"; + const char *p = strchr(from, *s); + + if(!p && ISPRINT(*s)) + continue; + + result = curlx_dyn_addn(&escaped, str, s - str); + str = s + 1; + + if(!result) { + if(p && *p) + result = curlx_dyn_addn(&escaped, to + 2 * (p - from), 2); + else { + const char *format = "\\x%02x"; + + if(len > 1 && ISXDIGIT(s[1])) { + /* Octal escape to avoid >2 digit hex. */ + format = "\\%03o"; + } + + result = curlx_dyn_addf(&escaped, format, + (unsigned int) *(unsigned char *) s); + } } - else - *e++ = c; } - while(cutoff--) - *e++ = '.'; - *e = '\0'; - return escaped; + + if(!result) + result = curlx_dyn_addn(&escaped, str, s - str); + + if(!result) + (void) !curlx_dyn_addn(&escaped, "...", cutoff); + + return curlx_dyn_ptr(&escaped); } /* setopt wrapper for enum types */ @@ -668,7 +635,7 @@ CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global, /* function pointers are never printable */ if(tag >= CURLOPTTYPE_FUNCTIONPOINT) { if(pval) { - value = "functionpointer"; + value = "function pointer"; remark = TRUE; } else @@ -680,7 +647,7 @@ CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global, escape = TRUE; } else if(pval) { - value = "objectpointer"; + value = "object pointer"; remark = TRUE; } else @@ -706,7 +673,7 @@ CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global, /* blobs are never printable */ if(pblob) { - value = "blobpointer"; + value = "blob pointer"; remark = TRUE; } else @@ -721,7 +688,7 @@ CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global, /* we only use this for real if --libcurl was used */ if(remark) - REM2("%s set to a %s", name, value); + REM3("%s was set to a%s %s", name, (*value == 'o' ? "n" : ""), value); else { if(escape) { curl_off_t len = ZERO_TERMINATED; diff --git a/contrib/libs/curl/src/tool_setopt.h b/contrib/libs/curl/src/tool_setopt.h index 2646edb44b..bc5afe9bcb 100644 --- a/contrib/libs/curl/src/tool_setopt.h +++ b/contrib/libs/curl/src/tool_setopt.h @@ -57,7 +57,6 @@ extern const struct NameValue setopt_nv_CURLFTPSSL_CCC[]; extern const struct NameValue setopt_nv_CURLUSESSL[]; extern const struct NameValueUnsigned setopt_nv_CURLSSLOPT[]; extern const struct NameValue setopt_nv_CURL_NETRC[]; -extern const struct NameValue setopt_nv_CURLPROTO[]; extern const struct NameValueUnsigned setopt_nv_CURLAUTH[]; extern const struct NameValueUnsigned setopt_nv_CURLHSTS[]; @@ -73,8 +72,6 @@ extern const struct NameValueUnsigned setopt_nv_CURLHSTS[]; #define setopt_nv_CURLOPT_SSL_OPTIONS setopt_nv_CURLSSLOPT #define setopt_nv_CURLOPT_PROXY_SSL_OPTIONS setopt_nv_CURLSSLOPT #define setopt_nv_CURLOPT_NETRC setopt_nv_CURL_NETRC -#define setopt_nv_CURLOPT_PROTOCOLS setopt_nv_CURLPROTO -#define setopt_nv_CURLOPT_REDIR_PROTOCOLS setopt_nv_CURLPROTO #define setopt_nv_CURLOPT_PROXYTYPE setopt_nv_CURLPROXY #define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH #define setopt_nv_CURLOPT_SOCKS5_AUTH setopt_nv_CURLAUTH diff --git a/contrib/libs/curl/src/tool_util.c b/contrib/libs/curl/src/tool_util.c index 8d32343fe7..fb4829f84a 100644 --- a/contrib/libs/curl/src/tool_util.c +++ b/contrib/libs/curl/src/tool_util.c @@ -23,6 +23,10 @@ ***************************************************************************/ #include "tool_setup.h" +#if defined(HAVE_STRCASECMP) && defined(HAVE_STRINGS_H) +#include <strings.h> +#endif + #include "tool_util.h" #include "memdebug.h" /* keep this as LAST include */ @@ -135,3 +139,27 @@ long tvdiff(struct timeval newer, struct timeval older) return (long)(newer.tv_sec-older.tv_sec)*1000+ (long)(newer.tv_usec-older.tv_usec)/1000; } + +/* Case insensitive compare. Accept NULL pointers. */ +int struplocompare(const char *p1, const char *p2) +{ + if(!p1) + return p2? -1: 0; + if(!p2) + return 1; +#ifdef HAVE_STRCASECMP + return strcasecmp(p1, p2); +#elif defined(HAVE_STRCMPI) + return strcmpi(p1, p2); +#elif defined(HAVE_STRICMP) + return stricmp(p1, p2); +#else + return strcmp(p1, p2); +#endif +} + +/* Indirect version to use as qsort callback. */ +int struplocompare4sort(const void *p1, const void *p2) +{ + return struplocompare(* (char * const *) p1, * (char * const *) p2); +} diff --git a/contrib/libs/curl/src/tool_util.h b/contrib/libs/curl/src/tool_util.h index 366afe4a8b..72b355e685 100644 --- a/contrib/libs/curl/src/tool_util.h +++ b/contrib/libs/curl/src/tool_util.h @@ -35,4 +35,8 @@ struct timeval tvnow(void); */ long tvdiff(struct timeval t1, struct timeval t2); +/* Case insensitive comparison support. */ +int struplocompare(const char *p1, const char *p2); +int struplocompare4sort(const void *p1, const void *p2); + #endif /* HEADER_CURL_TOOL_UTIL_H */ diff --git a/contrib/libs/curl/src/tool_version.h b/contrib/libs/curl/src/tool_version.h index ec47821fa6..0bbb9a5092 100644 --- a/contrib/libs/curl/src/tool_version.h +++ b/contrib/libs/curl/src/tool_version.h @@ -27,7 +27,7 @@ #define CURL_NAME "curl" #define CURL_COPYRIGHT LIBCURL_COPYRIGHT -#define CURL_VERSION "7.85.0" +#define CURL_VERSION "7.86.0" #define CURL_VERSION_MAJOR LIBCURL_VERSION_MAJOR #define CURL_VERSION_MINOR LIBCURL_VERSION_MINOR #define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH diff --git a/contrib/libs/curl/src/tool_writeout.c b/contrib/libs/curl/src/tool_writeout.c index 478e8cc46e..2789ee20bf 100644 --- a/contrib/libs/curl/src/tool_writeout.c +++ b/contrib/libs/curl/src/tool_writeout.c @@ -195,8 +195,8 @@ static int writeString(FILE *stream, const struct writeoutvar *wovar, switch(wovar->id) { case VAR_ERRORMSG: if(per_result) { - strinfo = per->errorbuffer[0] ? per->errorbuffer : - curl_easy_strerror(per_result); + strinfo = (per->errorbuffer && per->errorbuffer[0]) ? + per->errorbuffer : curl_easy_strerror(per_result); valid = true; } break; diff --git a/contrib/libs/curl/src/tool_xattr.c b/contrib/libs/curl/src/tool_xattr.c index b2a509d005..bd05749966 100644 --- a/contrib/libs/curl/src/tool_xattr.c +++ b/contrib/libs/curl/src/tool_xattr.c @@ -22,17 +22,6 @@ * ***************************************************************************/ #include "tool_setup.h" - -#ifdef HAVE_FSETXATTR -# include <sys/xattr.h> /* header from libc, not from libattr */ -# define USE_XATTR -#elif (defined(__FreeBSD_version) && (__FreeBSD_version > 500000)) || \ - defined(__MidnightBSD_version) -# include <sys/types.h> -# include <sys/extattr.h> -# define USE_XATTR -#endif - #include "tool_xattr.h" #include "memdebug.h" /* keep this as LAST include */ @@ -48,26 +37,25 @@ static const struct xattr_mapping { * https://freedesktop.org/wiki/CommonExtendedAttributes/ */ { "user.xdg.referrer.url", CURLINFO_REFERER }, - { "user.xdg.origin.url", CURLINFO_EFFECTIVE_URL }, { "user.mime_type", CURLINFO_CONTENT_TYPE }, { NULL, CURLINFO_NONE } /* last element, abort here */ }; -/* returns TRUE if a new URL is returned, that then needs to be freed */ +/* returns a new URL that needs to be freed */ /* @unittest: 1621 */ #ifdef UNITTESTS -bool stripcredentials(char **url); +char *stripcredentials(const char *url); #else static #endif -bool stripcredentials(char **url) +char *stripcredentials(const char *url) { CURLU *u; CURLUcode uc; char *nurl; u = curl_url(); if(u) { - uc = curl_url_set(u, CURLUPART_URL, *url, 0); + uc = curl_url_set(u, CURLUPART_URL, url, 0); if(uc) goto error; @@ -85,59 +73,64 @@ bool stripcredentials(char **url) curl_url_cleanup(u); - *url = nurl; - return TRUE; + return nurl; } error: curl_url_cleanup(u); - return FALSE; + return NULL; } +static int xattr(int fd, + const char *attr, /* name of the xattr */ + const char *value) +{ + int err = 0; + if(value) { +#ifdef DEBUGBUILD + if(getenv("CURL_FAKE_XATTR")) { + printf("%s => %s\n", attr, value); + } + return 0; +#endif +#ifdef HAVE_FSETXATTR_6 + err = fsetxattr(fd, attr, value, strlen(value), 0, 0); +#elif defined(HAVE_FSETXATTR_5) + err = fsetxattr(fd, attr, value, strlen(value), 0); +#elif defined(__FreeBSD_version) || defined(__MidnightBSD_version) + { + ssize_t rc = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, + attr, value, strlen(value)); + /* FreeBSD's extattr_set_fd returns the length of the extended + attribute */ + err = (rc < 0 ? -1 : 0); + } +#endif + } + return err; +} /* store metadata from the curl request alongside the downloaded * file using extended attributes */ -int fwrite_xattr(CURL *curl, int fd) +int fwrite_xattr(CURL *curl, const char *url, int fd) { int i = 0; int err = 0; /* loop through all xattr-curlinfo pairs and abort on a set error */ - while(err == 0 && mappings[i].attr) { + while(!err && mappings[i].attr) { char *value = NULL; CURLcode result = curl_easy_getinfo(curl, mappings[i].info, &value); - if(!result && value) { - bool freeptr = FALSE; - if(CURLINFO_EFFECTIVE_URL == mappings[i].info) - freeptr = stripcredentials(&value); - if(value) { -#ifdef HAVE_FSETXATTR_6 - err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0, 0); -#elif defined(HAVE_FSETXATTR_5) - err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0); -#elif defined(__FreeBSD_version) || defined(__MidnightBSD_version) - { - ssize_t rc = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, - mappings[i].attr, value, strlen(value)); - /* FreeBSD's extattr_set_fd returns the length of the extended - attribute */ - err = (rc < 0 ? -1 : 0); - } -#endif - if(freeptr) - curl_free(value); - } - } + if(!result && value) + err = xattr(fd, mappings[i].attr, value); i++; } - + if(!err) { + char *nurl = stripcredentials(url); + if(!nurl) + return 1; + err = xattr(fd, "user.xdg.origin.url", nurl); + curl_free(nurl); + } return err; } -#else -int fwrite_xattr(CURL *curl, int fd) -{ - (void)curl; - (void)fd; - - return 0; -} #endif diff --git a/contrib/libs/curl/src/tool_xattr.h b/contrib/libs/curl/src/tool_xattr.h index 8cc0204138..e85d4cded5 100644 --- a/contrib/libs/curl/src/tool_xattr.h +++ b/contrib/libs/curl/src/tool_xattr.h @@ -25,6 +25,21 @@ ***************************************************************************/ #include "tool_setup.h" -int fwrite_xattr(CURL *curl, int fd); +#ifdef HAVE_FSETXATTR +# include <sys/xattr.h> /* header from libc, not from libattr */ +# define USE_XATTR +#elif (defined(__FreeBSD_version) && (__FreeBSD_version > 500000)) || \ + defined(__MidnightBSD_version) +# include <sys/types.h> +# include <sys/extattr.h> +# define USE_XATTR +#endif + +#ifdef USE_XATTR +int fwrite_xattr(CURL *curl, const char *url, int fd); + +#else +#define fwrite_xattr(a,b,c) 0 +#endif #endif /* HEADER_CURL_TOOL_XATTR_H */ |