Merge topic 'xcode-scheme-lldb-init-file'

419cfe30d0 Xcode: Support for 'LLDB Init File' scheme property
65ad1bbd4c vim: Remove duplicated keywords from cmake.vim
a96d6a98d3 Tests/RunCMake/XcodeProject: Improve XcodeSchemaProperty failure messages

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !10093
diff --git a/Help/command/add_executable.rst b/Help/command/add_executable.rst
index b6833b4..bab3714 100644
--- a/Help/command/add_executable.rst
+++ b/Help/command/add_executable.rst
@@ -14,8 +14,8 @@
   add_executable(<name> <options>... <sources>...)
   :target: normal
 
-  Add an executable target called ``<name>`` to be built from the source
-  files listed in the command invocation.
+  Add an :ref:`executable <Executables>` target called ``<name>`` to
+  be built from the source files listed in the command invocation.
 
   The options are:
 
diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst
index cab380e..58b576d 100644
--- a/Help/command/add_library.rst
+++ b/Help/command/add_library.rst
@@ -20,14 +20,17 @@
   The optional ``<type>`` specifies the type of library to be created:
 
   ``STATIC``
-    An archive of object files for use when linking other targets.
+    A :ref:`Static Library <Static Libraries>`:
+    an archive of object files for use when linking other targets.
 
   ``SHARED``
-    A dynamic library that may be linked by other targets and loaded
+    A :ref:`Shared Library <Shared Libraries>`:
+    a dynamic library that may be linked by other targets and loaded
     at runtime.
 
   ``MODULE``
-    A plugin that may not be linked by other targets, but may be
+    A :ref:`Module Library <Module Libraries>`:
+    a plugin that may not be linked by other targets, but may be
     dynamically loaded at runtime using dlopen-like functionality.
 
   If no ``<type>`` is given the default is ``STATIC`` or ``SHARED``
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
index caa6441..07ab0c4 100644
--- a/Help/command/target_link_libraries.rst
+++ b/Help/command/target_link_libraries.rst
@@ -238,6 +238,8 @@
 ``general`` (or without any keyword) are treated as if specified for both
 ``debug`` and ``optimized``.
 
+.. _`Linking Object Libraries`:
+
 Linking Object Libraries
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/Help/manual/cmake-buildsystem.7.rst b/Help/manual/cmake-buildsystem.7.rst
index eb25a4a..ce96bb7 100644
--- a/Help/manual/cmake-buildsystem.7.rst
+++ b/Help/manual/cmake-buildsystem.7.rst
@@ -37,10 +37,13 @@
 When linking the ``zipapp`` executable, the ``archive`` static library is
 linked in.
 
-.. _`Binary Executables`:
+.. _`Executables`:
 
-Binary Executables
-------------------
+Executables
+-----------
+
+Executables are binaries created by linking object files together,
+one of which contains a program entry point, e.g., ``main``.
 
 The :command:`add_executable` command defines an executable target:
 
@@ -48,56 +51,101 @@
 
   add_executable(mytool mytool.cpp)
 
+CMake generates build rules to compile the source files into object
+files and link them into an executable.
+
+Link dependencies of executables may be specified using the
+:command:`target_link_libraries` command.  Linkers start with the
+object files compiled from the executable's own source files, and
+then resolve remaining symbol dependencies by searching linked libraries.
+
 Commands such as :command:`add_custom_command`, which generates rules to be
 run at build time can transparently use an :prop_tgt:`EXECUTABLE <TYPE>`
 target as a ``COMMAND`` executable.  The buildsystem rules will ensure that
 the executable is built before attempting to run the command.
 
-Binary Library Types
---------------------
+.. _`Static Libraries`:
 
-.. _`Normal Libraries`:
+Static Libraries
+----------------
 
-Normal Libraries
-^^^^^^^^^^^^^^^^
+Static libraries are archives of object files.  They are produced by an
+archiver, not a linker.  `Executables`_, `Shared Libraries`_, and
+`Module Libraries`_ may link to static libraries as dependencies.
+Linkers select subsets of object files from static libraries as needed
+to resolve symbols and link them into consuming binaries.  Each binary
+that links to a static library gets its own copy of the symbols, and
+the static library itself is not needed at runtime.
 
-By default, the :command:`add_library` command defines a ``STATIC`` library,
-unless a type is specified.  A type may be specified when using the command:
-
-.. code-block:: cmake
-
-  add_library(archive SHARED archive.cpp zip.cpp lzma.cpp)
+The :command:`add_library` command defines a static library target
+when called with the ``STATIC`` library type:
 
 .. code-block:: cmake
 
   add_library(archive STATIC archive.cpp zip.cpp lzma.cpp)
 
-The :variable:`BUILD_SHARED_LIBS` variable may be enabled to change the
-behavior of :command:`add_library` to build shared libraries by default.
-
-In the context of the buildsystem definition as a whole, it is largely
-irrelevant whether particular libraries are ``SHARED`` or ``STATIC`` --
-the commands, dependency specifications and other APIs work similarly
-regardless of the library type.  The ``MODULE`` library type is
-dissimilar in that it is generally not linked to -- it is not used in
-the right-hand-side of the :command:`target_link_libraries` command.
-It is a type which is loaded as a plugin using runtime techniques.
-If the library does not export any unmanaged symbols (e.g. Windows
-resource DLL, C++/CLI DLL), it is required that the library not be a
-``SHARED`` library because CMake expects ``SHARED`` libraries to export
-at least one symbol.
+or, when the :variable:`BUILD_SHARED_LIBS` variable is false, with no type:
 
 .. code-block:: cmake
 
-  add_library(archive MODULE 7z.cpp)
+  add_library(archive archive.cpp zip.cpp lzma.cpp)
+
+CMake generates build rules to compile the source files into object
+files and archive them into a static library.
+
+Link dependencies of static libraries may be specified using the
+:command:`target_link_libraries` command.  Since static libraries are
+archives rather than linked binaries, object files from their link
+dependencies are not included in the libraries themselves (except for
+`Object Libraries`_ specified as *direct* link dependencies).
+Instead, CMake records static libraries' link dependencies for
+transitive use when linking consuming binaries.
+
+.. _`Shared Libraries`:
+
+Shared Libraries
+----------------
+
+Shared libraries are binaries created by linking object files together.
+`Executables`_, other shared libraries, and `Module Libraries`_ may link
+to shared libraries as dependencies.  Linkers record references to shared
+libraries in consuming binaries.  At runtime, a dynamic loader searches
+for referenced shared libraries on disk and loads their symbols.
+
+The :command:`add_library` command defines a shared library target
+when called with the ``SHARED`` library type:
+
+.. code-block:: cmake
+
+  add_library(archive SHARED archive.cpp zip.cpp lzma.cpp)
+
+or, when the :variable:`BUILD_SHARED_LIBS` variable is true, with no type:
+
+.. code-block:: cmake
+
+  add_library(archive archive.cpp zip.cpp lzma.cpp)
+
+CMake generates build rules to compile the source files into object
+files and link them into a shared library.
+
+Link dependencies of shared libraries may be specified using the
+:command:`target_link_libraries` command.  Linkers start with the
+object files compiled from the shared library's own source files, and
+then resolve remaining symbol dependencies by searching linked libraries.
+
+.. note::
+
+  CMake expects shared libraries to export at least one symbol.  If a library
+  does not export any unmanaged symbols, e.g., a Windows resource DLL or
+  C++/CLI DLL, make it a `Module Library <Module Libraries>`_ instead.
 
 .. _`Apple Frameworks`:
 
 Apple Frameworks
-""""""""""""""""
+----------------
 
-A ``SHARED`` library may be marked with the :prop_tgt:`FRAMEWORK`
-target property to create an macOS or iOS Framework Bundle.
+`Shared Libraries`_ and `Static Libraries`_ may be marked with the
+:prop_tgt:`FRAMEWORK` target property to create a macOS or iOS Framework.
 A library with the ``FRAMEWORK`` target property should also set the
 :prop_tgt:`FRAMEWORK_VERSION` target property.  This property is typically
 set to the value of "A" by macOS conventions.
@@ -113,46 +161,80 @@
     MACOSX_FRAMEWORK_IDENTIFIER org.cmake.MyFramework
   )
 
+.. _`Module Libraries`:
+
+Module Libraries
+----------------
+
+Module libraries are binaries created by linking object files together.
+Unlike `Shared Libraries`_, module libraries may not be linked by other
+binaries as dependencies -- do not name them in the right-hand side of
+the :command:`target_link_libraries` command.  Instead, module libraries
+are plugins that an application can dynamically load on-demand at runtime,
+e.g., by ``dlopen``.
+
+The :command:`add_library` command defines a module library target
+when called with the ``MODULE`` library type:
+
+.. code-block:: cmake
+
+  add_library(archivePlugin MODULE 7z.cpp)
+
+CMake generates build rules to compile the source files into object
+files and link them into a module library.
+
+Link dependencies of module libraries may be specified using the
+:command:`target_link_libraries` command.  Linkers start with the
+object files compiled from the module library's own source files, and
+then resolve remaining symbol dependencies by searching linked libraries.
+
 .. _`Object Libraries`:
 
 Object Libraries
-^^^^^^^^^^^^^^^^
+----------------
 
-The ``OBJECT`` library type defines a non-archival collection of object files
-resulting from compiling the given source files.  The object files collection
-may be used as source inputs to other targets by using the syntax
-:genex:`$<TARGET_OBJECTS:name>`.  This is a
-:manual:`generator expression <cmake-generator-expressions(7)>` that can be
-used to supply the ``OBJECT`` library content to other targets:
+Object libraries are collections of object files created by compiling
+source files without any archiving or linking.  The object files may be
+used when linking `Executables`_, `Shared Libraries`_, and
+`Module Libraries`_, or when archiving `Static Libraries`_.
+
+The :command:`add_library` command defines an object library target
+when called with the ``OBJECT`` library type:
 
 .. code-block:: cmake
 
-  add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp)
+  add_library(archiveObjs OBJECT archive.cpp zip.cpp lzma.cpp)
 
-  add_library(archiveExtras STATIC $<TARGET_OBJECTS:archive> extras.cpp)
+CMake generates build rules to compile the source files into object files.
 
-  add_executable(test_exe $<TARGET_OBJECTS:archive> test.cpp)
-
-The link (or archiving) step of those other targets will use the object
-files collection in addition to those from their own sources.
-
-Alternatively, object libraries may be linked into other targets:
+Other targets may specify the object files as source inputs by using the
+:manual:`generator expression <cmake-generator-expressions(7)>` syntax
+:genex:`$<TARGET_OBJECTS:name>`:
 
 .. code-block:: cmake
 
-  add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp)
+  add_library(archiveExtras STATIC $<TARGET_OBJECTS:archiveObjs> extras.cpp)
+
+  add_executable(test_exe $<TARGET_OBJECTS:archiveObjs> test.cpp)
+
+The consuming targets are linked (or archived) using object files
+both from their own sources and from the named object libraries.
+
+Alternatively, object libraries may be specified as link dependencies
+of other targets:
+
+.. code-block:: cmake
 
   add_library(archiveExtras STATIC extras.cpp)
-  target_link_libraries(archiveExtras PUBLIC archive)
+  target_link_libraries(archiveExtras PUBLIC archiveObjs)
 
   add_executable(test_exe test.cpp)
-  target_link_libraries(test_exe archive)
+  target_link_libraries(test_exe archiveObjs)
 
-The link (or archiving) step of those other targets will use the object
-files from ``OBJECT`` libraries that are *directly* linked.  Additionally,
-usage requirements of the ``OBJECT`` libraries will be honored when compiling
-sources in those other targets.  Furthermore, those usage requirements
-will propagate transitively to dependents of those other targets.
+The consuming targets are linked (or archived) using object files
+both from their own sources and from object libraries specified as
+*direct* link dependencies by :command:`target_link_libraries`.
+See :ref:`Linking Object Libraries`.
 
 Object libraries may not be used as the ``TARGET`` in a use of the
 :command:`add_custom_command(TARGET)` command signature.  However,
@@ -386,14 +468,15 @@
 
 :prop_tgt:`LINK_LIBRARIES`
   List of link libraries for linking the target, if it is an executable,
-  shared library, or module library.  Entries for `Normal Libraries`_ are
-  passed to the linker either via paths to their link artifacts, or
-  with ``-l`` flags or equivalent.  Entries for `Object Libraries`_ are
-  passed to the linker via paths to their object files.
+  shared library, or module library.  Entries for `Static Libraries`_
+  and `Shared Libraries`_ are passed to the linker either via paths to
+  their link artifacts, or with ``-l`` flags or equivalent.  Entries for
+  `Object Libraries`_ are passed to the linker via paths to their object
+  files.
 
   Additionally, for compiling and linking the target itself,
   `usage requirements <Target Usage Requirements_>`_ are propagated from
-  ``LINK_LIBRARIES`` entries naming `Normal Libraries`_,
+  ``LINK_LIBRARIES`` entries naming `Static Libraries`_, `Shared Libraries`_,
   `Interface Libraries`_, `Object Libraries`_, and `Imported Targets`_,
   collected over the transitive closure of their
   :prop_tgt:`INTERFACE_LINK_LIBRARIES` properties.
@@ -581,8 +664,8 @@
   Additionally, for compiling and linking the target's consumers,
   `usage requirements <Target Usage Requirements_>`_ are collected from
   the transitive closure of ``INTERFACE_LINK_LIBRARIES`` entries naming
-  `Normal Libraries`_, `Interface Libraries`_, `Object Libraries`_,
-  and `Imported Targets`_,
+  `Static Libraries`_, `Shared Libraries`_, `Interface Libraries`_,
+  `Object Libraries`_, and `Imported Targets`_,
 
 :prop_tgt:`INTERFACE_LINK_DIRECTORIES`
   .. versionadded:: 3.13
diff --git a/Help/prop_tgt/DEBUGGER_WORKING_DIRECTORY.rst b/Help/prop_tgt/DEBUGGER_WORKING_DIRECTORY.rst
index 135e304..a95a465 100644
--- a/Help/prop_tgt/DEBUGGER_WORKING_DIRECTORY.rst
+++ b/Help/prop_tgt/DEBUGGER_WORKING_DIRECTORY.rst
@@ -3,9 +3,9 @@
 
 .. versionadded:: 3.32
 
-  Sets the local debugger working directory for C++ targets.
-  The property value may use
-  :manual:`generator expressions <cmake-generator-expressions(7)>`.
-  This property is initialized by the value of the variable
-  :variable:`CMAKE_DEBUGGER_WORKING_DIRECTORY` if it is set when a target is
-  created.
+Sets the local debugger working directory for C++ targets.
+The property value may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+This property is initialized by the value of the variable
+:variable:`CMAKE_DEBUGGER_WORKING_DIRECTORY` if it is set when a target is
+created.
diff --git a/Help/prop_tgt/IMPORTED_CONFIGURATIONS.rst b/Help/prop_tgt/IMPORTED_CONFIGURATIONS.rst
index a4746d3..9daefb8 100644
--- a/Help/prop_tgt/IMPORTED_CONFIGURATIONS.rst
+++ b/Help/prop_tgt/IMPORTED_CONFIGURATIONS.rst
@@ -9,8 +9,7 @@
 
 * :prop_tgt:`IMPORTED_LOCATION_<CONFIG>`, or
 * :prop_tgt:`IMPORTED_IMPLIB_<CONFIG>` (on DLL platforms, on AIX for
-  :ref:`Executables <Binary Executables>` or on Apple for
-  :ref:`Shared Libraries <Normal Libraries>`), or
+  :ref:`Executables` or on Apple for :ref:`Shared Libraries`), or
 * :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>` (for :ref:`Object Libraries`), or
 * :prop_tgt:`IMPORTED_LIBNAME_<CONFIG>` (for :ref:`Interface Libraries`).
 
diff --git a/Help/prop_tgt/LINK_WHAT_YOU_USE.rst b/Help/prop_tgt/LINK_WHAT_YOU_USE.rst
index d6de0d4..08d263c 100644
--- a/Help/prop_tgt/LINK_WHAT_YOU_USE.rst
+++ b/Help/prop_tgt/LINK_WHAT_YOU_USE.rst
@@ -3,14 +3,15 @@
 
 .. versionadded:: 3.7
 
-This is a boolean option that, when set to ``TRUE``, will automatically run
-contents of variable :variable:`CMAKE_LINK_WHAT_YOU_USE_CHECK` on the target
-after it is linked. In addition, the linker flag specified by variable
-:variable:`CMAKE_<LANG>_LINK_WHAT_YOU_USE_FLAG`  will be passed to the target
-with the link command so that all libraries specified on the command line will
-be linked into the target. This will result in the link producing a list of
-libraries that provide no symbols used by this target but are being linked to
-it.
+This is a boolean option that, when set to ``TRUE``, adds a link-time check
+to print a list of shared libraries that are being linked but provide no symbols
+used by the target.  This is intended as a lint.
+
+The flag specified by :variable:`CMAKE_<LANG>_LINK_WHAT_YOU_USE_FLAG` will
+be passed to the linker so that all libraries specified on the command line
+will be linked into the target.  Then the command specified by
+:variable:`CMAKE_LINK_WHAT_YOU_USE_CHECK` will run after the target is linked
+to check the binary for unnecessarily-linked shared libraries.
 
 .. note::
 
diff --git a/Help/variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG.rst b/Help/variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG.rst
index 5004530..ea1a3d2 100644
--- a/Help/variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG.rst
+++ b/Help/variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG.rst
@@ -3,7 +3,13 @@
 
 .. versionadded:: 3.22
 
-Linker flag to be used to configure linker so that all specified libraries on
-the command line will be linked into the target.
+Linker flag used by :prop_tgt:`LINK_WHAT_YOU_USE` to tell the linker to
+link all shared libraries specified on the command line even if none
+of their symbols is needed.  This is an implementation detail used so
+that the command in :variable:`CMAKE_LINK_WHAT_YOU_USE_CHECK` can check
+the binary for unnecessarily-linked shared libraries.
 
-See also variable :variable:`CMAKE_LINK_WHAT_YOU_USE_CHECK`.
+.. note::
+
+  Do not rely on this abstraction to intentionally link to
+  shared libraries whose symbols are not needed.
diff --git a/Help/variable/CMAKE_LINK_WHAT_YOU_USE_CHECK.rst b/Help/variable/CMAKE_LINK_WHAT_YOU_USE_CHECK.rst
index e626641..382b4db 100644
--- a/Help/variable/CMAKE_LINK_WHAT_YOU_USE_CHECK.rst
+++ b/Help/variable/CMAKE_LINK_WHAT_YOU_USE_CHECK.rst
@@ -3,7 +3,8 @@
 
 .. versionadded:: 3.22
 
-Defines the command executed after the link step to check libraries usage.
+Command executed by :prop_tgt:`LINK_WHAT_YOU_USE` after the linker to
+check for unnecessarily-linked shared libraries.
 This check is currently only defined on ``ELF`` platforms with value
 ``ldd -u -r``.
 
diff --git a/Modules/CMakeParseImplicitLinkInfo.cmake b/Modules/CMakeParseImplicitLinkInfo.cmake
index d9ecbd8..2eeb375 100644
--- a/Modules/CMakeParseImplicitLinkInfo.cmake
+++ b/Modules/CMakeParseImplicitLinkInfo.cmake
@@ -61,7 +61,7 @@
     endif()
   endif()
   # Parse implicit linker arguments.
-  set(linker "ld[0-9]*(\\.[a-z]+)?")
+  set(linker "ld[0-9]*(|\\.[a-rt-z][a-z]*|\\.s[a-np-z][a-z]*|\\.so[a-z]+)")
   if(is_lfortran_less_0_40)
     # lfortran < 0.40 has no way to pass -v to clang/gcc driver.
     string(APPEND linker "|clang|gcc")
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
index 856b9ec..f24f62c 100644
--- a/Modules/FindPython.cmake
+++ b/Modules/FindPython.cmake
@@ -433,9 +433,9 @@
 
   .. note::
 
-    If the component ``Development`` is requested, it is **strongly**
-    recommended to also include the component ``Interpreter`` to get expected
-    result.
+    If the component ``Development`` is requested (or one of its
+    sub-components) and is not found or the wrong artifacts are returned,
+    including also the component ``Interpreter`` may be helpful.
 
 ``Python_FIND_IMPLEMENTATIONS``
   .. versionadded:: 3.18
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index c741ec1..7e04890 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -1727,7 +1727,22 @@
 else()
   set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STANDARD)
 endif()
-
+if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$" AND DEFINED ENV{VIRTUAL_ENV})
+  # retrieve root_dir of python installation
+  block(SCOPE_FOR VARIABLES PROPAGATE _${_PYTHON_PREFIX}_VIRTUALENV_ROOT_DIR)
+    if (IS_READABLE "$ENV{VIRTUAL_ENV}/pyvenv.cfg")
+      file(STRINGS "$ENV{VIRTUAL_ENV}/pyvenv.cfg" python_home REGEX "^home = .+")
+      if(python_home MATCHES "^home = (.+)$")
+        cmake_path(SET _${_PYTHON_PREFIX}_VIRTUALENV_ROOT_DIR "${CMAKE_MATCH_1}")
+        if (_${_PYTHON_PREFIX}_VIRTUALENV_ROOT_DIR MATCHES "bin$")
+          cmake_path(GET _${_PYTHON_PREFIX}_VIRTUALENV_ROOT_DIR PARENT_PATH _${_PYTHON_PREFIX}_VIRTUALENV_ROOT_DIR)
+        endif()
+      endif()
+    endif()
+  endblock()
+else()
+  unset(_${_PYTHON_PREFIX}_VIRTUALENV_ROOT_DIR)
+endif()
 
 # Python naming handling
 if (DEFINED ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES)
@@ -2821,7 +2836,7 @@
       set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
       unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
       if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
-        set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+        set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS "${_${_PYTHON_PREFIX}_VIRTUALENV_ROOT_DIR}" ENV VIRTUAL_ENV ENV CONDA_PREFIX)
       endif()
 
       if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
@@ -2829,37 +2844,69 @@
           # Framework Paths
         _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
 
-        # Apple frameworks handling
-        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+        while (TRUE)
+          # Virtual environments handling
+          if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+            find_program (_${_PYTHON_PREFIX}_CONFIG
+                          NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                          NAMES_PER_DIR
+                          HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                          PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                          PATH_SUFFIXES bin
+                          NO_CMAKE_PATH
+                          NO_CMAKE_ENVIRONMENT_PATH
+                          NO_SYSTEM_ENVIRONMENT_PATH
+                          NO_CMAKE_SYSTEM_PATH)
+            if (_${_PYTHON_PREFIX}_CONFIG)
+              break()
+            endif()
+            if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+              break()
+            endif()
+          endif()
+
+          # Apple frameworks handling
+          if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+            find_program (_${_PYTHON_PREFIX}_CONFIG
+                          NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                          NAMES_PER_DIR
+                          HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                          PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                          PATH_SUFFIXES bin
+                          NO_CMAKE_PATH
+                          NO_CMAKE_ENVIRONMENT_PATH
+                          NO_SYSTEM_ENVIRONMENT_PATH
+                          NO_CMAKE_SYSTEM_PATH)
+            if (_${_PYTHON_PREFIX}_CONFIG)
+              break()
+            endif()
+          endif()
+
           find_program (_${_PYTHON_PREFIX}_CONFIG
                         NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
                         NAMES_PER_DIR
                         HINTS ${_${_PYTHON_PREFIX}_HINTS}
                         PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
-                              ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
-                        PATH_SUFFIXES bin
-                        NO_CMAKE_PATH
-                        NO_CMAKE_ENVIRONMENT_PATH
-                        NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
-        endif()
+                        PATH_SUFFIXES bin)
+          if (_${_PYTHON_PREFIX}_CONFIG)
+            break()
+          endif()
 
-        find_program (_${_PYTHON_PREFIX}_CONFIG
-                      NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
-                      NAMES_PER_DIR
-                      HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                      PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
-                      PATH_SUFFIXES bin)
+          # Apple frameworks handling
+          if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+            find_program (_${_PYTHON_PREFIX}_CONFIG
+                          NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                          NAMES_PER_DIR
+                          PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                          PATH_SUFFIXES bin
+                          NO_DEFAULT_PATH)
+            if (_${_PYTHON_PREFIX}_CONFIG)
+              break()
+            endif()
+          endif()
 
-        # Apple frameworks handling
-        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
-          find_program (_${_PYTHON_PREFIX}_CONFIG
-                        NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
-                        NAMES_PER_DIR
-                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
-                        PATH_SUFFIXES bin
-                        NO_DEFAULT_PATH)
-        endif()
+          break()
+        endwhile()
 
         _python_get_launcher (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER CONFIG "${_${_PYTHON_PREFIX}_CONFIG}")
 
@@ -2919,37 +2966,69 @@
           # Framework Paths
           _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
 
-          # Apple frameworks handling
-          if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+          while (TRUE)
+            # Virtual environments handling
+            if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+              find_program (_${_PYTHON_PREFIX}_CONFIG
+                            NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                            NAMES_PER_DIR
+                            HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                            PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                            PATH_SUFFIXES bin
+                            NO_CMAKE_PATH
+                            NO_CMAKE_ENVIRONMENT_PATH
+                            NO_SYSTEM_ENVIRONMENT_PATH
+                            NO_CMAKE_SYSTEM_PATH)
+              if (_${_PYTHON_PREFIX}_CONFIG)
+                break()
+              endif()
+              if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+                break()
+              endif()
+            endif()
+
+            # Apple frameworks handling
+            if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+              find_program (_${_PYTHON_PREFIX}_CONFIG
+                            NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                            NAMES_PER_DIR
+                            HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                            PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                            PATH_SUFFIXES bin
+                            NO_CMAKE_PATH
+                            NO_CMAKE_ENVIRONMENT_PATH
+                            NO_SYSTEM_ENVIRONMENT_PATH
+                            NO_CMAKE_SYSTEM_PATH)
+              if (_${_PYTHON_PREFIX}_CONFIG)
+                break()
+              endif()
+            endif()
+
             find_program (_${_PYTHON_PREFIX}_CONFIG
                           NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
                           NAMES_PER_DIR
                           HINTS ${_${_PYTHON_PREFIX}_HINTS}
                           PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
-                                ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
-                          PATH_SUFFIXES bin
-                          NO_CMAKE_PATH
-                          NO_CMAKE_ENVIRONMENT_PATH
-                          NO_SYSTEM_ENVIRONMENT_PATH
-                          NO_CMAKE_SYSTEM_PATH)
-          endif()
+                          PATH_SUFFIXES bin)
+            if (_${_PYTHON_PREFIX}_CONFIG)
+              break()
+            endif()
 
-          find_program (_${_PYTHON_PREFIX}_CONFIG
-                        NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
-                        NAMES_PER_DIR
-                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                        PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
-                        PATH_SUFFIXES bin)
+            # Apple frameworks handling
+            if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+              find_program (_${_PYTHON_PREFIX}_CONFIG
+                            NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                            NAMES_PER_DIR
+                            PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                            PATH_SUFFIXES bin
+                            NO_DEFAULT_PATH)
+              if (_${_PYTHON_PREFIX}_CONFIG)
+                break()
+              endif()
+            endif()
 
-          # Apple frameworks handling
-          if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
-            find_program (_${_PYTHON_PREFIX}_CONFIG
-                          NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
-                          NAMES_PER_DIR
-                          PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
-                          PATH_SUFFIXES bin
-                          NO_DEFAULT_PATH)
-          endif()
+            break()
+          endwhile()
 
           unset (_${_PYTHON_PREFIX}_CONFIG_NAMES)
 
@@ -3057,7 +3136,7 @@
 
         unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
         if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
-          set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+          set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS "${_${_PYTHON_PREFIX}_VIRTUALENV_ROOT_DIR}" ENV VIRTUAL_ENV ENV CONDA_PREFIX)
         endif()
 
         if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
@@ -3324,7 +3403,7 @@
 
           unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
           if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
-            set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+            set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS "${_${_PYTHON_PREFIX}_VIRTUALENV_ROOT_DIR}" ENV VIRTUAL_ENV ENV CONDA_PREFIX)
           endif()
 
           if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
@@ -3561,7 +3640,7 @@
       if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
         unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
         if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
-          set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+          set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS "${_${_PYTHON_PREFIX}_VIRTUALENV_ROOT_DIR}" ENV VIRTUAL_ENV ENV CONDA_PREFIX)
         endif()
         unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS)
 
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
index cdb4038..fbf2827 100644
--- a/Modules/FindPython2.cmake
+++ b/Modules/FindPython2.cmake
@@ -321,9 +321,9 @@
 
   .. note::
 
-    If the component ``Development`` is requested, it is **strongly**
-    recommended to also include the component ``Interpreter`` to get expected
-    result.
+    If the component ``Development`` is requested (or one of its
+    sub-components) and is not found or the wrong artifacts are returned,
+    including also the component ``Interpreter`` may be helpful.
 
 ``Python2_FIND_IMPLEMENTATIONS``
   .. versionadded:: 3.18
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
index 2061a27..6aec784 100644
--- a/Modules/FindPython3.cmake
+++ b/Modules/FindPython3.cmake
@@ -431,9 +431,9 @@
 
   .. note::
 
-    If the component ``Development`` is requested, it is **strongly**
-    recommended to also include the component ``Interpreter`` to get expected
-    result.
+    If the component ``Development`` is requested (or one of its
+    sub-components) and is not found or the wrong artifacts are returned,
+    including also the component ``Interpreter`` may be helpful.
 
 ``Python3_FIND_IMPLEMENTATIONS``
   .. versionadded:: 3.18
diff --git a/Modules/Platform/GNU-GNU-C.cmake b/Modules/Platform/GNU-GNU-C.cmake
new file mode 100644
index 0000000..2e433dc
--- /dev/null
+++ b/Modules/Platform/GNU-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/GNU-GNU)
+__gnu_compiler_gnu(C)
diff --git a/Modules/Platform/GNU-GNU-CXX.cmake b/Modules/Platform/GNU-GNU-CXX.cmake
new file mode 100644
index 0000000..1c213bd
--- /dev/null
+++ b/Modules/Platform/GNU-GNU-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/GNU-GNU)
+__gnu_compiler_gnu(CXX)
diff --git a/Modules/Platform/GNU-GNU-Fortran.cmake b/Modules/Platform/GNU-GNU-Fortran.cmake
new file mode 100644
index 0000000..b552b16
--- /dev/null
+++ b/Modules/Platform/GNU-GNU-Fortran.cmake
@@ -0,0 +1,3 @@
+include(Platform/GNU-GNU)
+__gnu_compiler_gnu(Fortran)
+set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "")
diff --git a/Modules/Platform/GNU-GNU.cmake b/Modules/Platform/GNU-GNU.cmake
new file mode 100644
index 0000000..c03d6c9
--- /dev/null
+++ b/Modules/Platform/GNU-GNU.cmake
@@ -0,0 +1,27 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__GNU_COMPILER_GNU)
+  return()
+endif()
+set(__GNU_COMPILER_GNU 1)
+
+macro(__gnu_compiler_gnu lang)
+  # We pass this for historical reasons.  Projects may have
+  # executables that use dlopen but do not set ENABLE_EXPORTS.
+  set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
+
+  set(CMAKE_${lang}_VERBOSE_LINK_FLAG "-Wl,-v")
+
+  # linker selection
+  set(CMAKE_${lang}_USING_LINKER_SYSTEM "")
+  set(CMAKE_${lang}_USING_LINKER_LLD "-fuse-ld=lld")
+  set(CMAKE_${lang}_USING_LINKER_BFD "-fuse-ld=bfd")
+  set(CMAKE_${lang}_USING_LINKER_GOLD "-fuse-ld=gold")
+  if(NOT CMAKE_${lang}_COMPILER_ID STREQUAL "GNU"
+      OR CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
+    set(CMAKE_${lang}_USING_LINKER_MOLD "-fuse-ld=mold")
+  endif()
+endmacro()
diff --git a/Modules/Platform/GNU.cmake b/Modules/Platform/GNU.cmake
index a30667b..6a25b00 100644
--- a/Modules/Platform/GNU.cmake
+++ b/Modules/Platform/GNU.cmake
@@ -9,6 +9,27 @@
 set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
 set(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
 
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
+# Initialize C link type selection flags.  These flags are used when
+# building a shared library, shared module, or executable that links
+# to other libraries to select whether to use the static or shared
+# versions of the libraries.
+foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+  set(CMAKE_${type}_LINK_STATIC_C_FLAGS "-Wl,-Bstatic")
+  set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Wl,-Bdynamic")
+endforeach()
+
+
+# Features for LINK_GROUP generator expression
+## RESCAN: request the linker to rescan static libraries until there is
+## no pending undefined symbols
+set(CMAKE_LINK_GROUP_USING_RESCAN "LINKER:--start-group" "LINKER:--end-group")
+set(CMAKE_LINK_GROUP_USING_RESCAN_SUPPORTED TRUE)
+
+
 # Debian policy requires that shared libraries be installed without
 # executable permission.  Fedora policy requires that shared libraries
 # be installed with the executable permission.  Since the native tools
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 308b69a..fc2e8f3 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 31)
-set(CMake_VERSION_PATCH 20241212)
+set(CMake_VERSION_PATCH 20241216)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index f3d95b5..da29b9e 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -1437,7 +1437,7 @@
       // The file location was cached.  Look for the correct file.
       std::string file;
       if (this->FindConfigFile(dir, file)) {
-        this->FileFound = file;
+        this->FileFound = std::move(file);
         fileFound = true;
       }
       def = this->Makefile->GetDefinition(this->Variable);
@@ -2409,9 +2409,9 @@
   }
 
   // Look for the file in this directory.
-  if (this->FindConfigFile(d, this->FileFound)) {
-    // Remove duplicate slashes.
-    cmSystemTools::ConvertToUnixSlashes(this->FileFound);
+  std::string file;
+  if (this->FindConfigFile(d, file)) {
+    this->FileFound = std::move(file);
     return true;
   }
   return false;
@@ -2429,6 +2429,8 @@
       // Allow resolving symlinks when the config file is found through a link
       if (this->UseRealPath) {
         file = cmSystemTools::GetRealPath(file);
+      } else {
+        file = cmSystemTools::ToNormalizedPathOnDisk(file);
       }
       return true;
     }
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index be510b1..bcb3b17 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -684,7 +684,7 @@
 
   # Configure the header for this class.
   configure_file(${PROJECT_SOURCE_DIR}/${c}.hxx.in ${KWSYS_HEADER_DIR}/${c}.hxx
-                 @ONLY IMMEDIATE)
+                 @ONLY)
   set(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${c}.hxx)
 
   # Create an install target for the header.
@@ -699,7 +699,7 @@
 foreach(h IN LISTS KWSYS_H_FILES)
   # Configure the header into the given directory.
   configure_file(${PROJECT_SOURCE_DIR}/${h}.h.in ${KWSYS_HEADER_DIR}/${h}.h
-                 @ONLY IMMEDIATE)
+                 @ONLY)
   set(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${KWSYS_HEADER_DIR}/${h}.h)
 
   # Create an install target for the header.
@@ -714,7 +714,7 @@
 foreach(h IN LISTS KWSYS_HXX_FILES)
   # Configure the header into the given directory.
   configure_file(${PROJECT_SOURCE_DIR}/${h}.hxx.in ${KWSYS_HEADER_DIR}/${h}.hxx
-                 @ONLY IMMEDIATE)
+                 @ONLY)
   set(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${h}.hxx)
 
   # Create an install target for the header.
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 92eae41..272ad85 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -27,7 +27,7 @@
 #include <cstdio>
 #include <cstring>
 namespace KWSYS_NAMESPACE {
-#if defined(_WIN32) || defined(__APPLE__)
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(__APPLE__)
 // On Windows and Apple, no difference between lower and upper case
 #  define KWSYS_GLOB_CASE_INDEPENDENT
 #endif
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index 252b9e9..6056030 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -59,7 +59,6 @@
   { include: [ "@<.*curl/system.h>", private, "<cm3p/curl/curl.h>", public ] },
   { include: [ "@<.*json/config.h>", private, "<cm3p/json/value.h>", public ] },
   { include: [ "@<.*json/forwards.h>", private, "<cm3p/json/value.h>", public ] },
-  { include: [ "@<.*json/version.h>", private, "<cm3p/json/value.h>", public ] },
   { include: [ "@<.*uv/.+\\.h>", private, "<cm3p/uv.h>", public ] },
   { include: [ "@<.*expat_external.h>", private, "<cm3p/expat.h>", public ] },
   { include: [ "@<.*zconf.h>", private, "<cm3p/zlib.h>", public ] },
diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash
index fb2a12a..ffae7b6 100755
--- a/Utilities/Scripts/update-curl.bash
+++ b/Utilities/Scripts/update-curl.bash
@@ -8,7 +8,7 @@
 readonly ownership="Curl Upstream <curl-library@lists.haxx.se>"
 readonly subtree="Utilities/cmcurl"
 readonly repo="https://github.com/curl/curl.git"
-readonly tag="curl-8_10_1"
+readonly tag="curl-8_11_1"
 readonly shortlog=false
 readonly paths="
   CMake/*
diff --git a/Utilities/cm3p/json/version.h b/Utilities/cm3p/json/version.h
new file mode 100644
index 0000000..49f83fa
--- /dev/null
+++ b/Utilities/cm3p/json/version.h
@@ -0,0 +1,11 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+/* Use the jsoncpp library configured for CMake.  */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_JSONCPP
+#  include <json/version.h> // IWYU pragma: export
+#else
+#  include <cmjsoncpp/include/json/version.h> // IWYU pragma: export
+#endif
diff --git a/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake b/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake
index 00b7b3c..16ec3fe 100644
--- a/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake
+++ b/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake
@@ -21,8 +21,6 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-include(CheckCSourceCompiles)
-
 option(CURL_HIDDEN_SYMBOLS "Hide libcurl internal symbols (=hide all symbols that are not officially external)" ON)
 mark_as_advanced(CURL_HIDDEN_SYMBOLS)
 
@@ -33,48 +31,36 @@
   set(CURL_HIDDEN_SYMBOLS OFF)
 endif()
 
-if(CURL_HIDDEN_SYMBOLS)
-  set(_supports_symbol_hiding FALSE)
+set(CURL_HIDES_PRIVATE_SYMBOLS FALSE)
+unset(CURL_EXTERN_SYMBOL)
+unset(CURL_CFLAG_SYMBOLS_HIDE)
 
+if(CURL_HIDDEN_SYMBOLS)
   if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT MSVC)
-    set(_supports_symbol_hiding TRUE)
-    set(_symbol_extern "__attribute__ ((__visibility__ (\"default\")))")
-    set(_cflag_symbols_hide "-fvisibility=hidden")
+    set(CURL_HIDES_PRIVATE_SYMBOLS TRUE)
+    set(CURL_EXTERN_SYMBOL "__attribute__((__visibility__(\"default\")))")
+    set(CURL_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
   elseif(CMAKE_COMPILER_IS_GNUCC)
     if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
       # Note: This is considered buggy prior to 4.0 but the autotools do not care, so let us ignore that fact
-      set(_supports_symbol_hiding TRUE)
-      set(_symbol_extern "__attribute__ ((__visibility__ (\"default\")))")
-      set(_cflag_symbols_hide "-fvisibility=hidden")
+      set(CURL_HIDES_PRIVATE_SYMBOLS TRUE)
+      set(CURL_EXTERN_SYMBOL "__attribute__((__visibility__(\"default\")))")
+      set(CURL_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
     endif()
   elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0)
-    set(_supports_symbol_hiding TRUE)
-    set(_symbol_extern "__global")
-    set(_cflag_symbols_hide "-xldscope=hidden")
-  elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0)
-    # Note: This should probably just check for version 9.1.045 but I am not 100% sure
-    #       so let us do it the same way autotools do.
-    set(_supports_symbol_hiding TRUE)
-    set(_symbol_extern "__attribute__ ((__visibility__ (\"default\")))")
-    set(_cflag_symbols_hide "-fvisibility=hidden")
-    check_c_source_compiles("#include <stdio.h>
-      int main(void) { printf(\"icc fvisibility bug test\"); return 0; }" _no_bug)
-    if(NOT _no_bug)
-      set(_supports_symbol_hiding FALSE)
-      set(_symbol_extern "")
-      set(_cflag_symbols_hide "")
-    endif()
+    set(CURL_HIDES_PRIVATE_SYMBOLS TRUE)
+    set(CURL_EXTERN_SYMBOL "__global")
+    set(CURL_CFLAG_SYMBOLS_HIDE "-xldscope=hidden")
+  elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0)  # Requires 9.1.045
+    set(CURL_HIDES_PRIVATE_SYMBOLS TRUE)
+    set(CURL_EXTERN_SYMBOL "__attribute__((__visibility__(\"default\")))")
+    set(CURL_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
   elseif(MSVC)
-    set(_supports_symbol_hiding TRUE)
+    set(CURL_HIDES_PRIVATE_SYMBOLS TRUE)
   endif()
-
-  set(CURL_HIDES_PRIVATE_SYMBOLS ${_supports_symbol_hiding})
 else()
   if(MSVC)
+    # Note: This option is prone to export non-curl extra symbols.
     set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
   endif()
-  set(CURL_HIDES_PRIVATE_SYMBOLS FALSE)
 endif()
-
-set(CURL_CFLAG_SYMBOLS_HIDE ${_cflag_symbols_hide})
-set(CURL_EXTERN_SYMBOL ${_symbol_extern})
diff --git a/Utilities/cmcurl/CMake/CurlTests.c b/Utilities/cmcurl/CMake/CurlTests.c
index 5797586..0334618 100644
--- a/Utilities/cmcurl/CMake/CurlTests.c
+++ b/Utilities/cmcurl/CMake/CurlTests.c
@@ -50,6 +50,7 @@
   int flags = 0;
   if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK))
     return 1;
+  ;
   return 0;
 }
 #endif
@@ -159,15 +160,12 @@
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                        && LARGE_OFF_T % 2147483647 == 1)
                       ? 1 : -1];
-int main(void) { ; return 0; }
+int main(void) { return 0; }
 #endif
 
 #ifdef HAVE_IOCTLSOCKET
 /* includes start */
 #ifdef _WIN32
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
 #  include <winsock2.h>
 #endif
 int main(void)
@@ -184,9 +182,6 @@
 #ifdef HAVE_IOCTLSOCKET_CAMEL
 /* includes start */
 #ifdef _WIN32
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
 #  include <winsock2.h>
 #endif
 int main(void)
@@ -202,9 +197,6 @@
 #ifdef HAVE_IOCTLSOCKET_CAMEL_FIONBIO
 /* includes start */
 #ifdef _WIN32
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
 #  include <winsock2.h>
 #endif
 int main(void)
@@ -221,9 +213,6 @@
 #ifdef HAVE_IOCTLSOCKET_FIONBIO
 /* includes start */
 #ifdef _WIN32
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
 #  include <winsock2.h>
 #endif
 int main(void)
@@ -296,9 +285,6 @@
 #ifdef HAVE_SETSOCKOPT_SO_NONBLOCK
 /* includes start */
 #ifdef _WIN32
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
 #  include <winsock2.h>
 #endif
 /* includes start */
@@ -409,9 +395,6 @@
 #ifdef HAVE_WIN32_WINNT
 /* includes start */
 #ifdef _WIN32
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
 #  ifndef NOGDI
 #    define NOGDI
 #  endif
diff --git a/Utilities/cmcurl/CMake/FindBearSSL.cmake b/Utilities/cmcurl/CMake/FindBearSSL.cmake
index dba4f5e..ff55be0 100644
--- a/Utilities/cmcurl/CMake/FindBearSSL.cmake
+++ b/Utilities/cmcurl/CMake/FindBearSSL.cmake
@@ -21,19 +21,18 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-# Find the bearssl library
+# Find the BearSSL library
 #
 # Input variables:
 #
-# BEARSSL_INCLUDE_DIR   The bearssl include directory
-# BEARSSL_INCLUDE_DIRS  The bearssl include directory (deprecated)
-# BEARSSL_LIBRARY       Path to bearssl library
+# - `BEARSSL_INCLUDE_DIR`:   The BearSSL include directory.
+# - `BEARSSL_LIBRARY`:       Path to `bearssl` library.
 #
 # Result variables:
 #
-# BEARSSL_FOUND         System has bearssl
-# BEARSSL_INCLUDE_DIRS  The bearssl include directories
-# BEARSSL_LIBRARIES     The bearssl library names
+# - `BEARSSL_FOUND`:         System has BearSSL.
+# - `BEARSSL_INCLUDE_DIRS`:  The BearSSL include directories.
+# - `BEARSSL_LIBRARIES`:     The BearSSL library names.
 
 if(DEFINED BEARSSL_INCLUDE_DIRS AND NOT DEFINED BEARSSL_INCLUDE_DIR)
   message(WARNING "BEARSSL_INCLUDE_DIRS is deprecated, use BEARSSL_INCLUDE_DIR instead.")
diff --git a/Utilities/cmcurl/CMake/FindBrotli.cmake b/Utilities/cmcurl/CMake/FindBrotli.cmake
index 1150d4c..767abf0 100644
--- a/Utilities/cmcurl/CMake/FindBrotli.cmake
+++ b/Utilities/cmcurl/CMake/FindBrotli.cmake
@@ -25,16 +25,16 @@
 #
 # Input variables:
 #
-# BROTLI_INCLUDE_DIR   The brotli include directory
-# BROTLICOMMON_LIBRARY Path to brotlicommon library
-# BROTLIDEC_LIBRARY    Path to brotlidec library
+# - `BROTLI_INCLUDE_DIR`:    The brotli include directory.
+# - `BROTLICOMMON_LIBRARY`:  Path to `brotlicommon` library.
+# - `BROTLIDEC_LIBRARY`:     Path to `brotlidec` library.
 #
 # Result variables:
 #
-# BROTLI_FOUND         System has brotli
-# BROTLI_INCLUDE_DIRS  The brotli include directories
-# BROTLI_LIBRARIES     The brotli library names
-# BROTLI_VERSION       Version of brotli
+# - `BROTLI_FOUND`:          System has brotli.
+# - `BROTLI_INCLUDE_DIRS`:   The brotli include directories.
+# - `BROTLI_LIBRARIES`:      The brotli library names.
+# - `BROTLI_VERSION`:        Version of brotli.
 
 if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
diff --git a/Utilities/cmcurl/CMake/FindCares.cmake b/Utilities/cmcurl/CMake/FindCares.cmake
index e7b821a..ac55be1 100644
--- a/Utilities/cmcurl/CMake/FindCares.cmake
+++ b/Utilities/cmcurl/CMake/FindCares.cmake
@@ -25,15 +25,15 @@
 #
 # Input variables:
 #
-# CARES_INCLUDE_DIR   The c-ares include directory
-# CARES_LIBRARY       Path to c-ares library
+# - `CARES_INCLUDE_DIR`:   The c-ares include directory.
+# - `CARES_LIBRARY`:       Path to `cares` library.
 #
 # Result variables:
 #
-# CARES_FOUND         System has c-ares
-# CARES_INCLUDE_DIRS  The c-ares include directories
-# CARES_LIBRARIES     The c-ares library names
-# CARES_VERSION       Version of c-ares
+# - `CARES_FOUND`:         System has c-ares.
+# - `CARES_INCLUDE_DIRS`:  The c-ares include directories.
+# - `CARES_LIBRARIES`:     The c-ares library names.
+# - `CARES_VERSION`:       Version of c-ares.
 
 if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
@@ -55,12 +55,22 @@
 if(PC_CARES_VERSION)
   set(CARES_VERSION ${PC_CARES_VERSION})
 elseif(CARES_INCLUDE_DIR AND EXISTS "${CARES_INCLUDE_DIR}/ares_version.h")
-  set(_version_regex "#[\t ]*define[\t ]+ARES_VERSION_STR[\t ]+\"([^\"]*)\"")
-  file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str REGEX "${_version_regex}")
-  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
-  set(CARES_VERSION "${_version_str}")
-  unset(_version_regex)
-  unset(_version_str)
+  set(_version_regex1 "#[\t ]*define[\t ]+ARES_VERSION_MAJOR[\t ]+([0-9]+).*")
+  set(_version_regex2 "#[\t ]*define[\t ]+ARES_VERSION_MINOR[\t ]+([0-9]+).*")
+  set(_version_regex3 "#[\t ]*define[\t ]+ARES_VERSION_PATCH[\t ]+([0-9]+).*")
+  file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str1 REGEX "${_version_regex1}")
+  file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str2 REGEX "${_version_regex2}")
+  file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str3 REGEX "${_version_regex3}")
+  string(REGEX REPLACE "${_version_regex1}" "\\1" _version_str1 "${_version_str1}")
+  string(REGEX REPLACE "${_version_regex2}" "\\1" _version_str2 "${_version_str2}")
+  string(REGEX REPLACE "${_version_regex3}" "\\1" _version_str3 "${_version_str3}")
+  set(CARES_VERSION "${_version_str1}.${_version_str2}.${_version_str3}")
+  unset(_version_regex1)
+  unset(_version_regex2)
+  unset(_version_regex3)
+  unset(_version_str1)
+  unset(_version_str2)
+  unset(_version_str3)
 endif()
 
 include(FindPackageHandleStandardArgs)
diff --git a/Utilities/cmcurl/CMake/FindGSS.cmake b/Utilities/cmcurl/CMake/FindGSS.cmake
index e84f894..94fdc5f 100644
--- a/Utilities/cmcurl/CMake/FindGSS.cmake
+++ b/Utilities/cmcurl/CMake/FindGSS.cmake
@@ -25,20 +25,21 @@
 #
 # Input variables:
 #
-# GSS_ROOT_DIR      Set this variable to the root installation of GSS
+# - `GSS_ROOT_DIR`:      Set this variable to the root installation of GSS. (also supported as environment)
 #
 # Result variables:
 #
-# GSS_FOUND         System has the Heimdal library
-# GSS_FLAVOUR       "MIT" or "Heimdal" if anything found
-# GSS_INCLUDE_DIRS  The GSS include directories
-# GSS_LIBRARIES     The GSS library names
-# GSS_LIBRARY_DIRS  The GSS library directories
-# GSS_LDFLAGS       Required linker flags
-# GSS_CFLAGS        Required compiler flags
-# GSS_VERSION       This is set to version advertised by pkg-config or read from manifest.
-#                   In case the library is found but no version info available it is set to "unknown"
+# - `GSS_FOUND`:         System has the Heimdal library.
+# - `GSS_FLAVOUR`:       "GNU", "MIT" or "Heimdal" if anything found.
+# - `GSS_INCLUDE_DIRS`:  The GSS include directories.
+# - `GSS_LIBRARIES`:     The GSS library names.
+# - `GSS_LIBRARY_DIRS`:  The GSS library directories.
+# - `GSS_PC_REQUIRES`:   The GSS pkg-config packages.
+# - `GSS_CFLAGS`:        Required compiler flags.
+# - `GSS_VERSION`:       This is set to version advertised by pkg-config or read from manifest.
+#                        In case the library is found but no version info available it is set to "unknown"
 
+set(_gnu_modname "gss")
 set(_mit_modname "mit-krb5-gssapi")
 set(_heimdal_modname "heimdal-gssapi")
 
@@ -55,7 +56,7 @@
 if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
   if(CURL_USE_PKGCONFIG)
     find_package(PkgConfig QUIET)
-    pkg_search_module(_GSS ${_mit_modname} ${_heimdal_modname})
+    pkg_search_module(_GSS ${_gnu_modname} ${_mit_modname} ${_heimdal_modname})
     list(APPEND _gss_root_hints "${_GSS_PREFIX}")
   endif()
   if(WIN32)
@@ -90,7 +91,7 @@
       RESULT_VARIABLE _gss_configure_failed
       OUTPUT_STRIP_TRAILING_WHITESPACE
     )
-    message(STATUS "FindGSS CFLAGS: ${_GSS_CFLAGS}")
+    message(STATUS "FindGSS krb5-config --cflags: ${_GSS_CFLAGS}")
     if(NOT _gss_configure_failed)  # 0 means success
       # Should also work in an odd case when multiple directories are given
       string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS)
@@ -113,7 +114,7 @@
       RESULT_VARIABLE _gss_configure_failed
       OUTPUT_STRIP_TRAILING_WHITESPACE
     )
-    message(STATUS "FindGSS LDFLAGS: ${_gss_lib_flags}")
+    message(STATUS "FindGSS krb5-config --libs: ${_gss_lib_flags}")
 
     if(NOT _gss_configure_failed)  # 0 means success
       # This script gives us libraries and link directories. Blah. We have to deal with it.
@@ -128,8 +129,6 @@
         elseif(_flag MATCHES "^-L.*")
           string(REGEX REPLACE "^-L" "" _val "${_flag}")
           list(APPEND _GSS_LIBRARY_DIRS "${_val}")
-        else()
-          list(APPEND _GSS_LDFLAGS "${_flag}")
         endif()
       endforeach()
     endif()
@@ -175,6 +174,7 @@
     )
 
     if(_GSS_INCLUDE_DIRS)  # jay, we have found something
+      cmake_push_check_state()
       set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIRS}")
       check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers)
 
@@ -189,8 +189,8 @@
         if(_gss_have_roken_h OR _gss_have_heimdal_roken_h)
           set(GSS_FLAVOUR "Heimdal")
         endif()
-        list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS "-D__ROKEN_H__")
       endif()
+      cmake_pop_check_state()
     else()
       # I am not convinced if this is the right way but this is what autotools do at the moment
       find_path(_GSS_INCLUDE_DIRS NAMES "gssapi.h"
@@ -203,6 +203,18 @@
 
       if(_GSS_INCLUDE_DIRS)
         set(GSS_FLAVOUR "Heimdal")
+      else()
+        find_path(_GSS_INCLUDE_DIRS NAMES "gss.h"
+          HINTS
+            ${_gss_root_hints}
+          PATH_SUFFIXES
+            "include"
+        )
+
+        if(_GSS_INCLUDE_DIRS)
+          set(GSS_FLAVOUR "GNU")
+          set(GSS_PC_REQUIRES "gss")
+        endif()
       endif()
     endif()
 
@@ -216,14 +228,18 @@
       if(WIN32)
         if(CMAKE_SIZEOF_VOID_P EQUAL 8)
           list(APPEND _gss_libdir_suffixes "lib/AMD64")
-          if(GSS_FLAVOUR STREQUAL "MIT")
+          if(GSS_FLAVOUR STREQUAL "GNU")
+            set(_gss_libname "gss")
+          elseif(GSS_FLAVOUR STREQUAL "MIT")
             set(_gss_libname "gssapi64")
           else()
             set(_gss_libname "libgssapi")
           endif()
         else()
           list(APPEND _gss_libdir_suffixes "lib/i386")
-          if(GSS_FLAVOUR STREQUAL "MIT")
+          if(GSS_FLAVOUR STREQUAL "GNU")
+            set(_gss_libname "gss")
+          elseif(GSS_FLAVOUR STREQUAL "MIT")
             set(_gss_libname "gssapi32")
           else()
             set(_gss_libname "libgssapi")
@@ -231,7 +247,9 @@
         endif()
       else()
         list(APPEND _gss_libdir_suffixes "lib;lib64")  # those suffixes are not checked for HINTS
-        if(GSS_FLAVOUR STREQUAL "MIT")
+        if(GSS_FLAVOUR STREQUAL "GNU")
+          set(_gss_libname "gss")
+        elseif(GSS_FLAVOUR STREQUAL "MIT")
           set(_gss_libname "gssapi_krb5")
         else()
           set(_gss_libname "gssapi")
@@ -247,13 +265,22 @@
     endif()
   endif()
 else()
-  if(_GSS_MODULE_NAME STREQUAL _mit_modname OR _GSS_${_mit_modname}_VERSION)  # _GSS_MODULE_NAME set since CMake 3.16
+  # _GSS_MODULE_NAME set since CMake 3.16
+  if(_GSS_MODULE_NAME STREQUAL _gnu_modname OR _GSS_${_gnu_modname}_VERSION)
+    set(GSS_FLAVOUR "GNU")
+    set(GSS_PC_REQUIRES "gss")
+    if(NOT _GSS_VERSION)  # for old CMake versions?
+      set(_GSS_VERSION ${_GSS_${_gnu_modname}_VERSION})
+    endif()
+  elseif(_GSS_MODULE_NAME STREQUAL _mit_modname OR _GSS_${_mit_modname}_VERSION)
     set(GSS_FLAVOUR "MIT")
+    set(GSS_PC_REQUIRES "mit-krb5-gssapi")
     if(NOT _GSS_VERSION)  # for old CMake versions?
       set(_GSS_VERSION ${_GSS_${_mit_modname}_VERSION})
     endif()
   else()
     set(GSS_FLAVOUR "Heimdal")
+    set(GSS_PC_REQUIRES "heimdal-gssapi")
     if(NOT _GSS_VERSION)  # for old CMake versions?
       set(_GSS_VERSION ${_GSS_${_heimdal_modname}_VERSION})
     endif()
@@ -261,10 +288,11 @@
   message(STATUS "Found GSS/${GSS_FLAVOUR} (via pkg-config): ${_GSS_INCLUDE_DIRS} (found version \"${_GSS_VERSION}\")")
 endif()
 
+string(REPLACE ";" " " _GSS_CFLAGS "${_GSS_CFLAGS}")
+
 set(GSS_INCLUDE_DIRS ${_GSS_INCLUDE_DIRS})
 set(GSS_LIBRARIES ${_GSS_LIBRARIES})
 set(GSS_LIBRARY_DIRS ${_GSS_LIBRARY_DIRS})
-set(GSS_LDFLAGS ${_GSS_LDFLAGS})
 set(GSS_CFLAGS ${_GSS_CFLAGS})
 set(GSS_VERSION ${_GSS_VERSION})
 
@@ -294,6 +322,15 @@
     else()
       set(GSS_VERSION "MIT Unknown")
     endif()
+  elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "GNU")
+    if(GSS_INCLUDE_DIRS AND EXISTS "${GSS_INCLUDE_DIRS}/gss.h")
+      set(_version_regex "#[\t ]*define[\t ]+GSS_VERSION[\t ]+\"([^\"]*)\"")
+      file(STRINGS "${GSS_INCLUDE_DIRS}/gss.h" _version_str REGEX "${_version_regex}")
+      string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+      set(GSS_VERSION "${_version_str}")
+      unset(_version_regex)
+      unset(_version_str)
+    endif()
   endif()
 endif()
 
@@ -312,7 +349,6 @@
   _GSS_CFLAGS
   _GSS_FOUND
   _GSS_INCLUDE_DIRS
-  _GSS_LDFLAGS
   _GSS_LIBRARIES
   _GSS_LIBRARY_DIRS
   _GSS_MODULE_NAME
diff --git a/Utilities/cmcurl/CMake/FindLibgsasl.cmake b/Utilities/cmcurl/CMake/FindLibgsasl.cmake
index ed930eb..82ed07e 100644
--- a/Utilities/cmcurl/CMake/FindLibgsasl.cmake
+++ b/Utilities/cmcurl/CMake/FindLibgsasl.cmake
@@ -25,17 +25,17 @@
 #
 # Input variables:
 #
-# LIBGSASL_INCLUDE_DIR   The libgsasl include directory
-# LIBGSASL_LIBRARY       Path to libgsasl library
+# - `LIBGSASL_INCLUDE_DIR`:   The libgsasl include directory.
+# - `LIBGSASL_LIBRARY`:       Path to `libgsasl` library.
 #
 # Result variables:
 #
-# LIBGSASL_FOUND         System has libgsasl
-# LIBGSASL_INCLUDE_DIRS  The libgsasl include directories
-# LIBGSASL_LIBRARIES     The libgsasl library names
-# LIBGSASL_LIBRARY_DIRS  The libgsasl library directories
-# LIBGSASL_CFLAGS        Required compiler flags
-# LIBGSASL_VERSION       Version of libgsasl
+# - `LIBGSASL_FOUND`:         System has libgsasl.
+# - `LIBGSASL_INCLUDE_DIRS`:  The libgsasl include directories.
+# - `LIBGSASL_LIBRARIES`:     The libgsasl library names.
+# - `LIBGSASL_LIBRARY_DIRS`:  The libgsasl library directories.
+# - `LIBGSASL_CFLAGS`:        Required compiler flags.
+# - `LIBGSASL_VERSION`:       Version of libgsasl.
 
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBGSASL_INCLUDE_DIR AND
@@ -51,6 +51,7 @@
   find_path(LIBGSASL_INCLUDE_DIR NAMES "gsasl.h")
   find_library(LIBGSASL_LIBRARY NAMES "gsasl" "libgsasl")
 
+  unset(LIBGSASL_VERSION CACHE)
   if(LIBGSASL_INCLUDE_DIR AND EXISTS "${LIBGSASL_INCLUDE_DIR}/gsasl-version.h")
     set(_version_regex "#[\t ]*define[\t ]+GSASL_VERSION[\t ]+\"([^\"]*)\"")
     file(STRINGS "${LIBGSASL_INCLUDE_DIR}/gsasl-version.h" _version_str REGEX "${_version_regex}")
diff --git a/Utilities/cmcurl/CMake/FindLibidn2.cmake b/Utilities/cmcurl/CMake/FindLibidn2.cmake
index 47d4a58..35580ae 100644
--- a/Utilities/cmcurl/CMake/FindLibidn2.cmake
+++ b/Utilities/cmcurl/CMake/FindLibidn2.cmake
@@ -25,17 +25,17 @@
 #
 # Input variables:
 #
-# LIBIDN2_INCLUDE_DIR   The libidn2 include directory
-# LIBIDN2_LIBRARY       Path to libidn2 library
+# - `LIBIDN2_INCLUDE_DIR`:   The libidn2 include directory.
+# - `LIBIDN2_LIBRARY`:       Path to `libidn2` library.
 #
 # Result variables:
 #
-# LIBIDN2_FOUND         System has libidn2
-# LIBIDN2_INCLUDE_DIRS  The libidn2 include directories
-# LIBIDN2_LIBRARIES     The libidn2 library names
-# LIBIDN2_LIBRARY_DIRS  The libidn2 library directories
-# LIBIDN2_CFLAGS        Required compiler flags
-# LIBIDN2_VERSION       Version of libidn2
+# - `LIBIDN2_FOUND`:         System has libidn2.
+# - `LIBIDN2_INCLUDE_DIRS`:  The libidn2 include directories.
+# - `LIBIDN2_LIBRARIES`:     The libidn2 library names.
+# - `LIBIDN2_LIBRARY_DIRS`:  The libidn2 library directories.
+# - `LIBIDN2_CFLAGS`:        Required compiler flags.
+# - `LIBIDN2_VERSION`:       Version of libidn2.
 
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBIDN2_INCLUDE_DIR AND
@@ -51,6 +51,7 @@
   find_path(LIBIDN2_INCLUDE_DIR NAMES "idn2.h")
   find_library(LIBIDN2_LIBRARY NAMES "idn2" "libidn2")
 
+  unset(LIBIDN2_VERSION CACHE)
   if(LIBIDN2_INCLUDE_DIR AND EXISTS "${LIBIDN2_INCLUDE_DIR}/idn2.h")
     set(_version_regex "#[\t ]*define[\t ]+IDN2_VERSION[\t ]+\"([^\"]*)\"")
     file(STRINGS "${LIBIDN2_INCLUDE_DIR}/idn2.h" _version_str REGEX "${_version_regex}")
diff --git a/Utilities/cmcurl/CMake/FindLibpsl.cmake b/Utilities/cmcurl/CMake/FindLibpsl.cmake
index b2cd64f..bb323f4 100644
--- a/Utilities/cmcurl/CMake/FindLibpsl.cmake
+++ b/Utilities/cmcurl/CMake/FindLibpsl.cmake
@@ -25,15 +25,15 @@
 #
 # Input variables:
 #
-# LIBPSL_INCLUDE_DIR   The libpsl include directory
-# LIBPSL_LIBRARY       Path to libpsl library
+# - `LIBPSL_INCLUDE_DIR`:   The libpsl include directory.
+# - `LIBPSL_LIBRARY`:       Path to `libpsl` library.
 #
 # Result variables:
 #
-# LIBPSL_FOUND         System has libpsl
-# LIBPSL_INCLUDE_DIRS  The libpsl include directories
-# LIBPSL_LIBRARIES     The libpsl library names
-# LIBPSL_VERSION       Version of libpsl
+# - `LIBPSL_FOUND`:         System has libpsl.
+# - `LIBPSL_INCLUDE_DIRS`:  The libpsl include directories.
+# - `LIBPSL_LIBRARIES`:     The libpsl library names.
+# - `LIBPSL_VERSION`:       Version of libpsl.
 
 if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
diff --git a/Utilities/cmcurl/CMake/FindLibssh.cmake b/Utilities/cmcurl/CMake/FindLibssh.cmake
index 7dc019b..2b95fd8 100644
--- a/Utilities/cmcurl/CMake/FindLibssh.cmake
+++ b/Utilities/cmcurl/CMake/FindLibssh.cmake
@@ -25,17 +25,17 @@
 #
 # Input variables:
 #
-# LIBSSH_INCLUDE_DIR   The libssh include directory
-# LIBSSH_LIBRARY       Path to libssh library
+# LIBSSH_INCLUDE_DIR   The libssh include directory.
+# LIBSSH_LIBRARY       Path to libssh library.
 #
 # Result variables:
 #
-# LIBSSH_FOUND         System has libssh
-# LIBSSH_INCLUDE_DIRS  The libssh include directories
-# LIBSSH_LIBRARIES     The libssh library names
-# LIBSSH_LIBRARY_DIRS  The libssh library directories
-# LIBSSH_CFLAGS        Required compiler flags
-# LIBSSH_VERSION       Version of libssh
+# LIBSSH_FOUND         System has libssh.
+# LIBSSH_INCLUDE_DIRS  The libssh include directories.
+# LIBSSH_LIBRARIES     The libssh library names.
+# LIBSSH_LIBRARY_DIRS  The libssh library directories.
+# LIBSSH_CFLAGS        Required compiler flags.
+# LIBSSH_VERSION       Version of libssh.
 
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBSSH_INCLUDE_DIR AND
@@ -51,6 +51,7 @@
   find_path(LIBSSH_INCLUDE_DIR NAMES "libssh/libssh.h")
   find_library(LIBSSH_LIBRARY NAMES "ssh" "libssh")
 
+  unset(LIBSSH_VERSION CACHE)
   if(LIBSSH_INCLUDE_DIR AND EXISTS "${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h")
     set(_version_regex1 "#[\t ]*define[\t ]+LIBSSH_VERSION_MAJOR[\t ]+([0-9]+).*")
     set(_version_regex2 "#[\t ]*define[\t ]+LIBSSH_VERSION_MINOR[\t ]+([0-9]+).*")
diff --git a/Utilities/cmcurl/CMake/FindLibssh2.cmake b/Utilities/cmcurl/CMake/FindLibssh2.cmake
index 0007a8a..0785214 100644
--- a/Utilities/cmcurl/CMake/FindLibssh2.cmake
+++ b/Utilities/cmcurl/CMake/FindLibssh2.cmake
@@ -25,15 +25,15 @@
 #
 # Input variables:
 #
-# LIBSSH2_INCLUDE_DIR   The libssh2 include directory
-# LIBSSH2_LIBRARY       Path to libssh2 library
+# - `LIBSSH2_INCLUDE_DIR`:   The libssh2 include directory.
+# - `LIBSSH2_LIBRARY`:       Path to `libssh2` library.
 #
 # Result variables:
 #
-# LIBSSH2_FOUND         System has libssh2
-# LIBSSH2_INCLUDE_DIRS  The libssh2 include directories
-# LIBSSH2_LIBRARIES     The libssh2 library names
-# LIBSSH2_VERSION       Version of libssh2
+# - `LIBSSH2_FOUND`:         System has libssh2.
+# - `LIBSSH2_INCLUDE_DIRS`:  The libssh2 include directories.
+# - `LIBSSH2_LIBRARIES`:     The libssh2 library names.
+# - `LIBSSH2_VERSION`:       Version of libssh2.
 
 if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
diff --git a/Utilities/cmcurl/CMake/FindLibuv.cmake b/Utilities/cmcurl/CMake/FindLibuv.cmake
index d4dfa24..d647e34 100644
--- a/Utilities/cmcurl/CMake/FindLibuv.cmake
+++ b/Utilities/cmcurl/CMake/FindLibuv.cmake
@@ -25,17 +25,17 @@
 #
 # Input variables:
 #
-# LIBUV_INCLUDE_DIR   The libuv include directory
-# LIBUV_LIBRARY       Path to libuv library
+# - `LIBUV_INCLUDE_DIR`:   The libuv include directory.
+# - `LIBUV_LIBRARY`:       Path to `libuv` library.
 #
 # Result variables:
 #
-# LIBUV_FOUND         System has libuv
-# LIBUV_INCLUDE_DIRS  The libuv include directories
-# LIBUV_LIBRARIES     The libuv library names
-# LIBUV_LIBRARY_DIRS  The libuv library directories
-# LIBUV_CFLAGS        Required compiler flags
-# LIBUV_VERSION       Version of libuv
+# - `LIBUV_FOUND`:         System has libuv.
+# - `LIBUV_INCLUDE_DIRS`:  The libuv include directories.
+# - `LIBUV_LIBRARIES`:     The libuv library names.
+# - `LIBUV_LIBRARY_DIRS`:  The libuv library directories.
+# - `LIBUV_CFLAGS`:        Required compiler flags.
+# - `LIBUV_VERSION`:       Version of libuv.
 
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBUV_INCLUDE_DIR AND
@@ -51,6 +51,7 @@
   find_path(LIBUV_INCLUDE_DIR NAMES "uv.h")
   find_library(LIBUV_LIBRARY NAMES "uv" "libuv")
 
+  unset(LIBUV_VERSION CACHE)
   if(LIBUV_INCLUDE_DIR AND EXISTS "${LIBUV_INCLUDE_DIR}/uv/version.h")
     set(_version_regex1 "#[\t ]*define[\t ]+UV_VERSION_MAJOR[\t ]+([0-9]+).*")
     set(_version_regex2 "#[\t ]*define[\t ]+UV_VERSION_MINOR[\t ]+([0-9]+).*")
diff --git a/Utilities/cmcurl/CMake/FindMSH3.cmake b/Utilities/cmcurl/CMake/FindMSH3.cmake
index 46cee88..387d30b 100644
--- a/Utilities/cmcurl/CMake/FindMSH3.cmake
+++ b/Utilities/cmcurl/CMake/FindMSH3.cmake
@@ -25,49 +25,45 @@
 #
 # Input variables:
 #
-# MSH3_INCLUDE_DIR   The msh3 include directory
-# MSH3_LIBRARY       Path to msh3 library
+# - `MSH3_INCLUDE_DIR`:   The msh3 include directory.
+# - `MSH3_LIBRARY`:       Path to `msh3` library.
 #
 # Result variables:
 #
-# MSH3_FOUND         System has msh3
-# MSH3_INCLUDE_DIRS  The msh3 include directories
-# MSH3_LIBRARIES     The msh3 library names
-# MSH3_VERSION       Version of msh3
+# - `MSH3_FOUND`:         System has msh3.
+# - `MSH3_INCLUDE_DIRS`:  The msh3 include directories.
+# - `MSH3_LIBRARIES`:     The msh3 library names.
+# - `MSH3_LIBRARY_DIRS`:  The msh3 library directories.
+# - `MSH3_PC_REQUIRES`:   The msh3 pkg-config packages.
+# - `MSH3_CFLAGS`:        Required compiler flags.
+# - `MSH3_VERSION`:       Version of msh3.
 
-if(CURL_USE_PKGCONFIG)
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED MSH3_INCLUDE_DIR AND
+   NOT DEFINED MSH3_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_MSH3 "libmsh3")
+  pkg_check_modules(MSH3 "libmsh3")
 endif()
 
-find_path(MSH3_INCLUDE_DIR NAMES "msh3.h"
-  HINTS
-    ${PC_MSH3_INCLUDEDIR}
-    ${PC_MSH3_INCLUDE_DIRS}
-)
-
-find_library(MSH3_LIBRARY NAMES "msh3"
-  HINTS
-    ${PC_MSH3_LIBDIR}
-    ${PC_MSH3_LIBRARY_DIRS}
-)
-
-if(PC_MSH3_VERSION)
-  set(MSH3_VERSION ${PC_MSH3_VERSION})
-endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(MSH3
-  REQUIRED_VARS
-    MSH3_INCLUDE_DIR
-    MSH3_LIBRARY
-  VERSION_VAR
-    MSH3_VERSION
-)
-
 if(MSH3_FOUND)
-  set(MSH3_INCLUDE_DIRS ${MSH3_INCLUDE_DIR})
-  set(MSH3_LIBRARIES    ${MSH3_LIBRARY})
-endif()
+  set(MSH3_PC_REQUIRES "libmsh3")
+  string(REPLACE ";" " " MSH3_CFLAGS "${MSH3_CFLAGS}")
+  message(STATUS "Found MSH3 (via pkg-config): ${MSH3_INCLUDE_DIRS} (found version \"${MSH3_VERSION}\")")
+else()
+  find_path(MSH3_INCLUDE_DIR NAMES "msh3.h")
+  find_library(MSH3_LIBRARY NAMES "msh3")
 
-mark_as_advanced(MSH3_INCLUDE_DIR MSH3_LIBRARY)
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(MSH3
+    REQUIRED_VARS
+      MSH3_INCLUDE_DIR
+      MSH3_LIBRARY
+  )
+
+  if(MSH3_FOUND)
+    set(MSH3_INCLUDE_DIRS ${MSH3_INCLUDE_DIR})
+    set(MSH3_LIBRARIES    ${MSH3_LIBRARY})
+  endif()
+
+  mark_as_advanced(MSH3_INCLUDE_DIR MSH3_LIBRARY)
+endif()
diff --git a/Utilities/cmcurl/CMake/FindMbedTLS.cmake b/Utilities/cmcurl/CMake/FindMbedTLS.cmake
index 53b8614..e361c96 100644
--- a/Utilities/cmcurl/CMake/FindMbedTLS.cmake
+++ b/Utilities/cmcurl/CMake/FindMbedTLS.cmake
@@ -21,22 +21,24 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-# Find the mbedtls library
+# Find the mbedTLS library
 #
 # Input variables:
 #
-# MBEDTLS_INCLUDE_DIR   The mbedtls include directory
-# MBEDTLS_INCLUDE_DIRS  The mbedtls include directory (deprecated)
-# MBEDTLS_LIBRARY       Path to mbedtls library
-# MBEDX509_LIBRARY      Path to mbedx509 library
-# MBEDCRYPTO_LIBRARY    Path to mbedcrypto library
+# - `MBEDTLS_INCLUDE_DIR`:   The mbedTLS include directory.
+# - `MBEDTLS_LIBRARY`:       Path to `mbedtls` library.
+# - `MBEDX509_LIBRARY`:      Path to `mbedx509` library.
+# - `MBEDCRYPTO_LIBRARY`:    Path to `mbedcrypto` library.
 #
 # Result variables:
 #
-# MBEDTLS_FOUND         System has mbedtls
-# MBEDTLS_INCLUDE_DIRS  The mbedtls include directories
-# MBEDTLS_LIBRARIES     The mbedtls library names
-# MBEDTLS_VERSION       Version of mbedtls
+# - `MBEDTLS_FOUND`:         System has mbedTLS.
+# - `MBEDTLS_INCLUDE_DIRS`:  The mbedTLS include directories.
+# - `MBEDTLS_LIBRARIES`:     The mbedTLS library names.
+# - `MBEDTLS_LIBRARY_DIRS`:  The mbedTLS library directories.
+# - `MBEDTLS_PC_REQUIRES`:   The mbedTLS pkg-config packages.
+# - `MBEDTLS_CFLAGS`:        Required compiler flags.
+# - `MBEDTLS_VERSION`:       Version of mbedTLS.
 
 if(DEFINED MBEDTLS_INCLUDE_DIRS AND NOT DEFINED MBEDTLS_INCLUDE_DIR)
   message(WARNING "MBEDTLS_INCLUDE_DIRS is deprecated, use MBEDTLS_INCLUDE_DIR instead.")
@@ -44,68 +46,64 @@
   unset(MBEDTLS_INCLUDE_DIRS)
 endif()
 
-if(CURL_USE_PKGCONFIG)
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED MBEDTLS_INCLUDE_DIR AND
+   NOT DEFINED MBEDTLS_LIBRARY AND
+   NOT DEFINED MBEDX509_LIBRARY AND
+   NOT DEFINED MBEDCRYPTO_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_MBEDTLS "mbedtls")
+  pkg_check_modules(MBEDTLS "mbedtls")
+  pkg_check_modules(MBEDX509 "mbedx509")
+  pkg_check_modules(MBEDCRYPTO "mbedcrypto")
 endif()
 
-find_path(MBEDTLS_INCLUDE_DIR NAMES "mbedtls/ssl.h"
-  HINTS
-    ${PC_MBEDTLS_INCLUDEDIR}
-    ${PC_MBEDTLS_INCLUDE_DIRS}
-)
+if(MBEDTLS_FOUND AND MBEDX509_FOUND AND MBEDCRYPTO_FOUND)
+  list(APPEND MBEDTLS_LIBRARIES ${MBEDX509_LIBRARIES} ${MBEDCRYPTO_LIBRARIES})
+  list(REMOVE_DUPLICATES MBEDTLS_LIBRARIES)
+  set(MBEDTLS_PC_REQUIRES "mbedtls")
+  string(REPLACE ";" " " MBEDTLS_CFLAGS "${MBEDTLS_CFLAGS}")
+  message(STATUS "Found MbedTLS (via pkg-config): ${MBEDTLS_INCLUDE_DIRS} (found version \"${MBEDTLS_VERSION}\")")
+else()
+  find_path(MBEDTLS_INCLUDE_DIR NAMES "mbedtls/ssl.h")
+  find_library(MBEDTLS_LIBRARY NAMES "mbedtls" "libmbedtls")
+  find_library(MBEDX509_LIBRARY NAMES "mbedx509" "libmbedx509")
+  find_library(MBEDCRYPTO_LIBRARY NAMES "mbedcrypto" "libmbedcrypto")
 
-find_library(MBEDTLS_LIBRARY NAMES "mbedtls"
-  HINTS
-    ${PC_MBEDTLS_LIBDIR}
-    ${PC_MBEDTLS_LIBRARY_DIRS}
-)
-find_library(MBEDX509_LIBRARY NAMES "mbedx509"
-  HINTS
-    ${PC_MBEDTLS_LIBDIR}
-    ${PC_MBEDTLS_LIBRARY_DIRS}
-)
-find_library(MBEDCRYPTO_LIBRARY NAMES "mbedcrypto"
-  HINTS
-    ${PC_MBEDTLS_LIBDIR}
-    ${PC_MBEDTLS_LIBRARY_DIRS}
-)
-
-if(PC_MBEDTLS_VERSION)
-  set(MBEDTLS_VERSION ${PC_MBEDTLS_VERSION})
-elseif(MBEDTLS_INCLUDE_DIR)
-  if(EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")  # 3.x
-    set(_version_header "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
-  elseif(EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")  # 2.x
-    set(_version_header "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
-  else()
-    unset(_version_header)
+  unset(MBEDTLS_VERSION CACHE)
+  if(MBEDTLS_INCLUDE_DIR)
+    if(EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")  # 3.x
+      set(_version_header "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
+    elseif(EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")  # 2.x
+      set(_version_header "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
+    else()
+      unset(_version_header)
+    endif()
+    if(_version_header)
+      set(_version_regex "#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"([0-9.]+)\"")
+      file(STRINGS "${_version_header}" _version_str REGEX "${_version_regex}")
+      string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+      set(MBEDTLS_VERSION "${_version_str}")
+      unset(_version_regex)
+      unset(_version_str)
+      unset(_version_header)
+    endif()
   endif()
-  if(_version_header)
-    set(_version_regex "#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"([0-9.]+)\"")
-    file(STRINGS "${_version_header}" _version_str REGEX "${_version_regex}")
-    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
-    set(MBEDTLS_VERSION "${_version_str}")
-    unset(_version_regex)
-    unset(_version_str)
-    unset(_version_header)
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(MbedTLS
+    REQUIRED_VARS
+      MBEDTLS_INCLUDE_DIR
+      MBEDTLS_LIBRARY
+      MBEDX509_LIBRARY
+      MBEDCRYPTO_LIBRARY
+    VERSION_VAR
+      MBEDTLS_VERSION
+  )
+
+  if(MBEDTLS_FOUND)
+    set(MBEDTLS_INCLUDE_DIRS ${MBEDTLS_INCLUDE_DIR})
+    set(MBEDTLS_LIBRARIES    ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY})
   endif()
+
+  mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
 endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(MbedTLS
-  REQUIRED_VARS
-    MBEDTLS_INCLUDE_DIR
-    MBEDTLS_LIBRARY
-    MBEDX509_LIBRARY
-    MBEDCRYPTO_LIBRARY
-  VERSION_VAR
-    MBEDTLS_VERSION
-)
-
-if(MBEDTLS_FOUND)
-  set(MBEDTLS_INCLUDE_DIRS ${MBEDTLS_INCLUDE_DIR})
-  set(MBEDTLS_LIBRARIES    ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY})
-endif()
-
-mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
diff --git a/Utilities/cmcurl/CMake/FindNGHTTP2.cmake b/Utilities/cmcurl/CMake/FindNGHTTP2.cmake
index e632d20..a0aacbf 100644
--- a/Utilities/cmcurl/CMake/FindNGHTTP2.cmake
+++ b/Utilities/cmcurl/CMake/FindNGHTTP2.cmake
@@ -25,15 +25,15 @@
 #
 # Input variables:
 #
-# NGHTTP2_INCLUDE_DIR   The nghttp2 include directory
-# NGHTTP2_LIBRARY       Path to nghttp2 library
+# - `NGHTTP2_INCLUDE_DIR`:   The nghttp2 include directory.
+# - `NGHTTP2_LIBRARY`:       Path to `nghttp2` library.
 #
 # Result variables:
 #
-# NGHTTP2_FOUND         System has nghttp2
-# NGHTTP2_INCLUDE_DIRS  The nghttp2 include directories
-# NGHTTP2_LIBRARIES     The nghttp2 library names
-# NGHTTP2_VERSION       Version of nghttp2
+# - `NGHTTP2_FOUND`:         System has nghttp2.
+# - `NGHTTP2_INCLUDE_DIRS`:  The nghttp2 include directories.
+# - `NGHTTP2_LIBRARIES`:     The nghttp2 library names.
+# - `NGHTTP2_VERSION`:       Version of nghttp2.
 
 if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
diff --git a/Utilities/cmcurl/CMake/FindNGHTTP3.cmake b/Utilities/cmcurl/CMake/FindNGHTTP3.cmake
index 02a0c87..1adbd60 100644
--- a/Utilities/cmcurl/CMake/FindNGHTTP3.cmake
+++ b/Utilities/cmcurl/CMake/FindNGHTTP3.cmake
@@ -25,15 +25,15 @@
 #
 # Input variables:
 #
-# NGHTTP3_INCLUDE_DIR   The nghttp3 include directory
-# NGHTTP3_LIBRARY       Path to nghttp3 library
+# - `NGHTTP3_INCLUDE_DIR`:   The nghttp3 include directory.
+# - `NGHTTP3_LIBRARY`:       Path to `nghttp3` library.
 #
 # Result variables:
 #
-# NGHTTP3_FOUND         System has nghttp3
-# NGHTTP3_INCLUDE_DIRS  The nghttp3 include directories
-# NGHTTP3_LIBRARIES     The nghttp3 library names
-# NGHTTP3_VERSION       Version of nghttp3
+# - `NGHTTP3_FOUND`:         System has nghttp3.
+# - `NGHTTP3_INCLUDE_DIRS`:  The nghttp3 include directories.
+# - `NGHTTP3_LIBRARIES`:     The nghttp3 library names.
+# - `NGHTTP3_VERSION`:       Version of nghttp3.
 
 if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
diff --git a/Utilities/cmcurl/CMake/FindNGTCP2.cmake b/Utilities/cmcurl/CMake/FindNGTCP2.cmake
index 194483d..99b022d 100644
--- a/Utilities/cmcurl/CMake/FindNGTCP2.cmake
+++ b/Utilities/cmcurl/CMake/FindNGTCP2.cmake
@@ -26,22 +26,22 @@
 # This module accepts optional COMPONENTS to control the crypto library (these are
 # mutually exclusive):
 #
-# quictls:    Use libngtcp2_crypto_quictls   (choose this for LibreSSL)
-# BoringSSL:  Use libngtcp2_crypto_boringssl (choose this for AWS-LC)
-# wolfSSL:    Use libngtcp2_crypto_wolfssl
-# GnuTLS:     Use libngtcp2_crypto_gnutls
+# - quictls:    Use `libngtcp2_crypto_quictls`.   (choose this for LibreSSL)
+# - BoringSSL:  Use `libngtcp2_crypto_boringssl`. (choose this for AWS-LC)
+# - wolfSSL:    Use `libngtcp2_crypto_wolfssl`.
+# - GnuTLS:     Use `libngtcp2_crypto_gnutls`.
 #
 # Input variables:
 #
-# NGTCP2_INCLUDE_DIR   The ngtcp2 include directory
-# NGTCP2_LIBRARY       Path to ngtcp2 library
+# - `NGTCP2_INCLUDE_DIR`:   The ngtcp2 include directory.
+# - `NGTCP2_LIBRARY`:       Path to `ngtcp2` library.
 #
 # Result variables:
 #
-# NGTCP2_FOUND         System has ngtcp2
-# NGTCP2_INCLUDE_DIRS  The ngtcp2 include directories
-# NGTCP2_LIBRARIES     The ngtcp2 library names
-# NGTCP2_VERSION       Version of ngtcp2
+# - `NGTCP2_FOUND`:         System has ngtcp2.
+# - `NGTCP2_INCLUDE_DIRS`:  The ngtcp2 include directories.
+# - `NGTCP2_LIBRARIES`:     The ngtcp2 library names.
+# - `NGTCP2_VERSION`:       Version of ngtcp2.
 
 if(CURL_USE_PKGCONFIG)
   find_package(PkgConfig QUIET)
@@ -84,14 +84,19 @@
 
   if(_ngtcp2_crypto_backend)
     string(TOLOWER "ngtcp2_crypto_${_ngtcp2_crypto_backend}" _crypto_library)
+
     if(CURL_USE_PKGCONFIG)
       pkg_check_modules(PC_${_crypto_library} "lib${_crypto_library}")
     endif()
+
+    get_filename_component(_ngtcp2_library_dir "${NGTCP2_LIBRARY}" DIRECTORY)
     find_library(${_crypto_library}_LIBRARY NAMES ${_crypto_library}
       HINTS
+        ${_ngtcp2_library_dir}
         ${PC_${_crypto_library}_LIBDIR}
         ${PC_${_crypto_library}_LIBRARY_DIRS}
     )
+
     if(${_crypto_library}_LIBRARY)
       set(NGTCP2_${_ngtcp2_crypto_backend}_FOUND TRUE)
       set(NGTCP2_CRYPTO_LIBRARY ${${_crypto_library}_LIBRARY})
diff --git a/Utilities/cmcurl/CMake/FindNettle.cmake b/Utilities/cmcurl/CMake/FindNettle.cmake
index b5da05b..56f2a94 100644
--- a/Utilities/cmcurl/CMake/FindNettle.cmake
+++ b/Utilities/cmcurl/CMake/FindNettle.cmake
@@ -25,17 +25,17 @@
 #
 # Input variables:
 #
-# NETTLE_INCLUDE_DIR   The nettle include directory
-# NETTLE_LIBRARY       Path to nettle library
+# - `NETTLE_INCLUDE_DIR`:   The nettle include directory.
+# - `NETTLE_LIBRARY`:       Path to `nettle` library.
 #
 # Result variables:
 #
-# NETTLE_FOUND         System has nettle
-# NETTLE_INCLUDE_DIRS  The nettle include directories
-# NETTLE_LIBRARIES     The nettle library names
-# NETTLE_LIBRARY_DIRS  The nettle library directories
-# NETTLE_CFLAGS        Required compiler flags
-# NETTLE_VERSION       Version of nettle
+# - `NETTLE_FOUND`:         System has nettle.
+# - `NETTLE_INCLUDE_DIRS`:  The nettle include directories.
+# - `NETTLE_LIBRARIES`:     The nettle library names.
+# - `NETTLE_LIBRARY_DIRS`:  The nettle library directories.
+# - `NETTLE_CFLAGS`:        Required compiler flags.
+# - `NETTLE_VERSION`:       Version of nettle.
 
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED NETTLE_INCLUDE_DIR AND
@@ -51,6 +51,7 @@
   find_path(NETTLE_INCLUDE_DIR NAMES "nettle/sha2.h")
   find_library(NETTLE_LIBRARY NAMES "nettle")
 
+  unset(NETTLE_VERSION CACHE)
   if(NETTLE_INCLUDE_DIR AND EXISTS "${NETTLE_INCLUDE_DIR}/nettle/version.h")
     set(_version_regex1 "#[\t ]*define[ \t]+NETTLE_VERSION_MAJOR[ \t]+([0-9]+).*")
     set(_version_regex2 "#[\t ]*define[ \t]+NETTLE_VERSION_MINOR[ \t]+([0-9]+).*")
diff --git a/Utilities/cmcurl/CMake/FindQuiche.cmake b/Utilities/cmcurl/CMake/FindQuiche.cmake
index 7d1626a..6db5cb0 100644
--- a/Utilities/cmcurl/CMake/FindQuiche.cmake
+++ b/Utilities/cmcurl/CMake/FindQuiche.cmake
@@ -25,49 +25,43 @@
 #
 # Input variables:
 #
-# QUICHE_INCLUDE_DIR   The quiche include directory
-# QUICHE_LIBRARY       Path to quiche library
+# - `QUICHE_INCLUDE_DIR`:   The quiche include directory.
+# - `QUICHE_LIBRARY`:       Path to `quiche` library.
 #
 # Result variables:
 #
-# QUICHE_FOUND         System has quiche
-# QUICHE_INCLUDE_DIRS  The quiche include directories
-# QUICHE_LIBRARIES     The quiche library names
-# QUICHE_VERSION       Version of quiche
+# - `QUICHE_FOUND`:         System has quiche.
+# - `QUICHE_INCLUDE_DIRS`:  The quiche include directories.
+# - `QUICHE_LIBRARIES`:     The quiche library names.
+# - `QUICHE_LIBRARY_DIRS`:  The quiche library directories.
+# - `QUICHE_CFLAGS`:        Required compiler flags.
+# - `QUICHE_VERSION`:       Version of quiche.
 
-if(CURL_USE_PKGCONFIG)
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED QUICHE_INCLUDE_DIR AND
+   NOT DEFINED QUICHE_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_QUICHE "quiche")
+  pkg_check_modules(QUICHE "quiche")
 endif()
 
-find_path(QUICHE_INCLUDE_DIR NAMES "quiche.h"
-  HINTS
-    ${PC_QUICHE_INCLUDEDIR}
-    ${PC_QUICHE_INCLUDE_DIRS}
-)
-
-find_library(QUICHE_LIBRARY NAMES "quiche"
-  HINTS
-    ${PC_QUICHE_LIBDIR}
-    ${PC_QUICHE_LIBRARY_DIRS}
-)
-
-if(PC_QUICHE_VERSION)
-  set(QUICHE_VERSION ${PC_QUICHE_VERSION})
-endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Quiche
-  REQUIRED_VARS
-    QUICHE_INCLUDE_DIR
-    QUICHE_LIBRARY
-  VERSION_VAR
-    QUICHE_VERSION
-)
-
 if(QUICHE_FOUND)
-  set(QUICHE_INCLUDE_DIRS ${QUICHE_INCLUDE_DIR})
-  set(QUICHE_LIBRARIES    ${QUICHE_LIBRARY})
-endif()
+  string(REPLACE ";" " " QUICHE_CFLAGS "${QUICHE_CFLAGS}")
+  message(STATUS "Found Quiche (via pkg-config): ${QUICHE_INCLUDE_DIRS} (found version \"${QUICHE_VERSION}\")")
+else()
+  find_path(QUICHE_INCLUDE_DIR NAMES "quiche.h")
+  find_library(QUICHE_LIBRARY NAMES "quiche")
 
-mark_as_advanced(QUICHE_INCLUDE_DIR QUICHE_LIBRARY)
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Quiche
+    REQUIRED_VARS
+      QUICHE_INCLUDE_DIR
+      QUICHE_LIBRARY
+  )
+
+  if(QUICHE_FOUND)
+    set(QUICHE_INCLUDE_DIRS ${QUICHE_INCLUDE_DIR})
+    set(QUICHE_LIBRARIES    ${QUICHE_LIBRARY})
+  endif()
+
+  mark_as_advanced(QUICHE_INCLUDE_DIR QUICHE_LIBRARY)
+endif()
diff --git a/Utilities/cmcurl/CMake/FindRustls.cmake b/Utilities/cmcurl/CMake/FindRustls.cmake
index ffd6859..db0e153 100644
--- a/Utilities/cmcurl/CMake/FindRustls.cmake
+++ b/Utilities/cmcurl/CMake/FindRustls.cmake
@@ -21,53 +21,83 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-# Find the rustls library
+# Find the Rustls library
 #
 # Input variables:
 #
-# RUSTLS_INCLUDE_DIR   The rustls include directory
-# RUSTLS_LIBRARY       Path to rustls library
+# - `RUSTLS_INCLUDE_DIR`:   The Rustls include directory.
+# - `RUSTLS_LIBRARY`:       Path to `rustls` library.
 #
 # Result variables:
 #
-# RUSTLS_FOUND         System has rustls
-# RUSTLS_INCLUDE_DIRS  The rustls include directories
-# RUSTLS_LIBRARIES     The rustls library names
-# RUSTLS_VERSION       Version of rustls
+# - `RUSTLS_FOUND`:         System has Rustls.
+# - `RUSTLS_INCLUDE_DIRS`:  The Rustls include directories.
+# - `RUSTLS_LIBRARIES`:     The Rustls library names.
+# - `RUSTLS_LIBRARY_DIRS`:  The Rustls library directories.
+# - `RUSTLS_PC_REQUIRES`:   The Rustls pkg-config packages.
+# - `RUSTLS_CFLAGS`:        Required compiler flags.
+# - `RUSTLS_VERSION`:       Version of Rustls.
 
-if(CURL_USE_PKGCONFIG)
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED RUSTLS_INCLUDE_DIR AND
+   NOT DEFINED RUSTLS_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_RUSTLS "rustls")
+  pkg_check_modules(RUSTLS "rustls")
 endif()
 
-find_path(RUSTLS_INCLUDE_DIR NAMES "rustls.h"
-  HINTS
-    ${PC_RUSTLS_INCLUDEDIR}
-    ${PC_RUSTLS_INCLUDE_DIRS}
-)
-
-find_library(RUSTLS_LIBRARY NAMES "rustls"
-  HINTS
-    ${PC_RUSTLS_LIBDIR}
-    ${PC_RUSTLS_LIBRARY_DIRS}
-)
-
-if(PC_RUSTLS_VERSION)
-  set(RUSTLS_VERSION ${PC_RUSTLS_VERSION})
-endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Rustls
-  REQUIRED_VARS
-    RUSTLS_INCLUDE_DIR
-    RUSTLS_LIBRARY
-  VERSION_VAR
-    RUSTLS_VERSION
-)
-
 if(RUSTLS_FOUND)
-  set(RUSTLS_INCLUDE_DIRS ${RUSTLS_INCLUDE_DIR})
-  set(RUSTLS_LIBRARIES    ${RUSTLS_LIBRARY})
+  set(RUSTLS_PC_REQUIRES "rustls")
+  string(REPLACE ";" " " RUSTLS_CFLAGS "${RUSTLS_CFLAGS}")
+  message(STATUS "Found Rustls (via pkg-config): ${RUSTLS_INCLUDE_DIRS} (found version \"${RUSTLS_VERSION}\")")
+else()
+  find_path(RUSTLS_INCLUDE_DIR NAMES "rustls.h")
+  find_library(RUSTLS_LIBRARY NAMES "rustls")
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Rustls
+    REQUIRED_VARS
+      RUSTLS_INCLUDE_DIR
+      RUSTLS_LIBRARY
+  )
+
+  if(RUSTLS_FOUND)
+    set(RUSTLS_INCLUDE_DIRS ${RUSTLS_INCLUDE_DIR})
+    set(RUSTLS_LIBRARIES    ${RUSTLS_LIBRARY})
+  endif()
+
+  mark_as_advanced(RUSTLS_INCLUDE_DIR RUSTLS_LIBRARY)
 endif()
 
-mark_as_advanced(RUSTLS_INCLUDE_DIR RUSTLS_LIBRARY)
+if(APPLE)
+  find_library(SECURITY_FRAMEWORK "Security")
+  mark_as_advanced(SECURITY_FRAMEWORK)
+  if(NOT SECURITY_FRAMEWORK)
+    message(FATAL_ERROR "Security framework not found")
+  endif()
+  list(APPEND RUSTLS_LIBRARIES "-framework Security")
+
+  find_library(FOUNDATION_FRAMEWORK "Foundation")
+  mark_as_advanced(FOUNDATION_FRAMEWORK)
+  if(NOT FOUNDATION_FRAMEWORK)
+    message(FATAL_ERROR "Foundation framework not found")
+  endif()
+  list(APPEND RUSTLS_LIBRARIES "-framework Foundation")
+elseif(NOT WIN32)
+  find_library(_pthread_library "pthread")
+  if(_pthread_library)
+    list(APPEND RUSTLS_LIBRARIES "pthread")
+  endif()
+  mark_as_advanced(_pthread_library)
+
+  find_library(_dl_library "dl")
+  if(_dl_library)
+    list(APPEND RUSTLS_LIBRARIES "dl")
+  endif()
+  mark_as_advanced(_dl_library)
+
+  find_library(_math_library "m")
+  if(_math_library)
+    list(APPEND RUSTLS_LIBRARIES "m")
+  endif()
+  mark_as_advanced(_math_library)
+endif()
diff --git a/Utilities/cmcurl/CMake/FindWolfSSH.cmake b/Utilities/cmcurl/CMake/FindWolfSSH.cmake
index 608e3ab..98de656 100644
--- a/Utilities/cmcurl/CMake/FindWolfSSH.cmake
+++ b/Utilities/cmcurl/CMake/FindWolfSSH.cmake
@@ -21,23 +21,24 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-# Find the wolfssh library
+# Find the wolfSSH library
 #
 # Input variables:
 #
-# WOLFSSH_INCLUDE_DIR   The wolfssh include directory
-# WOLFSSH_LIBRARY       Path to wolfssh library
+# - `WOLFSSH_INCLUDE_DIR`:   The wolfSSH include directory.
+# - `WOLFSSH_LIBRARY`:       Path to `wolfssh` library.
 #
 # Result variables:
 #
-# WOLFSSH_FOUND         System has wolfssh
-# WOLFSSH_INCLUDE_DIRS  The wolfssh include directories
-# WOLFSSH_LIBRARIES     The wolfssh library names
-# WOLFSSH_VERSION       Version of wolfssh
+# - `WOLFSSH_FOUND`:         System has wolfSSH.
+# - `WOLFSSH_INCLUDE_DIRS`:  The wolfSSH include directories.
+# - `WOLFSSH_LIBRARIES`:     The wolfSSH library names.
+# - `WOLFSSH_VERSION`:       Version of wolfSSH.
 
 find_path(WOLFSSH_INCLUDE_DIR NAMES "wolfssh/ssh.h")
 find_library(WOLFSSH_LIBRARY NAMES "wolfssh" "libwolfssh")
 
+unset(WOLFSSH_VERSION CACHE)
 if(WOLFSSH_INCLUDE_DIR AND EXISTS "${WOLFSSH_INCLUDE_DIR}/wolfssh/version.h")
   set(_version_regex "#[\t ]*define[\t ]+LIBWOLFSSH_VERSION_STRING[\t ]+\"([^\"]*)\"")
   file(STRINGS "${WOLFSSH_INCLUDE_DIR}/wolfssh/version.h" _version_str REGEX "${_version_regex}")
diff --git a/Utilities/cmcurl/CMake/FindWolfSSL.cmake b/Utilities/cmcurl/CMake/FindWolfSSL.cmake
index 905fbfd..8f6f964 100644
--- a/Utilities/cmcurl/CMake/FindWolfSSL.cmake
+++ b/Utilities/cmcurl/CMake/FindWolfSSL.cmake
@@ -21,21 +21,21 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-# Find the wolfssl library
+# Find the wolfSSL library
 #
 # Input variables:
 #
-# WOLFSSL_INCLUDE_DIR   The wolfssl include directory
-# WolfSSL_INCLUDE_DIR   The wolfssl include directory (deprecated)
-# WOLFSSL_LIBRARY       Path to wolfssl library
-# WolfSSL_LIBRARY       Path to wolfssl library (deprecated)
+# - `WOLFSSL_INCLUDE_DIR`:   The wolfSSL include directory.
+# - `WOLFSSL_LIBRARY`:       Path to `wolfssl` library.
 #
 # Result variables:
 #
-# WOLFSSL_FOUND         System has wolfssl
-# WOLFSSL_INCLUDE_DIRS  The wolfssl include directories
-# WOLFSSL_LIBRARIES     The wolfssl library names
-# WOLFSSL_VERSION       Version of wolfssl
+# - `WOLFSSL_FOUND`:         System has wolfSSL.
+# - `WOLFSSL_INCLUDE_DIRS`:  The wolfSSL include directories.
+# - `WOLFSSL_LIBRARIES`:     The wolfSSL library names.
+# - `WOLFSSL_LIBRARY_DIRS`:  The wolfSSL library directories.
+# - `WOLFSSL_CFLAGS`:        Required compiler flags.
+# - `WOLFSSL_VERSION`:       Version of wolfSSL.
 
 if(DEFINED WolfSSL_INCLUDE_DIR AND NOT DEFINED WOLFSSL_INCLUDE_DIR)
   message(WARNING "WolfSSL_INCLUDE_DIR is deprecated, use WOLFSSL_INCLUDE_DIR instead.")
@@ -46,53 +46,51 @@
   set(WOLFSSL_LIBRARY "${WolfSSL_LIBRARY}")
 endif()
 
-if(CURL_USE_PKGCONFIG)
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED WOLFSSL_INCLUDE_DIR AND
+   NOT DEFINED WOLFSSL_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_WOLFSSL "wolfssl")
+  pkg_check_modules(WOLFSSL "wolfssl")
 endif()
 
-find_path(WOLFSSL_INCLUDE_DIR NAMES "wolfssl/ssl.h"
-  HINTS
-    ${PC_WOLFSSL_INCLUDEDIR}
-    ${PC_WOLFSSL_INCLUDE_DIRS}
-)
-
-find_library(WOLFSSL_LIBRARY NAMES "wolfssl"
-  HINTS
-    ${PC_WOLFSSL_LIBDIR}
-    ${PC_WOLFSSL_LIBRARY_DIRS}
-)
-
-if(PC_WOLFSSL_VERSION)
-  set(WOLFSSL_VERSION ${PC_WOLFSSL_VERSION})
-elseif(WOLFSSL_INCLUDE_DIR AND EXISTS "${WOLFSSL_INCLUDE_DIR}/wolfssl/version.h")
-  set(_version_regex "#[\t ]*define[\t ]+LIBWOLFSSL_VERSION_STRING[\t ]+\"([^\"]*)\"")
-  file(STRINGS "${WOLFSSL_INCLUDE_DIR}/wolfssl/version.h" _version_str REGEX "${_version_regex}")
-  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
-  set(WOLFSSL_VERSION "${_version_str}")
-  unset(_version_regex)
-  unset(_version_str)
-endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(WolfSSL
-  REQUIRED_VARS
-    WOLFSSL_INCLUDE_DIR
-    WOLFSSL_LIBRARY
-  VERSION_VAR
-    WOLFSSL_VERSION
-)
-
 if(WOLFSSL_FOUND)
-  set(WOLFSSL_INCLUDE_DIRS ${WOLFSSL_INCLUDE_DIR})
-  set(WOLFSSL_LIBRARIES    ${WOLFSSL_LIBRARY})
+  string(REPLACE ";" " " WOLFSSL_CFLAGS "${WOLFSSL_CFLAGS}")
+  message(STATUS "Found WolfSSL (via pkg-config): ${WOLFSSL_INCLUDE_DIRS} (found version \"${WOLFSSL_VERSION}\")")
+else()
+  find_path(WOLFSSL_INCLUDE_DIR NAMES "wolfssl/ssl.h")
+  find_library(WOLFSSL_LIBRARY NAMES "wolfssl")
 
-  if(NOT WIN32)
-    find_library(_math_library "m")
-    if(_math_library)
-      list(APPEND WOLFSSL_LIBRARIES "m")  # for log and pow
-    endif()
+  unset(WOLFSSL_VERSION CACHE)
+  if(WOLFSSL_INCLUDE_DIR AND EXISTS "${WOLFSSL_INCLUDE_DIR}/wolfssl/version.h")
+    set(_version_regex "#[\t ]*define[\t ]+LIBWOLFSSL_VERSION_STRING[\t ]+\"([^\"]*)\"")
+    file(STRINGS "${WOLFSSL_INCLUDE_DIR}/wolfssl/version.h" _version_str REGEX "${_version_regex}")
+    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+    set(WOLFSSL_VERSION "${_version_str}")
+    unset(_version_regex)
+    unset(_version_str)
   endif()
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(WolfSSL
+    REQUIRED_VARS
+      WOLFSSL_INCLUDE_DIR
+      WOLFSSL_LIBRARY
+    VERSION_VAR
+      WOLFSSL_VERSION
+  )
+
+  if(WOLFSSL_FOUND)
+    set(WOLFSSL_INCLUDE_DIRS ${WOLFSSL_INCLUDE_DIR})
+    set(WOLFSSL_LIBRARIES    ${WOLFSSL_LIBRARY})
+  endif()
+
+  mark_as_advanced(WOLFSSL_INCLUDE_DIR WOLFSSL_LIBRARY)
 endif()
 
-mark_as_advanced(WOLFSSL_INCLUDE_DIR WOLFSSL_LIBRARY)
+if(NOT WIN32)
+  find_library(_math_library "m")
+  if(_math_library)
+    list(APPEND WOLFSSL_LIBRARIES "m")  # for log and pow
+  endif()
+  mark_as_advanced(_math_library)
+endif()
diff --git a/Utilities/cmcurl/CMake/FindZstd.cmake b/Utilities/cmcurl/CMake/FindZstd.cmake
index 10558cc..7b0f557 100644
--- a/Utilities/cmcurl/CMake/FindZstd.cmake
+++ b/Utilities/cmcurl/CMake/FindZstd.cmake
@@ -25,17 +25,15 @@
 #
 # Input variables:
 #
-# ZSTD_INCLUDE_DIR   The zstd include directory
-# Zstd_INCLUDE_DIR   The zstd include directory (deprecated)
-# ZSTD_LIBRARY       Path to zstd library
-# Zstd_LIBRARY       Path to zstd library (deprecated)
+# - `ZSTD_INCLUDE_DIR`:   The zstd include directory.
+# - `ZSTD_LIBRARY`:       Path to `zstd` library.
 #
 # Result variables:
 #
-# ZSTD_FOUND         System has zstd
-# ZSTD_INCLUDE_DIRS  The zstd include directories
-# ZSTD_LIBRARIES     The zstd library names
-# ZSTD_VERSION       Version of zstd
+# - `ZSTD_FOUND`:         System has zstd.
+# - `ZSTD_INCLUDE_DIRS`:  The zstd include directories.
+# - `ZSTD_LIBRARIES`:     The zstd library names.
+# - `ZSTD_VERSION`:       Version of zstd.
 
 if(DEFINED Zstd_INCLUDE_DIR AND NOT DEFINED ZSTD_INCLUDE_DIR)
   message(WARNING "Zstd_INCLUDE_DIR is deprecated, use ZSTD_INCLUDE_DIR instead.")
diff --git a/Utilities/cmcurl/CMake/Macros.cmake b/Utilities/cmcurl/CMake/Macros.cmake
index d268667..7877f4c 100644
--- a/Utilities/cmcurl/CMake/Macros.cmake
+++ b/Utilities/cmcurl/CMake/Macros.cmake
@@ -30,8 +30,7 @@
 macro(check_include_file_concat _file _variable)
   check_include_files("${CURL_INCLUDES};${_file}" ${_variable})
   if(${_variable})
-    set(CURL_INCLUDES ${CURL_INCLUDES} ${_file})
-    set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D${_variable}")
+    list(APPEND CURL_INCLUDES ${_file})
   endif()
 endmacro()
 
@@ -39,8 +38,7 @@
 # Return result in variable: CURL_TEST_OUTPUT
 macro(curl_internal_test _curl_test)
   if(NOT DEFINED "${_curl_test}")
-    set(_macro_check_function_definitions
-      "-D${_curl_test} ${CURL_TEST_DEFINES} ${CMAKE_REQUIRED_FLAGS}")
+    string(REPLACE ";" " " _cmake_required_definitions "${CMAKE_REQUIRED_DEFINITIONS}")
     if(CMAKE_REQUIRED_LIBRARIES)
       set(_curl_test_add_libraries
         "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
@@ -48,10 +46,10 @@
 
     message(STATUS "Performing Test ${_curl_test}")
     try_compile(${_curl_test}
-      ${CMAKE_BINARY_DIR}
+      ${PROJECT_BINARY_DIR}
       "${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c"
       CMAKE_FLAGS
-        "-DCOMPILE_DEFINITIONS:STRING=${_macro_check_function_definitions}"
+        "-DCOMPILE_DEFINITIONS:STRING=-D${_curl_test} ${CURL_TEST_DEFINES} ${_cmake_required_definitions}"
         "${_curl_test_add_libraries}"
       OUTPUT_VARIABLE CURL_TEST_OUTPUT)
     if(${_curl_test})
@@ -64,7 +62,7 @@
   endif()
 endmacro()
 
-macro(optional_dependency _dependency)
+macro(curl_dependency_option _dependency)
   set(CURL_${_dependency} "AUTO" CACHE STRING "Build curl with ${_dependency} support (AUTO, ON or OFF)")
   set_property(CACHE CURL_${_dependency} PROPERTY STRINGS "AUTO" "ON" "OFF")
 
@@ -74,3 +72,11 @@
     find_package(${_dependency} REQUIRED)
   endif()
 endmacro()
+
+# Convert the passed paths to libpath linker options and add them to CMAKE_REQUIRED_LINK_OPTIONS.
+macro(curl_required_libpaths _libpaths_arg)
+  set(_libpaths "${_libpaths_arg}")
+  foreach(_libpath IN LISTS _libpaths)
+    list(APPEND CMAKE_REQUIRED_LINK_OPTIONS "${CMAKE_LIBRARY_PATH_FLAG}${_libpath}")
+  endforeach()
+endmacro()
diff --git a/Utilities/cmcurl/CMake/OtherTests.cmake b/Utilities/cmcurl/CMake/OtherTests.cmake
index 8936cea..62eef12 100644
--- a/Utilities/cmcurl/CMake/OtherTests.cmake
+++ b/Utilities/cmcurl/CMake/OtherTests.cmake
@@ -32,20 +32,21 @@
   endif()
 endmacro()
 
-set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+set(_cmake_try_compile_target_type_save ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
 
 if(NOT DEFINED HAVE_STRUCT_SOCKADDR_STORAGE)
+  cmake_push_check_state()
   unset(CMAKE_EXTRA_INCLUDE_FILES)
   if(WIN32)
     set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
-    set(CMAKE_REQUIRED_DEFINITIONS "-DWIN32_LEAN_AND_MEAN")
     set(CMAKE_REQUIRED_LIBRARIES "ws2_32")
   elseif(HAVE_SYS_SOCKET_H)
     set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
   endif()
   check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE)
   set(HAVE_STRUCT_SOCKADDR_STORAGE ${HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE})
-  set(CMAKE_EXTRA_INCLUDE_FILES "")
+  cmake_pop_check_state()
 endif()
 
 if(NOT WIN32)
@@ -74,35 +75,8 @@
     return 0;
   }" HAVE_STRUCT_TIMEVAL)
 
-unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
-
-if(NOT APPLE)
-  set(_source_epilogue "#undef inline")
-  add_header_include(HAVE_SYS_POLL_H "sys/poll.h")
-  add_header_include(HAVE_POLL_H "poll.h")
-  if(NOT CMAKE_CROSSCOMPILING)
-    check_c_source_runs("${_source_epilogue}
-      #include <stdlib.h>
-      int main(void)
-      {
-        if(0 != poll(0, 0, 10)) {
-          return 1; /* fail */
-        }
-        return 0;
-      }" HAVE_POLL_FINE)
-  elseif(UNIX)
-    check_c_source_compiles("${_source_epilogue}
-      #include <stdlib.h>
-      int main(void)
-      {
-        #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L
-          (void)poll(0, 0, 0);
-        #else
-          #error force compilation error
-        #endif
-      }" HAVE_POLL_FINE)
-  endif()
-endif()
+set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_cmake_try_compile_target_type_save})
+unset(_cmake_try_compile_target_type_save)
 
 # Detect HAVE_GETADDRINFO_THREADSAFE
 
@@ -118,7 +92,7 @@
        CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
        CMAKE_SYSTEM_NAME STREQUAL "SunOS")
   set(HAVE_GETADDRINFO_THREADSAFE TRUE)
-elseif(CMAKE_SYSTEM_NAME MATCHES "BSD")
+elseif(BSD OR CMAKE_SYSTEM_NAME MATCHES "BSD")
   set(HAVE_GETADDRINFO_THREADSAFE FALSE)
 endif()
 
@@ -178,3 +152,5 @@
       return 0;
     }" HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
 endif()
+
+unset(_source_epilogue)
diff --git a/Utilities/cmcurl/CMake/PickyWarnings.cmake b/Utilities/cmcurl/CMake/PickyWarnings.cmake
index a711efa..b62f97f 100644
--- a/Utilities/cmcurl/CMake/PickyWarnings.cmake
+++ b/Utilities/cmcurl/CMake/PickyWarnings.cmake
@@ -23,24 +23,27 @@
 ###########################################################################
 include(CheckCCompilerFlag)
 
-unset(WPICKY)
+unset(_picky)
 
 if(CURL_WERROR AND
    ((CMAKE_COMPILER_IS_GNUCC AND
      NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0 AND
      NOT CMAKE_VERSION VERSION_LESS 3.23.0) OR  # to avoid check_symbol_exists() conflicting with GCC -pedantic-errors
    CMAKE_C_COMPILER_ID MATCHES "Clang"))
-  set(WPICKY "${WPICKY} -pedantic-errors")
+  list(APPEND _picky "-pedantic-errors")
+  if(MSVC)  # clang-cl
+    list(APPEND _picky "-Wno-language-extension-token")  # Override default error to make __int64 size detection pass
+  endif()
 endif()
 
 if(APPLE AND
    (CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR
    (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.3))
-  set(WPICKY "${WPICKY} -Werror=partial-availability")  # clang 3.6  appleclang 6.3
+  list(APPEND _picky "-Werror=partial-availability")  # clang 3.6  appleclang 6.3
 endif()
 
 if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
-  set(WPICKY "${WPICKY} -Werror-implicit-function-declaration")  # clang 1.0  gcc 2.95
+  list(APPEND _picky "-Werror-implicit-function-declaration")  # clang 1.0  gcc 2.95
 endif()
 
 if(PICKY_COMPILER)
@@ -49,29 +52,29 @@
     # https://clang.llvm.org/docs/DiagnosticsReference.html
     # https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
 
-    # WPICKY_ENABLE = Options we want to enable as-is.
-    # WPICKY_DETECT = Options we want to test first and enable if available.
+    # _picky_enable = Options we want to enable as-is.
+    # _picky_detect = Options we want to test first and enable if available.
 
     # Prefer the -Wextra alias with clang.
     if(CMAKE_C_COMPILER_ID MATCHES "Clang")
-      set(WPICKY_ENABLE "-Wextra")
+      set(_picky_enable "-Wextra")
     else()
-      set(WPICKY_ENABLE "-W")
+      set(_picky_enable "-W")
     endif()
 
-    list(APPEND WPICKY_ENABLE
+    list(APPEND _picky_enable
       -Wall -pedantic
     )
 
     # ----------------------------------
     # Add new options here, if in doubt:
     # ----------------------------------
-    set(WPICKY_DETECT
+    set(_picky_detect
     )
 
     # Assume these options always exist with both clang and gcc.
     # Require clang 3.0 / gcc 2.95 or later.
-    list(APPEND WPICKY_ENABLE
+    list(APPEND _picky_enable
       -Wbad-function-cast                  # clang  2.7  gcc  2.95
       -Wconversion                         # clang  2.7  gcc  2.95
       -Winline                             # clang  1.0  gcc  1.0
@@ -89,7 +92,7 @@
     )
 
     # Always enable with clang, version dependent with gcc
-    set(WPICKY_COMMON_OLD
+    set(_picky_common_old
       -Waddress                            # clang  2.7  gcc  4.3
       -Wattributes                         # clang  2.7  gcc  4.1
       -Wcast-align                         # clang  1.0  gcc  4.2
@@ -118,7 +121,7 @@
       -Wvla                                # clang  2.8  gcc  4.3
     )
 
-    set(WPICKY_COMMON
+    set(_picky_common
       -Wdouble-promotion                   # clang  3.6  gcc  4.6  appleclang  6.3
       -Wenum-conversion                    # clang  3.2  gcc 10.0  appleclang  4.6  g++ 11.0
       -Wpragmas                            # clang  3.5  gcc  4.1  appleclang  6.0
@@ -126,51 +129,55 @@
     )
 
     if(CMAKE_C_COMPILER_ID MATCHES "Clang")
-      list(APPEND WPICKY_ENABLE
-        ${WPICKY_COMMON_OLD}
+      list(APPEND _picky_enable
+        ${_picky_common_old}
         -Wshift-sign-overflow              # clang  2.9
         -Wshorten-64-to-32                 # clang  1.0
-        -Wlanguage-extension-token         # clang  3.0
         -Wformat=2                         # clang  3.0  gcc  4.8
       )
+      if(NOT MSVC)
+        list(APPEND _picky_enable
+          -Wlanguage-extension-token         # clang  3.0  # Avoid for clang-cl to allow __int64
+        )
+      endif()
       # Enable based on compiler version
       if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR
          (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.3))
-        list(APPEND WPICKY_ENABLE
-          ${WPICKY_COMMON}
-          -Wunreachable-code-break         # clang  3.5            appleclang  6.0
+        list(APPEND _picky_enable
+          ${_picky_common}
+        # -Wunreachable-code-break         # clang  3.5            appleclang  6.0  # Not used: Silent in "unity" builds
           -Wheader-guard                   # clang  3.4            appleclang  5.1
           -Wsometimes-uninitialized        # clang  3.2            appleclang  4.6
         )
       endif()
       if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.9) OR
          (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.3))
-        list(APPEND WPICKY_ENABLE
+        list(APPEND _picky_enable
           -Wcomma                          # clang  3.9            appleclang  8.3
           -Wmissing-variable-declarations  # clang  3.2            appleclang  4.6
         )
       endif()
       if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0) OR
          (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.3))
-        list(APPEND WPICKY_ENABLE
+        list(APPEND _picky_enable
           -Wassign-enum                    # clang  7.0            appleclang 10.3
           -Wextra-semi-stmt                # clang  7.0            appleclang 10.3
         )
       endif()
       if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.0) OR
          (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.4))
-        list(APPEND WPICKY_ENABLE
+        list(APPEND _picky_enable
           -Wimplicit-fallthrough           # clang  4.0  gcc  7.0  appleclang 12.4  # We do silencing for clang 10.0 and above only
         )
       endif()
     else()  # gcc
-      list(APPEND WPICKY_DETECT
-        ${WPICKY_COMMON}
+      list(APPEND _picky_detect
+        ${_picky_common}
       )
       # Enable based on compiler version
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.3)
-        list(APPEND WPICKY_ENABLE
-          ${WPICKY_COMMON_OLD}
+        list(APPEND _picky_enable
+          ${_picky_common_old}
           -Wclobbered                      #             gcc  4.3
           -Wmissing-parameter-type         #             gcc  4.3
           -Wold-style-declaration          #             gcc  4.3
@@ -179,22 +186,22 @@
         )
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5 AND MINGW)
-        list(APPEND WPICKY_ENABLE
+        list(APPEND _picky_enable
           -Wno-pedantic-ms-format          #             gcc  4.5 (MinGW-only)
         )
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
-        list(APPEND WPICKY_ENABLE
+        list(APPEND _picky_enable
           -Wformat=2                       # clang  3.0  gcc  4.8
         )
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
-        list(APPEND WPICKY_ENABLE
+        list(APPEND _picky_enable
           -Warray-bounds=2 -ftree-vrp      # clang  3.0  gcc  5.0 (clang default: -Warray-bounds)
         )
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.0)
-        list(APPEND WPICKY_ENABLE
+        list(APPEND _picky_enable
           -Wduplicated-cond                #             gcc  6.0
           -Wnull-dereference               # clang  3.0  gcc  6.0 (clang default)
             -fdelete-null-pointer-checks
@@ -203,17 +210,16 @@
         )
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0)
-        list(APPEND WPICKY_ENABLE
+        list(APPEND _picky_enable
           -Walloc-zero                     #             gcc  7.0
           -Wduplicated-branches            #             gcc  7.0
-          -Wno-format-overflow             #             gcc  7.0
           -Wformat-truncation=2            #             gcc  7.0
           -Wimplicit-fallthrough           # clang  4.0  gcc  7.0
           -Wrestrict                       #             gcc  7.0
         )
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.0)
-        list(APPEND WPICKY_ENABLE
+        list(APPEND _picky_enable
           -Warith-conversion               #             gcc 10.0
         )
       endif()
@@ -221,26 +227,39 @@
 
     #
 
-    foreach(_ccopt IN LISTS WPICKY_ENABLE)
-      set(WPICKY "${WPICKY} ${_ccopt}")
+    foreach(_ccopt IN LISTS _picky_enable)
+      list(APPEND _picky "${_ccopt}")
     endforeach()
 
-    foreach(_ccopt IN LISTS WPICKY_DETECT)
-      # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new
-      # test result in.
+    foreach(_ccopt IN LISTS _picky_detect)
+      # Use a unique variable name 1. for meaningful log output 2. to have a fresh, undefined variable for each detection
       string(MAKE_C_IDENTIFIER "OPT${_ccopt}" _optvarname)
       # GCC only warns about unknown -Wno- options if there are also other diagnostic messages,
       # so test for the positive form instead
       string(REPLACE "-Wno-" "-W" _ccopt_on "${_ccopt}")
       check_c_compiler_flag(${_ccopt_on} ${_optvarname})
       if(${_optvarname})
-        set(WPICKY "${WPICKY} ${_ccopt}")
+        list(APPEND _picky "${_ccopt}")
       endif()
     endforeach()
   endif()
 endif()
 
-if(WPICKY)
-  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WPICKY}")
-  message(STATUS "Picky compiler options:${WPICKY}")
+# clang-cl
+if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND MSVC)
+  if(CMAKE_VERSION VERSION_LESS 3.12)
+    set(_picky_tmp "")
+    foreach(_ccopt IN LISTS _picky)
+      list(APPEND _picky_tmp "/clang:${_ccopt}")
+    endforeach()
+    set(_picky ${_picky_tmp})
+  else()
+    list(TRANSFORM _picky PREPEND "/clang:")
+  endif()
+endif()
+
+if(_picky)
+  string(REPLACE ";" " " _picky "${_picky}")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_picky}")
+  message(STATUS "Picky compiler options: ${_picky}")
 endif()
diff --git a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
index 317f21c..077bed2 100644
--- a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
+++ b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
@@ -88,6 +88,7 @@
 set(HAVE_FCHMOD 0)
 set(HAVE_SOCKETPAIR 0)
 set(HAVE_SENDMSG 0)
+set(HAVE_SENDMMSG 0)
 set(HAVE_ALARM 0)
 set(HAVE_FCNTL 0)
 set(HAVE_GETPPID 0)
@@ -101,13 +102,12 @@
 set(HAVE_GETRLIMIT 0)
 set(HAVE_SETRLIMIT 0)
 set(HAVE_FSETXATTR 0)
-set(HAVE_LIBSOCKET 0)
 set(HAVE_SETLOCALE 1)
 set(HAVE_SETMODE 1)
+set(HAVE__SETMODE 1)
 set(HAVE_GETPEERNAME 1)
 set(HAVE_GETSOCKNAME 1)
 set(HAVE_GETHOSTNAME 1)
-set(HAVE_LIBZ 0)
 
 set(HAVE_RECV 1)
 set(HAVE_SEND 1)
@@ -122,12 +122,13 @@
 set(HAVE_IO_H 1)
 set(HAVE_NETDB_H 0)
 set(HAVE_NETINET_IN_H 0)
+set(HAVE_NETINET_IN6_H 0)
 set(HAVE_NETINET_TCP_H 0)
 set(HAVE_NETINET_UDP_H 0)
 set(HAVE_NET_IF_H 0)
 set(HAVE_IOCTL_SIOCGIFADDR 0)
 set(HAVE_POLL_H 0)
-set(HAVE_POLL_FINE 0)
+set(HAVE_POLL 0)
 set(HAVE_PWD_H 0)
 set(HAVE_SYS_EVENTFD_H 0)
 set(HAVE_SYS_FILIO_H 0)
@@ -147,7 +148,6 @@
 set(HAVE_LINUX_TCP_H 0)
 
 set(HAVE_FSEEKO 0)  # mingw-w64 2.0.0 and newer has it
-set(HAVE__FSEEKI64 1)
 set(HAVE_SOCKET 1)
 set(HAVE_SELECT 1)
 set(HAVE_STRDUP 1)
@@ -166,7 +166,6 @@
 set(HAVE_SIGNAL 1)
 set(HAVE_SIGACTION 0)
 set(HAVE_GLIBC_STRERROR_R 0)
-set(HAVE_MACH_ABSOLUTE_TIME 0)
 set(HAVE_GETIFADDRS 0)
 set(HAVE_FCNTL_O_NONBLOCK 0)
 set(HAVE_IOCTLSOCKET 1)
diff --git a/Utilities/cmcurl/CMake/curl-config.cmake.in b/Utilities/cmcurl/CMake/curl-config.cmake.in
index 7dc1f99..aa9eb51 100644
--- a/Utilities/cmcurl/CMake/curl-config.cmake.in
+++ b/Utilities/cmcurl/CMake/curl-config.cmake.in
@@ -23,20 +23,19 @@
 ###########################################################################
 @PACKAGE_INIT@
 
-if(NOT DEFINED CURL_USE_PKGCONFIG)
-  if(UNIX OR (MSVC AND VCPKG_TOOLCHAIN))  # Keep in sync with root CMakeLists.txt
-    set(CURL_USE_PKGCONFIG ON)
-  else()
-    set(CURL_USE_PKGCONFIG OFF)
-  endif()
+if(UNIX OR VCPKG_TOOLCHAIN OR (MINGW AND NOT CMAKE_CROSSCOMPILING))  # Keep in sync with root CMakeLists.txt
+  set(_curl_use_pkgconfig_default ON)
+else()
+  set(_curl_use_pkgconfig_default OFF)
 endif()
+option(CURL_USE_PKGCONFIG "Enable pkg-config to detect @PROJECT_NAME@ dependencies" ${_curl_use_pkgconfig_default})
 
 include(CMakeFindDependencyMacro)
-if(@USE_OPENSSL@)
-  find_dependency(OpenSSL @OPENSSL_VERSION_MAJOR@)
+if("@USE_OPENSSL@")
+  find_dependency(OpenSSL "@OPENSSL_VERSION_MAJOR@")
 endif()
-if(@USE_ZLIB@)
-  find_dependency(ZLIB @ZLIB_VERSION_MAJOR@)
+if("@HAVE_LIBZ@")
+  find_dependency(ZLIB "@ZLIB_VERSION_MAJOR@")
 endif()
 
 include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
index ef6c269..a7e350e 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -5,6 +5,7 @@
 set(BUILD_SHARED_LIBS OFF)
 set(BUILD_STATIC_LIBS ON)
 set(BUILD_STATIC_CURL OFF)
+set(CURL_CA_SEARCH_SAFE OFF)
 set(CURL_USE_BEARSSL OFF)
 set(CURL_USE_GSASL OFF)
 set(CURL_USE_GSSAPI OFF)
@@ -27,6 +28,7 @@
 set(CURL_DISABLE_BASIC_AUTH OFF)
 set(CURL_DISABLE_BEARER_AUTH OFF)
 set(CURL_DISABLE_BINDLOCAL OFF)
+set(CURL_DISABLE_CA_SEARCH OFF)
 set(CURL_DISABLE_COOKIES OFF CACHE INTERNAL "Do not disable curl cookie support")
 set(CURL_DISABLE_DICT ON CACHE INTERNAL "Disable curl dict protocol?")
 set(CURL_DISABLE_DIGEST_AUTH OFF)
@@ -42,6 +44,7 @@
 set(CURL_DISABLE_HTTP OFF CACHE INTERNAL "Disable curl http protocol?")
 set(CURL_DISABLE_IMAP ON CACHE INTERNAL "Disable curl imap protocol?")
 set(CURL_DISABLE_INSTALL ON)
+set(CURL_DISABLE_IPFS OFF)
 set(CURL_DISABLE_KERBEROS_AUTH OFF)
 set(CURL_DISABLE_LDAP ON CACHE INTERNAL "Disable curl ldap protocol?")
 set(CURL_DISABLE_LDAPS ON CACHE INTERNAL "Disable curl ldaps protocol?")
@@ -66,11 +69,13 @@
 set(CURL_DISABLE_TELNET ON CACHE INTERNAL "Disable curl telnet protocol?")
 set(CURL_DISABLE_TFTP ON CACHE INTERNAL "Disable curl tftp protocol?")
 set(CURL_DISABLE_VERBOSE_STRINGS OFF CACHE INTERNAL "Do not disable curl verbosity")
+set(CURL_DISABLE_WEBSOCKETS OFF)
 set(CURL_ENABLE_EXPORT_TARGET OFF)
 set(CURL_HIDDEN_SYMBOLS OFF CACHE INTERNAL "No curl hidden symbols")
 set(CURL_LTO OFF CACHE INTERNAL "Turn on compiler Link Time Optimizations")
 set(CURL_STATIC_CRT OFF CACHE INTERNAL "Set to ON to build libcurl with static CRT on Windows (/MT).")
 set(CURL_WERROR OFF CACHE INTERNAL "Turn compiler warnings into errors")
+set(CURL_ZLIB "AUTO" CACHE INTERNAL "Build curl with ZLIB support (AUTO, ON or OFF)")
 set(CURL_ZSTD OFF)
 set(DISABLED_THREADSAFE OFF CACHE INTERNAL "Curl can use thread-safe functions")
 set(ENABLE_ARES OFF CACHE INTERNAL "No curl c-ares support")
@@ -216,20 +221,32 @@
 
 # Collect command-line arguments for buildinfo.txt.
 # Must reside at the top of the script to work as expected.
-get_cmake_property(_cache_vars CACHE_VARIABLES)
-unset(_cmake_args)
-foreach(_cache_var ${_cache_vars})
-  get_property(_cache_var_helpstring CACHE ${_cache_var} PROPERTY HELPSTRING)
-  if(_cache_var_helpstring STREQUAL "No help, variable specified on the command line.")
-    get_property(_cache_var_type CACHE ${_cache_var} PROPERTY TYPE)
-    if(_cache_var_type STREQUAL "UNINITIALIZED")
-      set(_cache_var_type)
-    else()
-      set(_cache_var_type ":${_cache_var_type}")
+set(_cmake_args "")
+if(NOT "$ENV{CURL_BUILDINFO}$ENV{CURL_CI}$ENV{CI}" STREQUAL "")
+  get_cmake_property(_cache_vars CACHE_VARIABLES)
+  foreach(_cache_var IN ITEMS ${_cache_vars})
+    get_property(_cache_var_helpstring CACHE ${_cache_var} PROPERTY HELPSTRING)
+    if(_cache_var_helpstring STREQUAL "No help, variable specified on the command line.")
+      get_property(_cache_var_type CACHE ${_cache_var} PROPERTY TYPE)
+      get_property(_cache_var_value CACHE ${_cache_var} PROPERTY VALUE)
+      if(_cache_var_type STREQUAL "UNINITIALIZED")
+        set(_cache_var_type)
+      else()
+        set(_cache_var_type ":${_cache_var_type}")
+      endif()
+      set(_cmake_args "${_cmake_args} -D${_cache_var}${_cache_var_type}=\"${_cache_var_value}\"")
     endif()
-    set(_cmake_args "${_cmake_args} -D${_cache_var}${_cache_var_type}=\"${${_cache_var}}\"")
-  endif()
-endforeach()
+  endforeach()
+endif()
+
+function(curl_dumpvars)  # Dump all defined variables with their values
+  message("::group::CMake Variable Dump")
+  get_cmake_property(_vars VARIABLES)
+  foreach(_var ${_vars})
+    message("${_var} = ${${_var}}")
+  endforeach()
+  message("::endgroup::")
+endfunction()
 endif()
 
 set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
@@ -238,7 +255,27 @@
 include(CMakeDependentOption)
 include(CheckCCompilerFlag)
 
-project(CURL C)
+file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/curl/curlver.h" _curl_version_h_contents REGEX "#define LIBCURL_VERSION( |_NUM )")
+string(REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*" _curl_version ${_curl_version_h_contents})
+string(REGEX REPLACE "[^\"]+\"" "" _curl_version ${_curl_version})
+string(REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+" _curl_version_num ${_curl_version_h_contents})
+string(REGEX REPLACE "[^0]+0x" "" _curl_version_num ${_curl_version_num})
+unset(_curl_version_h_contents)
+
+if(0) # This code not needed for building within CMake.
+message(STATUS "curl version=[${_curl_version}]")
+endif()
+# XXX(CMake): Set these as normal variables to suppress cache entries.
+set(CMAKE_PROJECT_VERSION 0)
+set(CMAKE_PROJECT_VERSION_MAJOR 0)
+set(CMAKE_PROJECT_VERSION_MINOR 0)
+set(CMAKE_PROJECT_VERSION_PATCH 0)
+set(CMAKE_PROJECT_VERSION_TWEAK 0)
+
+string(REGEX REPLACE "([0-9]+\.[0-9]+\.[0-9]+).+" "\\1" _curl_version_sem "${_curl_version}")
+project(CURL
+  VERSION "${_curl_version_sem}"
+  LANGUAGES C)
 
 unset(_target_flags)
 if(APPLE)
@@ -247,9 +284,15 @@
 if(UNIX)
   set(_target_flags "${_target_flags} UNIX")
 endif()
+if(BSD)
+  set(_target_flags "${_target_flags} BSD")
+endif()
 if(WIN32)
   set(_target_flags "${_target_flags} WIN32")
 endif()
+if(WINDOWS_STORE)
+  set(_target_flags "${_target_flags} UWP")
+endif()
 if(CYGWIN)
   set(_target_flags "${_target_flags} CYGWIN")
 endif()
@@ -281,38 +324,29 @@
     "${CMAKE_SYSTEM_NAME}/${CMAKE_SYSTEM_PROCESSOR}")
 endif()
 
-function(curl_dumpvars)  # Dump all defined variables with their values
-  message("::group::CMake Variable Dump")
-  get_cmake_property(_vars VARIABLES)
-  foreach(_var ${_vars})
-    message("${_var} = ${${_var}}")
-  endforeach()
-  message("::endgroup::")
-endfunction()
-
-file(STRINGS "${CURL_SOURCE_DIR}/include/curl/curlver.h" _curl_version_h_contents REGEX "#define LIBCURL_VERSION( |_NUM )")
-string(REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*" CURL_VERSION ${_curl_version_h_contents})
-string(REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION})
-string(REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+" CURL_VERSION_NUM ${_curl_version_h_contents})
-string(REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM})
-unset(_curl_version_h_contents)
-
-if(0) # This code not needed for building within CMake.
-message(STATUS "curl version=[${CURL_VERSION}]")
-endif()
-
 if(CMAKE_C_COMPILER_TARGET)
-  set(OS "\"${CMAKE_C_COMPILER_TARGET}\"")
+  set(CURL_OS "\"${CMAKE_C_COMPILER_TARGET}\"")
 else()
-  set(OS "\"${CMAKE_SYSTEM_NAME}\"")
+  set(CURL_OS "\"${CMAKE_SYSTEM_NAME}\"")
 endif()
 
-include_directories("${CURL_SOURCE_DIR}/include")
+include_directories("${PROJECT_SOURCE_DIR}/include")
 
 if(NOT DEFINED CMAKE_UNITY_BUILD_BATCH_SIZE)
   set(CMAKE_UNITY_BUILD_BATCH_SIZE 0)
 endif()
 
+# Having CMAKE_TRY_COMPILE_TARGET_TYPE set to STATIC_LIBRARY breaks certain
+# 'check_function_exists()' detections (possibly more), by detecting
+# non-existing features. This happens by default when using 'ios.toolchain.cmake'.
+# Work it around by setting this value to `EXECUTABLE`.
+if(CMAKE_TRY_COMPILE_TARGET_TYPE STREQUAL "STATIC_LIBRARY")
+  message(STATUS "CMAKE_TRY_COMPILE_TARGET_TYPE was found set to STATIC_LIBRARY. "
+    "Overriding with EXECUTABLE for feature detections to work.")
+  set(_cmake_try_compile_target_type_save ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE "EXECUTABLE")
+endif()
+
 option(CURL_WERROR "Turn compiler warnings into errors" OFF)
 option(PICKY_COMPILER "Enable picky compiler options" ON)
 option(BUILD_CURL_EXE "Build curl executable" ON)
@@ -323,14 +357,17 @@
 option(CURL_DISABLE_INSTALL "Disable installation targets" OFF)
 
 if(WIN32)
-  option(CURL_STATIC_CRT "Build libcurl with static CRT on Windows (/MT)" OFF)
-  if(CURL_STATIC_CRT)
+  option(CURL_STATIC_CRT "Build libcurl with static CRT with MSVC (/MT)" OFF)
+  if(CURL_STATIC_CRT AND MSVC)
     set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
     set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
     set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
   endif()
 
   option(ENABLE_UNICODE "Use the Unicode version of the Windows API functions" OFF)
+  if(WINDOWS_STORE)
+    set(ENABLE_UNICODE ON)
+  endif()
   if(ENABLE_UNICODE)
     add_definitions("-DUNICODE" "-D_UNICODE")
     if(MINGW)
@@ -339,11 +376,12 @@
   endif()
 
   if(0) # This code not needed for building within CMake.
+  list(APPEND CMAKE_REQUIRED_DEFINITIONS "-DWIN32_LEAN_AND_MEAN")  # Apply to all feature checks
+
   set(CURL_TARGET_WINDOWS_VERSION "" CACHE STRING "Minimum target Windows version as hex string")
   if(CURL_TARGET_WINDOWS_VERSION)
     add_definitions("-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}")
-    list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}")
-    set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}")
+    list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}")  # Apply to all feature checks
   endif()
   endif()
 
@@ -369,8 +407,15 @@
 include(PickyWarnings)
 endif()
 
-option(ENABLE_DEBUG "Enable curl debug features" OFF)
-option(ENABLE_CURLDEBUG "Enable TrackMemory feature" ${ENABLE_DEBUG})
+if(CMAKE_SYSTEM_NAME MATCHES "Linux")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE")  # Required for sendmmsg()
+endif()
+
+option(ENABLE_DEBUG "Enable curl debug features (for developing curl itself)" OFF)
+if(ENABLE_DEBUG)
+  message(WARNING "This curl build is Debug-enabled, do not use in production.")
+endif()
+option(ENABLE_CURLDEBUG "Enable TrackMemory debug feature" ${ENABLE_DEBUG})
 
 if(MSVC)
   set(ENABLE_CURLDEBUG OFF)  # FIXME: TrackMemory + MSVC fails test 558 and 1330. Tested with static build, Debug mode.
@@ -418,14 +463,14 @@
 endif()
 
 # Override to force-disable or force-enable the use of pkg-config.
-if(UNIX OR (MSVC AND VCPKG_TOOLCHAIN))  # Keep in sync with CMake/curl-config.cmake.in
+if(UNIX OR VCPKG_TOOLCHAIN OR (MINGW AND NOT CMAKE_CROSSCOMPILING))  # Keep in sync with CMake/curl-config.cmake.in
   set(_curl_use_pkgconfig_default ON)
 else()
   set(_curl_use_pkgconfig_default OFF)
 endif()
 option(CURL_USE_PKGCONFIG "Enable pkg-config to detect dependencies" ${_curl_use_pkgconfig_default})
 
-# Initialize CURL_LIBS
+# Initialize variables collecting dependency libs, paths, pkg-config names.
 set(CURL_LIBS "")
 set(CURL_LIBDIRS "")
 set(LIBCURL_PC_REQUIRES_PRIVATE "")
@@ -461,7 +506,7 @@
 mark_as_advanced(CURL_DISABLE_KERBEROS_AUTH)
 option(CURL_DISABLE_NEGOTIATE_AUTH "Disable negotiate authentication" OFF)
 mark_as_advanced(CURL_DISABLE_NEGOTIATE_AUTH)
-option(CURL_DISABLE_AWS "Disable AWS-SIG4" OFF)
+option(CURL_DISABLE_AWS "Disable aws-sigv4" OFF)
 mark_as_advanced(CURL_DISABLE_AWS)
 option(CURL_DISABLE_DICT "Disable DICT" OFF)
 mark_as_advanced(CURL_DISABLE_DICT)
@@ -469,12 +514,6 @@
 mark_as_advanced(CURL_DISABLE_DOH)
 option(CURL_DISABLE_FILE "Disable FILE" OFF)
 mark_as_advanced(CURL_DISABLE_FILE)
-if(0) # This code not needed for building within CMake.
-cmake_dependent_option(CURL_DISABLE_FORM_API "Disable form-api"
-  OFF "NOT CURL_DISABLE_MIME"
-  ON)
-mark_as_advanced(CURL_DISABLE_FORM_API)
-endif()
 option(CURL_DISABLE_FTP "Disable FTP" OFF)
 mark_as_advanced(CURL_DISABLE_FTP)
 option(CURL_DISABLE_GETOPTIONS "Disable curl_easy_options API for existing options to curl_easy_setopt" OFF)
@@ -499,10 +538,16 @@
 mark_as_advanced(CURL_DISABLE_LIBCURL_OPTION)
 option(CURL_DISABLE_MIME "Disable MIME support" OFF)
 mark_as_advanced(CURL_DISABLE_MIME)
+if(0) # This code not needed for building within CMake.
+cmake_dependent_option(CURL_DISABLE_FORM_API "Disable form-api"
+  OFF "NOT CURL_DISABLE_MIME"
+  ON)
+mark_as_advanced(CURL_DISABLE_FORM_API)
+endif()
 option(CURL_DISABLE_MQTT "Disable MQTT" OFF)
-mark_as_advanced(CURL_DISABLE_BINDLOCAL)
-option(CURL_DISABLE_BINDLOCAL "Disable local binding support" OFF)
 mark_as_advanced(CURL_DISABLE_MQTT)
+option(CURL_DISABLE_BINDLOCAL "Disable local binding support" OFF)
+mark_as_advanced(CURL_DISABLE_BINDLOCAL)
 option(CURL_DISABLE_NETRC "Disable netrc parser" OFF)
 mark_as_advanced(CURL_DISABLE_NETRC)
 option(CURL_DISABLE_NTLM "Disable NTLM support" OFF)
@@ -515,6 +560,8 @@
 mark_as_advanced(CURL_DISABLE_PROGRESS_METER)
 option(CURL_DISABLE_PROXY "Disable proxy support" OFF)
 mark_as_advanced(CURL_DISABLE_PROXY)
+option(CURL_DISABLE_IPFS "Disable IPFS" OFF)
+mark_as_advanced(CURL_DISABLE_IPFS)
 option(CURL_DISABLE_RTSP "Disable RTSP" OFF)
 mark_as_advanced(CURL_DISABLE_SHA512_256)
 option(CURL_DISABLE_SHA512_256 "Disable SHA-512/256 hash algorithm" OFF)
@@ -527,6 +574,8 @@
 mark_as_advanced(CURL_DISABLE_SMTP)
 option(CURL_DISABLE_SOCKETPAIR "Disable use of socketpair for curl_multi_poll" OFF)
 mark_as_advanced(CURL_DISABLE_SOCKETPAIR)
+option(CURL_DISABLE_WEBSOCKETS "Disable WebSocket" OFF)
+mark_as_advanced(CURL_DISABLE_WEBSOCKETS)
 option(CURL_DISABLE_TELNET "Disable Telnet" OFF)
 mark_as_advanced(CURL_DISABLE_TELNET)
 option(CURL_DISABLE_TFTP "Disable TFTP" OFF)
@@ -535,6 +584,7 @@
 mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS)
 
 if(CURL_DISABLE_HTTP)
+  set(CURL_DISABLE_IPFS ON)
   set(CURL_DISABLE_RTSP ON)
   set(CURL_DISABLE_ALTSVC ON)
   set(CURL_DISABLE_HSTS ON)
@@ -554,6 +604,7 @@
   set(CURL_DISABLE_LDAPS ON)
   set(CURL_DISABLE_MQTT ON)
   set(CURL_DISABLE_POP3 ON)
+  set(CURL_DISABLE_IPFS ON)
   set(CURL_DISABLE_RTSP ON)
   set(CURL_DISABLE_SMB ON)
   set(CURL_DISABLE_SMTP ON)
@@ -569,10 +620,8 @@
 mark_as_advanced(ENABLE_IPV6)
 if(ENABLE_IPV6 AND NOT WIN32)
   include(CheckStructHasMember)
-  check_struct_has_member("struct sockaddr_in6" "sin6_addr" "netinet/in.h"
-                          HAVE_SOCKADDR_IN6_SIN6_ADDR)
-  check_struct_has_member("struct sockaddr_in6" "sin6_scope_id" "netinet/in.h"
-                          HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
+  check_struct_has_member("struct sockaddr_in6" "sin6_addr" "netinet/in.h" HAVE_SOCKADDR_IN6_SIN6_ADDR)
+  check_struct_has_member("struct sockaddr_in6" "sin6_scope_id" "netinet/in.h" HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
   if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR)
     message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support")
     # Force the feature off as this name is used as guard macro...
@@ -639,7 +688,12 @@
 
 # Preload settings on Windows
 if(WIN32)
-  include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/Platforms/WindowsCache.cmake)
+  include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/Platforms/WindowsCache.cmake")
+elseif(APPLE)
+  # Fast-track predictable feature detections
+  set(HAVE_EVENTFD 0)
+  set(HAVE_GETPASS_R 0)
+  set(HAVE_SENDMMSG 0)
 endif()
 
 if(ENABLE_THREADED_RESOLVER)
@@ -654,9 +708,11 @@
 endif()
 
 # Check for all needed libraries
-check_library_exists("socket" "connect" "" HAVE_LIBSOCKET)
-if(HAVE_LIBSOCKET)
-  set(CURL_LIBS "socket;${CURL_LIBS}")
+if(NOT WIN32 AND NOT APPLE)
+  check_library_exists("socket" "connect" "" HAVE_LIBSOCKET)
+  if(HAVE_LIBSOCKET)
+    set(CURL_LIBS "socket;${CURL_LIBS}")
+  endif()
 endif()
 
 check_function_exists("gethostname" HAVE_GETHOSTNAME)
@@ -674,10 +730,10 @@
 endif()
 
 if(APPLE)
-  cmake_dependent_option(CURL_USE_SECTRANSP "Enable Apple OS native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+  cmake_dependent_option(CURL_USE_SECTRANSP "Enable Apple OS native SSL/TLS (Secure Transport)" OFF CURL_ENABLE_SSL OFF)
 endif()
 if(WIN32)
-  cmake_dependent_option(CURL_USE_SCHANNEL "Enable Windows native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+  cmake_dependent_option(CURL_USE_SCHANNEL "Enable Windows native SSL/TLS (Schannel)" OFF CURL_ENABLE_SSL OFF)
   option(CURL_WINDOWS_SSPI "Enable SSPI on Windows" ${CURL_USE_SCHANNEL})
 endif()
 cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
@@ -686,9 +742,17 @@
 cmake_dependent_option(CURL_USE_GNUTLS "Enable GnuTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
 cmake_dependent_option(CURL_USE_RUSTLS "Enable Rustls for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
 
-set(_openssl_default ON)
-if(WIN32 OR CURL_USE_SECTRANSP OR CURL_USE_SCHANNEL OR CURL_USE_MBEDTLS OR CURL_USE_WOLFSSL)
+if(WIN32 OR
+   CURL_USE_SECTRANSP OR
+   CURL_USE_SCHANNEL OR
+   CURL_USE_MBEDTLS OR
+   CURL_USE_BEARSSL OR
+   CURL_USE_WOLFSSL OR
+   CURL_USE_GNUTLS OR
+   CURL_USE_RUSTLS)
   set(_openssl_default OFF)
+else()
+  set(_openssl_default ON)
 endif()
 cmake_dependent_option(CURL_USE_OPENSSL "Enable OpenSSL for SSL/TLS" ${_openssl_default} CURL_ENABLE_SSL OFF)
 option(USE_OPENSSL_QUIC "Use OpenSSL and nghttp3 libraries for HTTP/3 support" OFF)
@@ -785,6 +849,7 @@
   endif()
   set(_curl_ca_bundle_supported TRUE)
 
+  cmake_push_check_state()
   set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
   if(NOT DEFINED HAVE_BORINGSSL)
     check_symbol_exists("OPENSSL_IS_BORINGSSL" "openssl/base.h" HAVE_BORINGSSL)
@@ -792,6 +857,7 @@
   if(NOT DEFINED HAVE_AWSLC)
     check_symbol_exists("OPENSSL_IS_AWSLC" "openssl/base.h" HAVE_AWSLC)
   endif()
+  cmake_pop_check_state()
 
   # Optionally build with a specific CA cert bundle.
   if(CURL_CA_BUNDLE)
@@ -808,8 +874,13 @@
   set(_ssl_enabled ON)
   set(USE_MBEDTLS ON)
   list(APPEND CURL_LIBS ${MBEDTLS_LIBRARIES})
-  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "mbedtls")
-  include_directories(${MBEDTLS_INCLUDE_DIRS})
+  list(APPEND CURL_LIBDIRS ${MBEDTLS_LIBRARY_DIRS})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE ${MBEDTLS_PC_REQUIRES})
+  include_directories(SYSTEM ${MBEDTLS_INCLUDE_DIRS})
+  link_directories(${MBEDTLS_LIBRARY_DIRS})
+  if(MBEDTLS_CFLAGS)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MBEDTLS_CFLAGS}")
+  endif()
 
   if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "mbedtls")
     set(_valid_default_ssl_backend TRUE)
@@ -822,7 +893,7 @@
   set(_ssl_enabled ON)
   set(USE_BEARSSL ON)
   list(APPEND CURL_LIBS ${BEARSSL_LIBRARIES})
-  include_directories(${BEARSSL_INCLUDE_DIRS})
+  include_directories(SYSTEM ${BEARSSL_INCLUDE_DIRS})
 
   if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "bearssl")
     set(_valid_default_ssl_backend TRUE)
@@ -839,8 +910,13 @@
   set(_ssl_enabled ON)
   set(USE_WOLFSSL ON)
   list(APPEND CURL_LIBS ${WOLFSSL_LIBRARIES})
+  list(APPEND CURL_LIBDIRS ${WOLFSSL_LIBRARY_DIRS})
   list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "wolfssl")
-  include_directories(${WOLFSSL_INCLUDE_DIRS})
+  include_directories(SYSTEM ${WOLFSSL_INCLUDE_DIRS})
+  link_directories(${WOLFSSL_LIBRARY_DIRS})
+  if(WOLFSSL_CFLAGS)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WOLFSSL_CFLAGS}")
+  endif()
 
   if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "wolfssl")
     set(_valid_default_ssl_backend TRUE)
@@ -865,7 +941,7 @@
   list(APPEND CURL_LIBS ${GNUTLS_LIBRARIES} ${NETTLE_LIBRARIES})
   list(APPEND CURL_LIBDIRS ${NETTLE_LIBRARY_DIRS})
   list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "gnutls" "nettle")
-  include_directories(${GNUTLS_INCLUDE_DIRS} ${NETTLE_INCLUDE_DIRS})
+  include_directories(SYSTEM ${GNUTLS_INCLUDE_DIRS} ${NETTLE_INCLUDE_DIRS})
   link_directories(${NETTLE_LIBRARY_DIRS})
   if(NETTLE_CFLAGS)
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${NETTLE_CFLAGS}")
@@ -890,8 +966,13 @@
   set(_ssl_enabled ON)
   set(USE_RUSTLS ON)
   list(APPEND CURL_LIBS ${RUSTLS_LIBRARIES})
-  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "rustls")
-  include_directories(${RUSTLS_INCLUDE_DIRS})
+  list(APPEND CURL_LIBDIRS ${RUSTLS_LIBRARY_DIRS})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE ${RUSTLS_PC_REQUIRES})
+  include_directories(SYSTEM ${RUSTLS_INCLUDE_DIRS})
+  link_directories(${RUSTLS_LIBRARY_DIRS})
+  if(RUSTLS_CFLAGS)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${RUSTLS_CFLAGS}")
+  endif()
 
   if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "rustls")
     set(_valid_default_ssl_backend TRUE)
@@ -907,11 +988,9 @@
 # and before calling openssl_check_symbol_exists().
 
 set(HAVE_LIBZ OFF)
-set(USE_ZLIB OFF)
-find_package(ZLIB)
+curl_dependency_option(ZLIB)
 if(ZLIB_FOUND)
   set(HAVE_LIBZ ON)
-  set(USE_ZLIB ON)
 
   # Depend on ZLIB via imported targets. This allows our dependents to
   # get our dependencies transitively.
@@ -931,8 +1010,7 @@
     set(HAVE_BROTLI ON)
     list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})
     list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libbrotlidec")
-    include_directories(${BROTLI_INCLUDE_DIRS})
-    list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS})
+    include_directories(SYSTEM ${BROTLI_INCLUDE_DIRS})
   endif()
 endif()
 
@@ -944,7 +1022,7 @@
     set(HAVE_ZSTD ON)
     list(APPEND CURL_LIBS ${ZSTD_LIBRARIES})
     list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libzstd")
-    include_directories(${ZSTD_INCLUDE_DIRS})
+    include_directories(SYSTEM ${ZSTD_INCLUDE_DIRS})
   else()
     message(WARNING "zstd v1.0.0 or newer is required, disabling zstd support.")
   endif()
@@ -966,6 +1044,7 @@
   elseif(USE_WOLFSSL)
     set(CMAKE_REQUIRED_INCLUDES   "${WOLFSSL_INCLUDE_DIRS}")
     set(CMAKE_REQUIRED_LIBRARIES  "${WOLFSSL_LIBRARIES}")
+    curl_required_libpaths("${WOLFSSL_LIBRARY_DIRS}")
     if(HAVE_LIBZ)
       list(APPEND CMAKE_REQUIRED_INCLUDES  "${ZLIB_INCLUDE_DIRS}")  # Public wolfSSL headers require zlib headers
       list(APPEND CMAKE_REQUIRED_LIBRARIES "${ZLIB_LIBRARIES}")
@@ -996,8 +1075,9 @@
 endmacro()
 
 if(USE_WOLFSSL)
-  openssl_check_symbol_exists("wolfSSL_DES_ecb_encrypt" "wolfssl/openssl/des.h" HAVE_WOLFSSL_DES_ECB_ENCRYPT "")
-  openssl_check_symbol_exists("wolfSSL_BIO_set_shutdown" "wolfssl/ssl.h" HAVE_WOLFSSL_FULL_BIO "")
+  openssl_check_symbol_exists("wolfSSL_DES_ecb_encrypt" "wolfssl/options.h;wolfssl/openssl/des.h" HAVE_WOLFSSL_DES_ECB_ENCRYPT "")
+  openssl_check_symbol_exists("wolfSSL_BIO_new" "wolfssl/options.h;wolfssl/ssl.h" HAVE_WOLFSSL_BIO "")
+  openssl_check_symbol_exists("wolfSSL_BIO_set_shutdown" "wolfssl/options.h;wolfssl/ssl.h" HAVE_WOLFSSL_FULL_BIO "")
 endif()
 
 if(USE_OPENSSL OR USE_WOLFSSL)
@@ -1009,13 +1089,13 @@
   endif()
 endif()
 
-option(USE_HTTPSRR "Enable HTTPS RR support for ECH (experimental)" OFF)
+option(USE_HTTPSRR "Enable HTTPS RR support" OFF)
 option(USE_ECH "Enable ECH support" OFF)
 if(USE_ECH)
   if(USE_OPENSSL OR USE_WOLFSSL)
     # Be sure that the TLS library actually supports ECH.
     if(NOT DEFINED HAVE_ECH)
-      if(USE_OPENSSL AND HAVE_BORINGSSL)
+      if(USE_OPENSSL AND (HAVE_BORINGSSL OR HAVE_AWSLC))
         openssl_check_symbol_exists("SSL_set1_ech_config_list" "openssl/ssl.h" HAVE_ECH "")
       elseif(USE_OPENSSL)
         openssl_check_symbol_exists("SSL_ech_set1_echconfig" "openssl/ech.h" HAVE_ECH "")
@@ -1024,12 +1104,12 @@
       endif()
     endif()
     if(NOT HAVE_ECH)
-      message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/wolfSSL")
+      message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/AWS-LC/wolfSSL")
     else()
       message(STATUS "ECH enabled.")
     endif()
   else()
-    message(FATAL_ERROR "ECH requires ECH-enablded OpenSSL, BoringSSL or wolfSSL")
+    message(FATAL_ERROR "ECH requires ECH-enablded OpenSSL, BoringSSL, AWS-LC or wolfSSL")
   endif()
 endif()
 
@@ -1037,7 +1117,7 @@
 if(USE_NGHTTP2)
   find_package(NGHTTP2)
   if(NGHTTP2_FOUND)
-    include_directories(${NGHTTP2_INCLUDE_DIRS})
+    include_directories(SYSTEM ${NGHTTP2_INCLUDE_DIRS})
     list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES})
     list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libnghttp2")
   else()
@@ -1065,14 +1145,13 @@
   else()
     message(FATAL_ERROR "ngtcp2 requires OpenSSL, wolfSSL or GnuTLS")
   endif()
-  set(USE_NGTCP2 ON)
-  include_directories(${NGTCP2_INCLUDE_DIRS})
+  include_directories(SYSTEM ${NGTCP2_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${NGTCP2_LIBRARIES})
   list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2")
 
   find_package(NGHTTP3 REQUIRED)
   set(USE_NGHTTP3 ON)
-  include_directories(${NGHTTP3_INCLUDE_DIRS})
+  include_directories(SYSTEM ${NGHTTP3_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${NGHTTP3_LIBRARIES})
   list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libnghttp3")
 endif()
@@ -1080,17 +1159,21 @@
 option(USE_QUICHE "Use quiche library for HTTP/3 support" OFF)
 if(USE_QUICHE)
   if(USE_NGTCP2)
-    message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
+    message(FATAL_ERROR "Only one HTTP/3 backend can be selected")
   endif()
   find_package(Quiche REQUIRED)
   if(NOT HAVE_BORINGSSL)
     message(FATAL_ERROR "quiche requires BoringSSL")
   endif()
   openssl_check_quic()
-  set(USE_QUICHE ON)
-  include_directories(${QUICHE_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${QUICHE_LIBRARIES})
+  list(APPEND CURL_LIBDIRS ${QUICHE_LIBRARY_DIRS})
   list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "quiche")
+  include_directories(SYSTEM ${QUICHE_INCLUDE_DIRS})
+  link_directories(${QUICHE_LIBRARY_DIRS})
+  if(QUICHE_CFLAGS)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${QUICHE_CFLAGS}")
+  endif()
   if(NOT DEFINED HAVE_QUICHE_CONN_SET_QLOG_FD)
     cmake_push_check_state()
     set(CMAKE_REQUIRED_INCLUDES   "${QUICHE_INCLUDE_DIRS}")
@@ -1100,27 +1183,37 @@
   endif()
 endif()
 
-option(USE_MSH3 "Use msquic library for HTTP/3 support" OFF)
+option(USE_MSH3 "Use msh3/msquic library for HTTP/3 support" OFF)
 if(USE_MSH3)
   if(USE_NGTCP2 OR USE_QUICHE)
-    message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
+    message(FATAL_ERROR "Only one HTTP/3 backend can be selected")
+  endif()
+  if(NOT WIN32)
+    if(NOT USE_OPENSSL)
+      message(FATAL_ERROR "msh3/msquic requires OpenSSL fork with QUIC API")
+    endif()
+    openssl_check_quic()
   endif()
   find_package(MSH3 REQUIRED)
-  set(USE_MSH3 ON)
-  include_directories(${MSH3_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${MSH3_LIBRARIES})
-  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libmsh3")
+  list(APPEND CURL_LIBDIRS ${MSH3_LIBRARY_DIRS})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE ${MSH3_PC_REQUIRES})
+  include_directories(SYSTEM ${MSH3_INCLUDE_DIRS})
+  link_directories(${MSH3_LIBRARY_DIRS})
+  if(MSH3_CFLAGS)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MSH3_CFLAGS}")
+  endif()
 endif()
 
 if(USE_OPENSSL_QUIC)
   if(USE_NGTCP2 OR USE_QUICHE OR USE_MSH3)
-    message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
+    message(FATAL_ERROR "Only one HTTP/3 backend can be selected")
   endif()
   find_package(OpenSSL 3.3.0 REQUIRED)
 
   find_package(NGHTTP3 REQUIRED)
   set(USE_NGHTTP3 ON)
-  include_directories(${NGHTTP3_INCLUDE_DIRS})
+  include_directories(SYSTEM ${NGHTTP3_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${NGHTTP3_LIBRARIES})
   list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libnghttp3")
 endif()
@@ -1144,83 +1237,65 @@
     endif()
   endif()
 
-  set(CMAKE_LDAP_LIB "ldap" CACHE STRING "Name or full path to ldap library")
-  set(CMAKE_LBER_LIB "lber" CACHE STRING "Name or full path to lber library")
-
   # Now that we know, we are not using Windows LDAP...
   if(NOT USE_WIN32_LDAP)
-    # Check for LDAP
-    set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
-    check_library_exists("${CMAKE_LDAP_LIB}" "ldap_init" "" HAVE_LIBLDAP)
-    if(HAVE_LIBLDAP)
-      check_library_exists("${CMAKE_LDAP_LIB};${CMAKE_LBER_LIB}" "ber_init" "" HAVE_LIBLBER)
-    else()
-      check_library_exists("${CMAKE_LBER_LIB}" "ber_init" "" HAVE_LIBLBER)
+    if(NOT DEFINED LDAP_LIBRARY)
+      set(LDAP_LIBRARY "ldap" CACHE STRING "Name or full path to ldap library")
+    endif()
+    if(NOT DEFINED LDAP_LBER_LIBRARY)
+      set(LDAP_LBER_LIBRARY "lber" CACHE STRING "Name or full path to lber library")
+    endif()
+    if(NOT DEFINED LDAP_INCLUDE_DIR)
+      set(LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory")
     endif()
 
-    set(CMAKE_REQUIRED_INCLUDES_BAK ${CMAKE_REQUIRED_INCLUDES})
-    set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory")
-    if(CMAKE_LDAP_INCLUDE_DIR)
-      list(APPEND CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR})
+    # Check for LDAP
+    cmake_push_check_state()
+    if(USE_OPENSSL)
+      set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
     endif()
-    check_include_file_concat("ldap.h" HAVE_LDAP_H)
-    check_include_file_concat("lber.h" HAVE_LBER_H)
+    check_library_exists("${LDAP_LIBRARY}" "ldap_init" "" HAVE_LIBLDAP)
+    if(HAVE_LIBLDAP)
+      check_library_exists("${LDAP_LIBRARY};${LDAP_LBER_LIBRARY}" "ber_init" "" HAVE_LIBLBER)
+    else()
+      check_library_exists("${LDAP_LBER_LIBRARY}" "ber_init" "" HAVE_LIBLBER)
+    endif()
+
+    if(LDAP_INCLUDE_DIR)
+      list(APPEND CMAKE_REQUIRED_INCLUDES ${LDAP_INCLUDE_DIR})
+    endif()
+
+    unset(_include_list)
+    check_include_file("lber.h" HAVE_LBER_H)
+    if(HAVE_LBER_H)
+      list(APPEND _include_list "lber.h")
+    endif()
+    check_include_files("${_include_list};ldap.h" HAVE_LDAP_H)
+    unset(_include_list)
 
     if(NOT HAVE_LDAP_H)
       message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON")
       set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
-      set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK})  # LDAP includes will not be used
     elseif(NOT HAVE_LIBLDAP)
-      message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON")
+      message(STATUS "LDAP library '${LDAP_LIBRARY}' not found CURL_DISABLE_LDAP set ON")
       set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
-      set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK})  # LDAP includes will not be used
     else()
-      if(CMAKE_LDAP_INCLUDE_DIR)
-        include_directories(${CMAKE_LDAP_INCLUDE_DIR})
+      if(LDAP_INCLUDE_DIR)
+        include_directories(SYSTEM ${LDAP_INCLUDE_DIR})
       endif()
-      set(NEED_LBER_H ON)
-      unset(_header_list)
-      if(WIN32)
-        list(APPEND _header_list "windows.h")
-      endif()
-      if(HAVE_SYS_TYPES_H)
-        list(APPEND _header_list "sys/types.h")
-      endif()
-      list(APPEND _header_list "ldap.h")
-
-      set(_include_string "")
-      foreach(_header IN LISTS _header_list)
-        set(_include_string "${_include_string}#include <${_header}>\n")
-      endforeach()
-
       list(APPEND CMAKE_REQUIRED_DEFINITIONS "-DLDAP_DEPRECATED=1")
-      list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB})
-      set(CURL_LIBS "${CMAKE_LDAP_LIB};${CURL_LIBS}")
+      list(APPEND CMAKE_REQUIRED_LIBRARIES ${LDAP_LIBRARY})
+      set(CURL_LIBS "${LDAP_LIBRARY};${CURL_LIBS}")
+      # FIXME: uncomment once pkg-config-based detection landed: https://github.com/curl/curl/pull/15273
+      # set(LIBCURL_PC_REQUIRES_PRIVATE "${LDAP_PC_REQUIRES};${LIBCURL_PC_REQUIRES_PRIVATE}")
       if(HAVE_LIBLBER)
-        list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB})
-        set(CURL_LIBS "${CMAKE_LBER_LIB};${CURL_LIBS}")
-      endif()
-
-      check_c_source_compiles("
-        ${_include_string}
-        int main(int argc, char ** argv)
-        {
-          BerValue *bvp = NULL;
-          BerElement *bep = ber_init(bvp);
-          ber_free(bep, 1);
-          return 0;
-        }" NOT_NEED_LBER_H)
-      if(NOT_NEED_LBER_H)
-        set(NEED_LBER_H OFF)
-      else()
-        set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H")
+        list(APPEND CMAKE_REQUIRED_LIBRARIES ${LDAP_LBER_LIBRARY})
+        set(CURL_LIBS "${LDAP_LBER_LIBRARY};${CURL_LIBS}")
       endif()
 
       check_function_exists("ldap_url_parse" HAVE_LDAP_URL_PARSE)
       check_function_exists("ldap_init_fd" HAVE_LDAP_INIT_FD)
 
-      unset(CMAKE_REQUIRED_LIBRARIES)
-
       check_include_file("ldap_ssl.h" HAVE_LDAP_SSL_H)
 
       if(HAVE_LDAP_INIT_FD)
@@ -1231,6 +1306,7 @@
         set(HAVE_LDAP_SSL ON)
       endif()
     endif()
+    cmake_pop_check_state()
   endif()
 endif()
 
@@ -1278,7 +1354,7 @@
     set(CURL_LIBS "${LIBIDN2_LIBRARIES};${CURL_LIBS}")
     list(APPEND CURL_LIBDIRS ${LIBIDN2_LIBRARY_DIRS})
     set(LIBCURL_PC_REQUIRES_PRIVATE "libidn2;${LIBCURL_PC_REQUIRES_PRIVATE}")
-    include_directories(${LIBIDN2_INCLUDE_DIRS})
+    include_directories(SYSTEM ${LIBIDN2_INCLUDE_DIRS})
     link_directories(${LIBIDN2_LIBRARY_DIRS})
     if(LIBIDN2_CFLAGS)
       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBIDN2_CFLAGS}")
@@ -1298,8 +1374,7 @@
   if(LIBPSL_FOUND)
     list(APPEND CURL_LIBS ${LIBPSL_LIBRARIES})
     list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libpsl")
-    list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBPSL_INCLUDE_DIRS}")
-    include_directories(${LIBPSL_INCLUDE_DIRS})
+    include_directories(SYSTEM ${LIBPSL_INCLUDE_DIRS})
     set(USE_LIBPSL ON)
   else()
     message(WARNING "libpsl is enabled, but not found.")
@@ -1307,7 +1382,7 @@
 endif()
 
 # libssh2
-option(CURL_USE_LIBSSH2 "Use libssh2" ON)  # FIXME: default is OFF in autotools
+option(CURL_USE_LIBSSH2 "Use libssh2" ON)
 mark_as_advanced(CURL_USE_LIBSSH2)
 set(USE_LIBSSH2 OFF)
 
@@ -1316,8 +1391,7 @@
   if(LIBSSH2_FOUND)
     list(APPEND CURL_LIBS ${LIBSSH2_LIBRARIES})
     list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libssh2")
-    list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIRS}")
-    include_directories(${LIBSSH2_INCLUDE_DIRS})
+    include_directories(SYSTEM ${LIBSSH2_INCLUDE_DIRS})
     set(USE_LIBSSH2 ON)
   endif()
 endif()
@@ -1331,7 +1405,7 @@
     list(APPEND CURL_LIBS ${LIBSSH_LIBRARIES})
     list(APPEND CURL_LIBDIRS ${LIBSSH_LIBRARY_DIRS})
     list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libssh")
-    include_directories(${LIBSSH_INCLUDE_DIRS})
+    include_directories(SYSTEM ${LIBSSH_INCLUDE_DIRS})
     link_directories(${LIBSSH_LIBRARY_DIRS})
     if(LIBSSH_CFLAGS)
       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBSSH_CFLAGS}")
@@ -1349,8 +1423,7 @@
     find_package(WolfSSH)
     if(WOLFSSH_FOUND)
       list(APPEND CURL_LIBS ${WOLFSSH_LIBRARIES})
-      list(APPEND CMAKE_REQUIRED_INCLUDES "${WOLFSSH_INCLUDE_DIRS}")
-      include_directories(${WOLFSSH_INCLUDE_DIRS})
+      include_directories(SYSTEM ${WOLFSSH_INCLUDE_DIRS})
       set(USE_WOLFSSH ON)
     endif()
   else()
@@ -1366,7 +1439,7 @@
     list(APPEND CURL_LIBS ${LIBGSASL_LIBRARIES})
     list(APPEND CURL_LIBDIRS ${LIBGSASL_LIBRARY_DIRS})
     list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libgsasl")
-    include_directories(${LIBGSASL_INCLUDE_DIRS})
+    include_directories(SYSTEM ${LIBGSASL_INCLUDE_DIRS})
     link_directories(${LIBGSASL_LIBRARY_DIRS})
     if(LIBGSASL_CFLAGS)
       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBGSASL_CFLAGS}")
@@ -1383,55 +1456,52 @@
 
   set(HAVE_GSSAPI ${GSS_FOUND})
   if(GSS_FOUND)
-    list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIRS})
+    if(GSS_FLAVOUR STREQUAL "GNU")
+      set(HAVE_GSSGNU 1)
+    else()
+      cmake_push_check_state()
+      list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIRS})
 
-    string(REPLACE ";" " " GSS_CFLAGS "${GSS_CFLAGS}")
-    string(REPLACE ";" " " GSS_LDFLAGS "${GSS_LDFLAGS}")
-
-    foreach(_dir IN LISTS GSS_LIBRARY_DIRS)
-      set(GSS_LDFLAGS "${GSS_LDFLAGS} -L\"${_dir}\"")
-    endforeach()
-
-    check_include_file_concat("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H)
-    check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H)
-    check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H)
-
-    if(GSS_FLAVOUR STREQUAL "MIT")
       set(_include_list "")
+      check_include_file("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H)
       if(HAVE_GSSAPI_GSSAPI_H)
         list(APPEND _include_list "gssapi/gssapi.h")
       endif()
-      if(HAVE_GSSAPI_GSSAPI_GENERIC_H)
-        list(APPEND _include_list "gssapi/gssapi_generic.h")
-      endif()
-      if(HAVE_GSSAPI_GSSAPI_KRB5_H)
-        list(APPEND _include_list "gssapi/gssapi_krb5.h")
-      endif()
+      check_include_files("${_include_list};gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H)
 
-      if(NOT DEFINED HAVE_GSS_C_NT_HOSTBASED_SERVICE)
-        set(CMAKE_REQUIRED_FLAGS "${GSS_CFLAGS} ${GSS_LDFLAGS}")
-        set(CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES})
-        check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" ${_include_list} HAVE_GSS_C_NT_HOSTBASED_SERVICE)
-        unset(CMAKE_REQUIRED_LIBRARIES)
+      if(GSS_FLAVOUR STREQUAL "MIT")
+        check_include_files("${_include_list};gssapi/gssapi_krb5.h" _have_gssapi_gssapi_krb5_h)
+        if(HAVE_GSSAPI_GSSAPI_GENERIC_H)
+          list(APPEND _include_list "gssapi/gssapi_generic.h")
+        endif()
+        if(_have_gssapi_gssapi_krb5_h)
+          list(APPEND _include_list "gssapi/gssapi_krb5.h")
+        endif()
+
+        if(NOT DEFINED HAVE_GSS_C_NT_HOSTBASED_SERVICE)
+          set(CMAKE_REQUIRED_FLAGS ${GSS_CFLAGS})
+          set(CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES})
+          curl_required_libpaths("${GSS_LIBRARY_DIRS}")
+          check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" "${_include_list}" HAVE_GSS_C_NT_HOSTBASED_SERVICE)
+        endif()
+        if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE)
+          set(HAVE_OLD_GSSMIT ON)
+        endif()
       endif()
-      if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE)
-        set(HAVE_OLD_GSSMIT ON)
-      endif()
+      unset(_include_list)
+      cmake_pop_check_state()
     endif()
 
-    include_directories(${GSS_INCLUDE_DIRS})
-    link_directories(${GSS_LIBRARY_DIRS})
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_CFLAGS}")
-    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LDFLAGS}")
-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LDFLAGS}")
     list(APPEND CURL_LIBS ${GSS_LIBRARIES})
-    if(GSS_FLAVOUR STREQUAL "MIT")
-      list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "mit-krb5-gssapi")
-    else()  # Heimdal
-      list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "heimdal-gssapi")
+    list(APPEND CURL_LIBDIRS ${GSS_LIBRARY_DIRS})
+    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE ${GSS_PC_REQUIRES})
+    include_directories(SYSTEM ${GSS_INCLUDE_DIRS})
+    link_directories(${GSS_LIBRARY_DIRS})
+    if(GSS_CFLAGS)
+      set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_CFLAGS}")
     endif()
   else()
-    message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.")
+    message(WARNING "GSSAPI has been requested, but no supporting libraries found. Skipping.")
   endif()
 endif()
 
@@ -1446,7 +1516,7 @@
     list(APPEND CURL_LIBS ${LIBUV_LIBRARIES})
     list(APPEND CURL_LIBDIRS ${LIBUV_LIBRARY_DIRS})
     list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libuv")
-    include_directories(${LIBUV_INCLUDE_DIRS})
+    include_directories(SYSTEM ${LIBUV_INCLUDE_DIRS})
     link_directories(${LIBUV_LIBRARY_DIRS})
     if(LIBUV_CFLAGS)
       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBUV_CFLAGS}")
@@ -1458,13 +1528,11 @@
 
 option(USE_LIBRTMP "Enable librtmp from rtmpdump" OFF)
 if(USE_LIBRTMP)
-  cmake_push_check_state()
   set(_extra_libs "rtmp")
   if(WIN32)
     list(APPEND _extra_libs "winmm")
   endif()
   openssl_check_symbol_exists("RTMP_Init" "librtmp/rtmp.h" HAVE_LIBRTMP "${_extra_libs}")
-  cmake_pop_check_state()
   if(HAVE_LIBRTMP)
     list(APPEND CURL_LIBS "rtmp")
     list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "librtmp")
@@ -1472,7 +1540,7 @@
       list(APPEND CURL_LIBS "winmm")
     endif()
   else()
-    message(WARNING "librtmp requested, but not found or missing OpenSSL. Skipping.")
+    message(WARNING "librtmp has been requested, but not found or missing OpenSSL. Skipping.")
     set(USE_LIBRTMP OFF)
   endif()
 endif()
@@ -1497,11 +1565,11 @@
   set(CURL_CA_BUNDLE "auto" CACHE
     STRING "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
   set(CURL_CA_FALLBACK OFF CACHE BOOL
-    "Set ON to use built-in CA store of TLS backend. Defaults to OFF")
+    "Use built-in CA store of TLS backend. Defaults to OFF")
   set(CURL_CA_PATH "auto" CACHE
     STRING "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
   set(CURL_CA_EMBED "" CACHE
-    STRING "Path to the CA bundle to embed into the curl tool.")
+    STRING "Path to the CA bundle to embed in the curl tool.")
 
   if(CURL_CA_BUNDLE STREQUAL "")
     message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.")
@@ -1572,6 +1640,7 @@
   if(BUILD_CURL_EXE AND NOT CURL_CA_EMBED STREQUAL "")
     if(EXISTS "${CURL_CA_EMBED}")
       set(CURL_CA_EMBED_SET TRUE)
+      message(STATUS "Found CA bundle to embed: ${CURL_CA_EMBED}")
     else()
       message(FATAL_ERROR "CA bundle to embed is missing: '${CURL_CA_EMBED}'")
     endif()
@@ -1579,11 +1648,15 @@
 endif()
 endif()
 
+if(WIN32)
+  option(CURL_DISABLE_CA_SEARCH "Disable unsafe CA bundle search in PATH on Windows" OFF)
+  option(CURL_CA_SEARCH_SAFE "Enable safe CA bundle search (within the curl tool directory) on Windows" OFF)
+endif()
+
 # Check for header files
 if(WIN32)
-  set(CURL_INCLUDES ${CURL_INCLUDES} "winsock2.h")
-  set(CURL_INCLUDES ${CURL_INCLUDES} "ws2tcpip.h")
-  set(CURL_INCLUDES ${CURL_INCLUDES} "windows.h")
+  list(APPEND CURL_INCLUDES "winsock2.h")
+  list(APPEND CURL_INCLUDES "ws2tcpip.h")
 
   if(HAVE_WIN32_WINNT)
     if(HAVE_WIN32_WINNT LESS 0x0501)
@@ -1606,46 +1679,72 @@
   endif()
 endif()
 
-check_include_file_concat("sys/eventfd.h"    HAVE_SYS_EVENTFD_H)
-check_include_file_concat("sys/filio.h"      HAVE_SYS_FILIO_H)
-check_include_file_concat("sys/wait.h"       HAVE_SYS_WAIT_H)
-check_include_file_concat("sys/ioctl.h"      HAVE_SYS_IOCTL_H)
-check_include_file_concat("sys/param.h"      HAVE_SYS_PARAM_H)
-check_include_file_concat("sys/poll.h"       HAVE_SYS_POLL_H)
-check_include_file_concat("sys/resource.h"   HAVE_SYS_RESOURCE_H)
+# Detect headers
+
+# Use check_include_file_concat() for headers required by subsequent
+# check_include_file_concat() or check_symbol_exists() detections.
+# Order for these is significant.
+check_include_file("sys/eventfd.h"    HAVE_SYS_EVENTFD_H)
+check_include_file("sys/filio.h"      HAVE_SYS_FILIO_H)
+check_include_file("sys/wait.h"       HAVE_SYS_WAIT_H)
+check_include_file("sys/ioctl.h"      HAVE_SYS_IOCTL_H)
+check_include_file("sys/param.h"      HAVE_SYS_PARAM_H)
+check_include_file("sys/poll.h"       HAVE_SYS_POLL_H)
+check_include_file("sys/resource.h"   HAVE_SYS_RESOURCE_H)
 check_include_file_concat("sys/select.h"     HAVE_SYS_SELECT_H)
 check_include_file_concat("sys/socket.h"     HAVE_SYS_SOCKET_H)
-check_include_file_concat("sys/sockio.h"     HAVE_SYS_SOCKIO_H)
-check_include_file_concat("sys/stat.h"       HAVE_SYS_STAT_H)
+check_include_file("sys/sockio.h"     HAVE_SYS_SOCKIO_H)
+check_include_file("sys/stat.h"       HAVE_SYS_STAT_H)
 check_include_file_concat("sys/time.h"       HAVE_SYS_TIME_H)
 check_include_file_concat("sys/types.h"      HAVE_SYS_TYPES_H)
-check_include_file_concat("sys/un.h"         HAVE_SYS_UN_H)
-check_include_file_concat("sys/utime.h"      HAVE_SYS_UTIME_H)
-check_include_file_concat("sys/xattr.h"      HAVE_SYS_XATTR_H)
+check_include_file("sys/un.h"         HAVE_SYS_UN_H)
+check_include_file("sys/utime.h"      HAVE_SYS_UTIME_H)
+check_include_file("sys/xattr.h"      HAVE_SYS_XATTR_H)
+
 check_include_file_concat("arpa/inet.h"      HAVE_ARPA_INET_H)
-check_include_file_concat("dirent.h"         HAVE_DIRENT_H)
-check_include_file_concat("fcntl.h"          HAVE_FCNTL_H)
+check_include_file("dirent.h"         HAVE_DIRENT_H)
+check_include_file("fcntl.h"          HAVE_FCNTL_H)
 check_include_file_concat("ifaddrs.h"        HAVE_IFADDRS_H)
-check_include_file_concat("io.h"             HAVE_IO_H)
+check_include_file("io.h"             HAVE_IO_H)
 check_include_file_concat("libgen.h"         HAVE_LIBGEN_H)
-check_include_file_concat("locale.h"         HAVE_LOCALE_H)
-check_include_file_concat("net/if.h"         HAVE_NET_IF_H)
+check_include_file("linux/tcp.h"      HAVE_LINUX_TCP_H)
+check_include_file("locale.h"         HAVE_LOCALE_H)
+check_include_file("net/if.h"         HAVE_NET_IF_H)
 check_include_file_concat("netdb.h"          HAVE_NETDB_H)
 check_include_file_concat("netinet/in.h"     HAVE_NETINET_IN_H)
-check_include_file_concat("netinet/tcp.h"    HAVE_NETINET_TCP_H)
-check_include_file_concat("netinet/udp.h"    HAVE_NETINET_UDP_H)
-check_include_file("linux/tcp.h"      HAVE_LINUX_TCP_H)
-
-check_include_file_concat("poll.h"           HAVE_POLL_H)
-check_include_file_concat("pwd.h"            HAVE_PWD_H)
-check_include_file_concat("stdatomic.h"      HAVE_STDATOMIC_H)
-check_include_file_concat("stdbool.h"        HAVE_STDBOOL_H)
-check_include_file_concat("strings.h"        HAVE_STRINGS_H)
-check_include_file_concat("stropts.h"        HAVE_STROPTS_H)
-check_include_file_concat("termio.h"         HAVE_TERMIO_H)
-check_include_file_concat("termios.h"        HAVE_TERMIOS_H)
+check_include_file("netinet/in6.h"    HAVE_NETINET_IN6_H)
+check_include_file_concat("netinet/tcp.h"    HAVE_NETINET_TCP_H)  # sys/types.h (e.g. Cygwin) netinet/in.h
+check_include_file_concat("netinet/udp.h"    HAVE_NETINET_UDP_H)  # sys/types.h (e.g. Cygwin)
+check_include_file("poll.h"           HAVE_POLL_H)
+check_include_file("pwd.h"            HAVE_PWD_H)
+check_include_file("stdatomic.h"      HAVE_STDATOMIC_H)
+check_include_file("stdbool.h"        HAVE_STDBOOL_H)
+check_include_file("strings.h"        HAVE_STRINGS_H)
+check_include_file("stropts.h"        HAVE_STROPTS_H)
+check_include_file("termio.h"         HAVE_TERMIO_H)
+check_include_file("termios.h"        HAVE_TERMIOS_H)
 check_include_file_concat("unistd.h"         HAVE_UNISTD_H)
-check_include_file_concat("utime.h"          HAVE_UTIME_H)
+check_include_file("utime.h"          HAVE_UTIME_H)
+
+if(CMAKE_SYSTEM_NAME MATCHES "AmigaOS")
+  check_include_file_concat("proto/bsdsocket.h" HAVE_PROTO_BSDSOCKET_H)
+endif()
+
+# Pass these detection results to curl_internal_test() for use in CurlTests.c
+# Add here all feature flags referenced from CurlTests.c
+foreach(_variable IN ITEMS
+    HAVE_STDATOMIC_H
+    HAVE_STDBOOL_H
+    HAVE_STROPTS_H
+    HAVE_SYS_IOCTL_H
+    HAVE_SYS_SOCKET_H
+    HAVE_SYS_TYPES_H
+    HAVE_UNISTD_H
+    )
+  if(${_variable})
+    set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D${_variable}")
+  endif()
+endforeach()
 
 check_type_size("size_t"      SIZEOF_SIZE_T)
 check_type_size("ssize_t"     SIZEOF_SSIZE_T)
@@ -1658,96 +1757,109 @@
 
 # Check for some functions that are used
 if(WIN32)
-  set(CMAKE_REQUIRED_LIBRARIES "ws2_32")
+  list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32")  # Apply to all feature checks
 elseif(HAVE_LIBSOCKET)
-  set(CMAKE_REQUIRED_LIBRARIES "socket")
+  list(APPEND CMAKE_REQUIRED_LIBRARIES "socket")  # Apply to all feature checks
 elseif(HAVE_LIBNETWORK)
-  set(CMAKE_REQUIRED_LIBRARIES "network")
+  list(APPEND CMAKE_REQUIRED_LIBRARIES "network")  # Apply to all feature checks
 endif()
 
-check_symbol_exists("fnmatch"         "${CURL_INCLUDES};fnmatch.h" HAVE_FNMATCH)
-check_symbol_exists("basename"        "${CURL_INCLUDES};string.h" HAVE_BASENAME)
-check_symbol_exists("opendir"         "${CURL_INCLUDES};dirent.h" HAVE_OPENDIR)
-check_symbol_exists("socket"          "${CURL_INCLUDES}" HAVE_SOCKET)
-check_symbol_exists("sched_yield"     "${CURL_INCLUDES};sched.h" HAVE_SCHED_YIELD)
-check_symbol_exists("socketpair"      "${CURL_INCLUDES}" HAVE_SOCKETPAIR)
-check_symbol_exists("recv"            "${CURL_INCLUDES}" HAVE_RECV)
-check_symbol_exists("send"            "${CURL_INCLUDES}" HAVE_SEND)
-check_symbol_exists("sendmsg"         "${CURL_INCLUDES}" HAVE_SENDMSG)
-check_symbol_exists("select"          "${CURL_INCLUDES}" HAVE_SELECT)
-check_symbol_exists("strdup"          "${CURL_INCLUDES};string.h" HAVE_STRDUP)
-check_symbol_exists("strtok_r"        "${CURL_INCLUDES};string.h" HAVE_STRTOK_R)
-check_symbol_exists("strcasecmp"      "${CURL_INCLUDES};string.h" HAVE_STRCASECMP)
-check_symbol_exists("stricmp"         "${CURL_INCLUDES};string.h" HAVE_STRICMP)
-check_symbol_exists("strcmpi"         "${CURL_INCLUDES};string.h" HAVE_STRCMPI)
-check_symbol_exists("memrchr"         "${CURL_INCLUDES};string.h" HAVE_MEMRCHR)
-check_symbol_exists("alarm"           "${CURL_INCLUDES}" HAVE_ALARM)
-check_symbol_exists("arc4random"      "${CURL_INCLUDES};stdlib.h" HAVE_ARC4RANDOM)
-check_symbol_exists("fcntl"           "${CURL_INCLUDES}" HAVE_FCNTL)
-check_symbol_exists("getppid"         "${CURL_INCLUDES}" HAVE_GETPPID)
-check_symbol_exists("utimes"          "${CURL_INCLUDES}" HAVE_UTIMES)
+check_function_exists("fnmatch"       HAVE_FNMATCH)
+check_symbol_exists("basename"        "${CURL_INCLUDES};string.h" HAVE_BASENAME)  # libgen.h unistd.h
+check_symbol_exists("opendir"         "dirent.h" HAVE_OPENDIR)
+check_function_exists("poll"          HAVE_POLL)  # poll.h
+check_symbol_exists("socket"          "${CURL_INCLUDES}" HAVE_SOCKET)  # winsock2.h sys/socket.h
+check_function_exists("sched_yield"   HAVE_SCHED_YIELD)
+check_symbol_exists("socketpair"      "${CURL_INCLUDES}" HAVE_SOCKETPAIR)  # sys/socket.h
+check_symbol_exists("recv"            "${CURL_INCLUDES}" HAVE_RECV)  # proto/bsdsocket.h sys/types.h sys/socket.h
+check_symbol_exists("send"            "${CURL_INCLUDES}" HAVE_SEND)  # proto/bsdsocket.h sys/types.h sys/socket.h
+check_function_exists("sendmsg"       HAVE_SENDMSG)
+check_function_exists("sendmmsg"      HAVE_SENDMMSG)
+check_symbol_exists("select"          "${CURL_INCLUDES}" HAVE_SELECT)  # proto/bsdsocket.h sys/select.h sys/socket.h
+check_symbol_exists("strdup"          "string.h" HAVE_STRDUP)
+check_symbol_exists("strtok_r"        "string.h" HAVE_STRTOK_R)
+check_symbol_exists("strcasecmp"      "string.h" HAVE_STRCASECMP)
+check_symbol_exists("stricmp"         "string.h" HAVE_STRICMP)
+check_symbol_exists("strcmpi"         "string.h" HAVE_STRCMPI)
+check_symbol_exists("memrchr"         "string.h" HAVE_MEMRCHR)
+check_symbol_exists("alarm"           "unistd.h" HAVE_ALARM)
+check_symbol_exists("fcntl"           "fcntl.h" HAVE_FCNTL)
+check_function_exists("getppid"       HAVE_GETPPID)
+check_function_exists("utimes"        HAVE_UTIMES)
 
-check_symbol_exists("gettimeofday"    "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY)
-check_symbol_exists("closesocket"     "${CURL_INCLUDES}" HAVE_CLOSESOCKET)
-check_symbol_exists("sigsetjmp"       "${CURL_INCLUDES};setjmp.h" HAVE_SIGSETJMP)
-check_symbol_exists("getpass_r"       "${CURL_INCLUDES}" HAVE_GETPASS_R)
-check_symbol_exists("getpwuid"        "${CURL_INCLUDES}" HAVE_GETPWUID)
-check_symbol_exists("getpwuid_r"      "${CURL_INCLUDES}" HAVE_GETPWUID_R)
-check_symbol_exists("geteuid"         "${CURL_INCLUDES}" HAVE_GETEUID)
-check_symbol_exists("utime"           "${CURL_INCLUDES}" HAVE_UTIME)
-check_symbol_exists("gmtime_r"        "${CURL_INCLUDES};stdlib.h;time.h" HAVE_GMTIME_R)
+check_function_exists("gettimeofday"  HAVE_GETTIMEOFDAY)  # sys/time.h
+check_symbol_exists("closesocket"     "${CURL_INCLUDES}" HAVE_CLOSESOCKET)  # winsock2.h
+check_symbol_exists("sigsetjmp"       "setjmp.h" HAVE_SIGSETJMP)
+check_function_exists("getpass_r"     HAVE_GETPASS_R)
+check_function_exists("getpwuid"      HAVE_GETPWUID)
+check_function_exists("getpwuid_r"    HAVE_GETPWUID_R)
+check_function_exists("geteuid"       HAVE_GETEUID)
+check_function_exists("utime"         HAVE_UTIME)
+check_symbol_exists("gmtime_r"        "stdlib.h;time.h" HAVE_GMTIME_R)
 
-check_symbol_exists("gethostbyname_r" "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R)
+check_symbol_exists("gethostbyname_r" "netdb.h" HAVE_GETHOSTBYNAME_R)
 
-check_symbol_exists("signal"          "${CURL_INCLUDES};signal.h" HAVE_SIGNAL)
-check_symbol_exists("strtoll"         "${CURL_INCLUDES};stdlib.h" HAVE_STRTOLL)
-check_symbol_exists("strerror_r"      "${CURL_INCLUDES};stdlib.h;string.h" HAVE_STRERROR_R)
+check_symbol_exists("signal"          "signal.h" HAVE_SIGNAL)
+check_symbol_exists("strtoll"         "stdlib.h" HAVE_STRTOLL)
+check_symbol_exists("strerror_r"      "stdlib.h;string.h" HAVE_STRERROR_R)
 check_symbol_exists("sigaction"       "signal.h" HAVE_SIGACTION)
-check_symbol_exists("siginterrupt"    "${CURL_INCLUDES};signal.h" HAVE_SIGINTERRUPT)
-check_symbol_exists("getaddrinfo"     "${CURL_INCLUDES};stdlib.h;string.h" HAVE_GETADDRINFO)
-check_symbol_exists("getifaddrs"      "${CURL_INCLUDES};stdlib.h" HAVE_GETIFADDRS)
-check_symbol_exists("freeaddrinfo"    "${CURL_INCLUDES}" HAVE_FREEADDRINFO)
-check_symbol_exists("pipe"            "${CURL_INCLUDES}" HAVE_PIPE)
-check_symbol_exists("eventfd"         "${CURL_INCLUDES};sys/eventfd.h" HAVE_EVENTFD)
-check_symbol_exists("ftruncate"       "${CURL_INCLUDES}" HAVE_FTRUNCATE)
-check_symbol_exists("_fseeki64"       "${CURL_INCLUDES};stdio.h" HAVE__FSEEKI64)
-check_symbol_exists("getpeername"     "${CURL_INCLUDES}" HAVE_GETPEERNAME)
-check_symbol_exists("getsockname"     "${CURL_INCLUDES}" HAVE_GETSOCKNAME)
-check_symbol_exists("if_nametoindex"  "${CURL_INCLUDES}" HAVE_IF_NAMETOINDEX)
-check_symbol_exists("getrlimit"       "${CURL_INCLUDES}" HAVE_GETRLIMIT)
-check_symbol_exists("setlocale"       "${CURL_INCLUDES}" HAVE_SETLOCALE)
-check_symbol_exists("setmode"         "${CURL_INCLUDES}" HAVE_SETMODE)
-check_symbol_exists("setrlimit"       "${CURL_INCLUDES}" HAVE_SETRLIMIT)
+check_symbol_exists("siginterrupt"    "signal.h" HAVE_SIGINTERRUPT)
+check_symbol_exists("getaddrinfo"     "${CURL_INCLUDES};stdlib.h;string.h" HAVE_GETADDRINFO)  # ws2tcpip.h sys/socket.h netdb.h
+check_symbol_exists("getifaddrs"      "${CURL_INCLUDES};stdlib.h" HAVE_GETIFADDRS)  # ifaddrs.h
+check_symbol_exists("freeaddrinfo"    "${CURL_INCLUDES}" HAVE_FREEADDRINFO)  # ws2tcpip.h sys/socket.h netdb.h
+check_function_exists("pipe"          HAVE_PIPE)
+check_function_exists("eventfd"       HAVE_EVENTFD)
+check_symbol_exists("ftruncate"       "unistd.h" HAVE_FTRUNCATE)
+check_symbol_exists("getpeername"     "${CURL_INCLUDES}" HAVE_GETPEERNAME)  # winsock2.h unistd.h proto/bsdsocket.h
+check_symbol_exists("getsockname"     "${CURL_INCLUDES}" HAVE_GETSOCKNAME)  # winsock2.h unistd.h proto/bsdsocket.h
+check_function_exists("if_nametoindex"  HAVE_IF_NAMETOINDEX)  # winsock2.h net/if.h
+check_function_exists("getrlimit"       HAVE_GETRLIMIT)
+check_function_exists("setlocale"       HAVE_SETLOCALE)
+check_function_exists("setmode"         HAVE_SETMODE)
+check_function_exists("setrlimit"       HAVE_SETRLIMIT)
+
+if(WIN32 OR CYGWIN)
+  check_function_exists("_setmode" HAVE__SETMODE)
+endif()
+
+if(CMAKE_SYSTEM_NAME MATCHES "AmigaOS")
+  check_symbol_exists("CloseSocket" "${CURL_INCLUDES}" HAVE_CLOSESOCKET_CAMEL)  # sys/socket.h proto/bsdsocket.h
+endif()
+
+if(NOT _ssl_enabled)
+  check_symbol_exists("arc4random" "${CURL_INCLUDES};stdlib.h" HAVE_ARC4RANDOM)
+endif()
 
 if(NOT MSVC OR (MSVC_VERSION GREATER_EQUAL 1900))
   # Earlier MSVC compilers had faulty snprintf implementations
-  check_symbol_exists("snprintf" "stdio.h" HAVE_SNPRINTF)
+  check_function_exists("snprintf" HAVE_SNPRINTF)
 endif()
-check_function_exists("mach_absolute_time" HAVE_MACH_ABSOLUTE_TIME)
-check_symbol_exists("inet_ntop" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_NTOP)
+if(APPLE)
+  check_function_exists("mach_absolute_time" HAVE_MACH_ABSOLUTE_TIME)
+endif()
+check_symbol_exists("inet_ntop" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_NTOP)  # arpa/inet.h
 if(MSVC AND (MSVC_VERSION LESS_EQUAL 1600))
   set(HAVE_INET_NTOP OFF)
 endif()
-check_symbol_exists("inet_pton" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_PTON)
+check_symbol_exists("inet_pton" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_PTON)  # arpa/inet.h
 
-check_symbol_exists("fsetxattr" "${CURL_INCLUDES}" HAVE_FSETXATTR)
+check_symbol_exists("fsetxattr" "sys/xattr.h" HAVE_FSETXATTR)
 if(HAVE_FSETXATTR)
-  foreach(_curl_test IN ITEMS HAVE_FSETXATTR_5 HAVE_FSETXATTR_6)
-    curl_internal_test(${_curl_test})
-  endforeach()
+  curl_internal_test(HAVE_FSETXATTR_5)
+  curl_internal_test(HAVE_FSETXATTR_6)
 endif()
 
-set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
-check_type_size("sa_family_t" SIZEOF_SA_FAMILY_T)
-set(HAVE_SA_FAMILY_T ${HAVE_SIZEOF_SA_FAMILY_T})
-set(CMAKE_EXTRA_INCLUDE_FILES "")
-
+cmake_push_check_state()
 if(WIN32)
   set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
   check_type_size("ADDRESS_FAMILY" SIZEOF_ADDRESS_FAMILY)
   set(HAVE_ADDRESS_FAMILY ${HAVE_SIZEOF_ADDRESS_FAMILY})
-  set(CMAKE_EXTRA_INCLUDE_FILES "")
+elseif(HAVE_SYS_SOCKET_H)
+  set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
+  check_type_size("sa_family_t" SIZEOF_SA_FAMILY_T)
+  set(HAVE_SA_FAMILY_T ${HAVE_SIZEOF_SA_FAMILY_T})
 endif()
+cmake_pop_check_state()
 
 # Do curl specific tests
 foreach(_curl_test IN ITEMS
@@ -1775,9 +1887,10 @@
   curl_internal_test(${_curl_test})
 endforeach()
 
+cmake_push_check_state()
 if(HAVE_FILE_OFFSET_BITS)
   set(_FILE_OFFSET_BITS 64)
-  set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64")
+  set(CMAKE_REQUIRED_DEFINITIONS "-D_FILE_OFFSET_BITS=64")
 endif()
 check_type_size("off_t" SIZEOF_OFF_T)
 
@@ -1791,12 +1904,14 @@
 endif()
 
 # Include this header to get the type
-set(CMAKE_REQUIRED_INCLUDES "${CURL_SOURCE_DIR}/include")
+cmake_push_check_state()
+set(CMAKE_REQUIRED_INCLUDES "${PROJECT_SOURCE_DIR}/include")
 set(CMAKE_EXTRA_INCLUDE_FILES "curl/system.h")
 check_type_size("curl_off_t" SIZEOF_CURL_OFF_T)
 set(CMAKE_EXTRA_INCLUDE_FILES "curl/curl.h")
 check_type_size("curl_socket_t" SIZEOF_CURL_SOCKET_T)
-set(CMAKE_EXTRA_INCLUDE_FILES "")
+cmake_pop_check_state()  # pop curl system headers
+cmake_pop_check_state()  # pop -D_FILE_OFFSET_BITS=64
 
 if(0) # This code not needed for building within CMake.
 if(NOT WIN32 AND NOT CMAKE_CROSSCOMPILING)
@@ -1812,24 +1927,8 @@
 endif()
 endif()
 
-unset(CMAKE_REQUIRED_FLAGS)
-
-option(ENABLE_WEBSOCKETS "Enable WebSockets (experimental)" OFF)
-
-if(ENABLE_WEBSOCKETS)
-  if(SIZEOF_CURL_OFF_T GREATER 4)
-    set(USE_WEBSOCKETS ON)
-  else()
-    message(WARNING "curl_off_t is too small to enable WebSockets")
-  endif()
-endif()
-
-foreach(_curl_test IN ITEMS
-    HAVE_GLIBC_STRERROR_R
-    HAVE_POSIX_STRERROR_R
-    )
-  curl_internal_test(${_curl_test})
-endforeach()
+curl_internal_test(HAVE_GLIBC_STRERROR_R)
+curl_internal_test(HAVE_POSIX_STRERROR_R)
 
 # Check for reentrant
 foreach(_curl_test IN ITEMS
@@ -1856,13 +1955,11 @@
 endif()
 
 if(NOT WIN32)
-  # Check clock_gettime(CLOCK_MONOTONIC, x) support
-  curl_internal_test(HAVE_CLOCK_GETTIME_MONOTONIC)
+  curl_internal_test(HAVE_CLOCK_GETTIME_MONOTONIC)  # Check clock_gettime(CLOCK_MONOTONIC, x) support
 endif()
 
 if(APPLE)
-  # Check compiler support of __builtin_available()
-  curl_internal_test(HAVE_BUILTIN_AVAILABLE)
+  curl_internal_test(HAVE_BUILTIN_AVAILABLE)  # Check compiler support of __builtin_available()
 endif()
 
 # Some other minor tests
@@ -1896,6 +1993,11 @@
   endif()
 endif()
 
+if(_cmake_try_compile_target_type_save)
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_cmake_try_compile_target_type_save})
+  unset(_cmake_try_compile_target_type_save)
+endif()
+
 include(CMake/OtherTests.cmake)
 
 add_definitions("-DHAVE_CONFIG_H")
@@ -1932,7 +2034,7 @@
   endif()
 
   # Use multithreaded compilation on VS 2008+
-  if(MSVC_VERSION GREATER_EQUAL 1500)
+  if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER_EQUAL 1500)
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP")
   endif()
 endif()
@@ -1948,17 +2050,17 @@
 
 if(CURL_LTO)
   if(CMAKE_VERSION VERSION_LESS 3.9)
-    message(FATAL_ERROR "Requested LTO but your cmake version ${CMAKE_VERSION} is to old. You need at least 3.9")
+    message(FATAL_ERROR "LTO has been requested, but your cmake version ${CMAKE_VERSION} is to old. You need at least 3.9")
   endif()
 
   cmake_policy(SET CMP0069 NEW)
 
   include(CheckIPOSupported)
-  check_ipo_supported(RESULT CURL_HAS_LTO OUTPUT CURL_LTO_ERROR LANGUAGES C)
+  check_ipo_supported(RESULT CURL_HAS_LTO OUTPUT _lto_error LANGUAGES C)
   if(CURL_HAS_LTO)
     message(STATUS "LTO supported and enabled")
   else()
-    message(FATAL_ERROR "LTO was requested - but compiler does not support it\n${CURL_LTO_ERROR}")
+    message(FATAL_ERROR "LTO has been requested, but the compiler does not support it\n${_lto_error}")
   endif()
 endif()
 
@@ -1967,8 +2069,8 @@
 # (= regenerate it).
 function(transform_makefile_inc _input_file _output_file)
   file(READ ${_input_file} _makefile_inc_text)
-  string(REPLACE "$(top_srcdir)"   "\${CURL_SOURCE_DIR}" _makefile_inc_text ${_makefile_inc_text})
-  string(REPLACE "$(top_builddir)" "\${CURL_BINARY_DIR}" _makefile_inc_text ${_makefile_inc_text})
+  string(REPLACE "$(top_srcdir)"   "\${PROJECT_SOURCE_DIR}" _makefile_inc_text ${_makefile_inc_text})
+  string(REPLACE "$(top_builddir)" "\${PROJECT_BINARY_DIR}" _makefile_inc_text ${_makefile_inc_text})
 
   string(REGEX REPLACE "\\\\\n" "!π!α!" _makefile_inc_text ${_makefile_inc_text})
   string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "set(\\1 \\2)" _makefile_inc_text ${_makefile_inc_text})
@@ -2001,17 +2103,22 @@
 
 include(GNUInstallDirs)
 
-set(CURL_INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+set(_install_cmake_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
 set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
 set(_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
 set(_project_config "${_generated_dir}/${PROJECT_NAME}Config.cmake")
 set(_version_config "${_generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
 
-cmake_dependent_option(BUILD_TESTING "Build tests"
-  ON "PERL_FOUND;NOT CURL_DISABLE_TESTS"
-  OFF)
+option(BUILD_TESTING "Build tests" ON)
+if(BUILD_TESTING AND PERL_FOUND AND NOT CURL_DISABLE_TESTS)
+  set(CURL_BUILD_TESTING ON)
+else()
+  set(CURL_BUILD_TESTING OFF)
+endif()
 
 if(HAVE_MANUAL_TOOLS)
+  set(CURL_MANPAGE "${PROJECT_BINARY_DIR}/docs/cmdline-opts/curl.1")
+  set(CURL_ASCIIPAGE "${PROJECT_BINARY_DIR}/docs/cmdline-opts/curl.txt")
   add_subdirectory(docs)
 endif()
 
@@ -2021,12 +2128,12 @@
   add_subdirectory(src)
 endif()
 
-option(BUILD_EXAMPLES "Build libcurl examples" OFF)
+option(BUILD_EXAMPLES "Build libcurl examples" ON)
 if(BUILD_EXAMPLES)
   add_subdirectory(docs/examples)
 endif()
 
-if(BUILD_TESTING)
+if(CURL_BUILD_TESTING)
   add_subdirectory(tests)
 endif()
 
@@ -2054,8 +2161,6 @@
 # Clear list and try to detect available protocols
 unset(_items)
 _add_if("HTTP"          NOT CURL_DISABLE_HTTP)
-_add_if("IPFS"          NOT CURL_DISABLE_HTTP)
-_add_if("IPNS"          NOT CURL_DISABLE_HTTP)
 _add_if("HTTPS"         NOT CURL_DISABLE_HTTP AND _ssl_enabled)
 _add_if("FTP"           NOT CURL_DISABLE_FTP)
 _add_if("FTPS"          NOT CURL_DISABLE_FTP AND _ssl_enabled)
@@ -2082,11 +2187,13 @@
 _add_if("SMTPS"         NOT CURL_DISABLE_SMTP AND _ssl_enabled)
 _add_if("SCP"           USE_LIBSSH2 OR USE_LIBSSH OR USE_WOLFSSH)
 _add_if("SFTP"          USE_LIBSSH2 OR USE_LIBSSH OR USE_WOLFSSH)
+_add_if("IPFS"          NOT CURL_DISABLE_IPFS)
+_add_if("IPNS"          NOT CURL_DISABLE_IPFS)
 _add_if("RTSP"          NOT CURL_DISABLE_RTSP)
 _add_if("RTMP"          USE_LIBRTMP)
 _add_if("MQTT"          NOT CURL_DISABLE_MQTT)
-_add_if("WS"            USE_WEBSOCKETS)
-_add_if("WSS"           USE_WEBSOCKETS AND _ssl_enabled)
+_add_if("WS"            NOT CURL_DISABLE_WEBSOCKETS)
+_add_if("WSS"           NOT CURL_DISABLE_WEBSOCKETS AND _ssl_enabled)
 if(_items)
   list(SORT _items)
 endif()
@@ -2126,7 +2233,7 @@
 _add_if("HTTPS-proxy"   _ssl_enabled AND (USE_OPENSSL OR USE_GNUTLS
                         OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
                         USE_MBEDTLS OR USE_SECTRANSP OR
-                        (USE_WOLFSSL AND HAVE_WOLFSSL_FULL_BIO)))
+                        (USE_WOLFSSL AND HAVE_WOLFSSL_BIO)))
 _add_if("Unicode"       ENABLE_UNICODE)
 _add_if("threadsafe"    HAVE_ATOMIC OR
                         (USE_THREADS_POSIX AND HAVE_PTHREAD_H) OR
@@ -2177,19 +2284,47 @@
   set(CC                      "${CMAKE_C_COMPILER}")
   # TODO: probably put a -D... options here?
   set(CONFIGURE_OPTIONS       "")
-  set(CURLVERSION             "${CURL_VERSION}")
-  set(VERSIONNUM              "${CURL_VERSION_NUM}")
+  set(CURLVERSION             "${_curl_version}")
+  set(VERSIONNUM              "${_curl_version_num}")
   set(prefix                  "${CMAKE_INSTALL_PREFIX}")
   set(exec_prefix             "\${prefix}")
-  set(includedir              "\${prefix}/include")
-  set(LDFLAGS                 "${CMAKE_SHARED_LINKER_FLAGS}")
-  set(libdir                  "${CMAKE_INSTALL_PREFIX}/lib")
+  if(IS_ABSOLUTE ${CMAKE_INSTALL_INCLUDEDIR})
+    set(includedir            "${CMAKE_INSTALL_INCLUDEDIR}")
+  else()
+    set(includedir            "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
+  endif()
+  if(IS_ABSOLUTE ${CMAKE_INSTALL_LIBDIR})
+    set(libdir                "${CMAKE_INSTALL_LIBDIR}")
+  else()
+    set(libdir                "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
+  endif()
   # "a" (Linux) or "lib" (Windows)
   string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}")
 
   set(_ldflags "")
   set(LIBCURL_PC_LIBS_PRIVATE "")
 
+  # Filter CMAKE_SHARED_LINKER_FLAGS for libs and libpaths
+  string(STRIP "${CMAKE_SHARED_LINKER_FLAGS}" _custom_ldflags)
+  string(REGEX REPLACE " +-([^ \\t;]*)" ";-\\1" _custom_ldflags "${_custom_ldflags}")
+
+  set(_custom_libs "")
+  set(_custom_libdirs "")
+  foreach(_flag IN LISTS _custom_ldflags)
+    if(_flag MATCHES "^-l")
+      string(REGEX REPLACE "^-l" "" _flag "${_flag}")
+      list(APPEND _custom_libs "${_flag}")
+    elseif(_flag MATCHES "^-framework|^-F")
+      list(APPEND _custom_libs "${_flag}")
+    elseif(_flag MATCHES "^-L")
+      string(REGEX REPLACE "^-L" "" _flag "${_flag}")
+      list(APPEND _custom_libdirs "${_flag}")
+    elseif(_flag MATCHES "^--library-path=")
+      string(REGEX REPLACE "^--library-path=" "" _flag "${_flag}")
+      list(APPEND _custom_libdirs "${_flag}")
+    endif()
+  endforeach()
+
   # Avoid getting unnecessary -L options for known system directories.
   unset(_sys_libdirs)
   foreach(_libdir IN LISTS CMAKE_SYSTEM_PREFIX_PATH)
@@ -2209,14 +2344,19 @@
     endif()
   endforeach()
 
-  foreach(_libdir IN LISTS CURL_LIBDIRS)
+  foreach(_libdir IN LISTS _custom_libdirs CURL_LIBDIRS)
     list(FIND _sys_libdirs "${_libdir}" _libdir_index)
     if(_libdir_index LESS 0)
       list(APPEND _ldflags "-L${_libdir}")
     endif()
   endforeach()
 
-  foreach(_lib IN LISTS CMAKE_C_IMPLICIT_LINK_LIBRARIES CURL_LIBS)
+  unset(_implicit_libs)
+  if(NOT MINGW AND NOT UNIX)
+    set(_implicit_libs ${CMAKE_C_IMPLICIT_LINK_LIBRARIES})
+  endif()
+
+  foreach(_lib IN LISTS _implicit_libs _custom_libs CURL_LIBS)
     if(TARGET "${_lib}")
       set(_libname "${_lib}")
       get_target_property(_imported "${_libname}" IMPORTED)
@@ -2262,8 +2402,10 @@
   if(_ldflags)
     list(REMOVE_DUPLICATES _ldflags)
     string(REPLACE ";" " " _ldflags "${_ldflags}")
-    set(LIBCURL_PC_LIBS_PRIVATE "${_ldflags} ${LIBCURL_PC_LIBS_PRIVATE}")
-    string(STRIP "${LIBCURL_PC_LIBS_PRIVATE}" LIBCURL_PC_LIBS_PRIVATE)
+    set(LIBCURL_PC_LDFLAGS_PRIVATE "${_ldflags}")
+    string(STRIP "${LIBCURL_PC_LDFLAGS_PRIVATE}" LIBCURL_PC_LDFLAGS_PRIVATE)
+  else()
+    set(LIBCURL_PC_LDFLAGS_PRIVATE "")
   endif()
   set(LIBCURL_PC_CFLAGS_PRIVATE "-DCURL_STATICLIB")
 
@@ -2285,7 +2427,7 @@
     set(ENABLE_STATIC       "no")
   endif()
 
-  # Finally generate a "curl-config" matching this config.
+  # Generate a "curl-config" matching this config.
   # Consumed variables:
   #   CC
   #   CONFIGURE_OPTIONS
@@ -2295,8 +2437,8 @@
   #   ENABLE_STATIC
   #   exec_prefix
   #   includedir
-  #   LDFLAGS
   #   LIBCURL_PC_CFLAGS
+  #   LIBCURL_PC_LDFLAGS_PRIVATE
   #   LIBCURL_PC_LIBS_PRIVATE
   #   libdir
   #   libext
@@ -2306,22 +2448,23 @@
   #   SUPPORT_PROTOCOLS
   #   VERSIONNUM
   configure_file(
-    "${CURL_SOURCE_DIR}/curl-config.in"
-    "${CURL_BINARY_DIR}/curl-config" @ONLY)
-  install(FILES "${CURL_BINARY_DIR}/curl-config"
+    "${PROJECT_SOURCE_DIR}/curl-config.in"
+    "${PROJECT_BINARY_DIR}/curl-config" @ONLY)
+  install(FILES "${PROJECT_BINARY_DIR}/curl-config"
     DESTINATION ${CMAKE_INSTALL_BINDIR}
     PERMISSIONS
       OWNER_READ OWNER_WRITE OWNER_EXECUTE
       GROUP_READ GROUP_EXECUTE
       WORLD_READ WORLD_EXECUTE)
 
-  # Finally generate a pkg-config file matching this config
+  # Generate a pkg-config file matching this config.
   # Consumed variables:
   #   CURLVERSION
   #   exec_prefix
   #   includedir
   #   LIBCURL_PC_CFLAGS
   #   LIBCURL_PC_CFLAGS_PRIVATE
+  #   LIBCURL_PC_LDFLAGS_PRIVATE
   #   LIBCURL_PC_LIBS
   #   LIBCURL_PC_LIBS_PRIVATE
   #   LIBCURL_PC_REQUIRES
@@ -2330,21 +2473,26 @@
   #   prefix
   #   SUPPORT_FEATURES
   #   SUPPORT_PROTOCOLS
+  # Documentation:
+  #   https://people.freedesktop.org/~dbn/pkg-config-guide.html
+  #   https://manpages.debian.org/unstable/pkgconf/pkg-config.1.en.html
+  #   https://manpages.debian.org/unstable/pkg-config/pkg-config.1.en.html
+  #   https://www.msys2.org/docs/pkgconfig/
   configure_file(
-    "${CURL_SOURCE_DIR}/libcurl.pc.in"
-    "${CURL_BINARY_DIR}/libcurl.pc" @ONLY)
-  install(FILES "${CURL_BINARY_DIR}/libcurl.pc"
+    "${PROJECT_SOURCE_DIR}/libcurl.pc.in"
+    "${PROJECT_BINARY_DIR}/libcurl.pc" @ONLY)
+  install(FILES "${PROJECT_BINARY_DIR}/libcurl.pc"
     DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
 
   # Install headers
-  install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl"
+  install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/curl"
     DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
     FILES_MATCHING PATTERN "*.h")
 
   include(CMakePackageConfigHelpers)
   write_basic_package_version_file(
     "${_version_config}"
-    VERSION ${CURL_VERSION}
+    VERSION ${_curl_version}
     COMPATIBILITY SameMajorVersion)
   file(READ "${_version_config}" _generated_version_config)
   file(WRITE "${_version_config}" "
@@ -2359,20 +2507,20 @@
   #   LIB_SELECTED
   #   TARGETS_EXPORT_NAME
   #   USE_OPENSSL
-  #   USE_ZLIB
+  #   HAVE_LIBZ
   configure_package_config_file("CMake/curl-config.cmake.in"
     "${_project_config}"
-    INSTALL_DESTINATION ${CURL_INSTALL_CMAKE_DIR}
+    INSTALL_DESTINATION ${_install_cmake_dir}
     PATH_VARS CMAKE_INSTALL_INCLUDEDIR)
 
   if(CURL_ENABLE_EXPORT_TARGET)
     install(EXPORT "${TARGETS_EXPORT_NAME}"
       NAMESPACE "${PROJECT_NAME}::"
-      DESTINATION ${CURL_INSTALL_CMAKE_DIR})
+      DESTINATION ${_install_cmake_dir})
   endif()
 
   install(FILES ${_version_config} ${_project_config}
-    DESTINATION ${CURL_INSTALL_CMAKE_DIR})
+    DESTINATION ${_install_cmake_dir})
 
   # Workaround for MSVS10 to avoid the Dialog Hell
   # FIXME: This could be removed with future version of CMake.
@@ -2387,7 +2535,7 @@
     configure_file(
       "${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in"
       "${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake"
-      IMMEDIATE @ONLY)
+      @ONLY)
 
     add_custom_target(curl_uninstall
       COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake")
@@ -2399,4 +2547,36 @@
       OWNER_READ OWNER_WRITE OWNER_EXECUTE
       GROUP_READ GROUP_EXECUTE
       WORLD_READ WORLD_EXECUTE)
+
+  # The `-DEV` part is important
+  string(REGEX REPLACE "([0-9]+\.[0-9]+)\.([0-9]+.*)" "\\2" CPACK_PACKAGE_VERSION_PATCH "${_curl_version}")
+  set(CPACK_GENERATOR "TGZ")
+  include(CPack)
+endif()
+
+# Save build info for test runner to pick up and log
+if(CMAKE_OSX_SYSROOT)
+  set(_cmake_sysroot ${CMAKE_OSX_SYSROOT})
+elseif(CMAKE_SYSROOT)
+  set(_cmake_sysroot ${CMAKE_SYSROOT})
+endif()
+set(_buildinfo "\
+buildinfo.configure.tool: cmake
+buildinfo.configure.command: ${CMAKE_COMMAND}
+buildinfo.configure.version: ${CMAKE_VERSION}
+buildinfo.configure.args:${_cmake_args}
+buildinfo.configure.generator: ${CMAKE_GENERATOR}
+buildinfo.configure.make: ${CMAKE_MAKE_PROGRAM}
+buildinfo.host.cpu: ${CMAKE_HOST_SYSTEM_PROCESSOR}
+buildinfo.host.os: ${CMAKE_HOST_SYSTEM_NAME}
+buildinfo.target.cpu: ${CMAKE_SYSTEM_PROCESSOR}
+buildinfo.target.os: ${CMAKE_SYSTEM_NAME}
+buildinfo.target.flags:${_target_flags}
+buildinfo.compiler: ${CMAKE_C_COMPILER_ID}
+buildinfo.compiler.version: ${CMAKE_C_COMPILER_VERSION}
+buildinfo.sysroot: ${_cmake_sysroot}
+")
+file(WRITE "${PROJECT_BINARY_DIR}/buildinfo.txt" "# This is a generated file.  Do not edit.\n${_buildinfo}")
+if(NOT "$ENV{CURL_BUILDINFO}$ENV{CURL_CI}$ENV{CI}" STREQUAL "")
+  message(STATUS "\n${_buildinfo}")
 endif()
diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h
index 00b346e..739b53a 100644
--- a/Utilities/cmcurl/include/curl/curl.h
+++ b/Utilities/cmcurl/include/curl/curl.h
@@ -30,14 +30,15 @@
  */
 
 #ifdef CURL_NO_OLDIES
-#define CURL_STRICTER
+#define CURL_STRICTER /* not used since 8.11.0 */
 #endif
 
 /* Compile-time deprecation macros. */
-#if (defined(__GNUC__) &&                                               \
-  ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) ||  \
-  defined(__IAR_SYSTEMS_ICC__)) &&                                      \
-  !defined(__INTEL_COMPILER) &&                                         \
+#if (defined(__GNUC__) &&                                              \
+  ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1))) ||  \
+  (defined(__clang__) && __clang_major__ >= 3) ||                      \
+  defined(__IAR_SYSTEMS_ICC__)) &&                                     \
+  !defined(__INTEL_COMPILER) &&                                        \
   !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
 #define CURL_DEPRECATED(version, message)                       \
   __attribute__((deprecated("since " # version ". " message)))
@@ -113,13 +114,8 @@
 extern "C" {
 #endif
 
-#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
-typedef struct Curl_easy CURL;
-typedef struct Curl_share CURLSH;
-#else
 typedef void CURL;
 typedef void CURLSH;
-#endif
 
 /*
  * libcurl external API function linkage decorations.
@@ -253,12 +249,12 @@
 #endif
 
 #ifndef CURL_MAX_WRITE_SIZE
-  /* Tests have proven that 20K is a very bad buffer size for uploads on
-     Windows, while 16K for some odd reason performed a lot better.
-     We do the ifndef check to allow this value to easier be changed at build
-     time for those who feel adventurous. The practical minimum is about
-     400 bytes since libcurl uses a buffer of this size as a scratch area
-     (unrelated to network send operations). */
+  /* Tests have proven that 20K is a bad buffer size for uploads on Windows,
+     while 16K for some odd reason performed a lot better. We do the ifndef
+     check to allow this value to easier be changed at build time for those
+     who feel adventurous. The practical minimum is about 400 bytes since
+     libcurl uses a buffer of this size as a scratch area (unrelated to
+     network send operations). */
 #define CURL_MAX_WRITE_SIZE 16384
 #endif
 
@@ -555,14 +551,14 @@
   CURLE_FTP_COULDNT_USE_REST,    /* 31 - the REST command failed */
   CURLE_OBSOLETE32,              /* 32 - NOT USED */
   CURLE_RANGE_ERROR,             /* 33 - RANGE "command" did not work */
-  CURLE_HTTP_POST_ERROR,         /* 34 */
+  CURLE_OBSOLETE34,              /* 34 */
   CURLE_SSL_CONNECT_ERROR,       /* 35 - wrong when connecting with SSL */
   CURLE_BAD_DOWNLOAD_RESUME,     /* 36 - could not resume download */
   CURLE_FILE_COULDNT_READ_FILE,  /* 37 */
   CURLE_LDAP_CANNOT_BIND,        /* 38 */
   CURLE_LDAP_SEARCH_FAILED,      /* 39 */
   CURLE_OBSOLETE40,              /* 40 - NOT USED */
-  CURLE_FUNCTION_NOT_FOUND,      /* 41 - NOT USED starting with 7.53.0 */
+  CURLE_OBSOLETE41,              /* 41 - NOT USED starting with 7.53.0 */
   CURLE_ABORTED_BY_CALLBACK,     /* 42 */
   CURLE_BAD_FUNCTION_ARGUMENT,   /* 43 */
   CURLE_OBSOLETE44,              /* 44 - NOT USED */
@@ -647,6 +643,12 @@
 #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
                           the obsolete stuff removed! */
 
+/* removed in 7.53.0 */
+#define CURLE_FUNCTION_NOT_FOUND CURLE_OBSOLETE41
+
+/* removed in 7.56.0 */
+#define CURLE_HTTP_POST_ERROR CURLE_OBSOLETE34
+
 /* Previously obsolete error code reused in 7.38.0 */
 #define CURLE_OBSOLETE16 CURLE_HTTP2
 
@@ -942,6 +944,9 @@
    a client certificate for authentication. (Schannel) */
 #define CURLSSLOPT_AUTO_CLIENT_CERT (1<<5)
 
+/* If possible, send data using TLS 1.3 early data */
+#define CURLSSLOPT_EARLYDATA (1<<6)
+
 /* The default connection attempt delay in milliseconds for happy eyeballs.
    CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document
    this value, keep them in sync. */
@@ -2953,7 +2958,8 @@
   CURLINFO_QUEUE_TIME_T     = CURLINFO_OFF_T + 65,
   CURLINFO_USED_PROXY       = CURLINFO_LONG + 66,
   CURLINFO_POSTTRANSFER_TIME_T = CURLINFO_OFF_T + 67,
-  CURLINFO_LASTONE          = 67
+  CURLINFO_EARLYDATA_SENT_T = CURLINFO_OFF_T + 68,
+  CURLINFO_LASTONE          = 68
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h
index 25ed10c..eb27bb4 100644
--- a/Utilities/cmcurl/include/curl/curlver.h
+++ b/Utilities/cmcurl/include/curl/curlver.h
@@ -32,12 +32,12 @@
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "8.10.1"
+#define LIBCURL_VERSION "8.11.1"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 8
-#define LIBCURL_VERSION_MINOR 10
+#define LIBCURL_VERSION_MINOR 11
 #define LIBCURL_VERSION_PATCH 1
 
 /* 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 0x080a01
+#define LIBCURL_VERSION_NUM 0x080b01
 
 /*
  * This is the date and time when the full source package was created. The
diff --git a/Utilities/cmcurl/include/curl/multi.h b/Utilities/cmcurl/include/curl/multi.h
index 7b6c351..42469bb 100644
--- a/Utilities/cmcurl/include/curl/multi.h
+++ b/Utilities/cmcurl/include/curl/multi.h
@@ -54,11 +54,7 @@
 extern "C" {
 #endif
 
-#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
-typedef struct Curl_multi CURLM;
-#else
 typedef void CURLM;
-#endif
 
 typedef enum {
   CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
@@ -248,13 +244,13 @@
  *          The data the returned pointer points to will not survive calling
  *          curl_multi_cleanup().
  *
- *          The 'CURLMsg' struct is meant to be very simple and only contain
- *          very basic information. If more involved information is wanted,
- *          we will provide the particular "transfer handle" in that struct
- *          and that should/could/would be used in subsequent
- *          curl_easy_getinfo() calls (or similar). The point being that we
- *          must never expose complex structs to applications, as then we will
- *          undoubtably get backwards compatibility problems in the future.
+ *          The 'CURLMsg' struct is meant to be simple and only contain basic
+ *          information. If more involved information is wanted, we will
+ *          provide the particular "transfer handle" in that struct and that
+ *          should/could/would be used in subsequent curl_easy_getinfo() calls
+ *          (or similar). The point being that we must never expose complex
+ *          structs to applications, as then we will undoubtably get backwards
+ *          compatibility problems in the future.
  *
  * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
  *          of structs. It also writes the number of messages left in the
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt
index 3f99f9f..1f1d876 100644
--- a/Utilities/cmcurl/lib/CMakeLists.txt
+++ b/Utilities/cmcurl/lib/CMakeLists.txt
@@ -21,8 +21,8 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-set(LIB_NAME libcurl)
-set(LIBCURL_OUTPUT_NAME libcurl CACHE STRING "Basename of the curl library")
+set(LIB_NAME "libcurl")
+set(LIBCURL_OUTPUT_NAME "libcurl" CACHE STRING "Basename of the curl library")
 add_definitions("-DBUILDING_LIBCURL")
 
 configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
@@ -39,11 +39,11 @@
 # The rest of the build
 
 include_directories(
-  "${CMAKE_CURRENT_BINARY_DIR}"
-  "${CMAKE_CURRENT_SOURCE_DIR}"
+  "${PROJECT_BINARY_DIR}/lib"  # for "curl_config.h"
+  "${PROJECT_SOURCE_DIR}/lib"  # for "curl_setup.h"
 )
 if(USE_ARES)
-  include_directories(${CARES_INCLUDE_DIRS})
+  include_directories(SYSTEM ${CARES_INCLUDE_DIRS})
 endif()
 
 #-----------------------------------------------------------------------------
@@ -84,7 +84,7 @@
 return() # The rest of this file is not needed for building within CMake.
 #-----------------------------------------------------------------------------
 
-if(BUILD_TESTING)
+if(CURL_BUILD_TESTING)
   add_library(
     curlu  # special libcurlu library just for unittests
     STATIC
@@ -150,7 +150,7 @@
 
   target_include_directories(${LIB_OBJECT} INTERFACE
     "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
-    "$<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>")
+    "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>")
 
   set(LIB_SOURCE $<TARGET_OBJECTS:${LIB_OBJECT}>)
 else()
@@ -163,7 +163,7 @@
   add_library(${LIB_STATIC} STATIC ${LIB_SOURCE})
   add_library(${PROJECT_NAME}::${LIB_STATIC} ALIAS ${LIB_STATIC})
   if(WIN32)
-    set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
+    set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
   endif()
   target_link_libraries(${LIB_STATIC} PRIVATE ${CURL_LIBS})
   # Remove the "lib" prefix since the library is already named "libcurl".
@@ -183,7 +183,7 @@
 
   target_include_directories(${LIB_STATIC} INTERFACE
     "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
-    "$<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>")
+    "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>")
 endif()
 
 if(BUILD_SHARED_LIBS)
@@ -194,15 +194,14 @@
     if(CYGWIN)
       # For Cygwin always compile dllmain.c as a separate unit since it
       # includes windows.h, which should not be included in other units.
-      set_source_files_properties("dllmain.c" PROPERTIES
-        SKIP_UNITY_BUILD_INCLUSION ON)
+      set_source_files_properties("dllmain.c" PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
     endif()
     set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "dllmain.c")
   endif()
   if(WIN32)
     set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "libcurl.rc")
     if(CURL_HIDES_PRIVATE_SYMBOLS)
-      set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${CURL_SOURCE_DIR}/lib/libcurl.def")
+      set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${PROJECT_SOURCE_DIR}/lib/libcurl.def")
     endif()
   endif()
   target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS})
@@ -223,7 +222,7 @@
 
   target_include_directories(${LIB_SHARED} INTERFACE
     "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
-    "$<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>")
+    "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>")
 
   if(CMAKE_DLL_NAME_WITH_SOVERSION OR
     CYGWIN OR
@@ -276,16 +275,21 @@
         set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "WOLFSSL_")
       elseif(CURL_USE_GNUTLS)
         set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "GNUTLS_")
+      elseif(CURL_USE_RUSTLS)
+        set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "RUSTLS_")
       endif()
     endif()
-    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libcurl.vers" "
-      HIDDEN {};
-      CURL_${CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX}${_cmakesoname}
-      {
-        global: curl_*;
-        local: *;
-      };")
+    # Generate version script for the linker, for versioned symbols.
+    # Consumed variables:
+    #   CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX
+    #   CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME
+    set(CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME ${_cmakesoname})
+    configure_file(
+      "${CMAKE_CURRENT_SOURCE_DIR}/libcurl.vers.in"
+      "${CMAKE_CURRENT_BINARY_DIR}/libcurl.vers" @ONLY)
+    include(CMakePushCheckState)
     include(CheckCSourceCompiles)
+    cmake_push_check_state()
     set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/libcurl.vers")
     check_c_source_compiles("int main(void) { return 0; }" HAVE_VERSIONED_SYMBOLS)
     if(HAVE_VERSIONED_SYMBOLS)
@@ -294,7 +298,7 @@
     else()
       message(WARNING "Versioned symbols requested, but not supported by the toolchain.")
     endif()
-    unset(CMAKE_REQUIRED_LINK_OPTIONS)
+    cmake_pop_check_state()
   endif()
 endif()
 
diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc
index 66680f3..1d3f69a 100644
--- a/Utilities/cmcurl/lib/Makefile.inc
+++ b/Utilities/cmcurl/lib/Makefile.inc
@@ -97,9 +97,11 @@
 LIB_VSSH_CFILES =  \
   vssh/libssh.c    \
   vssh/libssh2.c   \
+  vssh/curl_path.c \
   vssh/wolfssh.c
 
-LIB_VSSH_HFILES =  \
+LIB_VSSH_HFILES =    \
+  vssh/curl_path.h   \
   vssh/ssh.h
 
 LIB_CFILES =         \
@@ -131,7 +133,6 @@
   curl_memrchr.c     \
   curl_multibyte.c   \
   curl_ntlm_core.c   \
-  curl_path.c        \
   curl_range.c       \
   curl_rtmp.c        \
   curl_sasl.c        \
@@ -273,7 +274,6 @@
   curl_memrchr.h     \
   curl_multibyte.h   \
   curl_ntlm_core.h   \
-  curl_path.h        \
   curl_printf.h      \
   curl_range.h       \
   curl_rtmp.h        \
diff --git a/Utilities/cmcurl/lib/altsvc.c b/Utilities/cmcurl/lib/altsvc.c
index dcedc49..ea37b0a 100644
--- a/Utilities/cmcurl/lib/altsvc.c
+++ b/Utilities/cmcurl/lib/altsvc.c
@@ -64,6 +64,8 @@
     return ALPN_h2;
   if(strcasecompare(name, H3VERSION))
     return ALPN_h3;
+  if(strcasecompare(name, "http/1.1"))
+    return ALPN_h1;
   return ALPN_none; /* unknown, probably rubbish input */
 }
 
@@ -92,6 +94,7 @@
 
 static struct altsvc *altsvc_createid(const char *srchost,
                                       const char *dsthost,
+                                      size_t dlen, /* dsthost length */
                                       enum alpnid srcalpnid,
                                       enum alpnid dstalpnid,
                                       unsigned int srcport,
@@ -99,11 +102,9 @@
 {
   struct altsvc *as = calloc(1, sizeof(struct altsvc));
   size_t hlen;
-  size_t dlen;
   if(!as)
     return NULL;
   hlen = strlen(srchost);
-  dlen = strlen(dsthost);
   DEBUGASSERT(hlen);
   DEBUGASSERT(dlen);
   if(!hlen || !dlen) {
@@ -155,7 +156,8 @@
   enum alpnid srcalpnid = alpn2alpnid(srcalpn);
   if(!srcalpnid || !dstalpnid)
     return NULL;
-  return altsvc_createid(srchost, dsthost, srcalpnid, dstalpnid,
+  return altsvc_createid(srchost, dsthost, strlen(dsthost),
+                         srcalpnid, dstalpnid,
                          srcport, dstport);
 }
 
@@ -315,10 +317,8 @@
  */
 CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file)
 {
-  CURLcode result;
   DEBUGASSERT(asi);
-  result = altsvc_load(asi, file);
-  return result;
+  return altsvc_load(asi, file);
 }
 
 /*
@@ -490,8 +490,6 @@
                            unsigned short srcport)
 {
   const char *p = value;
-  size_t len;
-  char namebuf[MAX_ALTSVC_HOSTLEN] = "";
   char alpnbuf[MAX_ALTSVC_ALPNLEN] = "";
   struct altsvc *as;
   unsigned short dstport = srcport; /* the same by default */
@@ -521,6 +519,7 @@
       p++;
       if(*p == '\"') {
         const char *dsthost = "";
+        size_t dstlen = 0; /* destination hostname length */
         const char *value_ptr;
         char option[32];
         unsigned long num;
@@ -535,32 +534,31 @@
           const char *hostp = p;
           if(*p == '[') {
             /* pass all valid IPv6 letters - does not handle zone id */
-            len = strspn(++p, "0123456789abcdefABCDEF:.");
-            if(p[len] != ']')
+            dstlen = strspn(++p, "0123456789abcdefABCDEF:.");
+            if(p[dstlen] != ']')
               /* invalid host syntax, bail out */
               break;
             /* we store the IPv6 numerical address *with* brackets */
-            len += 2;
-            p = &p[len-1];
+            dstlen += 2;
+            p = &p[dstlen-1];
           }
           else {
             while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
               p++;
-            len = p - hostp;
+            dstlen = p - hostp;
           }
-          if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
+          if(!dstlen || (dstlen >= MAX_ALTSVC_HOSTLEN)) {
             infof(data, "Excessive alt-svc hostname, ignoring.");
             valid = FALSE;
           }
           else {
-            memcpy(namebuf, hostp, len);
-            namebuf[len] = 0;
-            dsthost = namebuf;
+            dsthost = hostp;
           }
         }
         else {
           /* no destination name, use source host */
           dsthost = srchost;
+          dstlen = strlen(srchost);
         }
         if(*p == ':') {
           unsigned long port = 0;
@@ -635,7 +633,7 @@
                this is the first entry of the line. */
             altsvc_flush(asi, srcalpnid, srchost, srcport);
 
-          as = altsvc_createid(srchost, dsthost,
+          as = altsvc_createid(srchost, dsthost, dstlen,
                                srcalpnid, dstalpnid,
                                srcport, dstport);
           if(as) {
diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c
index 782e3ac..ae436f2 100644
--- a/Utilities/cmcurl/lib/asyn-ares.c
+++ b/Utilities/cmcurl/lib/asyn-ares.c
@@ -290,23 +290,14 @@
 int Curl_resolver_getsock(struct Curl_easy *data,
                           curl_socket_t *socks)
 {
-  struct timeval maxtime;
+  struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
   struct timeval timebuf;
-  struct timeval *timeout;
-  long milli;
   int max = ares_getsock((ares_channel)data->state.async.resolver,
                          (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
-
-  maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
-  maxtime.tv_usec = 0;
-
-  timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
-                         &timebuf);
-  milli = (long)curlx_tvtoms(timeout);
-  if(milli == 0)
-    milli += 10;
+  struct timeval *timeout =
+    ares_timeout((ares_channel)data->state.async.resolver, &maxtime, &timebuf);
+  timediff_t milli = curlx_tvtoms(timeout);
   Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
-
   return max;
 }
 
@@ -366,10 +357,10 @@
     /* move through the descriptors and ask for processing on them */
     for(i = 0; i < num; i++)
       ares_process_fd((ares_channel)data->state.async.resolver,
-                      (pfd[i].revents & (POLLRDNORM|POLLIN))?
-                      pfd[i].fd:ARES_SOCKET_BAD,
-                      (pfd[i].revents & (POLLWRNORM|POLLOUT))?
-                      pfd[i].fd:ARES_SOCKET_BAD);
+                      (pfd[i].revents & (POLLRDNORM|POLLIN)) ?
+                      pfd[i].fd : ARES_SOCKET_BAD,
+                      (pfd[i].revents & (POLLWRNORM|POLLOUT)) ?
+                      pfd[i].fd : ARES_SOCKET_BAD);
   }
   return nfds;
 }
@@ -801,7 +792,7 @@
       }
 #endif /* CURLRES_IPV6 */
       hints.ai_family = pf;
-      hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
+      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
diff --git a/Utilities/cmcurl/lib/asyn-thread.c b/Utilities/cmcurl/lib/asyn-thread.c
index 79b9c23..a58e4b7 100644
--- a/Utilities/cmcurl/lib/asyn-thread.c
+++ b/Utilities/cmcurl/lib/asyn-thread.c
@@ -286,7 +286,7 @@
  * and wait on it.
  */
 static
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
 DWORD
 #else
 unsigned int
@@ -311,7 +311,7 @@
   rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
 
   if(rc) {
-    tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
+    tsd->sock_error = SOCKERRNO ? SOCKERRNO : rc;
     if(tsd->sock_error == 0)
       tsd->sock_error = RESOLVER_ENOMEM;
   }
@@ -354,7 +354,7 @@
  * gethostbyname_thread() resolves a name and then exits.
  */
 static
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
 DWORD
 #else
 unsigned int
@@ -728,7 +728,7 @@
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
+  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
     SOCK_STREAM : SOCK_DGRAM;
 
   reslv->start = Curl_now();
diff --git a/Utilities/cmcurl/lib/bufq.c b/Utilities/cmcurl/lib/bufq.c
index 46e6eaa..547d4d3 100644
--- a/Utilities/cmcurl/lib/bufq.c
+++ b/Utilities/cmcurl/lib/bufq.c
@@ -484,17 +484,17 @@
   ssize_t n;
   CURLcode result;
   n = Curl_bufq_write(q, (const unsigned char *)buf, len, &result);
-  *pnwritten = (n < 0)? 0 : (size_t)n;
+  *pnwritten = (n < 0) ? 0 : (size_t)n;
   return result;
 }
 
 CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len)
 {
   while(len && q->tail) {
-    len -= chunk_unwrite(q->head, len);
+    len -= chunk_unwrite(q->tail, len);
     prune_tail(q);
   }
-  return len? CURLE_AGAIN : CURLE_OK;
+  return len ? CURLE_AGAIN : CURLE_OK;
 }
 
 ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
@@ -526,7 +526,7 @@
   ssize_t n;
   CURLcode result;
   n = Curl_bufq_read(q, (unsigned char *)buf, len, &result);
-  *pnread = (n < 0)? 0 : (size_t)n;
+  *pnread = (n < 0) ? 0 : (size_t)n;
   return result;
 }
 
diff --git a/Utilities/cmcurl/lib/c-hyper.c b/Utilities/cmcurl/lib/c-hyper.c
index a9a62d0..2b8eb95 100644
--- a/Utilities/cmcurl/lib/c-hyper.c
+++ b/Utilities/cmcurl/lib/c-hyper.c
@@ -274,7 +274,7 @@
   /* We need to set 'httpcodeq' for functions that check the response code in
      a single place. */
   data->req.httpcode = http_status;
-  data->req.httpversion = http_version == HYPER_HTTP_VERSION_1_1? 11 :
+  data->req.httpversion = http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
                           (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
   if(data->state.hconnect)
     /* CONNECT */
@@ -481,8 +481,8 @@
         goto out;
 
       k->deductheadercount =
-        (100 <= http_status && 199 >= http_status)?k->headerbytecount:0;
-#ifdef USE_WEBSOCKETS
+        (100 <= http_status && 199 >= http_status) ? k->headerbytecount : 0;
+#ifndef CURL_DISABLE_WEBSOCKETS
       if(k->upgr101 == UPGR101_WS) {
         if(http_status == 101) {
           /* verify the response */
@@ -1035,7 +1035,7 @@
   }
 
   p_accept = Curl_checkheaders(data,
-                               STRCONST("Accept"))?NULL:"Accept: */*\r\n";
+                               STRCONST("Accept")) ? NULL : "Accept: */*\r\n";
   if(p_accept) {
     result = Curl_hyper_header(data, headers, p_accept);
     if(result)
diff --git a/Utilities/cmcurl/lib/cf-h1-proxy.c b/Utilities/cmcurl/lib/cf-h1-proxy.c
index 6de33d0..6b7f983 100644
--- a/Utilities/cmcurl/lib/cf-h1-proxy.c
+++ b/Utilities/cmcurl/lib/cf-h1-proxy.c
@@ -299,7 +299,7 @@
      (checkprefix("Proxy-authenticate:", header) &&
       (407 == k->httpcode))) {
 
-    bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
+    bool proxy = (k->httpcode == 407);
     char *auth = Curl_copy_header_value(header);
     if(!auth)
       return CURLE_OUT_OF_MEMORY;
@@ -547,8 +547,8 @@
   if(result)
     return result;
 
-  authority = aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
-                      port);
+  authority = aprintf("%s%s%s:%d", ipv6_ip ? "[":"", hostname,
+                      ipv6_ip ? "]" : "", port);
   if(!authority)
     return CURLE_OUT_OF_MEMORY;
 
diff --git a/Utilities/cmcurl/lib/cf-h2-proxy.c b/Utilities/cmcurl/lib/cf-h2-proxy.c
index 0a60ae4..e687dd1 100644
--- a/Utilities/cmcurl/lib/cf-h2-proxy.c
+++ b/Utilities/cmcurl/lib/cf-h2-proxy.c
@@ -98,7 +98,8 @@
     return result;
 
   ts->authority = /* host:port with IPv6 support */
-    aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", port);
+    aprintf("%s%s%s:%d", ipv6_ip ? "[":"", hostname,
+            ipv6_ip ? "]" : "", port);
   if(!ts->authority)
     return CURLE_OUT_OF_MEMORY;
 
@@ -276,6 +277,8 @@
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
   nghttp2_option *o;
+  nghttp2_mem mem = {NULL, Curl_nghttp2_malloc, Curl_nghttp2_free,
+                     Curl_nghttp2_calloc, Curl_nghttp2_realloc};
 
   int rc = nghttp2_option_new(&o);
   if(rc)
@@ -288,7 +291,7 @@
      HTTP field value. */
   nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1);
 #endif
-  rc = nghttp2_session_client_new2(&ctx->h2, cbs, cf, o);
+  rc = nghttp2_session_client_new3(&ctx->h2, cbs, cf, o, &mem);
   nghttp2_option_del(o);
   return rc;
 }
@@ -429,7 +432,7 @@
     return result;
   }
   CURL_TRC_CF(data, cf, "[0] nw send buffer flushed");
-  return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN;
+  return Curl_bufq_is_empty(&ctx->outbufq) ? CURLE_OK : CURLE_AGAIN;
 }
 
 /*
@@ -604,29 +607,27 @@
       return msnprintf(buffer, blen,
                        "FRAME[SETTINGS, len=%d]", (int)frame->hd.length);
     }
-    case NGHTTP2_PUSH_PROMISE: {
+    case NGHTTP2_PUSH_PROMISE:
       return msnprintf(buffer, blen,
                        "FRAME[PUSH_PROMISE, len=%d, hend=%d]",
                        (int)frame->hd.length,
                        !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS));
-    }
-    case NGHTTP2_PING: {
+    case NGHTTP2_PING:
       return msnprintf(buffer, blen,
                        "FRAME[PING, len=%d, ack=%d]",
                        (int)frame->hd.length,
-                       frame->hd.flags&NGHTTP2_FLAG_ACK);
-    }
+                       frame->hd.flags & NGHTTP2_FLAG_ACK);
     case NGHTTP2_GOAWAY: {
       char scratch[128];
       size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
-        size_t len = (frame->goaway.opaque_data_len < s_len)?
-                      frame->goaway.opaque_data_len : s_len-1;
-        if(len)
-          memcpy(scratch, frame->goaway.opaque_data, len);
-        scratch[len] = '\0';
-        return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', "
-                         "last_stream=%d]", frame->goaway.error_code,
-                         scratch, frame->goaway.last_stream_id);
+      size_t len = (frame->goaway.opaque_data_len < s_len) ?
+        frame->goaway.opaque_data_len : s_len-1;
+      if(len)
+        memcpy(scratch, frame->goaway.opaque_data, len);
+      scratch[len] = '\0';
+      return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', "
+                       "last_stream=%d]", frame->goaway.error_code,
+                       scratch, frame->goaway.last_stream_id);
     }
     case NGHTTP2_WINDOW_UPDATE: {
       return msnprintf(buffer, blen,
@@ -1220,7 +1221,7 @@
      (ctx && ctx->tunnel.state == H2_TUNNEL_ESTABLISHED &&
       !Curl_bufq_is_empty(&ctx->tunnel.recvbuf)))
     return TRUE;
-  return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
+  return cf->next ? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
 }
 
 static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
@@ -1586,7 +1587,7 @@
   default:
     break;
   }
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
diff --git a/Utilities/cmcurl/lib/cf-haproxy.c b/Utilities/cmcurl/lib/cf-haproxy.c
index 0fc7625..ae2402f 100644
--- a/Utilities/cmcurl/lib/cf-haproxy.c
+++ b/Utilities/cmcurl/lib/cf-haproxy.c
@@ -93,7 +93,7 @@
     client_ip = ipquad.local_ip;
 
   result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
-                         is_ipv6? "TCP6" : "TCP4",
+                         is_ipv6 ? "TCP6" : "TCP4",
                          client_ip, ipquad.remote_ip,
                          ipquad.local_port, ipquad.remote_port);
 
@@ -231,7 +231,7 @@
 
 out:
   cf_haproxy_ctx_free(ctx);
-  *pcf = result? NULL : cf;
+  *pcf = result ? NULL : cf;
   return result;
 }
 
diff --git a/Utilities/cmcurl/lib/cf-https-connect.c b/Utilities/cmcurl/lib/cf-https-connect.c
index bc71598..dd7cdcb 100644
--- a/Utilities/cmcurl/lib/cf-https-connect.c
+++ b/Utilities/cmcurl/lib/cf-https-connect.c
@@ -174,6 +174,7 @@
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
+  int reply_ms;
 
   DEBUGASSERT(winner->cf);
   if(winner != &ctx->h3_baller)
@@ -181,9 +182,15 @@
   if(winner != &ctx->h21_baller)
     cf_hc_baller_reset(&ctx->h21_baller, data);
 
-  CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms",
-              winner->name, (int)Curl_timediff(Curl_now(), winner->started),
-              cf_hc_baller_reply_ms(winner, data));
+  reply_ms = cf_hc_baller_reply_ms(winner, data);
+  if(reply_ms >= 0)
+    CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms",
+                winner->name, (int)Curl_timediff(Curl_now(), winner->started),
+                reply_ms);
+  else
+    CURL_TRC_CF(data, cf, "deferred handshake %s: %dms",
+                winner->name, (int)Curl_timediff(Curl_now(), winner->started));
+
   cf->next = winner->cf;
   winner->cf = NULL;
 
@@ -275,7 +282,7 @@
     }
     else if(ctx->h21_baller.enabled)
       cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
-                       cf->conn->transport);
+                        cf->conn->transport);
     ctx->state = CF_HC_CONNECT;
     FALLTHROUGH();
 
@@ -306,8 +313,8 @@
        (!ctx->h21_baller.enabled || ctx->h21_baller.result)) {
       /* both failed or disabled. we give up */
       CURL_TRC_CF(data, cf, "connect, all failed");
-      result = ctx->result = ctx->h3_baller.enabled?
-                              ctx->h3_baller.result : ctx->h21_baller.result;
+      result = ctx->result = ctx->h3_baller.enabled ?
+        ctx->h3_baller.result : ctx->h21_baller.result;
       ctx->state = CF_HC_FAILURE;
       goto out;
     }
@@ -420,13 +427,13 @@
 
   memset(&tmax, 0, sizeof(tmax));
   memset(&t, 0, sizeof(t));
-  cfb = ctx->h21_baller.enabled? ctx->h21_baller.cf : NULL;
+  cfb = ctx->h21_baller.enabled ? ctx->h21_baller.cf : NULL;
   if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
     if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
       tmax = t;
   }
   memset(&t, 0, sizeof(t));
-  cfb = ctx->h3_baller.enabled? ctx->h3_baller.cf : NULL;
+  cfb = ctx->h3_baller.enabled ? ctx->h3_baller.cf : NULL;
   if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
     if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
       tmax = t;
@@ -464,7 +471,7 @@
       break;
     }
   }
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
@@ -553,7 +560,7 @@
   cf_hc_reset(cf, data);
 
 out:
-  *pcf = result? NULL : cf;
+  *pcf = result ? NULL : cf;
   free(ctx);
   return result;
 }
diff --git a/Utilities/cmcurl/lib/cf-socket.c b/Utilities/cmcurl/lib/cf-socket.c
index e4d6a5b..497a3b9 100644
--- a/Utilities/cmcurl/lib/cf-socket.c
+++ b/Utilities/cmcurl/lib/cf-socket.c
@@ -177,7 +177,7 @@
 tcpkeepalive(struct Curl_easy *data,
              curl_socket_t sockfd)
 {
-  int optval = data->set.tcp_keepalive?1:0;
+  int optval = data->set.tcp_keepalive ? 1 : 0;
 
   /* only set IDLE and INTVL if setting KEEPALIVE is successful */
   if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
@@ -336,7 +336,7 @@
 
   if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
     dest->addrlen = sizeof(struct Curl_sockaddr_storage);
-  memcpy(&dest->sa_addr, ai->ai_addr, dest->addrlen);
+  memcpy(&dest->curl_sa_addr, ai->ai_addr, dest->addrlen);
 }
 
 static CURLcode socket_open(struct Curl_easy *data,
@@ -355,11 +355,11 @@
     * might have been changed and this 'new' address will actually be used
     * here to connect.
     */
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     *sockfd = data->set.fopensocket(data->set.opensocket_client,
                                     CURLSOCKTYPE_IPCXN,
                                     (struct curl_sockaddr *)addr);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
   }
   else {
     /* opensocket callback not set, so simply create the socket now */
@@ -372,7 +372,7 @@
 
 #if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
   if(data->conn->scope_id && (addr->family == AF_INET6)) {
-    struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
+    struct sockaddr_in6 * const sa6 = (void *)&addr->curl_sa_addr;
     sa6->sin6_scope_id = data->conn->scope_id;
   }
 #endif
@@ -413,9 +413,9 @@
   if(use_callback && conn && conn->fclosesocket) {
     int rc;
     Curl_multi_closed(data, sock);
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     rc = conn->fclosesocket(conn->closesocket_client, sock);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
     return rc;
   }
 
@@ -600,36 +600,39 @@
   if(!iface && !host && !port)
     /* no local kind of binding was requested */
     return CURLE_OK;
+  else if(iface && (strlen(iface) >= 255) )
+    return CURLE_BAD_FUNCTION_ARGUMENT;
 
   memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
 
-  if(iface && (strlen(iface)<255) ) {
+  if(iface || host) {
     char myhost[256] = "";
     int done = 0; /* -1 for error, 1 for address found */
     if2ip_result_t if2ip_result = IF2IP_NOT_FOUND;
 
-    /* interface */
 #ifdef SO_BINDTODEVICE
-    /*
-      * This binds the local socket to a particular interface. This will
-      * force even requests to other local interfaces to go out the external
-      * interface. Only bind to the interface when specified as interface,
-      * not just as a hostname or ip address.
-      *
-      * The interface might be a VRF, eg: vrf-blue, which means it cannot be
-      * converted to an IP address and would fail Curl_if2ip. Simply try to
-      * use it straight away.
-      */
-    if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
-                  iface, (curl_socklen_t)strlen(iface) + 1) == 0) {
-      /* This is often "errno 1, error: Operation not permitted" if you are
-        * not running as root or another suitable privileged user. If it
-        * succeeds it means the parameter was a valid interface and not an IP
-        * address. Return immediately.
-        */
-      if(!host_input) {
-        infof(data, "socket successfully bound to interface '%s'", iface);
-        return CURLE_OK;
+    if(iface) {
+      /*
+       * This binds the local socket to a particular interface. This will
+       * force even requests to other local interfaces to go out the external
+       * interface. Only bind to the interface when specified as interface,
+       * not just as a hostname or ip address.
+       *
+       * The interface might be a VRF, eg: vrf-blue, which means it cannot be
+       * converted to an IP address and would fail Curl_if2ip. Simply try to
+       * use it straight away.
+       */
+      if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+                    iface, (curl_socklen_t)strlen(iface) + 1) == 0) {
+        /* This is often "errno 1, error: Operation not permitted" if you are
+         * not running as root or another suitable privileged user. If it
+         * succeeds it means the parameter was a valid interface and not an IP
+         * address. Return immediately.
+         */
+        if(!host_input) {
+          infof(data, "socket successfully bound to interface '%s'", iface);
+          return CURLE_OK;
+        }
       }
     }
 #endif
@@ -1088,13 +1091,14 @@
   struct cf_socket_ctx *ctx = cf->ctx;
 
   /* store remote address and port used in this connection attempt */
-  if(!Curl_addr2string(&ctx->addr.sa_addr, (curl_socklen_t)ctx->addr.addrlen,
+  if(!Curl_addr2string(&ctx->addr.curl_sa_addr,
+                       (curl_socklen_t)ctx->addr.addrlen,
                        ctx->ip.remote_ip, &ctx->ip.remote_port)) {
     char buffer[STRERROR_LEN];
 
     ctx->error = errno;
     /* malformed address or bug in inet_ntop, try next address */
-    failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
+    failf(data, "curl_sa_addr inet_ntop() failed with errno %d: %s",
           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
     return CURLE_FAILED_INIT;
   }
@@ -1163,11 +1167,11 @@
 
   if(data->set.fsockopt) {
     /* activate callback for setting socket options */
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     error = data->set.fsockopt(data->set.sockopt_client,
                                ctx->sock,
                                CURLSOCKTYPE_IPCXN);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
 
     if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
       isconnected = TRUE;
@@ -1185,7 +1189,7 @@
 #endif
     ) {
     result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family,
-                       Curl_ipv6_scope(&ctx->addr.sa_addr));
+                       Curl_ipv6_scope(&ctx->addr.curl_sa_addr));
     if(result) {
       if(result == CURLE_UNSUPPORTED_PROTOCOL) {
         /* The address family is not supported on this interface.
@@ -1257,7 +1261,7 @@
       endpoints.sae_srcif = 0;
       endpoints.sae_srcaddr = NULL;
       endpoints.sae_srcaddrlen = 0;
-      endpoints.sae_dstaddr = &ctx->addr.sa_addr;
+      endpoints.sae_dstaddr = &ctx->addr.curl_sa_addr;
       endpoints.sae_dstaddrlen = ctx->addr.addrlen;
 
       rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY,
@@ -1265,10 +1269,10 @@
                     NULL, 0, NULL, NULL);
     }
     else {
-      rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+      rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
     }
 #  else
-    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+    rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
 #  endif /* HAVE_BUILTIN_AVAILABLE */
 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
     if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
@@ -1276,16 +1280,16 @@
       infof(data, "Failed to enable TCP Fast Open on fd %" FMT_SOCKET_T,
             ctx->sock);
 
-    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+    rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
 #elif defined(MSG_FASTOPEN) /* old Linux */
     if(cf->conn->given->flags & PROTOPT_SSL)
-      rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+      rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
     else
       rc = 0; /* Do nothing */
 #endif
   }
   else {
-    rc = connect(ctx->sock, &ctx->addr.sa_addr,
+    rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
                  (curl_socklen_t)ctx->addr.addrlen);
   }
   return rc;
@@ -1309,7 +1313,7 @@
   if(blocking)
     return CURLE_UNSUPPORTED_PROTOCOL;
 
-  *done = FALSE; /* a very negative world view is best */
+  *done = FALSE; /* a negative world view is best */
   if(ctx->sock == CURL_SOCKET_BAD) {
     int error;
 
@@ -1507,7 +1511,7 @@
 #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
   if(cf->conn->bits.tcp_fastopen) {
     nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
-                      &cf->conn->remote_addr->sa_addr,
+                      &cf->conn->remote_addr->curl_sa_addr,
                       cf->conn->remote_addr->addrlen);
     cf->conn->bits.tcp_fastopen = FALSE;
   }
@@ -1642,7 +1646,7 @@
     cf->conn->primary = ctx->ip;
     cf->conn->remote_addr = &ctx->addr;
   #ifdef USE_IPV6
-    cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
+    cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6);
   #endif
   }
   else {
@@ -1725,7 +1729,7 @@
   case CF_QUERY_CONNECT_REPLY_MS:
     if(ctx->got_first_byte) {
       timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
-      *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
+      *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
     }
     else
       *pres1 = -1;
@@ -1750,7 +1754,7 @@
   }
   case CF_QUERY_IP_INFO:
 #ifdef USE_IPV6
-    *pres1 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
+    *pres1 = (ctx->addr.family == AF_INET6);
 #else
     *pres1 = FALSE;
 #endif
@@ -1759,7 +1763,7 @@
   default:
     break;
   }
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
@@ -1806,7 +1810,7 @@
   result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
 
 out:
-  *pcf = (!result)? cf : NULL;
+  *pcf = (!result) ? cf : NULL;
   if(result) {
     Curl_safefree(cf);
     Curl_safefree(ctx);
@@ -1827,7 +1831,7 @@
   /* QUIC needs a connected socket, nonblocking */
   DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
 
-  rc = connect(ctx->sock, &ctx->addr.sa_addr,
+  rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
                (curl_socklen_t)ctx->addr.addrlen);
   if(-1 == rc) {
     return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
@@ -1836,7 +1840,7 @@
   set_local_ip(cf, data);
   CURL_TRC_CF(data, cf, "%s socket %" FMT_SOCKET_T
               " connected: [%s:%d] -> [%s:%d]",
-              (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
+              (ctx->transport == TRNSPRT_QUIC) ? "QUIC" : "UDP",
               ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
               ctx->ip.remote_ip, ctx->ip.remote_port);
 
@@ -1955,7 +1959,7 @@
   result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
 
 out:
-  *pcf = (!result)? cf : NULL;
+  *pcf = (!result) ? cf : NULL;
   if(result) {
     Curl_safefree(cf);
     Curl_safefree(ctx);
@@ -2007,7 +2011,7 @@
   result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
 
 out:
-  *pcf = (!result)? cf : NULL;
+  *pcf = (!result) ? cf : NULL;
   if(result) {
     Curl_safefree(cf);
     Curl_safefree(ctx);
@@ -2016,10 +2020,84 @@
   return result;
 }
 
+static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+  timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
+  timediff_t other;
+  struct curltime now;
+
+#ifndef CURL_DISABLE_FTP
+  if(data->set.accepttimeout > 0)
+    timeout_ms = data->set.accepttimeout;
+#endif
+
+  now = Curl_now();
+  /* check if the generic timeout possibly is set shorter */
+  other = Curl_timeleft(data, &now, FALSE);
+  if(other && (other < timeout_ms))
+    /* note that this also works fine for when other happens to be negative
+       due to it already having elapsed */
+    timeout_ms = other;
+  else {
+    /* subtract elapsed time */
+    timeout_ms -= Curl_timediff(now, ctx->started_at);
+    if(!timeout_ms)
+      /* avoid returning 0 as that means no timeout! */
+      timeout_ms = -1;
+  }
+  return timeout_ms;
+}
+
+static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+#ifdef HAVE_GETPEERNAME
+  char buffer[STRERROR_LEN];
+  struct Curl_sockaddr_storage ssrem;
+  curl_socklen_t plen;
+
+  ctx->ip.remote_ip[0] = 0;
+  ctx->ip.remote_port = 0;
+  plen = sizeof(ssrem);
+  memset(&ssrem, 0, plen);
+  if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
+    int error = SOCKERRNO;
+    failf(data, "getpeername() failed with errno %d: %s",
+          error, Curl_strerror(error, buffer, sizeof(buffer)));
+    return;
+  }
+  if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
+                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
+    failf(data, "ssrem inet_ntop() failed with errno %d: %s",
+          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+    return;
+  }
+#else
+  ctx->ip.remote_ip[0] = 0;
+  ctx->ip.remote_port = 0;
+  (void)data;
+#endif
+}
+
 static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
                                       struct Curl_easy *data,
                                       bool blocking, bool *done)
 {
+  struct cf_socket_ctx *ctx = cf->ctx;
+#ifdef USE_IPV6
+  struct Curl_sockaddr_storage add;
+#else
+  struct sockaddr_in add;
+#endif
+  curl_socklen_t size = (curl_socklen_t) sizeof(add);
+  curl_socket_t s_accepted = CURL_SOCKET_BAD;
+  timediff_t timeout_ms;
+  int socketstate = 0;
+  bool incoming = FALSE;
+
   /* we start accepted, if we ever close, we cannot go on */
   (void)data;
   (void)blocking;
@@ -2027,7 +2105,79 @@
     *done = TRUE;
     return CURLE_OK;
   }
-  return CURLE_FAILED_INIT;
+
+  timeout_ms = cf_tcp_accept_timeleft(cf, data);
+  if(timeout_ms < 0) {
+    /* if a timeout was already reached, bail out */
+    failf(data, "Accept timeout occurred while waiting server connect");
+    return CURLE_FTP_ACCEPT_TIMEOUT;
+  }
+
+  CURL_TRC_CF(data, cf, "Checking for incoming on fd=%" FMT_SOCKET_T
+              " ip=%s:%d", ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
+  socketstate = Curl_socket_check(ctx->sock, CURL_SOCKET_BAD,
+                                  CURL_SOCKET_BAD, 0);
+  CURL_TRC_CF(data, cf, "socket_check -> %x", socketstate);
+  switch(socketstate) {
+  case -1: /* error */
+    /* let's die here */
+    failf(data, "Error while waiting for server connect");
+    return CURLE_FTP_ACCEPT_FAILED;
+  default:
+    if(socketstate & CURL_CSELECT_IN) {
+      infof(data, "Ready to accept data connection from server");
+      incoming = TRUE;
+    }
+    break;
+  }
+
+  if(!incoming) {
+    CURL_TRC_CF(data, cf, "nothing heard from the server yet");
+    *done = FALSE;
+    return CURLE_OK;
+  }
+
+  if(0 == getsockname(ctx->sock, (struct sockaddr *) &add, &size)) {
+    size = sizeof(add);
+    s_accepted = accept(ctx->sock, (struct sockaddr *) &add, &size);
+  }
+
+  if(CURL_SOCKET_BAD == s_accepted) {
+    failf(data, "Error accept()ing server connect");
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  infof(data, "Connection accepted from server");
+  (void)curlx_nonblock(s_accepted, TRUE); /* enable non-blocking */
+  /* Replace any filter on SECONDARY with one listening on this socket */
+  ctx->listening = FALSE;
+  ctx->accepted = TRUE;
+  socket_close(data, cf->conn, TRUE, ctx->sock);
+  ctx->sock = s_accepted;
+
+  cf->conn->sock[cf->sockindex] = ctx->sock;
+  cf_tcp_set_accepted_remote_ip(cf, data);
+  set_local_ip(cf, data);
+  ctx->active = TRUE;
+  ctx->connected_at = Curl_now();
+  cf->connected = TRUE;
+  CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
+              ", remote=%s port=%d)",
+              ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
+
+  if(data->set.fsockopt) {
+    int error = 0;
+
+    /* activate callback for setting socket options */
+    Curl_set_in_callback(data, true);
+    error = data->set.fsockopt(data->set.sockopt_client,
+                               ctx->sock, CURLSOCKTYPE_ACCEPT);
+    Curl_set_in_callback(data, false);
+
+    if(error)
+      return CURLE_ABORTED_BY_CALLBACK;
+  }
+  return CURLE_OK;
 }
 
 struct Curl_cftype Curl_cft_tcp_accept = {
@@ -2075,13 +2225,12 @@
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
 
+  ctx->started_at = Curl_now();
   conn->sock[sockindex] = ctx->sock;
   set_local_ip(cf, data);
-  ctx->active = TRUE;
-  ctx->connected_at = Curl_now();
-  cf->connected = TRUE;
-  CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%" FMT_SOCKET_T ")",
-              ctx->sock);
+  CURL_TRC_CF(data, cf, "set filter for listen socket fd=%" FMT_SOCKET_T
+              " ip=%s:%d", ctx->sock,
+              ctx->ip.local_ip, ctx->ip.local_port);
 
 out:
   if(result) {
@@ -2091,67 +2240,16 @@
   return result;
 }
 
-static void set_accepted_remote_ip(struct Curl_cfilter *cf,
-                                   struct Curl_easy *data)
+bool Curl_conn_is_tcp_listen(struct Curl_easy *data,
+                             int sockindex)
 {
-  struct cf_socket_ctx *ctx = cf->ctx;
-#ifdef HAVE_GETPEERNAME
-  char buffer[STRERROR_LEN];
-  struct Curl_sockaddr_storage ssrem;
-  curl_socklen_t plen;
-
-  ctx->ip.remote_ip[0] = 0;
-  ctx->ip.remote_port = 0;
-  plen = sizeof(ssrem);
-  memset(&ssrem, 0, plen);
-  if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
-    int error = SOCKERRNO;
-    failf(data, "getpeername() failed with errno %d: %s",
-          error, Curl_strerror(error, buffer, sizeof(buffer)));
-    return;
+  struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
+  while(cf) {
+    if(cf->cft == &Curl_cft_tcp_accept)
+      return TRUE;
+    cf = cf->next;
   }
-  if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
-                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
-    failf(data, "ssrem inet_ntop() failed with errno %d: %s",
-          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
-    return;
-  }
-#else
-  ctx->ip.remote_ip[0] = 0;
-  ctx->ip.remote_port = 0;
-  (void)data;
-#endif
-}
-
-CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
-                                    struct connectdata *conn,
-                                    int sockindex, curl_socket_t *s)
-{
-  struct Curl_cfilter *cf = NULL;
-  struct cf_socket_ctx *ctx = NULL;
-
-  cf = conn->cfilter[sockindex];
-  if(!cf || cf->cft != &Curl_cft_tcp_accept)
-    return CURLE_FAILED_INIT;
-
-  ctx = cf->ctx;
-  DEBUGASSERT(ctx->listening);
-  /* discard the listen socket */
-  socket_close(data, conn, TRUE, ctx->sock);
-  ctx->listening = FALSE;
-  ctx->sock = *s;
-  conn->sock[sockindex] = ctx->sock;
-  set_accepted_remote_ip(cf, data);
-  set_local_ip(cf, data);
-  ctx->active = TRUE;
-  ctx->accepted = TRUE;
-  ctx->connected_at = Curl_now();
-  cf->connected = TRUE;
-  CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
-              ", remote=%s port=%d)",
-              ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
-
-  return CURLE_OK;
+  return FALSE;
 }
 
 /**
diff --git a/Utilities/cmcurl/lib/cf-socket.h b/Utilities/cmcurl/lib/cf-socket.h
index 35225f1..6510349 100644
--- a/Utilities/cmcurl/lib/cf-socket.h
+++ b/Utilities/cmcurl/lib/cf-socket.h
@@ -52,7 +52,7 @@
     struct Curl_sockaddr_storage buff;
   } _sa_ex_u;
 };
-#define sa_addr _sa_ex_u.addr
+#define curl_sa_addr _sa_ex_u.addr
 
 /*
  * Parse interface option, and return the interface name and the host part.
@@ -147,12 +147,11 @@
                                   curl_socket_t *s);
 
 /**
- * Replace the listen socket with the accept()ed one.
+ * Return TRUE iff the last filter at `sockindex` was set via
+ * Curl_conn_tcp_listen_set().
  */
-CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
-                                    struct connectdata *conn,
-                                    int sockindex,
-                                    curl_socket_t *s);
+bool Curl_conn_is_tcp_listen(struct Curl_easy *data,
+                             int sockindex);
 
 /**
  * Peek at the socket and remote ip/port the socket filter is using.
diff --git a/Utilities/cmcurl/lib/cfilters.c b/Utilities/cmcurl/lib/cfilters.c
index 3d7da0c..ca1d7b3 100644
--- a/Utilities/cmcurl/lib/cfilters.c
+++ b/Utilities/cmcurl/lib/cfilters.c
@@ -96,7 +96,7 @@
 bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
                               const struct Curl_easy *data)
 {
-  return cf->next?
+  return cf->next ?
     cf->next->cft->has_data_pending(cf->next, data) : FALSE;
 }
 
@@ -104,7 +104,7 @@
                           const void *buf, size_t len, bool eos,
                           CURLcode *err)
 {
-  return cf->next?
+  return cf->next ?
     cf->next->cft->do_send(cf->next, data, buf, len, eos, err) :
     CURLE_RECV_ERROR;
 }
@@ -112,7 +112,7 @@
 ssize_t  Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
                           char *buf, size_t len, CURLcode *err)
 {
-  return cf->next?
+  return cf->next ?
     cf->next->cft->do_recv(cf->next, data, buf, len, err) :
     CURLE_SEND_ERROR;
 }
@@ -121,7 +121,7 @@
                                struct Curl_easy *data,
                                bool *input_pending)
 {
-  return cf->next?
+  return cf->next ?
     cf->next->cft->is_alive(cf->next, data, input_pending) :
     FALSE; /* pessimistic in absence of data */
 }
@@ -129,7 +129,7 @@
 CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
                                      struct Curl_easy *data)
 {
-  return cf->next?
+  return cf->next ?
     cf->next->cft->keep_alive(cf->next, data) :
     CURLE_OK;
 }
@@ -138,7 +138,7 @@
                            struct Curl_easy *data,
                            int query, int *pres1, void *pres2)
 {
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
@@ -204,13 +204,14 @@
   now = Curl_now();
   if(!Curl_shutdown_started(data, sockindex)) {
     DEBUGF(infof(data, "shutdown start on%s connection",
-           sockindex? " secondary" : ""));
+           sockindex ? " secondary" : ""));
     Curl_shutdown_start(data, sockindex, &now);
   }
   else {
     timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
     if(timeout_ms < 0) {
-      failf(data, "SSL shutdown timeout");
+      /* info message, since this might be regarded as acceptable */
+      infof(data, "shutdown timeout");
       return CURLE_OPERATION_TIMEDOUT;
     }
   }
@@ -483,12 +484,12 @@
 
 bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
 {
-  return conn? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
+  return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
 }
 
 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
 {
-  struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+  struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
 
   for(; cf; cf = cf->next) {
     if(cf->cft->flags & CF_TYPE_MULTIPLEX)
@@ -522,10 +523,10 @@
                               struct Curl_easy *data)
 {
   CURLcode result;
-  int pending = FALSE;
-  result = cf? cf->cft->query(cf, data, CF_QUERY_NEED_FLUSH,
-                              &pending, NULL) : CURLE_UNKNOWN_OPTION;
-  return (result || pending == FALSE)? FALSE : TRUE;
+  int pending = 0;
+  result = cf ? cf->cft->query(cf, data, CF_QUERY_NEED_FLUSH,
+                               &pending, NULL) : CURLE_UNKNOWN_OPTION;
+  return (result || !pending) ? FALSE : TRUE;
 }
 
 bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex)
@@ -672,13 +673,13 @@
 {
   struct Curl_cfilter *cf;
 
-  cf = data->conn? data->conn->cfilter[sockindex] : NULL;
+  cf = data->conn ? data->conn->cfilter[sockindex] : NULL;
   /* if the top filter has not connected, ask it (and its sub-filters)
    * for the socket. Otherwise conn->sock[sockindex] should have it.
    */
   if(cf && !cf->connected)
     return Curl_conn_cf_get_socket(cf, data);
-  return data->conn? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
+  return data->conn ? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
 }
 
 void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
@@ -807,7 +808,7 @@
                               int sockindex)
 {
   struct Curl_cfilter *cf = conn->cfilter[sockindex];
-  return cf? cf->cft->keep_alive(cf, data) : CURLE_OK;
+  return cf ? cf->cft->keep_alive(cf, data) : CURLE_OK;
 }
 
 size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
@@ -818,9 +819,9 @@
   int n = 0;
 
   struct Curl_cfilter *cf = conn->cfilter[sockindex];
-  result = cf? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
-                              &n, NULL) : CURLE_UNKNOWN_OPTION;
-  return (result || n <= 0)? 1 : (size_t)n;
+  result = cf ? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
+                               &n, NULL) : CURLE_UNKNOWN_OPTION;
+  return (result || n <= 0) ? 1 : (size_t)n;
 }
 
 int Curl_conn_get_stream_error(struct Curl_easy *data,
@@ -831,9 +832,9 @@
   int n = 0;
 
   struct Curl_cfilter *cf = conn->cfilter[sockindex];
-  result = cf? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR,
-                              &n, NULL) : CURLE_UNKNOWN_OPTION;
-  return (result || n < 0)? 0 : n;
+  result = cf ? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR,
+                               &n, NULL) : CURLE_UNKNOWN_OPTION;
+  return (result || n < 0) ? 0 : n;
 }
 
 int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
@@ -854,7 +855,7 @@
   nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result);
   DEBUGASSERT(nread >= 0 || result);
   DEBUGASSERT(nread < 0 || !result);
-  *n = (nread >= 0)? (size_t)nread : 0;
+  *n = (nread >= 0) ? (size_t)nread : 0;
   return result;
 }
 
@@ -889,7 +890,7 @@
   nwritten = conn->send[sockindex](data, sockindex, buf, write_len, eos,
                                    &result);
   DEBUGASSERT((nwritten >= 0) || result);
-  *pnwritten = (nwritten < 0)? 0 : (size_t)nwritten;
+  *pnwritten = (nwritten < 0) ? 0 : (size_t)nwritten;
   return result;
 }
 
@@ -899,7 +900,7 @@
   size_t i;
   (void)data;
   memset(ps, 0, sizeof(*ps));
-  for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
+  for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++)
     ps->sockets[i] = CURL_SOCKET_BAD;
 }
 
@@ -961,8 +962,10 @@
                       bool do_in, bool do_out)
 {
   Curl_pollset_change(data, ps, sock,
-                      (do_in?CURL_POLL_IN:0)|(do_out?CURL_POLL_OUT:0),
-                      (!do_in?CURL_POLL_IN:0)|(!do_out?CURL_POLL_OUT:0));
+                      (do_in ? CURL_POLL_IN : 0)|
+                      (do_out ? CURL_POLL_OUT : 0),
+                      (!do_in ? CURL_POLL_IN : 0)|
+                      (!do_out ? CURL_POLL_OUT : 0));
 }
 
 static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c
index 8f47782..589205b 100644
--- a/Utilities/cmcurl/lib/conncache.c
+++ b/Utilities/cmcurl/lib/conncache.c
@@ -72,7 +72,7 @@
   } while(0)
 
 
-/* A list of connections to the same destinationn. */
+/* A list of connections to the same destination. */
 struct cpool_bundle {
   struct Curl_llist conns; /* connections in the bundle */
   size_t dest_len; /* total length of destination, including NUL */
@@ -163,16 +163,16 @@
   cpool->idata = curl_easy_init();
   if(!cpool->idata)
     return 1; /* bad */
-  cpool->idata->state.internal = true;
+  cpool->idata->state.internal = TRUE;
   /* TODO: this is quirky. We need an internal handle for certain
    * operations, but we do not add it to the multi (if there is one).
    * But we give it the multi so that socket event operations can work.
    * Probably better to have an internal handle owned by the multi that
    * can be used for cpool operations. */
   cpool->idata->multi = multi;
- #ifdef DEBUGBUILD
+#ifdef DEBUGBUILD
   if(getenv("CURL_DEBUG"))
-    cpool->idata->set.verbose = true;
+    cpool->idata->set.verbose = TRUE;
 #endif
 
   cpool->disconnect_cb = disconnect_cb;
@@ -269,25 +269,10 @@
 static void cpool_remove_bundle(struct cpool *cpool,
                                 struct cpool_bundle *bundle)
 {
-  struct Curl_hash_iterator iter;
-  struct Curl_hash_element *he;
-
   if(!cpool)
     return;
 
-  Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
-
-  he = Curl_hash_next_element(&iter);
-  while(he) {
-    if(he->ptr == bundle) {
-      /* The bundle is destroyed by the hash destructor function,
-         free_bundle_hash_entry() */
-      Curl_hash_delete(&cpool->dest2bundle, he->key, he->key_len);
-      return;
-    }
-
-    he = Curl_hash_next_element(&iter);
-  }
+  Curl_hash_delete(&cpool->dest2bundle, bundle->dest, bundle->dest_len);
 }
 
 static struct connectdata *
@@ -329,6 +314,9 @@
                    "limit of %zu", oldest_idle->connection_id,
                    Curl_llist_count(&bundle->conns), dest_limit));
       Curl_cpool_disconnect(data, oldest_idle, FALSE);
+
+      /* in case the bundle was destroyed in disconnect, look it up again */
+      bundle = cpool_find_bundle(cpool, conn);
     }
     if(bundle && (Curl_llist_count(&bundle->conns) >= dest_limit)) {
       result = CPOOL_LIMIT_DEST;
@@ -409,7 +397,7 @@
       cpool->num_conn--;
     }
     else {
-      /* Not in  a bundle, already in the shutdown list? */
+      /* Not in a bundle, already in the shutdown list? */
       DEBUGASSERT(list == &cpool->shutdowns);
     }
   }
@@ -491,7 +479,7 @@
                               struct connectdata *conn)
 {
   unsigned int maxconnects = !data->multi->maxconnects ?
-    data->multi->num_easy * 4: data->multi->maxconnects;
+    data->multi->num_easy * 4 : data->multi->maxconnects;
   struct connectdata *oldest_idle = NULL;
   struct cpool *cpool = cpool_get_instance(data);
   bool kept = TRUE;
@@ -820,7 +808,7 @@
   if(data->multi) {
     /* Add it to the multi's cpool for shutdown handling */
     infof(data, "%s connection #%" FMT_OFF_T,
-          aborted? "closing" : "shutting down", conn->connection_id);
+          aborted ? "closing" : "shutting down", conn->connection_id);
     cpool_discard_conn(&data->multi->cpool, data, conn, aborted);
   }
   else {
@@ -1180,7 +1168,7 @@
     timespent = Curl_timediff(Curl_now(), started);
     if(timespent >= (timediff_t)timeout_ms) {
       DEBUGF(infof(data, "cpool shutdown %s",
-                   (timeout_ms > 0)? "timeout" : "best effort done"));
+                   (timeout_ms > 0) ? "timeout" : "best effort done"));
       break;
     }
 
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index 923f37a..ee3b4c8 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -139,7 +139,7 @@
       return ctimeleft_ms; /* no general timeout, this is it */
   }
   /* return minimal time left or max amount already expired */
-  return (ctimeleft_ms < timeleft_ms)? ctimeleft_ms : timeleft_ms;
+  return (ctimeleft_ms < timeleft_ms) ? ctimeleft_ms : timeleft_ms;
 }
 
 void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
@@ -172,7 +172,7 @@
   }
   left_ms = conn->shutdown.timeout_ms -
             Curl_timediff(*nowp, conn->shutdown.start[sockindex]);
-  return left_ms? left_ms : -1;
+  return left_ms ? left_ms : -1;
 }
 
 timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
@@ -414,9 +414,9 @@
   if(!baller)
     return CURLE_OUT_OF_MEMORY;
 
-  baller->name = ((ai_family == AF_INET)? "ipv4" : (
+  baller->name = ((ai_family == AF_INET) ? "ipv4" : (
 #ifdef USE_IPV6
-                  (ai_family == AF_INET6)? "ipv6" :
+                  (ai_family == AF_INET6) ? "ipv6" :
 #endif
                   "ip"));
   baller->cf_create = cf_create;
@@ -424,7 +424,7 @@
   baller->ai_family = ai_family;
   baller->primary = primary;
   baller->delay_ms = delay_ms;
-  baller->timeoutms = addr_next_match(baller->addr, baller->ai_family)?
+  baller->timeoutms = addr_next_match(baller->addr, baller->ai_family) ?
     USETIME(timeout_ms) : timeout_ms;
   baller->timeout_id = timeout_id;
   baller->result = CURLE_COULDNT_CONNECT;
@@ -619,7 +619,7 @@
    * If transport is QUIC, we need to shutdown the ongoing 'other'
    * cot ballers in a QUIC appropriate way. */
 evaluate:
-  *connected = FALSE; /* a very negative world view is best */
+  *connected = FALSE; /* a negative world view is best */
   now = Curl_now();
   ongoing = not_started = 0;
   for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
@@ -1089,7 +1089,7 @@
     }
   }
 
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
@@ -1417,7 +1417,7 @@
   ctx = NULL;
 
 out:
-  *pcf = result? NULL : cf;
+  *pcf = result ? NULL : cf;
   free(ctx);
   return result;
 }
diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c
index 9552bb0..eda3d0a 100644
--- a/Utilities/cmcurl/lib/content_encoding.c
+++ b/Utilities/cmcurl/lib/content_encoding.c
@@ -33,13 +33,13 @@
 #endif
 
 #ifdef HAVE_BROTLI
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
 /* Ignore -Wvla warnings in brotli headers */
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wvla"
 #endif
 #include <brotli/decode.h>
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
 #pragma GCC diagnostic pop
 #endif
 #endif
@@ -154,7 +154,7 @@
 {
   z_stream *z = &zp->z;
   CURLcode result = CURLE_OK;
-  uInt len = z->avail_in < zp->trailerlen? z->avail_in: zp->trailerlen;
+  uInt len = z->avail_in < zp->trailerlen ? z->avail_in : zp->trailerlen;
 
   /* Consume expected trailer bytes. Terminate stream if exhausted.
      Issue an error if unexpected bytes follow. */
@@ -654,7 +654,7 @@
   (void) data;
 
   bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL);
-  return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
+  return bp->br ? CURLE_OK : CURLE_OUT_OF_MEMORY;
 }
 
 static CURLcode brotli_do_write(struct Curl_easy *data,
@@ -971,8 +971,8 @@
 CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                      const char *enclist, int is_transfer)
 {
-  Curl_cwriter_phase phase = is_transfer?
-                             CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE;
+  Curl_cwriter_phase phase = is_transfer ?
+    CURL_CW_TRANSFER_DECODE : CURL_CW_CONTENT_DECODE;
   CURLcode result;
 
   do {
@@ -995,7 +995,7 @@
       struct Curl_cwriter *writer;
 
       CURL_TRC_WRITE(data, "looking for %s decoder: %.*s",
-                     is_transfer? "transfer" : "content", (int)namelen, name);
+                     is_transfer ? "transfer" : "content", (int)namelen, name);
       is_chunked = (is_transfer && (namelen == 7) &&
                     strncasecompare(name, "chunked", 7));
       /* if we skip the decoding in this phase, do not look further.
@@ -1046,7 +1046,7 @@
 
       result = Curl_cwriter_create(&writer, data, cwt, phase);
       CURL_TRC_WRITE(data, "added %s decoder %s -> %d",
-                     is_transfer? "transfer" : "content", cwt->name, result);
+                     is_transfer ? "transfer" : "content", cwt->name, result);
       if(result)
         return result;
 
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c
index 95ca4a1..773e535 100644
--- a/Utilities/cmcurl/lib/cookie.c
+++ b/Utilities/cmcurl/lib/cookie.c
@@ -28,33 +28,20 @@
 RECEIVING COOKIE INFORMATION
 ============================
 
-struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
-                    const char *file, struct CookieInfo *inc, bool newsession);
+Curl_cookie_init()
 
         Inits a cookie struct to store data in a local file. This is always
         called before any cookies are set.
 
-struct Cookie *Curl_cookie_add(struct Curl_easy *data,
-                 struct CookieInfo *c, bool httpheader, bool noexpire,
-                 char *lineptr, const char *domain, const char *path,
-                 bool secure);
+Curl_cookie_add()
 
-        The 'lineptr' parameter is a full "Set-cookie:" line as
-        received from a server.
-
-        The function need to replace previously stored lines that this new
-        line supersedes.
-
-        It may remove lines that are expired.
-
-        It should return an indication of success/error.
+        Adds a cookie to the in-memory cookie jar.
 
 
 SENDING COOKIE INFORMATION
 ==========================
 
-struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie,
-                                    char *host, char *path, bool secure);
+Curl_cookie_getlist()
 
         For a given host and path, return a linked list of cookies that
         the client should send to the server if used now. The secure
@@ -63,7 +50,6 @@
 
         It shall only return cookies that have not expired.
 
-
 Example set of cookies:
 
     Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
@@ -102,6 +88,7 @@
 #include "rename.h"
 #include "fopen.h"
 #include "strdup.h"
+#include "llist.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -245,7 +232,7 @@
   if(outlen)
     *outlen = len;
 
-  return first? first: domain;
+  return first ? first : domain;
 }
 
 /* Avoid C1001, an "internal error" with MSVC14 */
@@ -335,17 +322,17 @@
   if(list) {
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
     while(list) {
-      struct CookieInfo *newcookies =
+      struct CookieInfo *ci =
         Curl_cookie_init(data, list->data, data->cookies,
                          data->set.cookiesession);
-      if(!newcookies)
+      if(!ci)
         /*
          * Failure may be due to OOM or a bad cookie; both are ignored
          * but only the first should be
          */
         infof(data, "ignoring failed cookie_init for %s", list->data);
       else
-        data->cookies = newcookies;
+        data->cookies = ci;
       list = list->next;
     }
     Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
@@ -378,9 +365,9 @@
  * more cookies expire, then processing will exit early in case this timestamp
  * is in the future.
  */
-static void remove_expired(struct CookieInfo *cookies)
+static void remove_expired(struct CookieInfo *ci)
 {
-  struct Cookie *co, *nx;
+  struct Cookie *co;
   curl_off_t now = (curl_off_t)time(NULL);
   unsigned int i;
 
@@ -392,37 +379,32 @@
    * recorded first expiration is the max offset, then perform the safe
    * fallback of checking all cookies.
    */
-  if(now < cookies->next_expiration &&
-      cookies->next_expiration != CURL_OFF_T_MAX)
+  if(now < ci->next_expiration &&
+     ci->next_expiration != CURL_OFF_T_MAX)
     return;
   else
-    cookies->next_expiration = CURL_OFF_T_MAX;
+    ci->next_expiration = CURL_OFF_T_MAX;
 
   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
-    struct Cookie *pv = NULL;
-    co = cookies->cookies[i];
-    while(co) {
-      nx = co->next;
+    struct Curl_llist_node *n;
+    struct Curl_llist_node *e = NULL;
+
+    for(n = Curl_llist_head(&ci->cookielist[i]); n; n = e) {
+      co = Curl_node_elem(n);
+      e = Curl_node_next(n);
       if(co->expires && co->expires < now) {
-        if(!pv) {
-          cookies->cookies[i] = co->next;
-        }
-        else {
-          pv->next = co->next;
-        }
-        cookies->numcookies--;
+        Curl_node_remove(n);
         freecookie(co);
+        ci->numcookies--;
       }
       else {
         /*
-         * If this cookie has an expiration timestamp earlier than what we have
-         * seen so far then record it for the next round of expirations.
+         * If this cookie has an expiration timestamp earlier than what we
+         * have seen so far then record it for the next round of expirations.
          */
-        if(co->expires && co->expires < cookies->next_expiration)
-          cookies->next_expiration = co->expires;
-        pv = co;
+        if(co->expires && co->expires < ci->next_expiration)
+          ci->next_expiration = co->expires;
       }
-      co = nx;
     }
   }
 }
@@ -470,558 +452,489 @@
   return (p[len] != '\0');
 }
 
-/*
- * Curl_cookie_add
- *
- * Add a single cookie line to the cookie keeping object. Be aware that
- * sometimes we get an IP-only hostname, and that might also be a numerical
- * IPv6 address.
- *
- * Returns NULL on out of memory or invalid cookie. This is suboptimal,
- * as they should be treated separately.
- */
-struct Cookie *
-Curl_cookie_add(struct Curl_easy *data,
-                struct CookieInfo *c,
-                bool httpheader, /* TRUE if HTTP header-style line */
-                bool noexpire, /* if TRUE, skip remove_expired() */
-                const char *lineptr,   /* first character of the line */
-                const char *domain, /* default domain */
-                const char *path,   /* full path used when this cookie is set,
-                                       used to get default path for the cookie
-                                       unless set */
-                bool secure)  /* TRUE if connection is over secure origin */
+#define CERR_OK            0
+#define CERR_TOO_LONG      1 /* input line too long */
+#define CERR_TAB           2 /* in a wrong place */
+#define CERR_TOO_BIG       3 /* name/value too large */
+#define CERR_BAD           4 /* deemed incorrect */
+#define CERR_NO_SEP        5 /* semicolon problem */
+#define CERR_NO_NAME_VALUE 6 /* name or value problem */
+#define CERR_INVALID_OCTET 7 /* bad content */
+#define CERR_BAD_SECURE    8 /* secure in a bad place */
+#define CERR_OUT_OF_MEMORY 9
+#define CERR_NO_TAILMATCH  10
+#define CERR_COMMENT       11 /* a commented line */
+#define CERR_RANGE         12 /* expire range problem */
+#define CERR_FIELDS        13 /* incomplete netscape line */
+#define CERR_PSL           14 /* a public suffix */
+#define CERR_LIVE_WINS     15
+
+static int
+parse_cookie_header(struct Curl_easy *data,
+                    struct Cookie *co,
+                    struct CookieInfo *ci,
+                    const char *ptr,
+                    const char *domain, /* default domain */
+                    const char *path,   /* full path used when this cookie is
+                                           set, used to get default path for
+                                           the cookie unless set */
+                    bool secure)  /* TRUE if connection is over secure
+                                     origin */
 {
-  struct Cookie *clist;
-  struct Cookie *co;
-  struct Cookie *lastc = NULL;
-  struct Cookie *replace_co = NULL;
-  struct Cookie *replace_clist = NULL;
-  time_t now = time(NULL);
-  bool replace_old = FALSE;
-  bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
-  size_t myhash;
+  /* This line was read off an HTTP-header */
+  time_t now;
+  size_t linelength = strlen(ptr);
+  if(linelength > MAX_COOKIE_LINE)
+    /* discard overly long lines at once */
+    return CERR_TOO_LONG;
 
-  DEBUGASSERT(data);
-  DEBUGASSERT(MAX_SET_COOKIE_AMOUNT <= 255); /* counter is an unsigned char */
-  if(data->req.setcookies >= MAX_SET_COOKIE_AMOUNT)
-    return NULL;
+  now = time(NULL);
+  do {
+    size_t vlen;
+    size_t nlen;
 
-  /* First, alloc and init a new struct for it */
-  co = calloc(1, sizeof(struct Cookie));
-  if(!co)
-    return NULL; /* bail out if we are this low on memory */
+    while(*ptr && ISBLANK(*ptr))
+      ptr++;
 
-  if(httpheader) {
-    /* This line was read off an HTTP-header */
-    const char *ptr;
+    /* we have a <name>=<value> pair or a stand-alone word here */
+    nlen = strcspn(ptr, ";\t\r\n=");
+    if(nlen) {
+      bool done = FALSE;
+      bool sep = FALSE;
+      const char *namep = ptr;
+      const char *valuep;
 
-    size_t linelength = strlen(lineptr);
-    if(linelength > MAX_COOKIE_LINE) {
-      /* discard overly long lines at once */
-      free(co);
-      return NULL;
-    }
+      ptr += nlen;
 
-    ptr = lineptr;
-    do {
-      size_t vlen;
-      size_t nlen;
+      /* trim trailing spaces and tabs after name */
+      while(nlen && ISBLANK(namep[nlen - 1]))
+        nlen--;
 
-      while(*ptr && ISBLANK(*ptr))
-        ptr++;
+      if(*ptr == '=') {
+        vlen = strcspn(++ptr, ";\r\n");
+        valuep = ptr;
+        sep = TRUE;
+        ptr = &valuep[vlen];
 
-      /* we have a <name>=<value> pair or a stand-alone word here */
-      nlen = strcspn(ptr, ";\t\r\n=");
-      if(nlen) {
-        bool done = FALSE;
-        bool sep = FALSE;
-        const char *namep = ptr;
-        const char *valuep;
+        /* Strip off trailing whitespace from the value */
+        while(vlen && ISBLANK(valuep[vlen-1]))
+          vlen--;
 
-        ptr += nlen;
-
-        /* trim trailing spaces and tabs after name */
-        while(nlen && ISBLANK(namep[nlen - 1]))
-          nlen--;
-
-        if(*ptr == '=') {
-          vlen = strcspn(++ptr, ";\r\n");
-          valuep = ptr;
-          sep = TRUE;
-          ptr = &valuep[vlen];
-
-          /* Strip off trailing whitespace from the value */
-          while(vlen && ISBLANK(valuep[vlen-1]))
-            vlen--;
-
-          /* Skip leading whitespace from the value */
-          while(vlen && ISBLANK(*valuep)) {
-            valuep++;
-            vlen--;
-          }
-
-          /* Reject cookies with a TAB inside the value */
-          if(memchr(valuep, '\t', vlen)) {
-            freecookie(co);
-            infof(data, "cookie contains TAB, dropping");
-            return NULL;
-          }
-        }
-        else {
-          valuep = NULL;
-          vlen = 0;
+        /* Skip leading whitespace from the value */
+        while(vlen && ISBLANK(*valuep)) {
+          valuep++;
+          vlen--;
         }
 
-        /*
-         * Check for too long individual name or contents, or too long
-         * combination of name + contents. Chrome and Firefox support 4095 or
-         * 4096 bytes combo
-         */
-        if(nlen >= (MAX_NAME-1) || vlen >= (MAX_NAME-1) ||
-           ((nlen + vlen) > MAX_NAME)) {
-          freecookie(co);
-          infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
-                nlen, vlen);
-          return NULL;
+        /* Reject cookies with a TAB inside the value */
+        if(memchr(valuep, '\t', vlen)) {
+          infof(data, "cookie contains TAB, dropping");
+          return CERR_TAB;
         }
-
-        /*
-         * 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
-         * "the rest". Prefixes must start with '__' and end with a '-', so
-         * only test for names where that can possibly be true.
-         */
-        if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') {
-          if(strncasecompare("__Secure-", namep, 9))
-            co->prefix |= COOKIE_PREFIX__SECURE;
-          else if(strncasecompare("__Host-", namep, 7))
-            co->prefix |= COOKIE_PREFIX__HOST;
-        }
-
-        /*
-         * Use strstore() below to properly deal with received cookie
-         * headers that have the same string property set more than once,
-         * and then we use the last one.
-         */
-
-        if(!co->name) {
-          /* The very first name/value pair is the actual cookie name */
-          if(!sep) {
-            /* Bad name/value pair. */
-            badcookie = TRUE;
-            break;
-          }
-          strstore(&co->name, namep, nlen);
-          strstore(&co->value, valuep, vlen);
-          done = TRUE;
-          if(!co->name || !co->value) {
-            badcookie = TRUE;
-            break;
-          }
-          if(invalid_octets(co->value) || invalid_octets(co->name)) {
-            infof(data, "invalid octets in name/value, cookie dropped");
-            badcookie = TRUE;
-            break;
-          }
-        }
-        else if(!vlen) {
-          /*
-           * this was a "<name>=" with no content, and we must allow
-           * 'secure' and 'httponly' specified this weirdly
-           */
-          done = TRUE;
-          /*
-           * secure cookies are only allowed to be set when the connection is
-           * using a secure protocol, or when the cookie is being set by
-           * reading from file
-           */
-          if((nlen == 6) && strncasecompare("secure", namep, 6)) {
-            if(secure || !c->running) {
-              co->secure = TRUE;
-            }
-            else {
-              badcookie = TRUE;
-              break;
-            }
-          }
-          else if((nlen == 8) && strncasecompare("httponly", namep, 8))
-            co->httponly = TRUE;
-          else if(sep)
-            /* there was a '=' so we are not done parsing this field */
-            done = FALSE;
-        }
-        if(done)
-          ;
-        else if((nlen == 4) && strncasecompare("path", namep, 4)) {
-          strstore(&co->path, valuep, vlen);
-          if(!co->path) {
-            badcookie = TRUE; /* out of memory bad */
-            break;
-          }
-          free(co->spath); /* if this is set again */
-          co->spath = sanitize_cookie_path(co->path);
-          if(!co->spath) {
-            badcookie = TRUE; /* out of memory bad */
-            break;
-          }
-        }
-        else if((nlen == 6) &&
-                strncasecompare("domain", namep, 6) && vlen) {
-          bool is_ip;
-
-          /*
-           * Now, we make sure that our host is within the given domain, or
-           * the given domain is not valid and thus cannot be set.
-           */
-
-          if('.' == valuep[0]) {
-            valuep++; /* ignore preceding dot */
-            vlen--;
-          }
-
-#ifndef USE_LIBPSL
-          /*
-           * Without PSL we do not know when the incoming cookie is set on a
-           * TLD or otherwise "protected" suffix. To reduce risk, we require a
-           * dot OR the exact hostname being "localhost".
-           */
-          if(bad_domain(valuep, vlen))
-            domain = ":";
-#endif
-
-          is_ip = Curl_host_is_ipnum(domain ? domain : valuep);
-
-          if(!domain
-             || (is_ip && !strncmp(valuep, domain, vlen) &&
-                 (vlen == strlen(domain)))
-             || (!is_ip && cookie_tailmatch(valuep, vlen, domain))) {
-            strstore(&co->domain, valuep, vlen);
-            if(!co->domain) {
-              badcookie = TRUE;
-              break;
-            }
-            if(!is_ip)
-              co->tailmatch = TRUE; /* we always do that if the domain name was
-                                       given */
-          }
-          else {
-            /*
-             * We did not get a tailmatch and then the attempted set domain is
-             * not a domain to which the current host belongs. Mark as bad.
-             */
-            badcookie = TRUE;
-            infof(data, "skipped cookie with bad tailmatch domain: %s",
-                  valuep);
-          }
-        }
-        else if((nlen == 7) && strncasecompare("version", namep, 7)) {
-          /* just ignore */
-        }
-        else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
-          /*
-           * Defined in RFC2109:
-           *
-           * Optional. The Max-Age attribute defines the lifetime of the
-           * cookie, in seconds. The delta-seconds value is a decimal non-
-           * negative integer. After delta-seconds seconds elapse, the
-           * client should discard the cookie. A value of zero means the
-           * cookie should be discarded immediately.
-           */
-          CURLofft offt;
-          const char *maxage = valuep;
-          offt = curlx_strtoofft((*maxage == '\"')?
-                                 &maxage[1]:&maxage[0], NULL, 10,
-                                 &co->expires);
-          switch(offt) {
-          case CURL_OFFT_FLOW:
-            /* overflow, used max value */
-            co->expires = CURL_OFF_T_MAX;
-            break;
-          case CURL_OFFT_INVAL:
-            /* negative or otherwise bad, expire */
-            co->expires = 1;
-            break;
-          case CURL_OFFT_OK:
-            if(!co->expires)
-              /* already expired */
-              co->expires = 1;
-            else if(CURL_OFF_T_MAX - now < co->expires)
-              /* would overflow */
-              co->expires = CURL_OFF_T_MAX;
-            else
-              co->expires += now;
-            break;
-          }
-        }
-        else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
-          char date[128];
-          if(!co->expires && (vlen < sizeof(date))) {
-            /* copy the date so that it can be null terminated */
-            memcpy(date, valuep, vlen);
-            date[vlen] = 0;
-            /*
-             * Let max-age have priority.
-             *
-             * If the date cannot get parsed for whatever reason, the cookie
-             * will be treated as a session cookie
-             */
-            co->expires = Curl_getdate_capped(date);
-
-            /*
-             * Session cookies have expires set to 0 so if we get that back
-             * from the date parser let's add a second to make it a
-             * non-session cookie
-             */
-            if(co->expires == 0)
-              co->expires = 1;
-            else if(co->expires < 0)
-              co->expires = 0;
-          }
-        }
-
-        /*
-         * Else, this is the second (or more) name we do not know about!
-         */
       }
       else {
-        /* this is an "illegal" <what>=<this> pair */
+        valuep = NULL;
+        vlen = 0;
       }
 
-      while(*ptr && ISBLANK(*ptr))
-        ptr++;
-      if(*ptr == ';')
-        ptr++;
-      else
-        break;
-    } while(1);
-
-    if(!badcookie && !co->domain) {
-      if(domain) {
-        /* no domain was given in the header line, set the default */
-        co->domain = strdup(domain);
-        if(!co->domain)
-          badcookie = TRUE;
+      /*
+       * Check for too long individual name or contents, or too long
+       * combination of name + contents. Chrome and Firefox support 4095 or
+       * 4096 bytes combo
+       */
+      if(nlen >= (MAX_NAME-1) || vlen >= (MAX_NAME-1) ||
+         ((nlen + vlen) > MAX_NAME)) {
+        infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
+              nlen, vlen);
+        return CERR_TOO_BIG;
       }
-    }
-
-    if(!badcookie && !co->path && path) {
-      /*
-       * No path was given in the header line, set the default. Note that the
-       * passed-in path to this function MAY have a '?' and following part that
-       * MUST NOT be stored as part of the path.
-       */
-      char *queryp = strchr(path, '?');
 
       /*
-       * queryp is where the interesting part of the path ends, so now we
-       * want to the find the last
+       * 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
+       * "the rest". Prefixes must start with '__' and end with a '-', so
+       * only test for names where that can possibly be true.
        */
-      char *endslash;
-      if(!queryp)
-        endslash = strrchr(path, '/');
-      else
-        endslash = memrchr(path, '/', (queryp - path));
-      if(endslash) {
-        size_t pathlen = (endslash-path + 1); /* include end slash */
-        co->path = Curl_memdup0(path, pathlen);
-        if(co->path) {
-          co->spath = sanitize_cookie_path(co->path);
-          if(!co->spath)
-            badcookie = TRUE; /* out of memory bad */
+      if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') {
+        if(strncasecompare("__Secure-", namep, 9))
+          co->prefix_secure = TRUE;
+        else if(strncasecompare("__Host-", namep, 7))
+          co->prefix_host = TRUE;
+      }
+
+      /*
+       * Use strstore() below to properly deal with received cookie
+       * headers that have the same string property set more than once,
+       * and then we use the last one.
+       */
+
+      if(!co->name) {
+        /* The very first name/value pair is the actual cookie name */
+        if(!sep)
+          /* Bad name/value pair. */
+          return CERR_NO_SEP;
+
+        strstore(&co->name, namep, nlen);
+        strstore(&co->value, valuep, vlen);
+        done = TRUE;
+        if(!co->name || !co->value)
+          return CERR_NO_NAME_VALUE;
+
+        if(invalid_octets(co->value) || invalid_octets(co->name)) {
+          infof(data, "invalid octets in name/value, cookie dropped");
+          return CERR_INVALID_OCTET;
         }
-        else
-          badcookie = TRUE;
       }
-    }
-
-    /*
-     * If we did not get a cookie name, or a bad one, the this is an illegal
-     * line so bail out.
-     */
-    if(badcookie || !co->name) {
-      freecookie(co);
-      return NULL;
-    }
-    data->req.setcookies++;
-  }
-  else {
-    /*
-     * This line is NOT an HTTP header style line, we do offer support for
-     * reading the odd netscape cookies-file format here
-     */
-    char *ptr;
-    char *firstptr;
-    char *tok_buf = NULL;
-    int fields;
-
-    /*
-     * IE introduced HTTP-only cookies to prevent XSS attacks. Cookies marked
-     * with httpOnly after the domain name are not accessible from javascripts,
-     * but since curl does not operate at javascript level, we include them
-     * anyway. In Firefox's cookie files, these lines are preceded with
-     * #HttpOnly_ and then everything is as usual, so we skip 10 characters of
-     * the line..
-     */
-    if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
-      lineptr += 10;
-      co->httponly = TRUE;
-    }
-
-    if(lineptr[0]=='#') {
-      /* do not even try the comments */
-      free(co);
-      return NULL;
-    }
-    /* strip off the possible end-of-line characters */
-    ptr = strchr(lineptr, '\r');
-    if(ptr)
-      *ptr = 0; /* clear it */
-    ptr = strchr(lineptr, '\n');
-    if(ptr)
-      *ptr = 0; /* clear it */
-
-    firstptr = strtok_r((char *)lineptr, "\t", &tok_buf); /* tokenize on TAB */
-
-    /*
-     * Now loop through the fields and init the struct we already have
-     * allocated
-     */
-    fields = 0;
-    for(ptr = firstptr; ptr && !badcookie;
-        ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
-      switch(fields) {
-      case 0:
-        if(ptr[0]=='.') /* skip preceding dots */
-          ptr++;
-        co->domain = strdup(ptr);
-        if(!co->domain)
-          badcookie = TRUE;
-        break;
-      case 1:
+      else if(!vlen) {
         /*
-         * flag: A TRUE/FALSE value indicating if all machines within a given
-         * domain can access the variable. Set TRUE when the cookie says
-         * .domain.com and to false when the domain is complete www.domain.com
+         * this was a "<name>=" with no content, and we must allow
+         * 'secure' and 'httponly' specified this weirdly
          */
-        co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
-        break;
-      case 2:
-        /* The file format allows the path field to remain not filled in */
-        if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
-          /* only if the path does not look like a boolean option! */
-          co->path = strdup(ptr);
-          if(!co->path)
-            badcookie = TRUE;
-          else {
-            co->spath = sanitize_cookie_path(co->path);
-            if(!co->spath) {
-              badcookie = TRUE; /* out of memory bad */
-            }
+        done = TRUE;
+        /*
+         * secure cookies are only allowed to be set when the connection is
+         * using a secure protocol, or when the cookie is being set by
+         * reading from file
+         */
+        if((nlen == 6) && strncasecompare("secure", namep, 6)) {
+          if(secure || !ci->running) {
+            co->secure = TRUE;
           }
+          else {
+            return CERR_BAD_SECURE;
+          }
+        }
+        else if((nlen == 8) && strncasecompare("httponly", namep, 8))
+          co->httponly = TRUE;
+        else if(sep)
+          /* there was a '=' so we are not done parsing this field */
+          done = FALSE;
+      }
+      if(done)
+        ;
+      else if((nlen == 4) && strncasecompare("path", namep, 4)) {
+        strstore(&co->path, valuep, vlen);
+        if(!co->path)
+          return CERR_OUT_OF_MEMORY;
+        free(co->spath); /* if this is set again */
+        co->spath = sanitize_cookie_path(co->path);
+        if(!co->spath)
+          return CERR_OUT_OF_MEMORY;
+      }
+      else if((nlen == 6) &&
+              strncasecompare("domain", namep, 6) && vlen) {
+        bool is_ip;
+
+        /*
+         * Now, we make sure that our host is within the given domain, or
+         * the given domain is not valid and thus cannot be set.
+         */
+
+        if('.' == valuep[0]) {
+          valuep++; /* ignore preceding dot */
+          vlen--;
+        }
+
+#ifndef USE_LIBPSL
+        /*
+         * Without PSL we do not know when the incoming cookie is set on a
+         * TLD or otherwise "protected" suffix. To reduce risk, we require a
+         * dot OR the exact hostname being "localhost".
+         */
+        if(bad_domain(valuep, vlen))
+          domain = ":";
+#endif
+
+        is_ip = Curl_host_is_ipnum(domain ? domain : valuep);
+
+        if(!domain
+           || (is_ip && !strncmp(valuep, domain, vlen) &&
+               (vlen == strlen(domain)))
+           || (!is_ip && cookie_tailmatch(valuep, vlen, domain))) {
+          strstore(&co->domain, valuep, vlen);
+          if(!co->domain)
+            return CERR_OUT_OF_MEMORY;
+
+          if(!is_ip)
+            co->tailmatch = TRUE; /* we always do that if the domain name was
+                                     given */
+        }
+        else {
+          /*
+           * We did not get a tailmatch and then the attempted set domain is
+           * not a domain to which the current host belongs. Mark as bad.
+           */
+          infof(data, "skipped cookie with bad tailmatch domain: %s",
+                valuep);
+          return CERR_NO_TAILMATCH;
+        }
+      }
+      else if((nlen == 7) && strncasecompare("version", namep, 7)) {
+        /* just ignore */
+      }
+      else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
+        /*
+         * Defined in RFC2109:
+         *
+         * Optional. The Max-Age attribute defines the lifetime of the
+         * cookie, in seconds. The delta-seconds value is a decimal non-
+         * negative integer. After delta-seconds seconds elapse, the
+         * client should discard the cookie. A value of zero means the
+         * cookie should be discarded immediately.
+         */
+        CURLofft offt;
+        const char *maxage = valuep;
+        offt = curlx_strtoofft((*maxage == '\"') ?
+                               &maxage[1] : &maxage[0], NULL, 10,
+                               &co->expires);
+        switch(offt) {
+        case CURL_OFFT_FLOW:
+          /* overflow, used max value */
+          co->expires = CURL_OFF_T_MAX;
+          break;
+        case CURL_OFFT_INVAL:
+          /* negative or otherwise bad, expire */
+          co->expires = 1;
+          break;
+        case CURL_OFFT_OK:
+          if(!co->expires)
+            /* already expired */
+            co->expires = 1;
+          else if(CURL_OFF_T_MAX - now < co->expires)
+            /* would overflow */
+            co->expires = CURL_OFF_T_MAX;
+          else
+            co->expires += now;
           break;
         }
-        /* this does not look like a path, make one up! */
-        co->path = strdup("/");
-        if(!co->path)
-          badcookie = TRUE;
-        co->spath = strdup("/");
-        if(!co->spath)
-          badcookie = TRUE;
-        fields++; /* add a field and fall down to secure */
-        FALLTHROUGH();
-      case 3:
-        co->secure = FALSE;
-        if(strcasecompare(ptr, "TRUE")) {
-          if(secure || c->running)
-            co->secure = TRUE;
-          else
-            badcookie = TRUE;
-        }
-        break;
-      case 4:
-        if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
-          badcookie = TRUE;
-        break;
-      case 5:
-        co->name = strdup(ptr);
-        if(!co->name)
-          badcookie = TRUE;
-        else {
-          /* For Netscape file format cookies we check prefix on the name */
-          if(strncasecompare("__Secure-", co->name, 9))
-            co->prefix |= COOKIE_PREFIX__SECURE;
-          else if(strncasecompare("__Host-", co->name, 7))
-            co->prefix |= COOKIE_PREFIX__HOST;
-        }
-        break;
-      case 6:
-        co->value = strdup(ptr);
-        if(!co->value)
-          badcookie = TRUE;
-        break;
       }
-    }
-    if(6 == fields) {
-      /* we got a cookie with blank contents, fix it */
-      co->value = strdup("");
-      if(!co->value)
-        badcookie = TRUE;
-      else
-        fields++;
-    }
+      else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
+        if(!co->expires) {
+          /*
+           * Let max-age have priority.
+           *
+           * If the date cannot get parsed for whatever reason, the cookie
+           * will be treated as a session cookie
+           */
+          co->expires = Curl_getdate_capped(valuep);
 
-    if(!badcookie && (7 != fields))
-      /* we did not find the sufficient number of fields */
-      badcookie = TRUE;
+          /*
+           * Session cookies have expires set to 0 so if we get that back
+           * from the date parser let's add a second to make it a
+           * non-session cookie
+           */
+          if(co->expires == 0)
+            co->expires = 1;
+          else if(co->expires < 0)
+            co->expires = 0;
+        }
+      }
 
-    if(badcookie) {
-      freecookie(co);
-      return NULL;
+      /*
+       * Else, this is the second (or more) name we do not know about!
+       */
     }
-
-  }
-
-  if(co->prefix & COOKIE_PREFIX__SECURE) {
-    /* The __Secure- prefix only requires that the cookie be set secure */
-    if(!co->secure) {
-      freecookie(co);
-      return NULL;
-    }
-  }
-  if(co->prefix & COOKIE_PREFIX__HOST) {
-    /*
-     * The __Host- prefix requires the cookie to be secure, have a "/" path
-     * and not have a domain set.
-     */
-    if(co->secure && co->path && strcmp(co->path, "/") == 0 && !co->tailmatch)
-      ;
     else {
-      freecookie(co);
-      return NULL;
+      /* this is an "illegal" <what>=<this> pair */
+    }
+
+    while(*ptr && ISBLANK(*ptr))
+      ptr++;
+    if(*ptr == ';')
+      ptr++;
+    else
+      break;
+  } while(1);
+
+  if(!co->domain && domain) {
+    /* no domain was given in the header line, set the default */
+    co->domain = strdup(domain);
+    if(!co->domain)
+      return CERR_OUT_OF_MEMORY;
+  }
+
+  if(!co->path && path) {
+    /*
+     * No path was given in the header line, set the default. Note that the
+     * passed-in path to this function MAY have a '?' and following part that
+     * MUST NOT be stored as part of the path.
+     */
+    char *queryp = strchr(path, '?');
+
+    /*
+     * queryp is where the interesting part of the path ends, so now we
+     * want to the find the last
+     */
+    char *endslash;
+    if(!queryp)
+      endslash = strrchr(path, '/');
+    else
+      endslash = memrchr(path, '/', (queryp - path));
+    if(endslash) {
+      size_t pathlen = (endslash-path + 1); /* include end slash */
+      co->path = Curl_memdup0(path, pathlen);
+      if(co->path) {
+        co->spath = sanitize_cookie_path(co->path);
+        if(!co->spath)
+          return CERR_OUT_OF_MEMORY;
+      }
+      else
+        return CERR_OUT_OF_MEMORY;
     }
   }
 
-  if(!c->running &&    /* read from a file */
-     c->newsession &&  /* clean session cookies */
-     !co->expires) {   /* this is a session cookie since it does not expire! */
-    freecookie(co);
-    return NULL;
-  }
-
-  co->livecookie = c->running;
-  co->creationtime = ++c->lastct;
-
   /*
-   * Now we have parsed the incoming line, we must now check if this supersedes
-   * an already existing cookie, which it may if the previous have the same
-   * domain and path as this.
+   * If we did not get a cookie name, or a bad one, the this is an illegal
+   * line so bail out.
    */
+  if(!co->name)
+    return CERR_BAD;
 
-  /* at first, remove expired cookies */
-  if(!noexpire)
-    remove_expired(c);
+  data->req.setcookies++;
+  return CERR_OK;
+}
 
+static int
+parse_netscape(struct Cookie *co,
+               struct CookieInfo *ci,
+               const char *lineptr,
+               bool secure)  /* TRUE if connection is over secure
+                                origin */
+{
+  /*
+   * This line is NOT an HTTP header style line, we do offer support for
+   * reading the odd netscape cookies-file format here
+   */
+  char *ptr;
+  char *firstptr;
+  char *tok_buf = NULL;
+  int fields;
+
+  /*
+   * In 2008, Internet Explorer introduced HTTP-only cookies to prevent XSS
+   * attacks. Cookies marked httpOnly are not accessible to JavaScript. In
+   * Firefox's cookie files, they are prefixed #HttpOnly_ and the rest
+   * remains as usual, so we skip 10 characters of the line.
+   */
+  if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
+    lineptr += 10;
+    co->httponly = TRUE;
+  }
+
+  if(lineptr[0]=='#')
+    /* do not even try the comments */
+    return CERR_COMMENT;
+
+  /* strip off the possible end-of-line characters */
+  ptr = strchr(lineptr, '\r');
+  if(ptr)
+    *ptr = 0; /* clear it */
+  ptr = strchr(lineptr, '\n');
+  if(ptr)
+    *ptr = 0; /* clear it */
+
+  /* tokenize on TAB */
+  firstptr = Curl_strtok_r((char *)lineptr, "\t", &tok_buf);
+
+  /*
+   * Now loop through the fields and init the struct we already have
+   * allocated
+   */
+  fields = 0;
+  for(ptr = firstptr; ptr;
+      ptr = Curl_strtok_r(NULL, "\t", &tok_buf), fields++) {
+    switch(fields) {
+    case 0:
+      if(ptr[0]=='.') /* skip preceding dots */
+        ptr++;
+      co->domain = strdup(ptr);
+      if(!co->domain)
+        return CERR_OUT_OF_MEMORY;
+      break;
+    case 1:
+      /*
+       * flag: A TRUE/FALSE value indicating if all machines within a given
+       * domain can access the variable. Set TRUE when the cookie says
+       * .domain.com and to false when the domain is complete www.domain.com
+       */
+      co->tailmatch = !!strcasecompare(ptr, "TRUE");
+      break;
+    case 2:
+      /* The file format allows the path field to remain not filled in */
+      if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
+        /* only if the path does not look like a boolean option! */
+        co->path = strdup(ptr);
+        if(!co->path)
+          return CERR_OUT_OF_MEMORY;
+        else {
+          co->spath = sanitize_cookie_path(co->path);
+          if(!co->spath)
+            return CERR_OUT_OF_MEMORY;
+        }
+        break;
+      }
+      /* this does not look like a path, make one up! */
+      co->path = strdup("/");
+      if(!co->path)
+        return CERR_OUT_OF_MEMORY;
+      co->spath = strdup("/");
+      if(!co->spath)
+        return CERR_OUT_OF_MEMORY;
+      fields++; /* add a field and fall down to secure */
+      FALLTHROUGH();
+    case 3:
+      co->secure = FALSE;
+      if(strcasecompare(ptr, "TRUE")) {
+        if(secure || ci->running)
+          co->secure = TRUE;
+        else
+          return CERR_BAD_SECURE;
+      }
+      break;
+    case 4:
+      if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
+        return CERR_RANGE;
+      break;
+    case 5:
+      co->name = strdup(ptr);
+      if(!co->name)
+        return CERR_OUT_OF_MEMORY;
+      else {
+        /* For Netscape file format cookies we check prefix on the name */
+        if(strncasecompare("__Secure-", co->name, 9))
+          co->prefix_secure = TRUE;
+        else if(strncasecompare("__Host-", co->name, 7))
+          co->prefix_host = TRUE;
+      }
+      break;
+    case 6:
+      co->value = strdup(ptr);
+      if(!co->value)
+        return CERR_OUT_OF_MEMORY;
+      break;
+    }
+  }
+  if(6 == fields) {
+    /* we got a cookie with blank contents, fix it */
+    co->value = strdup("");
+    if(!co->value)
+      return CERR_OUT_OF_MEMORY;
+    else
+      fields++;
+  }
+
+  if(7 != fields)
+    /* we did not find the sufficient number of fields */
+    return CERR_FIELDS;
+
+  return CERR_OK;
+}
+
+static int
+is_public_suffix(struct Curl_easy *data,
+                 struct Cookie *co,
+                 const char *domain)
+{
 #ifdef USE_LIBPSL
   /*
    * Check if the domain is a Public Suffix and if yes, ignore the cookie. We
@@ -1051,21 +964,34 @@
 
     if(!acceptable) {
       infof(data, "cookie '%s' dropped, domain '%s' must not "
-                  "set cookies for '%s'", co->name, domain, co->domain);
-      freecookie(co);
-      return NULL;
+            "set cookies for '%s'", co->name, domain, co->domain);
+      return CERR_PSL;
     }
   }
 #else
+  (void)data;
+  (void)co;
+  (void)domain;
   DEBUGF(infof(data, "NO PSL to check set-cookie '%s' for domain=%s in %s",
          co->name, co->domain, domain));
 #endif
+  return CERR_OK;
+}
 
-  /* A non-secure cookie may not overlay an existing secure cookie. */
-  myhash = cookiehash(co->domain);
-  clist = c->cookies[myhash];
-  while(clist) {
-    if(strcasecompare(clist->name, co->name)) {
+static int
+replace_existing(struct Curl_easy *data,
+                 struct Cookie *co,
+                 struct CookieInfo *ci,
+                 bool secure,
+                 bool *replacep)
+{
+  bool replace_old = FALSE;
+  struct Curl_llist_node *replace_n = NULL;
+  struct Curl_llist_node *n;
+  size_t myhash = cookiehash(co->domain);
+  for(n = Curl_llist_head(&ci->cookielist[myhash]); n; n = Curl_node_next(n)) {
+    struct Cookie *clist = Curl_node_elem(n);
+    if(!strcmp(clist->name, co->name)) {
       /* the names are identical */
       bool matching_domains = FALSE;
 
@@ -1100,13 +1026,12 @@
         if(strncasecompare(clist->spath, co->spath, cllen)) {
           infof(data, "cookie '%s' for domain '%s' dropped, would "
                 "overlay an existing cookie", co->name, co->domain);
-          freecookie(co);
-          return NULL;
+          return CERR_BAD_SECURE;
         }
       }
     }
 
-    if(!replace_co && strcasecompare(clist->name, co->name)) {
+    if(!replace_n && !strcmp(clist->name, co->name)) {
       /* the names are identical */
 
       if(clist->domain && co->domain) {
@@ -1135,62 +1060,137 @@
          * was read from a file and thus is not "live". "live" cookies are
          * preferred so the new cookie is freed.
          */
-        freecookie(co);
-        return NULL;
+        return CERR_LIVE_WINS;
       }
-      if(replace_old) {
-        replace_co = co;
-        replace_clist = clist;
-      }
+      if(replace_old)
+        replace_n = n;
     }
-    lastc = clist;
-    clist = clist->next;
   }
-  if(replace_co) {
-    co = replace_co;
-    clist = replace_clist;
-    co->next = clist->next; /* get the next-pointer first */
+  if(replace_n) {
+    struct Cookie *repl = Curl_node_elem(replace_n);
 
     /* when replacing, creationtime is kept from old */
-    co->creationtime = clist->creationtime;
+    co->creationtime = repl->creationtime;
 
-    /* then free all the old pointers */
-    free(clist->name);
-    free(clist->value);
-    free(clist->domain);
-    free(clist->path);
-    free(clist->spath);
+    /* unlink the old */
+    Curl_node_remove(replace_n);
 
-    *clist = *co;  /* then store all the new data */
+    /* free the old cookie */
+    freecookie(repl);
+  }
+  *replacep = replace_old;
+  return CERR_OK;
+}
 
-    free(co);   /* free the newly allocated memory */
-    co = clist;
+/*
+ * Curl_cookie_add
+ *
+ * Add a single cookie line to the cookie keeping object. Be aware that
+ * sometimes we get an IP-only hostname, and that might also be a numerical
+ * IPv6 address.
+ *
+ * Returns NULL on out of memory or invalid cookie. This is suboptimal,
+ * as they should be treated separately.
+ */
+struct Cookie *
+Curl_cookie_add(struct Curl_easy *data,
+                struct CookieInfo *ci,
+                bool httpheader, /* TRUE if HTTP header-style line */
+                bool noexpire, /* if TRUE, skip remove_expired() */
+                const char *lineptr,   /* first character of the line */
+                const char *domain, /* default domain */
+                const char *path,   /* full path used when this cookie is set,
+                                       used to get default path for the cookie
+                                       unless set */
+                bool secure)  /* TRUE if connection is over secure origin */
+{
+  struct Cookie *co;
+  size_t myhash;
+  int rc;
+  bool replaces = FALSE;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(MAX_SET_COOKIE_AMOUNT <= 255); /* counter is an unsigned char */
+  if(data->req.setcookies >= MAX_SET_COOKIE_AMOUNT)
+    return NULL;
+
+  /* First, alloc and init a new struct for it */
+  co = calloc(1, sizeof(struct Cookie));
+  if(!co)
+    return NULL; /* bail out if we are this low on memory */
+
+  if(httpheader)
+    rc = parse_cookie_header(data, co, ci, lineptr, domain, path, secure);
+  else
+    rc = parse_netscape(co, ci, lineptr, secure);
+
+  if(rc)
+    goto fail;
+
+  if(co->prefix_secure && !co->secure)
+    /* The __Secure- prefix only requires that the cookie be set secure */
+    goto fail;
+
+  if(co->prefix_host) {
+    /*
+     * The __Host- prefix requires the cookie to be secure, have a "/" path
+     * and not have a domain set.
+     */
+    if(co->secure && co->path && strcmp(co->path, "/") == 0 && !co->tailmatch)
+      ;
+    else
+      goto fail;
   }
 
-  if(c->running)
+  if(!ci->running &&    /* read from a file */
+     ci->newsession &&  /* clean session cookies */
+     !co->expires)      /* this is a session cookie since it does not expire */
+    goto fail;
+
+  co->livecookie = ci->running;
+  co->creationtime = ++ci->lastct;
+
+  /*
+   * Now we have parsed the incoming line, we must now check if this supersedes
+   * an already existing cookie, which it may if the previous have the same
+   * domain and path as this.
+   */
+
+  /* remove expired cookies */
+  if(!noexpire)
+    remove_expired(ci);
+
+  if(is_public_suffix(data, co, domain))
+    goto fail;
+
+  if(replace_existing(data, co, ci, secure, &replaces))
+    goto fail;
+
+  /* add this cookie to the list */
+  myhash = cookiehash(co->domain);
+  Curl_llist_append(&ci->cookielist[myhash], co, &co->node);
+
+  if(ci->running)
     /* Only show this when NOT reading the cookies from a file */
     infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
           "expire %" FMT_OFF_T,
-          replace_old?"Replaced":"Added", co->name, co->value,
+          replaces ? "Replaced":"Added", co->name, co->value,
           co->domain, co->path, co->expires);
 
-  if(!replace_old) {
-    /* then make the last item point on this new one */
-    if(lastc)
-      lastc->next = co;
-    else
-      c->cookies[myhash] = co;
-    c->numcookies++; /* one more cookie in the jar */
-  }
+  if(!replaces)
+    ci->numcookies++; /* one more cookie in the jar */
 
   /*
    * Now that we have added a new cookie to the jar, update the expiration
    * tracker in case it is the next one to expire.
    */
-  if(co->expires && (co->expires < c->next_expiration))
-    c->next_expiration = co->expires;
+  if(co->expires && (co->expires < ci->next_expiration))
+    ci->next_expiration = co->expires;
 
   return co;
+fail:
+  freecookie(co);
+  return NULL;
 }
 
 
@@ -1210,28 +1210,30 @@
  */
 struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
                                     const char *file,
-                                    struct CookieInfo *inc,
+                                    struct CookieInfo *ci,
                                     bool newsession)
 {
-  struct CookieInfo *c;
   FILE *handle = NULL;
 
-  if(!inc) {
+  if(!ci) {
+    int i;
+
     /* we did not get a struct, create one */
-    c = calloc(1, sizeof(struct CookieInfo));
-    if(!c)
+    ci = calloc(1, sizeof(struct CookieInfo));
+    if(!ci)
       return NULL; /* failed to get memory */
+
+    /* This does not use the destructor callback since we want to add
+       and remove to lists while keeping the cookie struct intact */
+    for(i = 0; i < COOKIE_HASH_SIZE; i++)
+      Curl_llist_init(&ci->cookielist[i], NULL);
     /*
      * Initialize the next_expiration time to signal that we do not have enough
      * information yet.
      */
-    c->next_expiration = CURL_OFF_T_MAX;
+    ci->next_expiration = CURL_OFF_T_MAX;
   }
-  else {
-    /* we got an already existing one, use that */
-    c = inc;
-  }
-  c->newsession = newsession; /* new session? */
+  ci->newsession = newsession; /* new session? */
 
   if(data) {
     FILE *fp = NULL;
@@ -1247,7 +1249,7 @@
       }
     }
 
-    c->running = FALSE; /* this is not running, this is init */
+    ci->running = FALSE; /* this is not running, this is init */
     if(fp) {
       struct dynbuf buf;
       Curl_dyn_init(&buf, MAX_COOKIE_LINE);
@@ -1262,7 +1264,7 @@
             lineptr++;
         }
 
-        Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
+        Curl_cookie_add(data, ci, headerline, TRUE, lineptr, NULL, NULL, TRUE);
       }
       Curl_dyn_free(&buf); /* free the line buffer */
 
@@ -1270,16 +1272,16 @@
        * Remove expired cookies from the hash. We must make sure to run this
        * after reading the file, and not on every cookie.
        */
-      remove_expired(c);
+      remove_expired(ci);
 
       if(handle)
         fclose(handle);
     }
     data->state.cookie_engine = TRUE;
   }
-  c->running = TRUE;          /* now, we are running */
+  ci->running = TRUE;          /* now, we are running */
 
-  return c;
+  return ci;
 }
 
 /*
@@ -1334,38 +1336,6 @@
   return (c2->creationtime > c1->creationtime) ? 1 : -1;
 }
 
-#define CLONE(field)                     \
-  do {                                   \
-    if(src->field) {                     \
-      d->field = strdup(src->field);     \
-      if(!d->field)                      \
-        goto fail;                       \
-    }                                    \
-  } while(0)
-
-static struct Cookie *dup_cookie(struct Cookie *src)
-{
-  struct Cookie *d = calloc(1, sizeof(struct Cookie));
-  if(d) {
-    CLONE(domain);
-    CLONE(path);
-    CLONE(spath);
-    CLONE(name);
-    CLONE(value);
-    d->expires = src->expires;
-    d->tailmatch = src->tailmatch;
-    d->secure = src->secure;
-    d->livecookie = src->livecookie;
-    d->httponly = src->httponly;
-    d->creationtime = src->creationtime;
-  }
-  return d;
-
-fail:
-  freecookie(d);
-  return NULL;
-}
-
 /*
  * Curl_cookie_getlist
  *
@@ -1374,33 +1344,37 @@
  * if a secure connection is achieved or not.
  *
  * It shall only return cookies that have not expired.
+ *
+ * Returns 0 when there is a list returned. Otherwise non-zero.
  */
-struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
-                                   struct CookieInfo *c,
-                                   const char *host, const char *path,
-                                   bool secure)
+int Curl_cookie_getlist(struct Curl_easy *data,
+                        struct CookieInfo *ci,
+                        const char *host, const char *path,
+                        bool secure,
+                        struct Curl_llist *list)
 {
-  struct Cookie *newco;
-  struct Cookie *co;
-  struct Cookie *mainco = NULL;
   size_t matches = 0;
   bool is_ip;
   const size_t myhash = cookiehash(host);
+  struct Curl_llist_node *n;
 
-  if(!c || !c->cookies[myhash])
-    return NULL; /* no cookie struct or no cookies in the struct */
+  Curl_llist_init(list, NULL);
+
+  if(!ci || !Curl_llist_count(&ci->cookielist[myhash]))
+    return 1; /* no cookie struct or no cookies in the struct */
 
   /* at first, remove expired cookies */
-  remove_expired(c);
+  remove_expired(ci);
 
   /* check if host is an IP(v4|v6) address */
   is_ip = Curl_host_is_ipnum(host);
 
-  co = c->cookies[myhash];
+  for(n = Curl_llist_head(&ci->cookielist[myhash]);
+      n; n = Curl_node_next(n)) {
+    struct Cookie *co = Curl_node_elem(n);
 
-  while(co) {
     /* if the cookie requires we are secure we must only continue if we are! */
-    if(co->secure?secure:TRUE) {
+    if(co->secure ? secure : TRUE) {
 
       /* now check if the domain is correct */
       if(!co->domain ||
@@ -1419,31 +1393,18 @@
         if(!co->spath || pathmatch(co->spath, path) ) {
 
           /*
-           * and now, we know this is a match and we should create an
-           * entry for the return-linked-list
+           * This is a match and we add it to the return-linked-list
            */
-
-          newco = dup_cookie(co);
-          if(newco) {
-            /* then modify our next */
-            newco->next = mainco;
-
-            /* point the main to us */
-            mainco = newco;
-
-            matches++;
-            if(matches >= MAX_COOKIE_SEND_AMOUNT) {
-              infof(data, "Included max number of cookies (%zu) in request!",
-                    matches);
-              break;
-            }
+          Curl_llist_append(list, co, &co->getnode);
+          matches++;
+          if(matches >= MAX_COOKIE_SEND_AMOUNT) {
+            infof(data, "Included max number of cookies (%zu) in request!",
+                  matches);
+            break;
           }
-          else
-            goto fail;
         }
       }
     }
-    co = co->next;
   }
 
   if(matches) {
@@ -1460,30 +1421,29 @@
     if(!array)
       goto fail;
 
-    co = mainco;
+    n = Curl_llist_head(list);
 
-    for(i = 0; co; co = co->next)
-      array[i++] = co;
+    for(i = 0; n; n = Curl_node_next(n))
+      array[i++] = Curl_node_elem(n);
 
     /* now sort the cookie pointers in path length order */
     qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
 
     /* remake the linked list order according to the new order */
+    Curl_llist_destroy(list, NULL);
 
-    mainco = array[0]; /* start here */
-    for(i = 0; i<matches-1; i++)
-      array[i]->next = array[i + 1];
-    array[matches-1]->next = NULL; /* terminate the list */
+    for(i = 0; i < matches; i++)
+      Curl_llist_append(list, array[i], &array[i]->getnode);
 
     free(array); /* remove the temporary data again */
   }
 
-  return mainco; /* return the new list */
+  return 0; /* success */
 
 fail:
   /* failure, clear up the allocated chain and return NULL */
-  Curl_cookie_freelist(mainco);
-  return NULL;
+  Curl_llist_destroy(list, NULL);
+  return 2; /* error */
 }
 
 /*
@@ -1491,30 +1451,21 @@
  *
  * Clear all existing cookies and reset the counter.
  */
-void Curl_cookie_clearall(struct CookieInfo *cookies)
+void Curl_cookie_clearall(struct CookieInfo *ci)
 {
-  if(cookies) {
+  if(ci) {
     unsigned int i;
     for(i = 0; i < COOKIE_HASH_SIZE; i++) {
-      Curl_cookie_freelist(cookies->cookies[i]);
-      cookies->cookies[i] = NULL;
+      struct Curl_llist_node *n;
+      for(n = Curl_llist_head(&ci->cookielist[i]); n;) {
+        struct Cookie *c = Curl_node_elem(n);
+        struct Curl_llist_node *e = Curl_node_next(n);
+        Curl_node_remove(n);
+        freecookie(c);
+        n = e;
+      }
     }
-    cookies->numcookies = 0;
-  }
-}
-
-/*
- * Curl_cookie_freelist
- *
- * Free a list of cookies previously returned by Curl_cookie_getlist();
- */
-void Curl_cookie_freelist(struct Cookie *co)
-{
-  struct Cookie *next;
-  while(co) {
-    next = co->next;
-    freecookie(co);
-    co = next;
+    ci->numcookies = 0;
   }
 }
 
@@ -1523,39 +1474,26 @@
  *
  * Free all session cookies in the cookies list.
  */
-void Curl_cookie_clearsess(struct CookieInfo *cookies)
+void Curl_cookie_clearsess(struct CookieInfo *ci)
 {
-  struct Cookie *first, *curr, *next, *prev = NULL;
   unsigned int i;
 
-  if(!cookies)
+  if(!ci)
     return;
 
   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
-    if(!cookies->cookies[i])
-      continue;
+    struct Curl_llist_node *n = Curl_llist_head(&ci->cookielist[i]);
+    struct Curl_llist_node *e = NULL;
 
-    first = curr = prev = cookies->cookies[i];
-
-    for(; curr; curr = next) {
-      next = curr->next;
+    for(; n; n = e) {
+      struct Cookie *curr = Curl_node_elem(n);
+      e = Curl_node_next(n); /* in case the node is removed, get it early */
       if(!curr->expires) {
-        if(first == curr)
-          first = next;
-
-        if(prev == curr)
-          prev = next;
-        else
-          prev->next = next;
-
+        Curl_node_remove(n);
         freecookie(curr);
-        cookies->numcookies--;
+        ci->numcookies--;
       }
-      else
-        prev = curr;
     }
-
-    cookies->cookies[i] = first;
   }
 }
 
@@ -1564,13 +1502,11 @@
  *
  * Free a "cookie object" previous created with Curl_cookie_init().
  */
-void Curl_cookie_cleanup(struct CookieInfo *c)
+void Curl_cookie_cleanup(struct CookieInfo *ci)
 {
-  if(c) {
-    unsigned int i;
-    for(i = 0; i < COOKIE_HASH_SIZE; i++)
-      Curl_cookie_freelist(c->cookies[i]);
-    free(c); /* free the base struct as well */
+  if(ci) {
+    Curl_cookie_clearall(ci);
+    free(ci); /* free the base struct as well */
   }
 }
 
@@ -1592,19 +1528,19 @@
     "%" FMT_OFF_T "\t"   /* expires */
     "%s\t"   /* name */
     "%s",    /* value */
-    co->httponly?"#HttpOnly_":"",
+    co->httponly ? "#HttpOnly_" : "",
     /*
      * Make sure all domains are prefixed with a dot if they allow
      * tailmatching. This is Mozilla-style.
      */
-    (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
-    co->domain?co->domain:"unknown",
-    co->tailmatch?"TRUE":"FALSE",
-    co->path?co->path:"/",
-    co->secure?"TRUE":"FALSE",
+    (co->tailmatch && co->domain && co->domain[0] != '.') ? "." : "",
+    co->domain ? co->domain : "unknown",
+    co->tailmatch ? "TRUE" : "FALSE",
+    co->path ? co->path : "/",
+    co->secure ? "TRUE" : "FALSE",
     co->expires,
     co->name,
-    co->value?co->value:"");
+    co->value ? co->value : "");
 }
 
 /*
@@ -1616,20 +1552,20 @@
  * The function returns non-zero on write failure.
  */
 static CURLcode cookie_output(struct Curl_easy *data,
-                              struct CookieInfo *c, const char *filename)
+                              struct CookieInfo *ci,
+                              const char *filename)
 {
-  struct Cookie *co;
   FILE *out = NULL;
   bool use_stdout = FALSE;
   char *tempstore = NULL;
   CURLcode error = CURLE_OK;
 
-  if(!c)
+  if(!ci)
     /* no cookie engine alive */
     return CURLE_OK;
 
   /* at first, remove expired cookies */
-  remove_expired(c);
+  remove_expired(ci);
 
   if(!strcmp("-", filename)) {
     /* use stdout */
@@ -1647,12 +1583,13 @@
         "# This file was generated by libcurl! Edit at your own risk.\n\n",
         out);
 
-  if(c->numcookies) {
+  if(ci->numcookies) {
     unsigned int i;
     size_t nvalid = 0;
     struct Cookie **array;
+    struct Curl_llist_node *n;
 
-    array = calloc(1, sizeof(struct Cookie *) * c->numcookies);
+    array = calloc(1, sizeof(struct Cookie *) * ci->numcookies);
     if(!array) {
       error = CURLE_OUT_OF_MEMORY;
       goto error;
@@ -1660,7 +1597,9 @@
 
     /* only sort the cookies with a domain property */
     for(i = 0; i < COOKIE_HASH_SIZE; i++) {
-      for(co = c->cookies[i]; co; co = co->next) {
+      for(n = Curl_llist_head(&ci->cookielist[i]); n;
+          n = Curl_node_next(n)) {
+        struct Cookie *co = Curl_node_elem(n);
         if(!co->domain)
           continue;
         array[nvalid++] = co;
@@ -1712,15 +1651,17 @@
 {
   struct curl_slist *list = NULL;
   struct curl_slist *beg;
-  struct Cookie *c;
-  char *line;
   unsigned int i;
+  struct Curl_llist_node *n;
 
   if(!data->cookies || (data->cookies->numcookies == 0))
     return NULL;
 
   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
-    for(c = data->cookies->cookies[i]; c; c = c->next) {
+    for(n = Curl_llist_head(&data->cookies->cookielist[i]); n;
+        n = Curl_node_next(n)) {
+      struct Cookie *c = Curl_node_elem(n);
+      char *line;
       if(!c->domain)
         continue;
       line = get_netscape_format(c);
diff --git a/Utilities/cmcurl/lib/cookie.h b/Utilities/cmcurl/lib/cookie.h
index 838d74d..c98f360 100644
--- a/Utilities/cmcurl/lib/cookie.h
+++ b/Utilities/cmcurl/lib/cookie.h
@@ -27,20 +27,24 @@
 
 #include <curl/curl.h>
 
+#include "llist.h"
+
 struct Cookie {
-  struct Cookie *next; /* next in the chain */
-  char *name;        /* <this> = value */
-  char *value;       /* name = <this> */
+  struct Curl_llist_node node; /* for the main cookie list */
+  struct Curl_llist_node getnode; /* for getlist */
+  char *name;         /* <this> = value */
+  char *value;        /* name = <this> */
   char *path;         /* path = <this> which is in Set-Cookie: */
   char *spath;        /* sanitized cookie path */
-  char *domain;      /* domain = <this> */
-  curl_off_t expires;  /* expires = <this> */
-  bool tailmatch;    /* whether we do tail-matching of the domain name */
-  bool secure;       /* whether the 'secure' keyword was used */
-  bool livecookie;   /* updated from a server, not a stored file */
-  bool httponly;     /* true if the httponly directive is present */
-  int creationtime;  /* time when the cookie was written */
-  unsigned char prefix; /* bitmap fields indicating which prefix are set */
+  char *domain;       /* domain = <this> */
+  curl_off_t expires; /* expires = <this> */
+  int creationtime;   /* time when the cookie was written */
+  BIT(tailmatch);     /* tail-match the domain name */
+  BIT(secure);        /* the 'secure' keyword was used */
+  BIT(livecookie);    /* updated from a server, not a stored file */
+  BIT(httponly);      /* the httponly directive is present */
+  BIT(prefix_secure); /* secure prefix is set */
+  BIT(prefix_host);   /* host prefix is set */
 };
 
 /*
@@ -53,8 +57,8 @@
 #define COOKIE_HASH_SIZE 63
 
 struct CookieInfo {
-  /* linked list of cookies we know of */
-  struct Cookie *cookies[COOKIE_HASH_SIZE];
+  /* linked lists of cookies we know of */
+  struct Curl_llist cookielist[COOKIE_HASH_SIZE];
   curl_off_t next_expiration; /* the next time at which expiration happens */
   int numcookies;  /* number of cookies in the "jar" */
   int lastct;      /* last creation-time used in the jar */
@@ -112,10 +116,10 @@
                                const char *domain, const char *path,
                                bool secure);
 
-struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
-                                   struct CookieInfo *c, const char *host,
-                                   const char *path, bool secure);
-void Curl_cookie_freelist(struct Cookie *cookies);
+int Curl_cookie_getlist(struct Curl_easy *data,
+                        struct CookieInfo *c, const char *host,
+                        const char *path, bool secure,
+                        struct Curl_llist *list);
 void Curl_cookie_clearall(struct CookieInfo *cookies);
 void Curl_cookie_clearsess(struct CookieInfo *cookies);
 
diff --git a/Utilities/cmcurl/lib/curl_addrinfo.c b/Utilities/cmcurl/lib/curl_addrinfo.c
index 44e10e9..a08caf3 100644
--- a/Utilities/cmcurl/lib/curl_addrinfo.c
+++ b/Utilities/cmcurl/lib/curl_addrinfo.c
@@ -252,6 +252,7 @@
  *     #define h_addr  h_addr_list[0]
  */
 
+#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
 struct Curl_addrinfo *
 Curl_he2ai(const struct hostent *he, int port)
 {
@@ -350,19 +351,7 @@
 
   return firstai;
 }
-
-
-struct namebuff {
-  struct hostent hostentry;
-  union {
-    struct in_addr  ina4;
-#ifdef USE_IPV6
-    struct in6_addr ina6;
 #endif
-  } addrentry;
-  char *h_addr_list[2];
-};
-
 
 /*
  * Curl_ip2addr()
@@ -377,71 +366,68 @@
 Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
 {
   struct Curl_addrinfo *ai;
-
-#if defined(__VMS) && \
-    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
-#pragma pointer_size save
-#pragma pointer_size short
-#pragma message disable PTRMISMATCH
-#endif
-
-  struct hostent  *h;
-  struct namebuff *buf;
-  char  *addrentry;
-  char  *hoststr;
   size_t addrsize;
+  size_t namelen;
+  struct sockaddr_in *addr;
+#ifdef USE_IPV6
+  struct sockaddr_in6 *addr6;
+#endif
 
   DEBUGASSERT(inaddr && hostname);
 
-  buf = malloc(sizeof(struct namebuff));
-  if(!buf)
+  namelen = strlen(hostname) + 1;
+
+  if(af == AF_INET)
+    addrsize = sizeof(struct sockaddr_in);
+#ifdef USE_IPV6
+  else if(af == AF_INET6)
+    addrsize = sizeof(struct sockaddr_in6);
+#endif
+  else
     return NULL;
 
-  hoststr = strdup(hostname);
-  if(!hoststr) {
-    free(buf);
+  /* allocate memory to hold the struct, the address and the name */
+  ai = calloc(1, sizeof(struct Curl_addrinfo) + addrsize + namelen);
+  if(!ai)
     return NULL;
-  }
+  /* put the address after the struct */
+  ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
+  /* then put the name after the address */
+  ai->ai_canonname = (char *)ai->ai_addr + addrsize;
+  memcpy(ai->ai_canonname, hostname, namelen);
+  ai->ai_family = af;
+  ai->ai_socktype = SOCK_STREAM;
+  ai->ai_addrlen = (curl_socklen_t)addrsize;
+  /* leave the rest of the struct filled with zero */
 
   switch(af) {
   case AF_INET:
-    addrsize = sizeof(struct in_addr);
-    addrentry = (void *)&buf->addrentry.ina4;
-    memcpy(addrentry, inaddr, sizeof(struct in_addr));
+    addr = (void *)ai->ai_addr; /* storage area for this info */
+
+    memcpy(&addr->sin_addr, inaddr, sizeof(struct in_addr));
+#ifdef __MINGW32__
+    addr->sin_family = (short)af;
+#else
+    addr->sin_family = (CURL_SA_FAMILY_T)af;
+#endif
+    addr->sin_port = htons((unsigned short)port);
     break;
+
 #ifdef USE_IPV6
   case AF_INET6:
-    addrsize = sizeof(struct in6_addr);
-    addrentry = (void *)&buf->addrentry.ina6;
-    memcpy(addrentry, inaddr, sizeof(struct in6_addr));
+    addr6 = (void *)ai->ai_addr; /* storage area for this info */
+
+    memcpy(&addr6->sin6_addr, inaddr, sizeof(struct in6_addr));
+#ifdef __MINGW32__
+    addr6->sin6_family = (short)af;
+#else
+    addr6->sin6_family = (CURL_SA_FAMILY_T)af;
+#endif
+    addr6->sin6_port = htons((unsigned short)port);
     break;
 #endif
-  default:
-    free(hoststr);
-    free(buf);
-    return NULL;
   }
 
-  h = &buf->hostentry;
-  h->h_name = hoststr;
-  h->h_aliases = NULL;
-  h->h_addrtype = (short)af;
-  h->h_length = (short)addrsize;
-  h->h_addr_list = &buf->h_addr_list[0];
-  h->h_addr_list[0] = addrentry;
-  h->h_addr_list[1] = NULL; /* terminate list of entries */
-
-#if defined(__VMS) && \
-    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
-#pragma pointer_size restore
-#pragma message enable PTRMISMATCH
-#endif
-
-  ai = Curl_he2ai(h, port);
-
-  free(hoststr);
-  free(buf);
-
   return ai;
 }
 
diff --git a/Utilities/cmcurl/lib/curl_addrinfo.h b/Utilities/cmcurl/lib/curl_addrinfo.h
index 9ceac99..2303e95 100644
--- a/Utilities/cmcurl/lib/curl_addrinfo.h
+++ b/Utilities/cmcurl/lib/curl_addrinfo.h
@@ -71,8 +71,10 @@
                     struct Curl_addrinfo **result);
 #endif
 
+#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
 struct Curl_addrinfo *
 Curl_he2ai(const struct hostent *he, int port);
+#endif
 
 struct Curl_addrinfo *
 Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);
diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake
index 02b2949..be3d0e1 100644
--- a/Utilities/cmcurl/lib/curl_config.h.cmake
+++ b/Utilities/cmcurl/lib/curl_config.h.cmake
@@ -21,7 +21,6 @@
  * SPDX-License-Identifier: curl
  *
  ***************************************************************************/
-/* lib/curl_config.h.in. Generated somehow by cmake.  */
 
 #include <cm3p/kwiml/abi.h>
 
@@ -49,7 +48,7 @@
 /* disables negotiate authentication */
 #cmakedefine CURL_DISABLE_NEGOTIATE_AUTH 1
 
-/* disables AWS-SIG4 */
+/* disables aws-sigv4 */
 #cmakedefine CURL_DISABLE_AWS 1
 
 /* disables DICT */
@@ -124,6 +123,9 @@
 /* disables proxies */
 #cmakedefine CURL_DISABLE_PROXY 1
 
+/* disables IPFS from the curl tool */
+#cmakedefine CURL_DISABLE_IPFS 1
+
 /* disables RTSP */
 #cmakedefine CURL_DISABLE_RTSP 1
 
@@ -139,6 +141,9 @@
 /* disables SMTP */
 #cmakedefine CURL_DISABLE_SMTP 1
 
+/* disabled WebSockets */
+#cmakedefine CURL_DISABLE_WEBSOCKETS 1
+
 /* disables use of socketpair for curl_multi_poll */
 #cmakedefine CURL_DISABLE_SOCKETPAIR 1
 
@@ -151,6 +156,12 @@
 /* disables verbose strings */
 #cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1
 
+/* disables unsafe CA bundle search on Windows from the curl tool */
+#cmakedefine CURL_DISABLE_CA_SEARCH 1
+
+/* safe CA bundle search (within the curl tool directory) on Windows */
+#cmakedefine CURL_CA_SEARCH_SAFE 1
+
 /* to make a symbol visible */
 #cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL}
 /* Ensure using CURL_EXTERN_SYMBOL is possible */
@@ -201,6 +212,9 @@
 /* Define to 1 if you have the `closesocket' function. */
 #cmakedefine HAVE_CLOSESOCKET 1
 
+/* Define to 1 if you have the `CloseSocket' function. */
+#cmakedefine HAVE_CLOSESOCKET_CAMEL 1
+
 /* Define to 1 if you have the <dirent.h> header file. */
 #cmakedefine HAVE_DIRENT_H 1
 
@@ -225,9 +239,6 @@
 /* Define to 1 if you have the fseeko declaration. */
 #cmakedefine HAVE_DECL_FSEEKO 1
 
-/* Define to 1 if you have the _fseeki64 function. */
-#cmakedefine HAVE__FSEEKI64 1
-
 /* Define to 1 if you have the ftruncate function. */
 #cmakedefine HAVE_FTRUNCATE 1
 
@@ -300,9 +311,6 @@
 /* Define to 1 if you have the <gssapi/gssapi.h> header file. */
 #cmakedefine HAVE_GSSAPI_GSSAPI_H 1
 
-/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
-#cmakedefine HAVE_GSSAPI_GSSAPI_KRB5_H 1
-
 /* if you have the GNU gssapi libraries */
 #cmakedefine HAVE_GSSGNU 1
 
@@ -346,9 +354,6 @@
 /* Define to 1 if you have the lber.h header file. */
 #cmakedefine HAVE_LBER_H 1
 
-/* Define to 1 if you have the ldap.h header file. */
-#cmakedefine HAVE_LDAP_H 1
-
 /* Use LDAPS implementation */
 #cmakedefine HAVE_LDAP_SSL 1
 
@@ -396,6 +401,9 @@
 /* Define to 1 if you have the <netinet/in.h> header file. */
 #cmakedefine HAVE_NETINET_IN_H 1
 
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+#cmakedefine HAVE_NETINET_IN6_H 1
+
 /* Define to 1 if you have the <netinet/tcp.h> header file. */
 #cmakedefine HAVE_NETINET_TCP_H 1
 
@@ -417,8 +425,8 @@
 /* Define to 1 if you have the `eventfd' function. */
 #cmakedefine HAVE_EVENTFD 1
 
-/* If you have a fine poll */
-#cmakedefine HAVE_POLL_FINE 1
+/* If you have poll */
+#cmakedefine HAVE_POLL 1
 
 /* Define to 1 if you have the <poll.h> header file. */
 #cmakedefine HAVE_POLL_H 1
@@ -450,6 +458,9 @@
 /* Define to 1 if you have the sendmsg function. */
 #cmakedefine HAVE_SENDMSG 1
 
+/* Define to 1 if you have the sendmmsg function. */
+#cmakedefine HAVE_SENDMMSG 1
+
 /* Define to 1 if you have the 'fsetxattr' function. */
 #cmakedefine HAVE_FSETXATTR 1
 
@@ -465,6 +476,9 @@
 /* Define to 1 if you have the `setmode' function. */
 #cmakedefine HAVE_SETMODE 1
 
+/* Define to 1 if you have the `_setmode' function. */
+#cmakedefine HAVE__SETMODE 1
+
 /* Define to 1 if you have the `setrlimit' function. */
 #cmakedefine HAVE_SETRLIMIT 1
 
@@ -492,6 +506,9 @@
 /* Define to 1 if you have the `socket' function. */
 #cmakedefine HAVE_SOCKET 1
 
+/* Define to 1 if you have the <proto/bsdsocket.h> header file. */
+#cmakedefine HAVE_PROTO_BSDSOCKET_H 1
+
 /* Define to 1 if you have the socketpair function. */
 #cmakedefine HAVE_SOCKETPAIR 1
 
@@ -603,9 +620,6 @@
 /* Define this symbol if your OS supports changing the contents of argv */
 #cmakedefine HAVE_WRITABLE_ARGV 1
 
-/* Define to 1 if you need the lber.h header file even with ldap.h */
-#cmakedefine NEED_LBER_H 1
-
 /* Define to 1 if you need the malloc.h header file even with stdlib.h */
 #cmakedefine NEED_MALLOC_H 1
 
@@ -613,7 +627,7 @@
 #cmakedefine NEED_REENTRANT 1
 
 /* cpu-machine-OS */
-#cmakedefine OS ${OS}
+#cmakedefine CURL_OS ${CURL_OS}
 
 /* Name of package */
 #cmakedefine PACKAGE ${PACKAGE}
@@ -713,6 +727,9 @@
 /* if wolfSSL has the wolfSSL_DES_ecb_encrypt function. */
 #cmakedefine HAVE_WOLFSSL_DES_ECB_ENCRYPT 1
 
+/* if wolfSSL has the wolfSSL_BIO_new function. */
+#cmakedefine HAVE_WOLFSSL_BIO 1
+
 /* if wolfSSL has the wolfSSL_BIO_set_shutdown function. */
 #cmakedefine HAVE_WOLFSSL_FULL_BIO 1
 
@@ -826,9 +843,6 @@
 /* to enable Apple IDN */
 #cmakedefine USE_APPLE_IDN 1
 
-/* Define to 1 to enable websocket support. */
-#cmakedefine USE_WEBSOCKETS 1
-
 /* Define to 1 if OpenSSL has the SSL_CTX_set_srp_username function. */
 #cmakedefine HAVE_OPENSSL_SRP 1
 
diff --git a/Utilities/cmcurl/lib/curl_fnmatch.c b/Utilities/cmcurl/lib/curl_fnmatch.c
index ab848e8..ffac804 100644
--- a/Utilities/cmcurl/lib/curl_fnmatch.c
+++ b/Utilities/cmcurl/lib/curl_fnmatch.c
@@ -161,7 +161,7 @@
   }
 }
 
-/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
+/* returns 1 (TRUE) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
 static int setcharset(unsigned char **p, unsigned char *charset)
 {
   setcharset_state state = CURLFNM_SCHS_DEFAULT;
@@ -293,7 +293,7 @@
       p++;
       break;
     case '\0':
-      return *s? CURL_FNMATCH_NOMATCH: CURL_FNMATCH_MATCH;
+      return *s ? CURL_FNMATCH_NOMATCH : CURL_FNMATCH_MATCH;
     case '\\':
       if(p[1])
         p++;
@@ -303,7 +303,7 @@
     case '[':
       pp = p + 1; /* Copy in case of syntax error in set. */
       if(setcharset(&pp, charset)) {
-        int found = FALSE;
+        bool found = FALSE;
         if(!*s)
           return CURL_FNMATCH_NOMATCH;
         if(charset[(unsigned int)*s])
diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c
index c6fe125..b7e774c 100644
--- a/Utilities/cmcurl/lib/curl_gssapi.c
+++ b/Utilities/cmcurl/lib/curl_gssapi.c
@@ -35,7 +35,7 @@
 #include "memdebug.h"
 
 #if defined(__GNUC__)
-#define CURL_ALIGN8   __attribute__ ((aligned(8)))
+#define CURL_ALIGN8  __attribute__((aligned(8)))
 #else
 #define CURL_ALIGN8
 #endif
diff --git a/Utilities/cmcurl/lib/curl_hmac.h b/Utilities/cmcurl/lib/curl_hmac.h
index 7a5387a..ed5035c 100644
--- a/Utilities/cmcurl/lib/curl_hmac.h
+++ b/Utilities/cmcurl/lib/curl_hmac.h
@@ -32,30 +32,28 @@
 
 #define HMAC_MD5_LENGTH 16
 
-typedef CURLcode (* HMAC_hinit_func)(void *context);
-typedef void    (* HMAC_hupdate_func)(void *context,
-                                      const unsigned char *data,
-                                      unsigned int len);
-typedef void    (* HMAC_hfinal_func)(unsigned char *result, void *context);
-
+typedef CURLcode (*HMAC_hinit)(void *context);
+typedef void    (*HMAC_hupdate)(void *context,
+                                const unsigned char *data,
+                                unsigned int len);
+typedef void    (*HMAC_hfinal)(unsigned char *result, void *context);
 
 /* Per-hash function HMAC parameters. */
 struct HMAC_params {
-  HMAC_hinit_func
-  hmac_hinit;     /* Initialize context procedure. */
-  HMAC_hupdate_func     hmac_hupdate;   /* Update context with data. */
-  HMAC_hfinal_func      hmac_hfinal;    /* Get final result procedure. */
-  unsigned int          hmac_ctxtsize;  /* Context structure size. */
-  unsigned int          hmac_maxkeylen; /* Maximum key length (bytes). */
-  unsigned int          hmac_resultlen; /* Result length (bytes). */
+  HMAC_hinit       hinit;     /* Initialize context procedure. */
+  HMAC_hupdate     hupdate;   /* Update context with data. */
+  HMAC_hfinal      hfinal;    /* Get final result procedure. */
+  unsigned int     ctxtsize;  /* Context structure size. */
+  unsigned int     maxkeylen; /* Maximum key length (bytes). */
+  unsigned int     resultlen; /* Result length (bytes). */
 };
 
 
 /* HMAC computation context. */
 struct HMAC_context {
-  const struct HMAC_params *hmac_hash; /* Hash function definition. */
-  void *hmac_hashctxt1;         /* Hash function context 1. */
-  void *hmac_hashctxt2;         /* Hash function context 2. */
+  const struct HMAC_params *hash; /* Hash function definition. */
+  void *hashctxt1;         /* Hash function context 1. */
+  void *hashctxt2;         /* Hash function context 2. */
 };
 
 
diff --git a/Utilities/cmcurl/lib/curl_md5.h b/Utilities/cmcurl/lib/curl_md5.h
index 61671c3..ec27503 100644
--- a/Utilities/cmcurl/lib/curl_md5.h
+++ b/Utilities/cmcurl/lib/curl_md5.h
@@ -31,11 +31,11 @@
 
 #define MD5_DIGEST_LEN  16
 
-typedef CURLcode (* Curl_MD5_init_func)(void *context);
-typedef void (* Curl_MD5_update_func)(void *context,
-                                      const unsigned char *data,
-                                      unsigned int len);
-typedef void (* Curl_MD5_final_func)(unsigned char *result, void *context);
+typedef CURLcode (*Curl_MD5_init_func)(void *context);
+typedef void (*Curl_MD5_update_func)(void *context,
+                                     const unsigned char *data,
+                                     unsigned int len);
+typedef void (*Curl_MD5_final_func)(unsigned char *result, void *context);
 
 struct MD5_params {
   Curl_MD5_init_func     md5_init_func;   /* Initialize context procedure */
@@ -50,8 +50,8 @@
   void                  *md5_hashctx;   /* Hash function context */
 };
 
-extern const struct MD5_params Curl_DIGEST_MD5[1];
-extern const struct HMAC_params Curl_HMAC_MD5[1];
+extern const struct MD5_params Curl_DIGEST_MD5;
+extern const struct HMAC_params Curl_HMAC_MD5;
 
 CURLcode Curl_md5it(unsigned char *output, const unsigned char *input,
                     const size_t len);
diff --git a/Utilities/cmcurl/lib/curl_memory.h b/Utilities/cmcurl/lib/curl_memory.h
index 714ad71..7f110da 100644
--- a/Utilities/cmcurl/lib/curl_memory.h
+++ b/Utilities/cmcurl/lib/curl_memory.h
@@ -84,6 +84,7 @@
 #undef socketpair
 #endif
 
+#ifndef CURL_NO_GETADDRINFO_OVERRIDE
 #ifdef HAVE_GETADDRINFO
 #if defined(getaddrinfo) && defined(__osf__)
 #undef ogetaddrinfo
@@ -95,6 +96,7 @@
 #ifdef HAVE_FREEADDRINFO
 #undef freeaddrinfo
 #endif /* HAVE_FREEADDRINFO */
+#endif /* !CURL_NO_GETADDRINFO_OVERRIDE */
 
 /* sclose is probably already defined, redefine it! */
 #undef sclose
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c
index eee33af..54491fc 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.c
@@ -71,13 +71,6 @@
 #  include <openssl/md5.h>
 #  include <openssl/ssl.h>
 #  include <openssl/rand.h>
-#else
-#  include <wolfssl/openssl/des.h>
-#  include <wolfssl/openssl/md5.h>
-#  include <wolfssl/openssl/ssl.h>
-#  include <wolfssl/openssl/rand.h>
-#endif
-
 #  if (defined(OPENSSL_VERSION_NUMBER) && \
        (OPENSSL_VERSION_NUMBER < 0x00907001L)) && !defined(USE_WOLFSSL)
 #    define DES_key_schedule des_key_schedule
@@ -95,6 +88,25 @@
 #    define DESKEYARG(x) *x
 #    define DESKEY(x) &x
 #  endif
+#else
+#  include <wolfssl/openssl/des.h>
+#  include <wolfssl/openssl/md5.h>
+#  include <wolfssl/openssl/ssl.h>
+#  include <wolfssl/openssl/rand.h>
+#  if defined(OPENSSL_COEXIST)
+#    define DES_key_schedule WOLFSSL_DES_key_schedule
+#    define DES_cblock WOLFSSL_DES_cblock
+#    define DES_set_odd_parity wolfSSL_DES_set_odd_parity
+#    define DES_set_key wolfSSL_DES_set_key
+#    define DES_set_key_unchecked wolfSSL_DES_set_key_unchecked
+#    define DES_ecb_encrypt wolfSSL_DES_ecb_encrypt
+#    define DESKEY(x) ((WOLFSSL_DES_key_schedule *)(x))
+#    define DESKEYARG(x) *x
+#  else
+#    define DESKEYARG(x) *x
+#    define DESKEY(x) &x
+#  endif
+#endif
 
 #elif defined(USE_GNUTLS)
 
@@ -483,7 +495,7 @@
      134774 days = 11644473600 seconds = 0x2B6109100 */
   r = ft->dwLowDateTime;
   ft->dwLowDateTime = (ft->dwLowDateTime + 0xB6109100U) & 0xFFFFFFFF;
-  ft->dwHighDateTime += ft->dwLowDateTime < r? 0x03: 0x02;
+  ft->dwHighDateTime += ft->dwLowDateTime < r ? 0x03 : 0x02;
 
   /* Convert to tenths of microseconds. */
   ft->dwHighDateTime *= 10000000;
@@ -528,7 +540,7 @@
   ascii_uppercase_to_unicode_le(identity, user, userlen);
   ascii_to_unicode_le(identity + (userlen << 1), domain, domlen);
 
-  result = Curl_hmacit(Curl_HMAC_MD5, ntlmhash, 16, identity, identity_len,
+  result = Curl_hmacit(&Curl_HMAC_MD5, ntlmhash, 16, identity, identity_len,
                        ntlmv2hash);
   free(identity);
 
@@ -613,7 +625,7 @@
 
   /* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */
   memcpy(ptr + 8, &ntlm->nonce[0], 8);
-  result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, HMAC_MD5_LENGTH, ptr + 8,
+  result = Curl_hmacit(&Curl_HMAC_MD5, ntlmv2hash, HMAC_MD5_LENGTH, ptr + 8,
                     NTLMv2_BLOB_LEN + 8, hmac_output);
   if(result) {
     free(ptr);
@@ -656,7 +668,7 @@
   memcpy(&data[0], challenge_server, 8);
   memcpy(&data[8], challenge_client, 8);
 
-  result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, 16, &data[0], 16,
+  result = Curl_hmacit(&Curl_HMAC_MD5, ntlmv2hash, 16, &data[0], 16,
                        hmac_output);
   if(result)
     return result;
diff --git a/Utilities/cmcurl/lib/curl_rtmp.c b/Utilities/cmcurl/lib/curl_rtmp.c
index 49f59e3..59fcc4e 100644
--- a/Utilities/cmcurl/lib/curl_rtmp.c
+++ b/Utilities/cmcurl/lib/curl_rtmp.c
@@ -255,7 +255,7 @@
     return CURLE_FAILED_INIT;
 
   /* Clients must send a periodic BytesReceived report to the server */
-  r->m_bSendCounter = true;
+  r->m_bSendCounter = TRUE;
 
   *done = TRUE;
   conn->recv[FIRSTSOCKET] = rtmp_recv;
diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h
index 01b9015..4824a43 100644
--- a/Utilities/cmcurl/lib/curl_setup.h
+++ b/Utilities/cmcurl/lib/curl_setup.h
@@ -33,7 +33,7 @@
 
 /* FIXME: Delete this once the warnings have been fixed. */
 #if !defined(CURL_WARN_SIGN_CONVERSION)
-#ifdef __GNUC__
+#if defined(__GNUC__) || defined(__clang__)
 #pragma GCC diagnostic ignored "-Wsign-conversion"
 #endif
 #endif
@@ -43,21 +43,24 @@
 #include <_mingw.h>
 #endif
 
-/* Workaround for Homebrew gcc 12.4.0, 13.3.0, 14.1.0 and newer (as of 14.1.0)
+/* Workaround for Homebrew gcc 12.4.0, 13.3.0, 14.1.0, 14.2.0 (initial build)
    that started advertising the `availability` attribute, which then gets used
-   by Apple SDK, but, in a way incompatible with gcc, resulting in a misc
-   errors inside SDK headers, e.g.:
+   by Apple SDK, but, in a way incompatible with gcc, resulting in misc errors
+   inside SDK headers, e.g.:
      error: attributes should be specified before the declarator in a function
             definition
      error: expected ',' or '}' before
    Followed by missing declarations.
-   Fix it by overriding the built-in feature-check macro used by the headers
-   to enable the problematic attributes. This makes the feature check fail. */
-#if defined(__APPLE__) &&                \
-  !defined(__clang__) &&                 \
-  defined(__GNUC__) && __GNUC__ >= 12 && \
+   Work it around by overriding the built-in feature-check macro used by the
+   headers to enable the problematic attributes. This makes the feature check
+   fail. Fixed in 14.2.0_1. Disable the workaround if the fix is detected. */
+#if defined(__APPLE__) && !defined(__clang__) && defined(__GNUC__) && \
   defined(__has_attribute)
-#define availability curl_pp_attribute_disabled
+#  if !defined(__has_feature)
+#    define availability curl_pp_attribute_disabled
+#  elif !__has_feature(attribute_availability)
+#    define availability curl_pp_attribute_disabled
+#  endif
 #endif
 
 #if defined(__APPLE__)
@@ -109,7 +112,7 @@
 #  include <winapifamily.h>
 #  if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) &&  \
      !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-#    define CURL_WINDOWS_APP
+#    define CURL_WINDOWS_UWP
 #  endif
 # endif
 #endif
@@ -212,6 +215,11 @@
 /*  please, do it beyond the point further indicated in this file.  */
 /* ================================================================ */
 
+/* Give calloc a chance to be dragging in early, so we do not redefine */
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+#  include <pthread.h>
+#endif
+
 /*
  * Disable other protocols when http is the only one desired.
  */
@@ -286,6 +294,14 @@
 #  define CURL_DISABLE_HTTP_AUTH 1
 #endif
 
+/*
+ * ECH requires HTTPSRR.
+ */
+
+#if defined(USE_ECH) && !defined(USE_HTTPSRR)
+#  define USE_HTTPSRR
+#endif
+
 /* ================================================================ */
 /* No system header file shall be included in this file before this */
 /* point.                                                           */
@@ -453,6 +469,12 @@
 #include <curl/stdcheaders.h>
 #endif
 
+#ifdef _WIN32
+#define Curl_getpid() GetCurrentProcessId()
+#else
+#define Curl_getpid() getpid()
+#endif
+
 /* Default Windows file API selection.  */
 #ifdef _WIN32
 # if defined(_MSC_VER) && (_INTEGRAL_MAX_BITS >= 64)
diff --git a/Utilities/cmcurl/lib/curl_sha256.h b/Utilities/cmcurl/lib/curl_sha256.h
index c3cf00a..00e5b74 100644
--- a/Utilities/cmcurl/lib/curl_sha256.h
+++ b/Utilities/cmcurl/lib/curl_sha256.h
@@ -31,7 +31,7 @@
 #include <curl/curl.h>
 #include "curl_hmac.h"
 
-extern const struct HMAC_params Curl_HMAC_SHA256[1];
+extern const struct HMAC_params Curl_HMAC_SHA256;
 
 #ifndef CURL_SHA256_DIGEST_LENGTH
 #define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
diff --git a/Utilities/cmcurl/lib/curl_sha512_256.c b/Utilities/cmcurl/lib/curl_sha512_256.c
index 576eda2..80fd8cf 100644
--- a/Utilities/cmcurl/lib/curl_sha512_256.c
+++ b/Utilities/cmcurl/lib/curl_sha512_256.c
@@ -34,7 +34,7 @@
  * * GnuTLS
  * * wolfSSL
  * * Schannel SSPI
- * * SecureTransport (Darwin)
+ * * Secure Transport (Darwin)
  * * mbedTLS
  * * BearSSL
  * * Rustls
diff --git a/Utilities/cmcurl/lib/curl_threads.c b/Utilities/cmcurl/lib/curl_threads.c
index 6d73273..fbbbf9b 100644
--- a/Utilities/cmcurl/lib/curl_threads.c
+++ b/Utilities/cmcurl/lib/curl_threads.c
@@ -103,7 +103,7 @@
 #elif defined(USE_THREADS_WIN32)
 
 curl_thread_t Curl_thread_create(
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
                                  DWORD
 #else
                                  unsigned int
@@ -111,14 +111,14 @@
                                  (CURL_STDCALL *func) (void *),
                                  void *arg)
 {
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
   typedef HANDLE curl_win_thread_handle_t;
 #else
   typedef uintptr_t curl_win_thread_handle_t;
 #endif
   curl_thread_t t;
   curl_win_thread_handle_t thread_handle;
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
   thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
 #else
   thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
diff --git a/Utilities/cmcurl/lib/curl_threads.h b/Utilities/cmcurl/lib/curl_threads.h
index be22352..c9f18a4 100644
--- a/Utilities/cmcurl/lib/curl_threads.h
+++ b/Utilities/cmcurl/lib/curl_threads.h
@@ -53,7 +53,7 @@
 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
 
 curl_thread_t Curl_thread_create(
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
                                  DWORD
 #else
                                  unsigned int
diff --git a/Utilities/cmcurl/lib/curl_trc.c b/Utilities/cmcurl/lib/curl_trc.c
index 58512d7..a3a107a 100644
--- a/Utilities/cmcurl/lib/curl_trc.c
+++ b/Utilities/cmcurl/lib/curl_trc.c
@@ -65,7 +65,7 @@
       "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
     if(data->set.fdebug) {
       bool inCallback = Curl_is_in_callback(data);
-      Curl_set_in_callback(data, true);
+      Curl_set_in_callback(data, TRUE);
       (void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
       Curl_set_in_callback(data, inCallback);
     }
@@ -239,7 +239,7 @@
 }
 #endif /* !CURL_DISABLE_SMTP */
 
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 struct curl_trc_feat Curl_trc_feat_ws = {
   "WS",
   CURL_LOG_LVL_NONE,
@@ -255,7 +255,7 @@
     va_end(ap);
   }
 }
-#endif /* USE_WEBSOCKETS && !CURL_DISABLE_HTTP */
+#endif /* !CURL_DISABLE_WEBSOCKETS && !CURL_DISABLE_HTTP */
 
 #define TRC_CT_NONE        (0)
 #define TRC_CT_PROTOCOL    (1<<(0))
@@ -279,7 +279,7 @@
 #ifndef CURL_DISABLE_SMTP
   { &Curl_trc_feat_smtp,      TRC_CT_PROTOCOL },
 #endif
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
   { &Curl_trc_feat_ws,        TRC_CT_PROTOCOL },
 #endif
 };
@@ -365,7 +365,7 @@
   if(!tmp)
     return CURLE_OUT_OF_MEMORY;
 
-  token = strtok_r(tmp, ", ", &tok_buf);
+  token = Curl_strtok_r(tmp, ", ", &tok_buf);
   while(token) {
     switch(*token) {
       case '-':
@@ -391,7 +391,7 @@
     else
       trc_apply_level_by_name(token, lvl);
 
-    token = strtok_r(NULL, ", ", &tok_buf);
+    token = Curl_strtok_r(NULL, ", ", &tok_buf);
   }
   free(tmp);
   return CURLE_OK;
@@ -399,7 +399,7 @@
 
 CURLcode Curl_trc_opt(const char *config)
 {
-  CURLcode result = config? trc_opt(config) : CURLE_OK;
+  CURLcode result = config ? trc_opt(config) : CURLE_OK;
 #ifdef DEBUGBUILD
   /* CURL_DEBUG can override anything */
   if(!result) {
diff --git a/Utilities/cmcurl/lib/curl_trc.h b/Utilities/cmcurl/lib/curl_trc.h
index 5f675b4..67a7f4a 100644
--- a/Utilities/cmcurl/lib/curl_trc.h
+++ b/Utilities/cmcurl/lib/curl_trc.h
@@ -94,11 +94,11 @@
   do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) \
          Curl_trc_smtp(data, __VA_ARGS__); } while(0)
 #endif /* !CURL_DISABLE_SMTP */
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
-#define CURL_TRC_WS(data, ...) \
+#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#define CURL_TRC_WS(data, ...)                             \
   do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) \
          Curl_trc_ws(data, __VA_ARGS__); } while(0)
-#endif /* USE_WEBSOCKETS && !CURL_DISABLE_HTTP */
+#endif /* !CURL_DISABLE_WEBSOCKETS && !CURL_DISABLE_HTTP */
 
 #else /* CURL_HAVE_C99 */
 
@@ -113,7 +113,7 @@
 #ifndef CURL_DISABLE_SMTP
 #define CURL_TRC_SMTP  Curl_trc_smtp
 #endif
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 #define CURL_TRC_WS    Curl_trc_ws
 #endif
 
@@ -152,8 +152,6 @@
  */
 void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
                        const char *fmt, ...) CURL_PRINTF(3, 4);
-void Curl_trc_ft_infof(struct Curl_easy *data, struct curl_trc_feat *ft,
-                       const char *fmt, ...) CURL_PRINTF(3, 4);
 void Curl_trc_write(struct Curl_easy *data,
                     const char *fmt, ...) CURL_PRINTF(2, 3);
 void Curl_trc_read(struct Curl_easy *data,
@@ -169,7 +167,7 @@
 void Curl_trc_smtp(struct Curl_easy *data,
                    const char *fmt, ...) CURL_PRINTF(2, 3);
 #endif
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 extern struct curl_trc_feat Curl_trc_feat_ws;
 void Curl_trc_ws(struct Curl_easy *data,
                  const char *fmt, ...) CURL_PRINTF(2, 3);
@@ -197,13 +195,6 @@
 
 struct curl_trc_feat;
 
-static void Curl_trc_ft_infof(struct Curl_easy *data,
-                              struct curl_trc_feat *ft,
-                              const char *fmt, ...)
-{
-  (void)data; (void)ft; (void)fmt;
-}
-
 static void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
 {
   (void)data; (void)fmt;
@@ -226,6 +217,12 @@
   (void)data; (void)fmt;
 }
 #endif
+#if !defined(CURL_DISABLE_WEBSOCKETS) || !defined(CURL_DISABLE_HTTP)
+static void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+#endif
 
 #endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
 
diff --git a/Utilities/cmcurl/lib/curlx.h b/Utilities/cmcurl/lib/curlx.h
index 0391d7c..f0e4e64 100644
--- a/Utilities/cmcurl/lib/curlx.h
+++ b/Utilities/cmcurl/lib/curlx.h
@@ -66,13 +66,4 @@
 #include "version_win32.h"
 /* "version_win32.h" provides curlx_verify_windows_version() */
 
-/* Now setup curlx_ * names for the functions that are to become curlx_ and
-   be removed from a future libcurl official API:
-   curlx_getenv
-   curlx_mprintf (and its variations)
-   curlx_strcasecompare
-   curlx_strncasecompare
-
-*/
-
 #endif /* HEADER_CURL_CURLX_H */
diff --git a/Utilities/cmcurl/lib/cw-out.c b/Utilities/cmcurl/lib/cw-out.c
index 56ec416..4d3df0a 100644
--- a/Utilities/cmcurl/lib/cw-out.c
+++ b/Utilities/cmcurl/lib/cw-out.c
@@ -177,8 +177,8 @@
     *pmin_write = 0;
     break;
   case CW_OUT_HDS:
-    *pwcb = data->set.fwrite_header? data->set.fwrite_header :
-             (data->set.writeheader? data->set.fwrite_func : NULL);
+    *pwcb = data->set.fwrite_header ? data->set.fwrite_header :
+             (data->set.writeheader ? data->set.fwrite_func : NULL);
     *pwcb_data = data->set.writeheader;
     *pmax_write = 0; /* do not chunk-write headers, write them as they are */
     *pmin_write = 0;
@@ -218,12 +218,12 @@
   while(blen && !ctx->paused) {
     if(!flush_all && blen < min_write)
       break;
-    wlen = max_write? CURLMIN(blen, max_write) : blen;
+    wlen = max_write ? CURLMIN(blen, max_write) : blen;
     Curl_set_in_callback(data, TRUE);
     nwritten = wcb((char *)buf, 1, wlen, wcb_data);
     Curl_set_in_callback(data, FALSE);
     CURL_TRC_WRITE(data, "cw_out, wrote %zu %s bytes -> %zu",
-                   wlen, (otype == CW_OUT_BODY)? "body" : "header",
+                   wlen, (otype == CW_OUT_BODY) ? "body" : "header",
                    nwritten);
     if(CURL_WRITEFUNC_PAUSE == nwritten) {
       if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) {
@@ -402,9 +402,8 @@
 {
   struct cw_out_ctx *ctx = writer->ctx;
   CURLcode result;
-  bool flush_all;
+  bool flush_all = !!(type & CLIENTWRITE_EOS);
 
-  flush_all = (type & CLIENTWRITE_EOS)? TRUE:FALSE;
   if((type & CLIENTWRITE_BODY) ||
      ((type & CLIENTWRITE_HEADER) && data->set.include_header)) {
     result = cw_out_do_write(ctx, data, CW_OUT_BODY, flush_all, buf, blen);
@@ -431,7 +430,7 @@
     return FALSE;
 
   ctx = (struct cw_out_ctx *)cw_out;
-  CURL_TRC_WRITE(data, "cw-out is%spaused", ctx->paused? "" : " not");
+  CURL_TRC_WRITE(data, "cw-out is%spaused", ctx->paused ? "" : " not");
   return ctx->paused;
 }
 
diff --git a/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c
index 52b3574..8769372 100644
--- a/Utilities/cmcurl/lib/doh.c
+++ b/Utilities/cmcurl/lib/doh.c
@@ -165,7 +165,7 @@
   *dnsp++ = 0; /* append zero-length label for root */
 
   /* There are assigned TYPE codes beyond 255: use range [1..65535]  */
-  *dnsp++ = (unsigned char)(255 & (dnstype>>8)); /* upper 8 bit TYPE */
+  *dnsp++ = (unsigned char)(255 & (dnstype >> 8)); /* upper 8 bit TYPE */
   *dnsp++ = (unsigned char)(255 & dnstype);      /* lower 8 bit TYPE */
 
   *dnsp++ = '\0'; /* upper 8 bit CLASS */
@@ -180,7 +180,7 @@
 }
 
 static size_t
-doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
+doh_write_cb(char *contents, size_t size, size_t nmemb, void *userp)
 {
   size_t realsize = size * nmemb;
   struct dynbuf *mem = (struct dynbuf *)userp;
@@ -198,10 +198,10 @@
 {
   unsigned char hexstr[LOCAL_PB_HEXMAX];
   size_t hlen = LOCAL_PB_HEXMAX;
-  bool truncated = false;
+  bool truncated = FALSE;
 
   if(len > (LOCAL_PB_HEXMAX / 2))
-    truncated = true;
+    truncated = TRUE;
   Curl_hexencode(buf, len, hexstr, hlen);
   if(!truncated)
     infof(data, "%s: len=%d, val=%s", prefix, (int)len, hexstr);
@@ -238,14 +238,14 @@
   return 0;
 }
 
-#define ERROR_CHECK_SETOPT(x,y) \
-do {                                          \
-  result = curl_easy_setopt(doh, x, y);       \
-  if(result &&                                \
-     result != CURLE_NOT_BUILT_IN &&          \
-     result != CURLE_UNKNOWN_OPTION)          \
-    goto error;                               \
-} while(0)
+#define ERROR_CHECK_SETOPT(x,y)                         \
+  do {                                                  \
+    result = curl_easy_setopt((CURL *)doh, x, y);       \
+    if(result &&                                        \
+       result != CURLE_NOT_BUILT_IN &&                  \
+       result != CURLE_UNKNOWN_OPTION)                  \
+      goto error;                                       \
+  } while(0)
 
 static CURLcode doh_run_probe(struct Curl_easy *data,
                               struct doh_probe *p, DNStype dnstype,
@@ -278,7 +278,7 @@
 
   /* pass in the struct pointer via a local variable to please coverity and
      the gcc typecheck helpers */
-  doh->state.internal = true;
+  doh->state.internal = TRUE;
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   doh->state.feat = &Curl_doh_trc;
 #endif
@@ -301,7 +301,7 @@
   ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
 #endif
   ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
-  ERROR_CHECK_SETOPT(CURLOPT_SHARE, data->share);
+  ERROR_CHECK_SETOPT(CURLOPT_SHARE, (CURLSH *)data->share);
   if(data->set.err && data->set.err != stderr)
     ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
   if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc))
@@ -847,15 +847,13 @@
     }
     else if(a->type == DNS_TYPE_AAAA) {
       int j;
-      char buffer[128];
-      char *ptr;
-      size_t len;
-      len = msnprintf(buffer, 128, "[DoH] AAAA: ");
-      ptr = &buffer[len];
+      char buffer[128] = "[DoH] AAAA: ";
+      size_t len = strlen(buffer);
+      char *ptr = &buffer[len];
       len = sizeof(buffer) - len;
       for(j = 0; j < 16; j += 2) {
         size_t l;
-        msnprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j],
+        msnprintf(ptr, len, "%s%02x%02x", j ? ":" : "", d->addr[i].ip.v6[j],
                   d->addr[i].ip.v6[j + 1]);
         l = strlen(ptr);
         len -= l;
@@ -1305,7 +1303,7 @@
   if(dohp->probe[DOH_SLOT_IPV4].easy_mid < 0 &&
      dohp->probe[DOH_SLOT_IPV6].easy_mid < 0) {
     failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
-    return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY:
+    return CONN_IS_PROXIED(data->conn) ? CURLE_COULDNT_RESOLVE_PROXY :
       CURLE_COULDNT_RESOLVE_HOST;
   }
   else if(!dohp->pending) {
@@ -1415,7 +1413,8 @@
       doh->probe[slot].easy_mid = -1;
       /* should have been called before data is removed from multi handle */
       DEBUGASSERT(data->multi);
-      probe_data = data->multi? Curl_multi_get_handle(data->multi, mid) : NULL;
+      probe_data = data->multi ? Curl_multi_get_handle(data->multi, mid) :
+        NULL;
       if(!probe_data) {
         DEBUGF(infof(data, "Curl_doh_close: xfer for mid=%"
                      FMT_OFF_T " not found!",
diff --git a/Utilities/cmcurl/lib/dynhds.c b/Utilities/cmcurl/lib/dynhds.c
index 9153838..2c92ca6 100644
--- a/Utilities/cmcurl/lib/dynhds.c
+++ b/Utilities/cmcurl/lib/dynhds.c
@@ -141,7 +141,7 @@
 struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n)
 {
   DEBUGASSERT(dynhds);
-  return (n < dynhds->hds_len)? dynhds->hds[n] : NULL;
+  return (n < dynhds->hds_len) ? dynhds->hds[n] : NULL;
 }
 
 struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds, const char *name,
@@ -272,7 +272,7 @@
 
 CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line)
 {
-  return Curl_dynhds_h1_add_line(dynhds, line, line? strlen(line) : 0);
+  return Curl_dynhds_h1_add_line(dynhds, line, line ? strlen(line) : 0);
 }
 
 #ifdef UNITTESTS
diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c
index 261445a..ac8fab3 100644
--- a/Utilities/cmcurl/lib/easy.c
+++ b/Utilities/cmcurl/lib/easy.c
@@ -347,7 +347,7 @@
  * curl_easy_init() is the external interface to alloc, setup and init an
  * easy handle that is returned. If anything goes wrong, NULL is returned.
  */
-struct Curl_easy *curl_easy_init(void)
+CURL *curl_easy_init(void)
 {
   CURLcode result;
   struct Curl_easy *data;
@@ -398,9 +398,9 @@
  * Callback that gets called with a new value when the timeout should be
  * updated.
  */
-static int events_timer(struct Curl_multi *multi,    /* multi handle */
+static int events_timer(CURLM *multi,    /* multi handle */
                         long timeout_ms, /* see above */
-                        void *userp)    /* private callback pointer */
+                        void *userp)     /* private callback pointer */
 {
   struct events *ev = userp;
   (void)multi;
@@ -449,7 +449,7 @@
  * Callback that gets called with information about socket activity to
  * monitor.
  */
-static int events_socket(struct Curl_easy *easy,      /* easy handle */
+static int events_socket(CURL *easy,      /* easy handle */
                          curl_socket_t s, /* socket */
                          int what,        /* see above */
                          void *userp,     /* private callback
@@ -461,6 +461,7 @@
   struct socketmonitor *m;
   struct socketmonitor *prev = NULL;
   bool found = FALSE;
+  struct Curl_easy *data = easy;
 
 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
   (void) easy;
@@ -479,16 +480,16 @@
         else
           ev->list = nxt;
         free(m);
-        infof(easy, "socket cb: socket %" FMT_SOCKET_T " REMOVED", s);
+        infof(data, "socket cb: socket %" FMT_SOCKET_T " REMOVED", s);
       }
       else {
         /* The socket 's' is already being monitored, update the activity
            mask. Convert from libcurl bitmask to the poll one. */
         m->socket.events = socketcb2poll(what);
-        infof(easy, "socket cb: socket %" FMT_SOCKET_T
+        infof(data, "socket cb: socket %" FMT_SOCKET_T
               " UPDATED as %s%s", s,
-              (what&CURL_POLL_IN)?"IN":"",
-              (what&CURL_POLL_OUT)?"OUT":"");
+              (what&CURL_POLL_IN) ? "IN" : "",
+              (what&CURL_POLL_OUT) ? "OUT" : "");
       }
       break;
     }
@@ -499,7 +500,7 @@
   if(!found) {
     if(what == CURL_POLL_REMOVE) {
       /* should not happen if our logic is correct, but is no drama. */
-      DEBUGF(infof(easy, "socket cb: asked to REMOVE socket %"
+      DEBUGF(infof(data, "socket cb: asked to REMOVE socket %"
                    FMT_SOCKET_T "but not present!", s));
       DEBUGASSERT(0);
     }
@@ -511,9 +512,9 @@
         m->socket.events = socketcb2poll(what);
         m->socket.revents = 0;
         ev->list = m;
-        infof(easy, "socket cb: socket %" FMT_SOCKET_T " ADDED as %s%s", s,
-              (what&CURL_POLL_IN)?"IN":"",
-              (what&CURL_POLL_OUT)?"OUT":"");
+        infof(data, "socket cb: socket %" FMT_SOCKET_T " ADDED as %s%s", s,
+              (what&CURL_POLL_IN) ? "IN" : "",
+              (what&CURL_POLL_OUT) ? "OUT" : "");
       }
       else
         return CURLE_OUT_OF_MEMORY;
@@ -617,7 +618,7 @@
       DEBUGASSERT(data);
 
       /* loop over the monitored sockets to see which ones had activity */
-      for(i = 0; i< numfds; i++) {
+      for(i = 0; i < numfds; i++) {
         if(fds[i].revents) {
           /* socket activity, tell libcurl */
           int act = poll2cselect(fds[i].revents); /* convert */
@@ -809,7 +810,7 @@
  * curl_easy_perform() is the external interface that performs a blocking
  * transfer as previously setup.
  */
-CURLcode curl_easy_perform(struct Curl_easy *data)
+CURLcode curl_easy_perform(CURL *data)
 {
   return easy_perform(data, FALSE);
 }
@@ -830,8 +831,9 @@
  * curl_easy_cleanup() is the external interface to cleaning/freeing the given
  * easy handle.
  */
-void curl_easy_cleanup(struct Curl_easy *data)
+void curl_easy_cleanup(CURL *ptr)
 {
+  struct Curl_easy *data = ptr;
   if(GOOD_EASY_HANDLE(data)) {
     SIGPIPE_VARIABLE(pipe_st);
     sigpipe_ignore(data, &pipe_st);
@@ -845,7 +847,7 @@
  * information from a performed transfer and similar.
  */
 #undef curl_easy_getinfo
-CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...)
+CURLcode curl_easy_getinfo(CURL *data, CURLINFO info, ...)
 {
   va_list arg;
   void *paramp;
@@ -877,7 +879,7 @@
   memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *));
 
   /* duplicate all strings */
-  for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
+  for(i = (enum dupstring)0; i < STRING_LASTZEROTERMINATED; i++) {
     result = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
     if(result)
       return result;
@@ -919,8 +921,9 @@
  * given input easy handle. The returned handle will be a new working handle
  * with all options set exactly as the input source handle.
  */
-struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
+CURL *curl_easy_duphandle(CURL *d)
 {
+  struct Curl_easy *data = d;
   struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
   if(!outcurl)
     goto fail;
@@ -937,6 +940,7 @@
     goto fail;
 
   Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
+  Curl_netrc_init(&outcurl->state.netrc);
 
   /* the connection pool is setup on demand */
   outcurl->state.lastconnect_id = -1;
@@ -1066,8 +1070,9 @@
  * curl_easy_reset() is an external interface that allows an app to re-
  * initialize a session handle to the default values.
  */
-void curl_easy_reset(struct Curl_easy *data)
+void curl_easy_reset(CURL *d)
 {
+  struct Curl_easy *data = d;
   Curl_req_hard_reset(&data->req, data);
 
   /* zero out UserDefined data: */
@@ -1107,7 +1112,7 @@
  * NOTE: This is one of few API functions that are allowed to be called from
  * within a callback.
  */
-CURLcode curl_easy_pause(struct Curl_easy *data, int action)
+CURLcode curl_easy_pause(CURL *d, int action)
 {
   struct SingleRequest *k;
   CURLcode result = CURLE_OK;
@@ -1115,6 +1120,7 @@
   int newstate;
   bool recursive = FALSE;
   bool keep_changed, unpause_read, not_all_paused;
+  struct Curl_easy *data = d;
 
   if(!GOOD_EASY_HANDLE(data) || !data->conn)
     /* crazy input, do not continue */
@@ -1127,8 +1133,8 @@
 
   /* first switch off both pause bits then set the new pause bits */
   newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) |
-    ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
-    ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
+    ((action & CURLPAUSE_RECV) ? KEEP_RECV_PAUSE : 0) |
+    ((action & CURLPAUSE_SEND) ? KEEP_SEND_PAUSE : 0);
 
   keep_changed = ((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) != oldstate);
   not_all_paused = (newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
@@ -1218,12 +1224,12 @@
  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
  * Returns CURLE_OK on success, error code on error.
  */
-CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
-                        size_t *n)
+CURLcode curl_easy_recv(CURL *d, void *buffer, size_t buflen, size_t *n)
 {
   CURLcode result;
   ssize_t n1;
   struct connectdata *c;
+  struct Curl_easy *data = d;
 
   if(Curl_is_in_callback(data))
     return CURLE_RECURSIVE_API_CALL;
@@ -1247,7 +1253,7 @@
   return CURLE_OK;
 }
 
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_WEBSOCKETS
 CURLcode Curl_connect_only_attach(struct Curl_easy *data)
 {
   CURLcode result;
@@ -1264,7 +1270,7 @@
 
   return CURLE_OK;
 }
-#endif /* USE_WEBSOCKETS */
+#endif /* !CURL_DISABLE_WEBSOCKETS */
 
 /*
  * Sends data over the connected socket.
@@ -1301,11 +1307,11 @@
  * 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)
+CURLcode curl_easy_send(CURL *d, const void *buffer, size_t buflen, size_t *n)
 {
   size_t written = 0;
   CURLcode result;
+  struct Curl_easy *data = d;
   if(Curl_is_in_callback(data))
     return CURLE_RECURSIVE_API_CALL;
 
@@ -1317,8 +1323,9 @@
 /*
  * Performs connection upkeep for the given session handle.
  */
-CURLcode curl_easy_upkeep(struct Curl_easy *data)
+CURLcode curl_easy_upkeep(CURL *d)
 {
+  struct Curl_easy *data = d;
   /* Verify that we got an easy handle we can work with. */
   if(!GOOD_EASY_HANDLE(data))
     return CURLE_BAD_FUNCTION_ARGUMENT;
diff --git a/Utilities/cmcurl/lib/easyif.h b/Utilities/cmcurl/lib/easyif.h
index d77bb98..181ce38 100644
--- a/Utilities/cmcurl/lib/easyif.h
+++ b/Utilities/cmcurl/lib/easyif.h
@@ -30,7 +30,7 @@
 CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
                        size_t buflen, size_t *n);
 
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_WEBSOCKETS
 CURLcode Curl_connect_only_attach(struct Curl_easy *data);
 #endif
 
diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c
index 9b6edb4..eaad6d3 100644
--- a/Utilities/cmcurl/lib/escape.c
+++ b/Utilities/cmcurl/lib/escape.c
@@ -29,6 +29,8 @@
 
 #include <curl/curl.h>
 
+struct Curl_easy;
+
 #include "urldata.h"
 #include "warnless.h"
 #include "escape.h"
@@ -53,7 +55,7 @@
 /* Escapes for URL the given unescaped string of given length.
  * 'data' is ignored since 7.82.0.
  */
-char *curl_easy_escape(struct Curl_easy *data, const char *string,
+char *curl_easy_escape(CURL *data, const char *string,
                        int inlength)
 {
   size_t length;
@@ -63,7 +65,7 @@
   if(!string || (inlength < 0))
     return NULL;
 
-  length = (inlength?(size_t)inlength:strlen(string));
+  length = (inlength ? (size_t)inlength : strlen(string));
   if(!length)
     return strdup("");
 
@@ -82,7 +84,7 @@
       /* encode it */
       const char hex[] = "0123456789ABCDEF";
       char out[3]={'%'};
-      out[1] = hex[in>>4];
+      out[1] = hex[in >> 4];
       out[2] = hex[in & 0xf];
       if(Curl_dyn_addn(&d, out, 3))
         return NULL;
@@ -128,7 +130,7 @@
   DEBUGASSERT(string);
   DEBUGASSERT(ctrl >= REJECT_NADA); /* crash on TRUE/FALSE */
 
-  alloc = (length?length:strlen(string));
+  alloc = (length ? length : strlen(string));
   ns = malloc(alloc + 1);
 
   if(!ns)
@@ -176,7 +178,7 @@
  * If olen == NULL, no output length is stored.
  * 'data' is ignored since 7.82.0.
  */
-char *curl_easy_unescape(struct Curl_easy *data, const char *string,
+char *curl_easy_unescape(CURL *data, const char *string,
                          int length, int *olen)
 {
   char *str = NULL;
@@ -223,7 +225,7 @@
     while(len-- && (olen >= 3)) {
       /* clang-tidy warns on this line without this comment: */
       /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */
-      *out++ = (unsigned char)hex[(*src & 0xF0)>>4];
+      *out++ = (unsigned char)hex[(*src & 0xF0) >> 4];
       *out++ = (unsigned char)hex[*src & 0x0F];
       ++src;
       olen -= 2;
diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c
index 01af52e..4cd8d0f 100644
--- a/Utilities/cmcurl/lib/file.c
+++ b/Utilities/cmcurl/lib/file.c
@@ -489,7 +489,7 @@
     headerlen =
       msnprintf(header, sizeof(header),
                 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
-                Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+                Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6],
                 tm->tm_mday,
                 Curl_month[tm->tm_mon],
                 tm->tm_year + 1900,
diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c
index c260d44..7ea7a8f 100644
--- a/Utilities/cmcurl/lib/formdata.c
+++ b/Utilities/cmcurl/lib/formdata.c
@@ -26,6 +26,8 @@
 
 #include <curl/curl.h>
 
+struct Curl_easy;
+
 #include "formdata.h"
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
 
@@ -282,8 +284,8 @@
       if(current_form->name)
         return_value = CURL_FORMADD_OPTION_TWICE;
       else {
-        char *name = array_state?
-          array_value:va_arg(params, char *);
+        char *name = array_state ?
+          array_value : va_arg(params, char *);
         if(name)
           current_form->name = name; /* store for the moment */
         else
@@ -295,7 +297,7 @@
         return_value = CURL_FORMADD_OPTION_TWICE;
       else
         current_form->namelength =
-          array_state?(size_t)array_value:(size_t)va_arg(params, long);
+          array_state ? (size_t)array_value : (size_t)va_arg(params, long);
       break;
 
       /*
@@ -309,7 +311,7 @@
         return_value = CURL_FORMADD_OPTION_TWICE;
       else {
         char *value =
-          array_state?array_value:va_arg(params, char *);
+          array_state ? array_value : va_arg(params, char *);
         if(value)
           current_form->value = value; /* store for the moment */
         else
@@ -318,13 +320,14 @@
       break;
     case CURLFORM_CONTENTSLENGTH:
       current_form->contentslength =
-        array_state?(size_t)array_value:(size_t)va_arg(params, long);
+        array_state ? (size_t)array_value : (size_t)va_arg(params, long);
       break;
 
     case CURLFORM_CONTENTLEN:
       current_form->flags |= CURL_HTTPPOST_LARGE;
       current_form->contentslength =
-        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
+        array_state ? (curl_off_t)(size_t)array_value :
+        va_arg(params, curl_off_t);
       break;
 
       /* Get contents from a given filename */
@@ -332,8 +335,8 @@
       if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
         return_value = CURL_FORMADD_OPTION_TWICE;
       else {
-        const char *filename = array_state?
-          array_value:va_arg(params, char *);
+        const char *filename = array_state ?
+          array_value : va_arg(params, char *);
         if(filename) {
           current_form->value = strdup(filename);
           if(!current_form->value)
@@ -351,7 +354,7 @@
       /* We upload a file */
     case CURLFORM_FILE:
       {
-        const char *filename = array_state?array_value:
+        const char *filename = array_state ? array_value :
           va_arg(params, char *);
 
         if(current_form->value) {
@@ -401,7 +404,7 @@
         return_value = CURL_FORMADD_OPTION_TWICE;
       else {
         char *buffer =
-          array_state?array_value:va_arg(params, char *);
+          array_state ? array_value : va_arg(params, char *);
         if(buffer) {
           current_form->buffer = buffer; /* store for the moment */
           current_form->value = buffer; /* make it non-NULL to be accepted
@@ -417,7 +420,7 @@
         return_value = CURL_FORMADD_OPTION_TWICE;
       else
         current_form->bufferlength =
-          array_state?(size_t)array_value:(size_t)va_arg(params, long);
+          array_state ? (size_t)array_value : (size_t)va_arg(params, long);
       break;
 
     case CURLFORM_STREAM:
@@ -426,7 +429,7 @@
         return_value = CURL_FORMADD_OPTION_TWICE;
       else {
         char *userp =
-          array_state?array_value:va_arg(params, char *);
+          array_state ? array_value : va_arg(params, char *);
         if(userp) {
           current_form->userp = userp;
           current_form->value = userp; /* this is not strictly true but we
@@ -442,7 +445,7 @@
     case CURLFORM_CONTENTTYPE:
       {
         const char *contenttype =
-          array_state?array_value:va_arg(params, char *);
+          array_state ? array_value : va_arg(params, char *);
         if(current_form->contenttype) {
           if(current_form->flags & HTTPPOST_FILENAME) {
             if(contenttype) {
@@ -485,8 +488,8 @@
       {
         /* this "cast increases required alignment of target type" but
            we consider it OK anyway */
-        struct curl_slist *list = array_state?
-          (struct curl_slist *)(void *)array_value:
+        struct curl_slist *list = array_state ?
+          (struct curl_slist *)(void *)array_value :
           va_arg(params, struct curl_slist *);
 
         if(current_form->contentheader)
@@ -499,7 +502,7 @@
     case CURLFORM_FILENAME:
     case CURLFORM_BUFFER:
       {
-        const char *filename = array_state?array_value:
+        const char *filename = array_state ? array_value :
           va_arg(params, char *);
         if(current_form->showfilename)
           return_value = CURL_FORMADD_OPTION_TWICE;
@@ -569,7 +572,7 @@
       if(((form->flags & HTTPPOST_FILENAME) ||
           (form->flags & HTTPPOST_BUFFER)) &&
          !form->contenttype) {
-        char *f = (form->flags & HTTPPOST_BUFFER)?
+        char *f = (form->flags & HTTPPOST_BUFFER) ?
           form->showfilename : form->value;
         char const *type;
         type = Curl_mime_contenttype(f);
@@ -603,8 +606,8 @@
            app passed in a bad combo, so we better check for that first. */
         if(form->name) {
           /* copy name (without strdup; possibly not null-terminated) */
-          form->name = Curl_memdup0(form->name, form->namelength?
-                                    form->namelength:
+          form->name = Curl_memdup0(form->name, form->namelength ?
+                                    form->namelength :
                                     strlen(form->name));
         }
         if(!form->name) {
@@ -790,7 +793,7 @@
 /* wrap call to fseeko so it matches the calling convention of callback */
 static int fseeko_wrapper(void *stream, curl_off_t offset, int whence)
 {
-#if defined(HAVE__FSEEKI64)
+#if defined(_WIN32) && defined(USE_WIN32_LARGE_FILES)
   return _fseeki64(stream, (__int64)offset, whence);
 #elif defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
   return fseeko(stream, (off_t)offset, whence);
@@ -811,7 +814,7 @@
  * a NULL pointer in the 'data' argument.
  */
 
-CURLcode Curl_getformdata(struct Curl_easy *data,
+CURLcode Curl_getformdata(CURL *data,
                           curl_mimepart *finalform,
                           struct curl_httppost *post,
                           curl_read_callback fread_func)
@@ -896,7 +899,8 @@
         }
         else if(post->flags & HTTPPOST_BUFFER)
           result = curl_mime_data(part, post->buffer,
-                                  post->bufferlength? post->bufferlength: -1);
+                                  post->bufferlength ?
+                                  post->bufferlength : -1);
         else if(post->flags & HTTPPOST_CALLBACK) {
           /* the contents should be read with the callback and the size is set
              with the contentslength */
diff --git a/Utilities/cmcurl/lib/formdata.h b/Utilities/cmcurl/lib/formdata.h
index 2ed96ff..0e35e18 100644
--- a/Utilities/cmcurl/lib/formdata.h
+++ b/Utilities/cmcurl/lib/formdata.h
@@ -49,7 +49,7 @@
   bool showfilename_alloc;
 };
 
-CURLcode Curl_getformdata(struct Curl_easy *data,
+CURLcode Curl_getformdata(CURL *data,
                           curl_mimepart *,
                           struct curl_httppost *post,
                           curl_read_callback fread_func);
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
index dab6e3e..dc12897 100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/ftp.c
@@ -302,10 +302,10 @@
  * requests on files respond with headers passed to the client/stdout that
  * looked like HTTP ones.
  *
- * This approach is not very elegant, it causes confusion and is error-prone.
- * It is subject for removal at the next (or at least a future) soname bump.
- * Until then you can test the effects of the removal by undefining the
- * following define named CURL_FTP_HTTPSTYLE_HEAD.
+ * This approach is not elegant, it causes confusion and is error-prone. It is
+ * subject for removal at the next (or at least a future) soname bump. Until
+ * then you can test the effects of the removal by undefining the following
+ * define named CURL_FTP_HTTPSTYLE_HEAD.
  */
 #define CURL_FTP_HTTPSTYLE_HEAD 1
 
@@ -419,138 +419,19 @@
 #endif /* CURL_PREFER_LF_LINEENDS */
 /***********************************************************************
  *
- * AcceptServerConnect()
- *
- * After connection request is received from the server this function is
- * called to accept the connection and close the listening socket
+ * ftp_check_ctrl_on_data_wait()
  *
  */
-static CURLcode AcceptServerConnect(struct Curl_easy *data)
-{
-  struct connectdata *conn = data->conn;
-  curl_socket_t sock = conn->sock[SECONDARYSOCKET];
-  curl_socket_t s = CURL_SOCKET_BAD;
-#ifdef USE_IPV6
-  struct Curl_sockaddr_storage add;
-#else
-  struct sockaddr_in add;
-#endif
-  curl_socklen_t size = (curl_socklen_t) sizeof(add);
-  CURLcode result;
-
-  if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
-    size = sizeof(add);
-
-    s = accept(sock, (struct sockaddr *) &add, &size);
-  }
-
-  if(CURL_SOCKET_BAD == s) {
-    failf(data, "Error accept()ing server connect");
-    return CURLE_FTP_PORT_FAILED;
-  }
-  infof(data, "Connection accepted from server");
-  /* when this happens within the DO state it is important that we mark us as
-     not needing DO_MORE anymore */
-  conn->bits.do_more = FALSE;
-
-  (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
-  /* Replace any filter on SECONDARY with one listening on this socket */
-  result = Curl_conn_tcp_accepted_set(data, conn, SECONDARYSOCKET, &s);
-  if(result) {
-    sclose(s);
-    return result;
-  }
-
-  if(data->set.fsockopt) {
-    int error = 0;
-
-    /* activate callback for setting socket options */
-    Curl_set_in_callback(data, true);
-    error = data->set.fsockopt(data->set.sockopt_client,
-                               s,
-                               CURLSOCKTYPE_ACCEPT);
-    Curl_set_in_callback(data, false);
-
-    if(error) {
-      close_secondarysocket(data);
-      return CURLE_ABORTED_BY_CALLBACK;
-    }
-  }
-
-  return CURLE_OK;
-
-}
-
-/*
- * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
- * waiting server to connect. If the value is negative, the timeout time has
- * already elapsed.
- *
- * The start time is stored in progress.t_acceptdata - as set with
- * Curl_pgrsTime(..., TIMER_STARTACCEPT);
- *
- */
-static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
-{
-  timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
-  timediff_t other;
-  struct curltime now;
-
-  if(data->set.accepttimeout > 0)
-    timeout_ms = data->set.accepttimeout;
-
-  now = Curl_now();
-
-  /* check if the generic timeout possibly is set shorter */
-  other = Curl_timeleft(data, &now, FALSE);
-  if(other && (other < timeout_ms))
-    /* note that this also works fine for when other happens to be negative
-       due to it already having elapsed */
-    timeout_ms = other;
-  else {
-    /* subtract elapsed time */
-    timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata);
-    if(!timeout_ms)
-      /* avoid returning 0 as that means no timeout! */
-      return -1;
-  }
-
-  return timeout_ms;
-}
-
-
-/***********************************************************************
- *
- * ReceivedServerConnect()
- *
- * After allowing server to connect to us from data port, this function
- * checks both data connection for connection establishment and ctrl
- * connection for a negative response regarding a failure in connecting
- *
- */
-static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
+static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data)
 {
   struct connectdata *conn = data->conn;
   curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
-  curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
-  int socketstate = 0;
-  timediff_t timeout_ms;
   ssize_t nread;
   int ftpcode;
   bool response = FALSE;
 
-  *received = FALSE;
-
-  timeout_ms = ftp_timeleft_accept(data);
-  infof(data, "Checking for server connect");
-  if(timeout_ms < 0) {
-    /* if a timeout was already reached, bail out */
-    failf(data, "Accept timeout occurred while waiting server connect");
-    return CURLE_FTP_ACCEPT_TIMEOUT;
-  }
-
   /* First check whether there is a cached response from server */
   if(Curl_dyn_len(&pp->recvbuf) && (*Curl_dyn_ptr(&pp->recvbuf) > '3')) {
     /* Data connection could not be established, let's return */
@@ -562,26 +443,22 @@
   if(pp->overflow)
     /* there is pending control data still in the buffer to read */
     response = TRUE;
-  else
-    socketstate = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
-
-  /* see if the connection request is already here */
-  switch(socketstate) {
-  case -1: /* error */
-    /* let's die here */
-    failf(data, "Error while waiting for server connect");
-    return CURLE_FTP_ACCEPT_FAILED;
-  case 0:  /* Server connect is not received yet */
-    break; /* loop */
-  default:
-    if(socketstate & CURL_CSELECT_IN2) {
-      infof(data, "Ready to accept data connection from server");
-      *received = TRUE;
+  else {
+    int socketstate = Curl_socket_check(ctrl_sock, CURL_SOCKET_BAD,
+                                        CURL_SOCKET_BAD, 0);
+    /* see if the connection request is already here */
+    switch(socketstate) {
+    case -1: /* error */
+      /* let's die here */
+      failf(data, "Error while waiting for server connect");
+      return CURLE_FTP_ACCEPT_FAILED;
+    default:
+      if(socketstate & CURL_CSELECT_IN)
+        response = TRUE;
+      break;
     }
-    else if(socketstate & CURL_CSELECT_IN)
-      response = TRUE;
-    break;
   }
+
   if(response) {
     infof(data, "Ctrl conn has data while waiting for data conn");
     if(pp->overflow > 3) {
@@ -600,7 +477,6 @@
              noticed. Leave the 226 in there and use this as a trigger to read
              the data socket. */
           infof(data, "Got 226 before data activity");
-          *received = TRUE;
           return CURLE_OK;
         }
       }
@@ -619,7 +495,6 @@
   return CURLE_OK;
 }
 
-
 /***********************************************************************
  *
  * InitiateTransfer()
@@ -635,12 +510,6 @@
   bool connected;
 
   CURL_TRC_FTP(data, "InitiateTransfer()");
-  if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port &&
-     !Curl_conn_is_ssl(conn, SECONDARYSOCKET)) {
-    result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET);
-    if(result)
-      return result;
-  }
   result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected);
   if(result || !connected)
     return result;
@@ -653,12 +522,14 @@
     /* set the SO_SNDBUF for the secondary socket for those who need it */
     Curl_sndbuf_init(conn->sock[SECONDARYSOCKET]);
 
-    Curl_xfer_setup2(data, CURL_XFER_SEND, -1, TRUE);
+    /* FTP upload, shutdown DATA, ignore shutdown errors, as we rely
+     * on the server response on the CONTROL connection. */
+    Curl_xfer_setup2(data, CURL_XFER_SEND, -1, TRUE, TRUE);
   }
   else {
-    /* FTP download: */
+    /* FTP download, shutdown, do not ignore errors */
     Curl_xfer_setup2(data, CURL_XFER_RECV,
-                     conn->proto.ftpc.retr_size_saved, TRUE);
+                     conn->proto.ftpc.retr_size_saved, TRUE, FALSE);
   }
 
   conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
@@ -667,60 +538,6 @@
   return CURLE_OK;
 }
 
-/***********************************************************************
- *
- * AllowServerConnect()
- *
- * When we have issue the PORT command, we have told the server to connect to
- * us. This function checks whether data connection is established if so it is
- * accepted.
- *
- */
-static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
-{
-  timediff_t timeout_ms;
-  CURLcode result = CURLE_OK;
-
-  *connected = FALSE;
-  infof(data, "Preparing for accepting server on data port");
-
-  /* Save the time we start accepting server connect */
-  Curl_pgrsTime(data, TIMER_STARTACCEPT);
-
-  timeout_ms = ftp_timeleft_accept(data);
-  if(timeout_ms < 0) {
-    /* if a timeout was already reached, bail out */
-    failf(data, "Accept timeout occurred while waiting server connect");
-    result = CURLE_FTP_ACCEPT_TIMEOUT;
-    goto out;
-  }
-
-  /* see if the connection request is already here */
-  result = ReceivedServerConnect(data, connected);
-  if(result)
-    goto out;
-
-  if(*connected) {
-    result = AcceptServerConnect(data);
-    if(result)
-      goto out;
-
-    result = InitiateTransfer(data);
-    if(result)
-      goto out;
-  }
-  else {
-    /* Add timeout to multi handle and break out of the loop */
-    Curl_expire(data, data->set.accepttimeout ?
-                data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT,
-                EXPIRE_FTP_ACCEPT);
-  }
-
-out:
-  CURL_TRC_FTP(data, "AllowServerConnect() -> %d", result);
-  return result;
-}
-
 static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
                           char *line, size_t len, int *code)
 {
@@ -864,8 +681,8 @@
        */
     }
     else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) {
-      curl_socket_t wsock = Curl_pp_needs_flush(data, pp)?
-                            sockfd : CURL_SOCKET_BAD;
+      curl_socket_t wsock = Curl_pp_needs_flush(data, pp) ?
+        sockfd : CURL_SOCKET_BAD;
       int ev = Curl_socket_check(sockfd, CURL_SOCKET_BAD, wsock, interval_ms);
       if(ev < 0) {
         failf(data, "FTP response aborted due to select/poll error: %d",
@@ -914,7 +731,7 @@
 {
   CURLcode result = Curl_pp_sendf(data,
                                   &conn->proto.ftpc.pp, "USER %s",
-                                  conn->user?conn->user:"");
+                                  conn->user ? conn->user : "");
   if(!result) {
     struct ftp_conn *ftpc = &conn->proto.ftpc;
     ftpc->ftp_trying_alternative = FALSE;
@@ -1138,7 +955,7 @@
       /* attempt to get the address of the given interface name */
       switch(Curl_if2ip(conn->remote_addr->family,
 #ifdef USE_IPV6
-                        Curl_ipv6_scope(&conn->remote_addr->sa_addr),
+                        Curl_ipv6_scope(&conn->remote_addr->curl_sa_addr),
                         conn->scope_id,
 #endif
                         ipstr, hbuf, sizeof(hbuf))) {
@@ -1304,12 +1121,6 @@
     conn->bits.ftp_use_eprt = TRUE;
 #endif
 
-  /* Replace any filter on SECONDARY with one listening on this socket */
-  result = Curl_conn_tcp_listen_set(data, conn, SECONDARYSOCKET, &portsock);
-  if(result)
-    goto out;
-  portsock = CURL_SOCKET_BAD; /* now held in filter */
-
   for(; fcmd != DONE; fcmd++) {
 
     if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
@@ -1343,7 +1154,7 @@
        */
 
       result = Curl_pp_sendf(data, &ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
-                             sa->sa_family == AF_INET?1:2,
+                             sa->sa_family == AF_INET ? 1 : 2,
                              myhost, port);
       if(result) {
         failf(data, "Failure sending EPRT command: %s",
@@ -1368,7 +1179,7 @@
         source++;
       }
       *dest = 0;
-      msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
+      msnprintf(dest, 20, ",%d,%d", (int)(port >> 8), (int)(port & 0xff));
 
       result = Curl_pp_sendf(data, &ftpc->pp, "%s %s", mode[fcmd], target);
       if(result) {
@@ -1382,9 +1193,13 @@
 
   /* store which command was sent */
   ftpc->count1 = fcmd;
-
   ftp_state(data, FTP_PORT);
 
+  /* Replace any filter on SECONDARY with one listening on this socket */
+  result = Curl_conn_tcp_listen_set(data, conn, SECONDARYSOCKET, &portsock);
+  if(!result)
+    portsock = CURL_SOCKET_BAD; /* now held in filter */
+
 out:
   /* If we looked up a dns_entry, now is the time to safely release it */
   if(dns_entry)
@@ -1392,6 +1207,18 @@
   if(result) {
     ftp_state(data, FTP_STOP);
   }
+  else {
+    /* successfully setup the list socket filter. Do we need more? */
+    if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port &&
+       !Curl_conn_is_ssl(conn, SECONDARYSOCKET)) {
+      result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET);
+    }
+    data->conn->bits.do_more = FALSE;
+    Curl_pgrsTime(data, TIMER_STARTACCEPT);
+    Curl_expire(data, data->set.accepttimeout ?
+                data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT,
+                EXPIRE_FTP_ACCEPT);
+  }
   if(portsock != CURL_SOCKET_BAD)
     Curl_socket_close(data, conn, portsock);
   return result;
@@ -1426,7 +1253,7 @@
     conn->bits.ftp_use_epsv = TRUE;
 #endif
 
-  modeoff = conn->bits.ftp_use_epsv?0:1;
+  modeoff = conn->bits.ftp_use_epsv ? 0 : 1;
 
   result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]);
   if(!result) {
@@ -1469,9 +1296,9 @@
       struct ftp_conn *ftpc = &conn->proto.ftpc;
       if(!conn->proto.ftpc.file)
         result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s",
-                               data->set.str[STRING_CUSTOMREQUEST]?
-                               data->set.str[STRING_CUSTOMREQUEST]:
-                               (data->state.list_only?"NLST":"LIST"));
+                               data->set.str[STRING_CUSTOMREQUEST] ?
+                               data->set.str[STRING_CUSTOMREQUEST] :
+                               (data->state.list_only ? "NLST" : "LIST"));
       else if(data->state.upload)
         result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s",
                                conn->proto.ftpc.file);
@@ -1576,11 +1403,11 @@
   }
 
   cmd = aprintf("%s%s%s",
-                data->set.str[STRING_CUSTOMREQUEST]?
-                data->set.str[STRING_CUSTOMREQUEST]:
-                (data->state.list_only?"NLST":"LIST"),
-                lstArg? " ": "",
-                lstArg? lstArg: "");
+                data->set.str[STRING_CUSTOMREQUEST] ?
+                data->set.str[STRING_CUSTOMREQUEST] :
+                (data->state.list_only ? "NLST" : "LIST"),
+                lstArg ? " " : "",
+                lstArg ? lstArg : "");
   free(lstArg);
 
   if(!cmd)
@@ -1702,10 +1529,10 @@
 
     /* Let's read off the proper amount of bytes from the input. */
     if(data->set.seek_func) {
-      Curl_set_in_callback(data, true);
+      Curl_set_in_callback(data, TRUE);
       seekerr = data->set.seek_func(data->set.seek_client,
                                     data->state.resume_from, SEEK_SET);
-      Curl_set_in_callback(data, false);
+      Curl_set_in_callback(data, FALSE);
     }
 
     if(seekerr != CURL_SEEKFUNC_OK) {
@@ -1736,7 +1563,7 @@
       } while(passed < data->state.resume_from);
     }
     /* now, decrease the size of the read */
-    if(data->state.infilesize>0) {
+    if(data->state.infilesize > 0) {
       data->state.infilesize -= data->state.resume_from;
 
       if(data->state.infilesize <= 0) {
@@ -1756,7 +1583,7 @@
     /* we have passed, proceed as normal */
   } /* resume_from */
 
-  result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
+  result = Curl_pp_sendf(data, &ftpc->pp, append ? "APPE %s" : "STOR %s",
                          ftpc->file);
   if(!result)
     ftp_state(data, FTP_STOR);
@@ -1804,7 +1631,7 @@
     int i = 0;
 
     /* Skip count1 items in the linked list */
-    while((i< ftpc->count1) && item) {
+    while((i < ftpc->count1) && item) {
       item = item->next;
       i++;
     }
@@ -2038,7 +1865,7 @@
     if(!ftpc->newhost)
       return CURLE_OUT_OF_MEMORY;
 
-    ftpc->newport = (unsigned short)(((ip[4]<<8) + ip[5]) & 0xffff);
+    ftpc->newport = (unsigned short)(((ip[4] << 8) + ip[5]) & 0xffff);
   }
   else if(ftpc->count1 == 0) {
     /* EPSV failed, move on to PASV */
@@ -2101,7 +1928,7 @@
   }
 
   result = Curl_conn_setup(data, conn, SECONDARYSOCKET, addr,
-                           conn->bits.ftp_use_data_ssl?
+                           conn->bits.ftp_use_data_ssl ?
                            CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);
 
   if(result) {
@@ -2215,10 +2042,10 @@
    * headers from CONNECT should not automatically be part of the
    * output. */
   CURLcode result;
-  int save = data->set.include_header;
+  bool save = data->set.include_header;
   data->set.include_header = TRUE;
   result = Curl_client_write(data, CLIENTWRITE_HEADER, buf, blen);
-  data->set.include_header = save? TRUE:FALSE;
+  data->set.include_header = save;
   return result;
 }
 
@@ -2267,15 +2094,16 @@
           return result;
 
         /* format: "Tue, 15 Nov 1994 12:45:26" */
-        headerbuflen = msnprintf(headerbuf, sizeof(headerbuf),
-                  "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
-                  Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
-                  tm->tm_mday,
-                  Curl_month[tm->tm_mon],
-                  tm->tm_year + 1900,
-                  tm->tm_hour,
-                  tm->tm_min,
-                  tm->tm_sec);
+        headerbuflen =
+          msnprintf(headerbuf, sizeof(headerbuf),
+                    "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+                    Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6],
+                    tm->tm_mday,
+                    Curl_month[tm->tm_mon],
+                    tm->tm_year + 1900,
+                    tm->tm_hour,
+                    tm->tm_min,
+                    tm->tm_sec);
         result = client_write_header(data, headerbuf, headerbuflen);
         if(result)
           return result;
@@ -2387,7 +2215,7 @@
     else {
       /* We got a file size report, so we check that there actually is a
          part of the file left to get, or else we go home.  */
-      if(data->state.resume_from< 0) {
+      if(data->state.resume_from < 0) {
         /* We are supposed to download the last abs(from) bytes */
         if(filesize < -data->state.resume_from) {
           failf(data, "Offset (%" FMT_OFF_T
@@ -2562,21 +2390,21 @@
 
   /* PORT means we are now awaiting the server to connect to us. */
   if(data->set.ftp_use_port) {
+    struct ftp_conn *ftpc = &conn->proto.ftpc;
     bool connected;
 
     ftp_state(data, FTP_STOP); /* no longer in STOR state */
 
-    result = AllowServerConnect(data, &connected);
+    result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected);
     if(result)
       return result;
 
     if(!connected) {
-      struct ftp_conn *ftpc = &conn->proto.ftpc;
       infof(data, "Data conn was not available immediately");
       ftpc->wait_data_conn = TRUE;
+      return ftp_check_ctrl_on_data_wait(data);
     }
-
-    return CURLE_OK;
+    ftpc->wait_data_conn = FALSE;
   }
   return InitiateTransfer(data);
 }
@@ -2626,10 +2454,10 @@
        !data->set.ignorecl &&
        (ftp->downloadsize < 1)) {
       /*
-       * It seems directory listings either do not show the size or very
-       * often uses size 0 anyway. ASCII transfers may very well turn out
-       * that the transferred amount of data is not the same as this line
-       * tells, why using this number in those cases only confuses us.
+       * It seems directory listings either do not show the size or often uses
+       * size 0 anyway. ASCII transfers may cause that the transferred amount
+       * of data is not the same as this line tells, why using this number in
+       * those cases only confuses us.
        *
        * Example D above makes this parsing a little tricky */
       char *bytes;
@@ -2676,21 +2504,22 @@
     conn->proto.ftpc.retr_size_saved = size;
 
     if(data->set.ftp_use_port) {
+      struct ftp_conn *ftpc = &conn->proto.ftpc;
       bool connected;
 
-      result = AllowServerConnect(data, &connected);
+      result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected);
       if(result)
         return result;
 
       if(!connected) {
-        struct ftp_conn *ftpc = &conn->proto.ftpc;
         infof(data, "Data conn was not available immediately");
         ftp_state(data, FTP_STOP);
         ftpc->wait_data_conn = TRUE;
+        return ftp_check_ctrl_on_data_wait(data);
       }
+      ftpc->wait_data_conn = FALSE;
     }
-    else
-      return InitiateTransfer(data);
+    return InitiateTransfer(data);
   }
   else {
     if((instate == FTP_LIST) && (ftpcode == 450)) {
@@ -2700,8 +2529,8 @@
     }
     else {
       failf(data, "RETR response: %03d", ftpcode);
-      return instate == FTP_RETR && ftpcode == 550?
-        CURLE_REMOTE_FILE_NOT_FOUND:
+      return instate == FTP_RETR && ftpcode == 550 ?
+        CURLE_REMOTE_FILE_NOT_FOUND :
         CURLE_FTP_COULDNT_RETR_FILE;
     }
   }
@@ -2753,7 +2582,7 @@
     /* 331 Password required for ...
        (the server requires to send the user's password too) */
     result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s",
-                           conn->passwd?conn->passwd:"");
+                           conn->passwd ? conn->passwd : "");
     if(!result)
       ftp_state(data, FTP_PASS);
   }
@@ -2964,7 +2793,7 @@
       if(ftpcode/100 == 2)
         /* We have enabled SSL for the data connection! */
         conn->bits.ftp_use_data_ssl =
-          (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
+          (data->set.use_ssl != CURLUSESSL_CONTROL);
       /* FTP servers typically responds with 500 if they decide to reject
          our 'P' request */
       else if(data->set.use_ssl > CURLUSESSL_CONTROL)
@@ -3281,7 +3110,7 @@
   /* Check for the state outside of the Curl_socket_check() return code checks
      since at times we are in fact already in this state when this function
      gets called. */
-  *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
+  *done = (ftpc->state == FTP_STOP);
 
   return result;
 }
@@ -3403,9 +3232,9 @@
 
   if(data->state.wildcardmatch) {
     if(data->set.chunk_end && ftpc->file) {
-      Curl_set_in_callback(data, true);
+      Curl_set_in_callback(data, TRUE);
       data->set.chunk_end(data->set.wildcardptr);
-      Curl_set_in_callback(data, false);
+      Curl_set_in_callback(data, FALSE);
     }
     ftpc->known_filesize = -1;
   }
@@ -3432,7 +3261,8 @@
         if(data->set.ftp_filemethod == FTPFILE_NOCWD)
           pathLen = 0; /* relative path => working directory is FTP home */
         else
-          pathLen -= ftpc->file?strlen(ftpc->file):0; /* file is url-decoded */
+          /* file is url-decoded */
+          pathLen -= ftpc->file ? strlen(ftpc->file) : 0;
 
         rawPath[pathLen] = '\0';
         ftpc->prevpath = rawPath;
@@ -3550,7 +3380,7 @@
     }
     else if(!ftpc->dont_check &&
             !data->req.bytecount &&
-            (data->req.size>0)) {
+            (data->req.size > 0)) {
       failf(data, "No data was received");
       result = CURLE_FTP_COULDNT_RETR_FILE;
     }
@@ -3634,7 +3464,7 @@
 static int ftp_need_type(struct connectdata *conn,
                          bool ascii_wanted)
 {
-  return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
+  return conn->proto.ftpc.transfertype != (ascii_wanted ? 'A' : 'I');
 }
 
 /***********************************************************************
@@ -3651,7 +3481,7 @@
 {
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   CURLcode result;
-  char want = (char)(ascii?'A':'I');
+  char want = (char)(ascii ? 'A' : 'I');
 
   if(ftpc->transfertype == want) {
     ftp_state(data, newstate);
@@ -3714,20 +3544,25 @@
    * complete */
   struct FTP *ftp = NULL;
 
-  /* if the second connection is not done yet, wait for it to have
-   * connected to the remote host. When using proxy tunneling, this
-   * means the tunnel needs to have been establish. However, we
-   * can not expect the remote host to talk to us in any way yet.
-   * So, when using ftps: the SSL handshake will not start until we
-   * tell the remote server that we are there. */
+  /* if the second connection has been set up, try to connect it fully
+   * to the remote host. This may not complete at this time, for several
+   * reasons:
+   * - we do EPTR and the server will not connect to our listen socket
+   *   until we send more FTP commands
+   * - an SSL filter is in place and the server will not start the TLS
+   *   handshake until we send more FTP commands
+   */
   if(conn->cfilter[SECONDARYSOCKET]) {
+    bool is_eptr = Curl_conn_is_tcp_listen(data, SECONDARYSOCKET);
     result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected);
-    if(result || !Curl_conn_is_ip_connected(data, SECONDARYSOCKET)) {
-      if(result && (ftpc->count1 == 0)) {
+    if(result || (!connected && !is_eptr &&
+                  !Curl_conn_is_ip_connected(data, SECONDARYSOCKET))) {
+      if(result && !is_eptr && (ftpc->count1 == 0)) {
         *completep = -1; /* go back to DOING please */
         /* this is a EPSV connect failing, try PASV instead */
         return ftp_epsv_disable(data, conn);
       }
+      *completep = (int)complete;
       return result;
     }
   }
@@ -3760,16 +3595,14 @@
     if(ftpc->wait_data_conn) {
       bool serv_conned;
 
-      result = ReceivedServerConnect(data, &serv_conned);
+      result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &serv_conned);
       if(result)
         return result; /* Failed to accept data connection */
 
       if(serv_conned) {
         /* It looks data connection is established */
-        result = AcceptServerConnect(data);
         ftpc->wait_data_conn = FALSE;
-        if(!result)
-          result = InitiateTransfer(data);
+        result = InitiateTransfer(data);
 
         if(result)
           return result;
@@ -3777,6 +3610,11 @@
         *completep = 1; /* this state is now complete when the server has
                            connected back to us */
       }
+      else {
+        result = ftp_check_ctrl_on_data_wait(data);
+        if(result)
+          return result;
+      }
     }
     else if(data->state.upload) {
       result = ftp_nb_type(data, conn, data->state.prefer_ascii,
@@ -3913,8 +3751,7 @@
     last_slash++;
     if(last_slash[0] == '\0') {
       wildcard->state = CURLWC_CLEAN;
-      result = ftp_parse_url_path(data);
-      return result;
+      return ftp_parse_url_path(data);
     }
     wildcard->pattern = strdup(last_slash);
     if(!wildcard->pattern)
@@ -3930,8 +3767,7 @@
     }
     else { /* only list */
       wildcard->state = CURLWC_CLEAN;
-      result = ftp_parse_url_path(data);
-      return result;
+      return ftp_parse_url_path(data);
     }
   }
 
@@ -4051,11 +3887,11 @@
       infof(data, "Wildcard - START of \"%s\"", finfo->filename);
       if(data->set.chunk_bgn) {
         long userresponse;
-        Curl_set_in_callback(data, true);
+        Curl_set_in_callback(data, TRUE);
         userresponse = data->set.chunk_bgn(
           finfo, data->set.wildcardptr,
           (int)Curl_llist_count(&wildcard->filelist));
-        Curl_set_in_callback(data, false);
+        Curl_set_in_callback(data, FALSE);
         switch(userresponse) {
         case CURL_CHUNK_BGN_FUNC_SKIP:
           infof(data, "Wildcard - \"%s\" skipped by user",
@@ -4094,9 +3930,9 @@
 
     case CURLWC_SKIP: {
       if(data->set.chunk_end) {
-        Curl_set_in_callback(data, true);
+        Curl_set_in_callback(data, TRUE);
         data->set.chunk_end(data->set.wildcardptr);
-        Curl_set_in_callback(data, false);
+        Curl_set_in_callback(data, FALSE);
       }
       Curl_node_remove(Curl_llist_head(&wildcard->filelist));
       wildcard->state = (Curl_llist_count(&wildcard->filelist) == 0) ?
@@ -4407,7 +4243,7 @@
       if(data->set.ftp_filemethod == FTPFILE_NOCWD)
         n = 0; /* CWD to entry for relative paths */
       else
-        n -= ftpc->file?strlen(ftpc->file):0;
+        n -= ftpc->file ? strlen(ftpc->file) : 0;
 
       if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) {
         infof(data, "Request has same path as previous transfer");
diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c
index 448f3a4..3088470 100644
--- a/Utilities/cmcurl/lib/ftplistparser.c
+++ b/Utilities/cmcurl/lib/ftplistparser.c
@@ -334,7 +334,7 @@
     compare = Curl_fnmatch;
 
   /* filter pattern-corresponding filenames */
-  Curl_set_in_callback(data, true);
+  Curl_set_in_callback(data, TRUE);
   if(compare(data->set.fnmatch_data, wc->pattern,
              finfo->filename) == 0) {
     /* discard symlink which is containing multiple " -> " */
@@ -346,7 +346,7 @@
   else {
     add = FALSE;
   }
-  Curl_set_in_callback(data, false);
+  Curl_set_in_callback(data, FALSE);
 
   if(add) {
     Curl_llist_append(llist, finfo, &infop->list);
diff --git a/Utilities/cmcurl/lib/getenv.c b/Utilities/cmcurl/lib/getenv.c
index 49a2e50..63eaeda 100644
--- a/Utilities/cmcurl/lib/getenv.c
+++ b/Utilities/cmcurl/lib/getenv.c
@@ -31,7 +31,7 @@
 
 static char *GetEnv(const char *variable)
 {
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) || \
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP) || \
   defined(__ORBIS__) || defined(__PROSPERO__) /* PlayStation 4 and 5 */
   (void)variable;
   return NULL;
@@ -70,7 +70,7 @@
   }
 #else
   char *env = getenv(variable);
-  return (env && env[0])?strdup(env):NULL;
+  return (env && env[0]) ? strdup(env) : NULL;
 #endif
 }
 
diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c
index 7146101..9144ad7 100644
--- a/Utilities/cmcurl/lib/getinfo.c
+++ b/Utilities/cmcurl/lib/getinfo.c
@@ -57,7 +57,7 @@
   pro->t_starttransfer = 0;
   pro->timespent = 0;
   pro->t_redirect = 0;
-  pro->is_t_startransfer_set = false;
+  pro->is_t_startransfer_set = FALSE;
 
   info->httpcode = 0;
   info->httpproxycode = 0;
@@ -96,7 +96,7 @@
 {
   switch(info) {
   case CURLINFO_EFFECTIVE_URL:
-    *param_charp = data->state.url?data->state.url:(char *)"";
+    *param_charp = data->state.url ? data->state.url : (char *)"";
     break;
   case CURLINFO_EFFECTIVE_METHOD: {
     const char *m = data->set.str[STRING_CUSTOMREQUEST];
@@ -405,12 +405,12 @@
     *param_offt = data->progress.ul.speed;
     break;
   case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
-    *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
-      data->progress.dl.total_size:-1;
+    *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN) ?
+      data->progress.dl.total_size : -1;
     break;
   case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
-    *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
-      data->progress.ul.total_size:-1;
+    *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN) ?
+      data->progress.ul.total_size : -1;
     break;
    case CURLINFO_TOTAL_TIME_T:
     *param_offt = data->progress.timespent;
@@ -446,9 +446,12 @@
     *param_offt = data->id;
     break;
   case CURLINFO_CONN_ID:
-    *param_offt = data->conn?
+    *param_offt = data->conn ?
       data->conn->connection_id : data->state.recent_conn_id;
     break;
+  case CURLINFO_EARLYDATA_SENT_T:
+    *param_offt = data->progress.earlydata_sent;
+    break;
   default:
     return CURLE_UNKNOWN_OPTION;
   }
@@ -512,12 +515,12 @@
     *param_doublep = (double)data->progress.ul.speed;
     break;
   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
-    *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
-      (double)data->progress.dl.total_size:-1;
+    *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN) ?
+      (double)data->progress.dl.total_size : -1;
     break;
   case CURLINFO_CONTENT_LENGTH_UPLOAD:
-    *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
-      (double)data->progress.ul.total_size:-1;
+    *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN) ?
+      (double)data->progress.ul.total_size : -1;
     break;
   case CURLINFO_REDIRECT_TIME:
     *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
diff --git a/Utilities/cmcurl/lib/headers.c b/Utilities/cmcurl/lib/headers.c
index 7c60c07..2985e1e 100644
--- a/Utilities/cmcurl/lib/headers.c
+++ b/Utilities/cmcurl/lib/headers.c
@@ -54,7 +54,7 @@
      impossible for applications to do == comparisons, as that would otherwise
      be very tempting and then lead to the reserved bits not being reserved
      anymore. */
-  h->origin = (unsigned int)(hs->type | (1<<27));
+  h->origin = (unsigned int)(hs->type | (1 << 27));
   h->anchor = e;
 }
 
diff --git a/Utilities/cmcurl/lib/hmac.c b/Utilities/cmcurl/lib/hmac.c
index 90f37f0..088c9bd 100644
--- a/Utilities/cmcurl/lib/hmac.c
+++ b/Utilities/cmcurl/lib/hmac.c
@@ -49,8 +49,6 @@
 static const unsigned char hmac_ipad = 0x36;
 static const unsigned char hmac_opad = 0x5C;
 
-
-
 struct HMAC_context *
 Curl_HMAC_init(const struct HMAC_params *hashparams,
                const unsigned char *key,
@@ -62,42 +60,40 @@
   unsigned char b;
 
   /* Create HMAC context. */
-  i = sizeof(*ctxt) + 2 * hashparams->hmac_ctxtsize +
-    hashparams->hmac_resultlen;
+  i = sizeof(*ctxt) + 2 * hashparams->ctxtsize + hashparams->resultlen;
   ctxt = malloc(i);
 
   if(!ctxt)
     return ctxt;
 
-  ctxt->hmac_hash = hashparams;
-  ctxt->hmac_hashctxt1 = (void *) (ctxt + 1);
-  ctxt->hmac_hashctxt2 = (void *) ((char *) ctxt->hmac_hashctxt1 +
-      hashparams->hmac_ctxtsize);
+  ctxt->hash = hashparams;
+  ctxt->hashctxt1 = (void *) (ctxt + 1);
+  ctxt->hashctxt2 = (void *) ((char *) ctxt->hashctxt1 + hashparams->ctxtsize);
 
   /* If the key is too long, replace it by its hash digest. */
-  if(keylen > hashparams->hmac_maxkeylen) {
-    (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1);
-    (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, key, keylen);
-    hkey = (unsigned char *) ctxt->hmac_hashctxt2 + hashparams->hmac_ctxtsize;
-    (*hashparams->hmac_hfinal)(hkey, ctxt->hmac_hashctxt1);
+  if(keylen > hashparams->maxkeylen) {
+    hashparams->hinit(ctxt->hashctxt1);
+    hashparams->hupdate(ctxt->hashctxt1, key, keylen);
+    hkey = (unsigned char *) ctxt->hashctxt2 + hashparams->ctxtsize;
+    hashparams->hfinal(hkey, ctxt->hashctxt1);
     key = hkey;
-    keylen = hashparams->hmac_resultlen;
+    keylen = hashparams->resultlen;
   }
 
   /* Prime the two hash contexts with the modified key. */
-  (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1);
-  (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt2);
+  hashparams->hinit(ctxt->hashctxt1);
+  hashparams->hinit(ctxt->hashctxt2);
 
   for(i = 0; i < keylen; i++) {
     b = (unsigned char)(*key ^ hmac_ipad);
-    (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &b, 1);
+    hashparams->hupdate(ctxt->hashctxt1, &b, 1);
     b = (unsigned char)(*key++ ^ hmac_opad);
-    (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &b, 1);
+    hashparams->hupdate(ctxt->hashctxt2, &b, 1);
   }
 
-  for(; i < hashparams->hmac_maxkeylen; i++) {
-    (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &hmac_ipad, 1);
-    (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &hmac_opad, 1);
+  for(; i < hashparams->maxkeylen; i++) {
+    hashparams->hupdate(ctxt->hashctxt1, &hmac_ipad, 1);
+    hashparams->hupdate(ctxt->hashctxt2, &hmac_opad, 1);
   }
 
   /* Done, return pointer to HMAC context. */
@@ -105,31 +101,29 @@
 }
 
 int Curl_HMAC_update(struct HMAC_context *ctxt,
-                     const unsigned char *data,
+                     const unsigned char *ptr,
                      unsigned int len)
 {
   /* Update first hash calculation. */
-  (*ctxt->hmac_hash->hmac_hupdate)(ctxt->hmac_hashctxt1, data, len);
+  ctxt->hash->hupdate(ctxt->hashctxt1, ptr, len);
   return 0;
 }
 
 
-int Curl_HMAC_final(struct HMAC_context *ctxt, unsigned char *result)
+int Curl_HMAC_final(struct HMAC_context *ctxt, unsigned char *output)
 {
-  const struct HMAC_params *hashparams = ctxt->hmac_hash;
+  const struct HMAC_params *hashparams = ctxt->hash;
 
-  /* Do not get result if called with a null parameter: only release
+  /* Do not get output if called with a null parameter: only release
      storage. */
 
-  if(!result)
-    result = (unsigned char *) ctxt->hmac_hashctxt2 +
-     ctxt->hmac_hash->hmac_ctxtsize;
+  if(!output)
+    output = (unsigned char *) ctxt->hashctxt2 + ctxt->hash->ctxtsize;
 
-  (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt1);
-  (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2,
-   result, hashparams->hmac_resultlen);
-  (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt2);
-  free((char *) ctxt);
+  hashparams->hfinal(output, ctxt->hashctxt1);
+  hashparams->hupdate(ctxt->hashctxt2, output, hashparams->resultlen);
+  hashparams->hfinal(output, ctxt->hashctxt2);
+  free(ctxt);
   return 0;
 }
 
@@ -144,15 +138,15 @@
  * hashparams [in]     - The hash function (Curl_HMAC_MD5).
  * key        [in]     - The key to use.
  * keylen     [in]     - The length of the key.
- * data       [in]     - The data to encrypt.
- * datalen    [in]     - The length of the data.
+ * buf        [in]     - The data to encrypt.
+ * buflen     [in]     - The length of the data.
  * output     [in/out] - The output buffer.
  *
  * Returns CURLE_OK on success.
  */
 CURLcode Curl_hmacit(const struct HMAC_params *hashparams,
                      const unsigned char *key, const size_t keylen,
-                     const unsigned char *data, const size_t datalen,
+                     const unsigned char *buf, const size_t buflen,
                      unsigned char *output)
 {
   struct HMAC_context *ctxt =
@@ -162,7 +156,7 @@
     return CURLE_OUT_OF_MEMORY;
 
   /* Update the digest with the given challenge */
-  Curl_HMAC_update(ctxt, data, curlx_uztoui(datalen));
+  Curl_HMAC_update(ctxt, buf, curlx_uztoui(buflen));
 
   /* Finalise the digest */
   Curl_HMAC_final(ctxt, output);
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index fc01dc3..1a9432d 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -313,7 +313,7 @@
   /* 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;
+    bool found = FALSE;
     struct Curl_addrinfo *addr = dns->addr;
 
 #ifdef PF_INET6
@@ -323,7 +323,7 @@
 
     while(addr) {
       if(addr->ai_family == pf) {
-        found = true;
+        found = TRUE;
         break;
       }
       addr = addr->ai_next;
@@ -630,7 +630,7 @@
       ipv6_works = 1;
       sclose(s);
     }
-    return (ipv6_works>0)?TRUE:FALSE;
+    return (ipv6_works > 0);
   }
 }
 #endif /* USE_IPV6 */
@@ -739,7 +739,7 @@
     /* notify the resolver start callback */
     if(data->set.resolver_start) {
       int st;
-      Curl_set_in_callback(data, true);
+      Curl_set_in_callback(data, TRUE);
       st = data->set.resolver_start(
 #ifdef USE_CURL_ASYNC
         data->state.async.resolver,
@@ -748,7 +748,7 @@
 #endif
         NULL,
         data->set.resolver_start_client);
-      Curl_set_in_callback(data, false);
+      Curl_set_in_callback(data, FALSE);
       if(st)
         return CURLRESOLV_ERROR;
     }
@@ -798,7 +798,9 @@
         return CURLRESOLV_ERROR;
 
       if(strcasecompare(hostname, "localhost") ||
-         tailmatch(hostname, ".localhost"))
+         strcasecompare(hostname, "localhost.") ||
+         tailmatch(hostname, ".localhost") ||
+         tailmatch(hostname, ".localhost."))
         addr = get_localhost(port, hostname);
 #ifndef CURL_DISABLE_DOH
       else if(allowDOH && data->set.doh && !ipnum)
@@ -1068,7 +1070,7 @@
 static void hostcache_unlink_entry(void *entry)
 {
   struct Curl_dns_entry *dns = (struct Curl_dns_entry *) entry;
-  DEBUGASSERT(dns && (dns->refcount>0));
+  DEBUGASSERT(dns && (dns->refcount > 0));
 
   dns->refcount--;
   if(dns->refcount == 0) {
@@ -1129,7 +1131,7 @@
   char *host_end;
 
   /* Default is no wildcard found */
-  data->state.wildcard_resolve = false;
+  data->state.wildcard_resolve = FALSE;
 
   for(hostp = data->state.resolve; hostp; hostp = hostp->next) {
     char entry_id[MAX_HOSTCACHE_LEN];
@@ -1179,7 +1181,7 @@
       char *end_ptr;
       bool permanent = TRUE;
       unsigned long tmp_port;
-      bool error = true;
+      bool error = TRUE;
       char *host_begin = hostp->data;
       size_t hlen = 0;
 
@@ -1256,7 +1258,7 @@
       if(!head)
         goto err;
 
-      error = false;
+      error = FALSE;
 err:
       if(error) {
         failf(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'",
@@ -1316,7 +1318,7 @@
       /* Wildcard hostname */
       if((hlen == 1) && (host_begin[0] == '*')) {
         infof(data, "RESOLVE *:%d using wildcard", port);
-        data->state.wildcard_resolve = true;
+        data->state.wildcard_resolve = TRUE;
       }
     }
   }
diff --git a/Utilities/cmcurl/lib/hostip4.c b/Utilities/cmcurl/lib/hostip4.c
index 3bfea48..58333fb 100644
--- a/Utilities/cmcurl/lib/hostip4.c
+++ b/Utilities/cmcurl/lib/hostip4.c
@@ -126,8 +126,10 @@
   int res;
 #endif
   struct Curl_addrinfo *ai = NULL;
+#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
   struct hostent *h = NULL;
   struct hostent *buf = NULL;
+#endif
 
 #if defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE)
   struct addrinfo hints;
@@ -288,12 +290,14 @@
 #endif /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
            HAVE_GETHOSTBYNAME_R */
 
+#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
   if(h) {
     ai = Curl_he2ai(h, port);
 
     if(buf) /* used a *_r() function */
       free(buf);
   }
+#endif
 
   return ai;
 }
diff --git a/Utilities/cmcurl/lib/hsts.c b/Utilities/cmcurl/lib/hsts.c
index a5c216f..5b01372 100644
--- a/Utilities/cmcurl/lib/hsts.c
+++ b/Utilities/cmcurl/lib/hsts.c
@@ -159,7 +159,7 @@
   do {
     while(*p && ISBLANK(*p))
       p++;
-    if(strncasecompare("max-age=", p, 8)) {
+    if(strncasecompare("max-age", p, 7)) {
       bool quoted = FALSE;
       CURLofft offt;
       char *endp;
@@ -167,9 +167,14 @@
       if(gotma)
         return CURLE_BAD_FUNCTION_ARGUMENT;
 
-      p += 8;
+      p += 7;
       while(*p && ISBLANK(*p))
         p++;
+      if(*p++ != '=')
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+      while(*p && ISBLANK(*p))
+        p++;
+
       if(*p == '\"') {
         p++;
         quoted = TRUE;
@@ -249,24 +254,23 @@
 struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
                            bool subdomain)
 {
+  struct stsentry *bestsub = NULL;
   if(h) {
-    char buffer[MAX_HSTS_HOSTLEN + 1];
     time_t now = time(NULL);
     size_t hlen = strlen(hostname);
     struct Curl_llist_node *e;
     struct Curl_llist_node *n;
+    size_t blen = 0;
 
     if((hlen > MAX_HSTS_HOSTLEN) || !hlen)
       return NULL;
-    memcpy(buffer, hostname, hlen);
     if(hostname[hlen-1] == '.')
       /* remove the trailing dot */
       --hlen;
-    buffer[hlen] = 0;
-    hostname = buffer;
 
     for(e = Curl_llist_head(&h->list); e; e = n) {
       struct stsentry *sts = Curl_node_elem(e);
+      size_t ntail;
       n = Curl_node_next(e);
       if(sts->expires <= now) {
         /* remove expired entries */
@@ -274,20 +278,23 @@
         hsts_free(sts);
         continue;
       }
-      if(subdomain && sts->includeSubDomains) {
-        size_t ntail = strlen(sts->host);
-        if(ntail < hlen) {
-          size_t offs = hlen - ntail;
-          if((hostname[offs-1] == '.') &&
-             strncasecompare(&hostname[offs], sts->host, ntail))
-            return sts;
+      ntail = strlen(sts->host);
+      if((subdomain && sts->includeSubDomains) && (ntail < hlen)) {
+        size_t offs = hlen - ntail;
+        if((hostname[offs-1] == '.') &&
+           strncasecompare(&hostname[offs], sts->host, ntail) &&
+           (ntail > blen)) {
+          /* save the tail match with the longest tail */
+          bestsub = sts;
+          blen = ntail;
         }
       }
-      if(strcasecompare(hostname, sts->host))
+      /* avoid strcasecompare because the host name is not null terminated */
+      if((hlen == ntail) && strncasecompare(hostname, sts->host, hlen))
         return sts;
     }
   }
-  return NULL; /* no match */
+  return bestsub;
 }
 
 /*
@@ -439,7 +446,7 @@
     e = Curl_hsts(h, p, subdomain);
     if(!e)
       result = hsts_create(h, p, subdomain, expires);
-    else {
+    else if(strcasecompare(p, e->host)) {
       /* the same hostname, use the largest expire time */
       if(expires > e->expires)
         e->expires = expires;
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
index f00c803..35e7085 100644
--- a/Utilities/cmcurl/lib/http.c
+++ b/Utilities/cmcurl/lib/http.c
@@ -407,7 +407,7 @@
 {
   curl_off_t bytessent = data->req.writebytecount;
   curl_off_t expectsend = Curl_creader_total_length(data);
-  curl_off_t upload_remain = (expectsend >= 0)? (expectsend - bytessent) : -1;
+  curl_off_t upload_remain = (expectsend >= 0) ? (expectsend - bytessent) : -1;
   bool little_upload_remains = (upload_remain >= 0 && upload_remain < 2000);
   bool needs_rewind = Curl_creader_needs_rewind(data);
   /* By default, we would like to abort the transfer when little or unknown
@@ -463,14 +463,14 @@
   if(abort_upload) {
     if(upload_remain >= 0)
       infof(data, "%s%sclose instead of sending %" FMT_OFF_T " more bytes",
-            ongoing_auth? ongoing_auth : "",
-            ongoing_auth? " send, " : "",
+            ongoing_auth ? ongoing_auth : "",
+            ongoing_auth ? " send, " : "",
             upload_remain);
     else
       infof(data, "%s%sclose instead of sending unknown amount "
             "of more bytes",
-            ongoing_auth? ongoing_auth : "",
-            ongoing_auth? " send, " : "");
+            ongoing_auth ? ongoing_auth : "",
+            ongoing_auth ? " send, " : "");
     /* We decided to abort the ongoing transfer */
     streamclose(conn, "Mid-auth HTTP and much data left to send");
     /* FIXME: questionable manipulation here, can we do this differently? */
@@ -502,7 +502,7 @@
     return CURLE_OK;
 
   if(data->state.authproblem)
-    return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
+    return data->set.http_fail_on_error ? CURLE_HTTP_RETURNED_ERROR : CURLE_OK;
 
   if((data->state.aptr.user || data->set.str[STRING_BEARER]) &&
      ((data->req.httpcode == 401) ||
@@ -677,7 +677,7 @@
           auth, data->state.aptr.user ?
           data->state.aptr.user : "");
 #endif
-    authstatus->multipass = (!authstatus->done) ? TRUE : FALSE;
+    authstatus->multipass = !authstatus->done;
   }
   else
     authstatus->multipass = FALSE;
@@ -1229,163 +1229,6 @@
 }
 #endif
 
-enum proxy_use {
-  HEADER_SERVER,  /* direct to server */
-  HEADER_PROXY,   /* regular request to proxy */
-  HEADER_CONNECT  /* sending CONNECT to a proxy */
-};
-
-static bool hd_name_eq(const char *n1, size_t n1len,
-                       const char *n2, size_t n2len)
-{
-  if(n1len == n2len) {
-    return strncasecompare(n1, n2, n1len);
-  }
-  return FALSE;
-}
-
-CURLcode Curl_dynhds_add_custom(struct Curl_easy *data,
-                                bool is_connect,
-                                struct dynhds *hds)
-{
-  struct connectdata *conn = data->conn;
-  char *ptr;
-  struct curl_slist *h[2];
-  struct curl_slist *headers;
-  int numlists = 1; /* by default */
-  int i;
-
-#ifndef CURL_DISABLE_PROXY
-  enum proxy_use proxy;
-
-  if(is_connect)
-    proxy = HEADER_CONNECT;
-  else
-    proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy?
-      HEADER_PROXY:HEADER_SERVER;
-
-  switch(proxy) {
-  case HEADER_SERVER:
-    h[0] = data->set.headers;
-    break;
-  case HEADER_PROXY:
-    h[0] = data->set.headers;
-    if(data->set.sep_headers) {
-      h[1] = data->set.proxyheaders;
-      numlists++;
-    }
-    break;
-  case HEADER_CONNECT:
-    if(data->set.sep_headers)
-      h[0] = data->set.proxyheaders;
-    else
-      h[0] = data->set.headers;
-    break;
-  }
-#else
-  (void)is_connect;
-  h[0] = data->set.headers;
-#endif
-
-  /* loop through one or two lists */
-  for(i = 0; i < numlists; i++) {
-    for(headers = h[i]; headers; headers = headers->next) {
-      const char *name, *value;
-      size_t namelen, valuelen;
-
-      /* There are 2 quirks in place for custom headers:
-       * 1. setting only 'name:' to suppress a header from being sent
-       * 2. setting only 'name;' to send an empty (illegal) header
-       */
-      ptr = strchr(headers->data, ':');
-      if(ptr) {
-        name = headers->data;
-        namelen = ptr - headers->data;
-        ptr++; /* pass the colon */
-        while(*ptr && ISSPACE(*ptr))
-          ptr++;
-        if(*ptr) {
-          value = ptr;
-          valuelen = strlen(value);
-        }
-        else {
-          /* quirk #1, suppress this header */
-          continue;
-        }
-      }
-      else {
-        ptr = strchr(headers->data, ';');
-
-        if(!ptr) {
-          /* neither : nor ; in provided header value. We seem
-           * to ignore this silently */
-          continue;
-        }
-
-        name = headers->data;
-        namelen = ptr - headers->data;
-        ptr++; /* pass the semicolon */
-        while(*ptr && ISSPACE(*ptr))
-          ptr++;
-        if(!*ptr) {
-          /* quirk #2, send an empty header */
-          value = "";
-          valuelen = 0;
-        }
-        else {
-          /* this may be used for something else in the future,
-           * ignore this for now */
-          continue;
-        }
-      }
-
-      DEBUGASSERT(name && value);
-      if(data->state.aptr.host &&
-         /* a Host: header was sent already, do not pass on any custom Host:
-            header as that will produce *two* in the same request! */
-         hd_name_eq(name, namelen, STRCONST("Host:")))
-        ;
-      else if(data->state.httpreq == HTTPREQ_POST_FORM &&
-              /* this header (extended by formdata.c) is sent later */
-              hd_name_eq(name, namelen, STRCONST("Content-Type:")))
-        ;
-      else if(data->state.httpreq == HTTPREQ_POST_MIME &&
-              /* this header is sent later */
-              hd_name_eq(name, namelen, STRCONST("Content-Type:")))
-        ;
-      else if(data->req.authneg &&
-              /* while doing auth neg, do not allow the custom length since
-                 we will force length zero then */
-              hd_name_eq(name, namelen, STRCONST("Content-Length:")))
-        ;
-      else if(data->state.aptr.te &&
-              /* when asking for Transfer-Encoding, do not pass on a custom
-                 Connection: */
-              hd_name_eq(name, namelen, STRCONST("Connection:")))
-        ;
-      else if((conn->httpversion >= 20) &&
-              hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:")))
-        /* HTTP/2 does not support chunked requests */
-        ;
-      else if((hd_name_eq(name, namelen, STRCONST("Authorization:")) ||
-               hd_name_eq(name, namelen, STRCONST("Cookie:"))) &&
-              /* be careful of sending this potentially sensitive header to
-                 other hosts */
-              !Curl_auth_allowed_to_host(data))
-        ;
-      else {
-        CURLcode result;
-
-        result = Curl_dynhds_add(hds, name, namelen, value, valuelen);
-        if(result)
-          return result;
-      }
-    }
-  }
-
-  return CURLE_OK;
-}
-
 CURLcode Curl_add_custom_headers(struct Curl_easy *data,
                                  bool is_connect,
 #ifndef USE_HYPER
@@ -1403,13 +1246,13 @@
   int i;
 
 #ifndef CURL_DISABLE_PROXY
-  enum proxy_use proxy;
+  enum Curl_proxy_use proxy;
 
   if(is_connect)
     proxy = HEADER_CONNECT;
   else
-    proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy?
-      HEADER_PROXY:HEADER_SERVER;
+    proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy ?
+      HEADER_PROXY : HEADER_SERVER;
 
   switch(proxy) {
   case HEADER_SERVER:
@@ -1602,7 +1445,7 @@
   msnprintf(datestr, sizeof(datestr),
             "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
             condp,
-            Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+            Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6],
             tm->tm_mday,
             Curl_month[tm->tm_mon],
             tm->tm_year + 1900,
@@ -1755,11 +1598,12 @@
         (conn->remote_port == PORT_HTTP)) )
       /* if(HTTPS on port 443) OR (HTTP on port 80) then do not include
          the port number in the host string */
-      aptr->host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"",
-                           host, conn->bits.ipv6_ip?"]":"");
+      aptr->host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip ? "[" : "",
+                           host, conn->bits.ipv6_ip ? "]" : "");
     else
-      aptr->host = aprintf("Host: %s%s%s:%d\r\n", conn->bits.ipv6_ip?"[":"",
-                           host, conn->bits.ipv6_ip?"]":"",
+      aptr->host = aprintf("Host: %s%s%s:%d\r\n",
+                           conn->bits.ipv6_ip ? "[" : "",
+                           host, conn->bits.ipv6_ip ? "]" : "",
                            conn->remote_port);
 
     if(!aptr->host)
@@ -1836,8 +1680,8 @@
     curl_url_cleanup(h);
 
     /* target or URL */
-    result = Curl_dyn_add(r, data->set.str[STRING_TARGET]?
-      data->set.str[STRING_TARGET]:url);
+    result = Curl_dyn_add(r, data->set.str[STRING_TARGET] ?
+      data->set.str[STRING_TARGET] : url);
     free(url);
     if(result)
       return (result);
@@ -1973,11 +1817,8 @@
 
   switch(httpreq) {
   case HTTPREQ_PUT: /* Let's PUT the data to the server! */
-    if(!postsize)
-      result = Curl_creader_set_null(data);
-    else
-      result = Curl_creader_set_fread(data, postsize);
-    return result;
+    return postsize ? Curl_creader_set_fread(data, postsize) :
+      Curl_creader_set_null(data);
 
 #if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
   case HTTPREQ_POST_FORM:
@@ -2010,7 +1851,7 @@
         chunked = Curl_compareheader(ptr, STRCONST("Transfer-Encoding:"),
                                      STRCONST("chunked"));
       }
-      result = Curl_creader_set_fread(data, chunked? -1 : postsize);
+      result = Curl_creader_set_fread(data, chunked ? -1 : postsize);
     }
     return result;
 
@@ -2250,8 +2091,9 @@
     addcookies = data->set.str[STRING_COOKIE];
 
   if(data->cookies || addcookies) {
-    struct Cookie *co = NULL; /* no cookies from start */
+    struct Curl_llist list;
     int count = 0;
+    int rc = 1;
 
     if(data->cookies && data->state.cookie_engine) {
       const char *host = data->state.aptr.cookiehost ?
@@ -2260,17 +2102,19 @@
         conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
         strcasecompare("localhost", host) ||
         !strcmp(host, "127.0.0.1") ||
-        !strcmp(host, "::1") ? TRUE : FALSE;
+        !strcmp(host, "::1");
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
-      co = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path,
-                               secure_context);
+      rc = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path,
+                               secure_context, &list);
       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
     }
-    if(co) {
-      struct Cookie *store = co;
+    if(!rc) {
+      struct Curl_llist_node *n;
       size_t clen = 8; /* hold the size of the generated Cookie: header */
-      /* now loop through all cookies that matched */
-      while(co) {
+
+      /* loop through all cookies that matched */
+      for(n = Curl_llist_head(&list); n; n = Curl_node_next(n)) {
+        struct Cookie *co = Curl_node_elem(n);
         if(co->value) {
           size_t add;
           if(!count) {
@@ -2285,22 +2129,21 @@
             linecap = TRUE;
             break;
           }
-          result = Curl_dyn_addf(r, "%s%s=%s", count?"; ":"",
+          result = Curl_dyn_addf(r, "%s%s=%s", count ? "; " : "",
                                  co->name, co->value);
           if(result)
             break;
           clen += add + (count ? 2 : 0);
           count++;
         }
-        co = co->next; /* next cookie please */
       }
-      Curl_cookie_freelist(store);
+      Curl_llist_destroy(&list, NULL);
     }
     if(addcookies && !result && !linecap) {
       if(!count)
         result = Curl_dyn_addn(r, STRCONST("Cookie: "));
       if(!result) {
-        result = Curl_dyn_addf(r, "%s%s", count?"; ":"", addcookies);
+        result = Curl_dyn_addf(r, "%s%s", count ? "; " : "", addcookies);
         count++;
       }
     }
@@ -2350,7 +2193,7 @@
         /* TODO: not sure if we want to send this header during authentication
          * negotiation, but test1084 checks for it. In which case we have a
          * "null" client reader installed that gives an unexpected length. */
-        curl_off_t total_len = data->req.authneg?
+        curl_off_t total_len = data->req.authneg ?
                                data->state.infilesize :
                                (data->state.resume_from + req_clen);
         data->state.aptr.rangeline =
@@ -2582,7 +2425,7 @@
     goto fail;
 
   p_accept = Curl_checkheaders(data,
-                               STRCONST("Accept"))?NULL:"Accept: */*\r\n";
+                               STRCONST("Accept")) ? NULL : "Accept: */*\r\n";
 
   result = Curl_http_range(data, httpreq);
   if(result)
@@ -2634,35 +2477,34 @@
                   "%s",/* Alt-Used */
 
                   httpstring,
-                  (data->state.aptr.host?data->state.aptr.host:""),
+                  (data->state.aptr.host ? data->state.aptr.host : ""),
 #ifndef CURL_DISABLE_PROXY
-                  data->state.aptr.proxyuserpwd?
-                  data->state.aptr.proxyuserpwd:"",
+                  data->state.aptr.proxyuserpwd ?
+                  data->state.aptr.proxyuserpwd : "",
 #else
                   "",
 #endif
-                  data->state.aptr.userpwd?data->state.aptr.userpwd:"",
-                  (data->state.use_range && data->state.aptr.rangeline)?
-                  data->state.aptr.rangeline:"",
+                  data->state.aptr.userpwd ? data->state.aptr.userpwd : "",
+                  (data->state.use_range && data->state.aptr.rangeline) ?
+                  data->state.aptr.rangeline : "",
                   (data->set.str[STRING_USERAGENT] &&
                    *data->set.str[STRING_USERAGENT] &&
-                   data->state.aptr.uagent)?
-                  data->state.aptr.uagent:"",
-                  p_accept?p_accept:"",
-                  data->state.aptr.te?data->state.aptr.te:"",
+                   data->state.aptr.uagent) ?
+                  data->state.aptr.uagent : "",
+                  p_accept ? p_accept : "",
+                  data->state.aptr.te ? data->state.aptr.te : "",
                   (data->set.str[STRING_ENCODING] &&
                    *data->set.str[STRING_ENCODING] &&
-                   data->state.aptr.accept_encoding)?
-                  data->state.aptr.accept_encoding:"",
-                  (data->state.referer && data->state.aptr.ref)?
-                  data->state.aptr.ref:"" /* Referer: <data> */,
+                   data->state.aptr.accept_encoding) ?
+                  data->state.aptr.accept_encoding : "",
+                  (data->state.referer && data->state.aptr.ref) ?
+                  data->state.aptr.ref : "" /* Referer: <data> */,
 #ifndef CURL_DISABLE_PROXY
                   (conn->bits.httpproxy &&
                    !conn->bits.tunnel_proxy &&
                    !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
-                   !Curl_checkProxyheaders(data,
-                                           conn,
-                                           STRCONST("Proxy-Connection")))?
+                   !Curl_checkProxyheaders(data, conn,
+                                           STRCONST("Proxy-Connection"))) ?
                   "Proxy-Connection: Keep-Alive\r\n":"",
 #else
                   "",
@@ -2697,7 +2539,7 @@
   }
 
   result = Curl_http_cookies(data, conn, &req);
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_WEBSOCKETS
   if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
     result = Curl_ws_request(data, &req);
 #endif
@@ -2754,7 +2596,7 @@
 {
   struct curl_slist *head = data->set.http200aliases;
   statusline rc = STATUS_BAD;
-  statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
+  statusline onmatch = len >= 5 ? STATUS_DONE : STATUS_UNKNOWN;
 
   while(head) {
     if(checkprefixmax(head->data, s, len)) {
@@ -2776,7 +2618,7 @@
                 const char *s, size_t len)
 {
   statusline result = STATUS_BAD;
-  statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
+  statusline onmatch = len >= 5 ? STATUS_DONE : STATUS_UNKNOWN;
   (void)data; /* unused */
   if(checkprefixmax("RTSP/", s, len))
     result = onmatch;
@@ -2837,10 +2679,10 @@
 #else
           0
 #endif
-        ))? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
+        )) ? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
     if(v) {
       /* the ALPN of the current request */
-      enum alpnid id = (conn->httpversion == 30)? ALPN_h3 :
+      enum alpnid id = (conn->httpversion == 30) ? ALPN_h3 :
                          (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
       return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
                                curlx_uitous((unsigned int)conn->remote_port));
@@ -2850,8 +2692,8 @@
   case 'c':
   case 'C':
     /* Check for Content-Length: header lines to get size */
-    v = (!k->http_bodyless && !data->set.ignorecl)?
-        HD_VAL(hd, hdlen, "Content-Length:") : NULL;
+    v = (!k->http_bodyless && !data->set.ignorecl) ?
+      HD_VAL(hd, hdlen, "Content-Length:") : NULL;
     if(v) {
       curl_off_t contentlength;
       CURLofft offt = curlx_strtoofft(v, NULL, 10, &contentlength);
@@ -2876,8 +2718,8 @@
       }
       return CURLE_OK;
     }
-    v = (!k->http_bodyless && data->set.str[STRING_ENCODING])?
-        HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
+    v = (!k->http_bodyless && data->set.str[STRING_ENCODING]) ?
+      HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
     if(v) {
       /*
        * Process Content-Encoding. Look for the values: identity,
@@ -2925,7 +2767,7 @@
       infof(data, "HTTP/1.0 connection set to keep alive");
       return CURLE_OK;
     }
-    v = !k->http_bodyless? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
+    v = !k->http_bodyless ? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
     if(v) {
       /* Content-Range: bytes [num]-
          Content-Range: bytes: [num]-
@@ -2959,7 +2801,7 @@
   case 'l':
   case 'L':
     v = (!k->http_bodyless &&
-         (data->set.timecondition || data->set.get_filetime))?
+         (data->set.timecondition || data->set.get_filetime)) ?
         HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
     if(v) {
       k->timeofdoc = Curl_getdate_capped(v);
@@ -3042,8 +2884,7 @@
         char *persistentauth = Curl_copy_header_value(hd);
         if(!persistentauth)
           return CURLE_OUT_OF_MEMORY;
-        negdata->noauthpersist = checkprefix("false", persistentauth)?
-          TRUE:FALSE;
+        negdata->noauthpersist = !!checkprefix("false", persistentauth);
         negdata->havenoauthpersist = TRUE;
         infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
               negdata->noauthpersist, persistentauth);
@@ -3073,18 +2914,18 @@
   case 's':
   case 'S':
 #if !defined(CURL_DISABLE_COOKIES)
-    v = (data->cookies && data->state.cookie_engine)?
+    v = (data->cookies && data->state.cookie_engine) ?
         HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
     if(v) {
       /* If there is a custom-set Host: name, use it here, or else use
        * real peer hostname. */
-      const char *host = data->state.aptr.cookiehost?
-        data->state.aptr.cookiehost:conn->host.name;
+      const char *host = data->state.aptr.cookiehost ?
+        data->state.aptr.cookiehost : conn->host.name;
       const bool secure_context =
         conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
         strcasecompare("localhost", host) ||
         !strcmp(host, "127.0.0.1") ||
-        !strcmp(host, "::1") ? TRUE : FALSE;
+        !strcmp(host, "::1");
 
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
                       CURL_LOCK_ACCESS_SINGLE);
@@ -3105,7 +2946,7 @@
            0
 #endif
             )
-        )? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
+        ) ? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
     if(v) {
       CURLcode check =
         Curl_hsts_parse(data->hsts, conn->host.name, v);
@@ -3133,8 +2974,8 @@
      */
     v = (!k->http_bodyless &&
          (data->state.httpreq != HTTPREQ_HEAD) &&
-         (k->httpcode != 304))?
-        HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
+         (k->httpcode != 304)) ?
+      HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
     if(v) {
       /* One or more encodings. We check for chunked and/or a compression
          algorithm. */
@@ -3372,8 +3213,8 @@
     return result;
 
   data->req.deductheadercount = (100 <= data->req.httpcode &&
-                                 199 >= data->req.httpcode)?
-                                data->req.headerbytecount:0;
+                                 199 >= data->req.httpcode) ?
+    data->req.headerbytecount : 0;
   return result;
 }
 
@@ -3449,7 +3290,7 @@
           goto out;
         *pconsumed += blen;
       }
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_WEBSOCKETS
       else if(k->upgr101 == UPGR101_WS) {
         /* verify the response. Any passed `buf` bytes are already in
          * WebSockets format and taken in by the protocol handler. */
@@ -3534,7 +3375,7 @@
   }
 #endif
 
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_WEBSOCKETS
   /* All >=200 HTTP status codes are errors when wanting WebSockets */
   if(data->req.upgr101 == UPGR101_WS) {
     failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
@@ -4052,7 +3893,7 @@
   }
   result = CURLE_OK;
 out:
-  *pstatus = result? -1 : status;
+  *pstatus = result ? -1 : status;
   return result;
 }
 
@@ -4095,7 +3936,7 @@
 out:
   if(result && req)
     Curl_http_req_free(req);
-  *preq = result? NULL : req;
+  *preq = result ? NULL : req;
   return result;
 }
 
@@ -4253,7 +4094,7 @@
 out:
   if(result && req)
     Curl_http_req_free(req);
-  *preq = result? NULL : req;
+  *preq = result ? NULL : req;
   return result;
 }
 
@@ -4319,8 +4160,8 @@
       infof(data, "set pseudo header %s to %s", HTTP_PSEUDO_SCHEME, scheme);
     }
     else {
-      scheme = (data->conn && data->conn->handler->flags & PROTOPT_SSL)?
-                "https" : "http";
+      scheme = (data->conn && data->conn->handler->flags & PROTOPT_SSL) ?
+        "https" : "http";
     }
   }
 
@@ -4384,7 +4225,7 @@
 out:
   if(result && resp)
     Curl_http_resp_free(resp);
-  *presp = result? NULL : resp;
+  *presp = result ? NULL : resp;
   return result;
 }
 
@@ -4479,7 +4320,7 @@
                            struct Curl_creader *reader, int premature)
 {
   struct cr_exp100_ctx *ctx = reader->ctx;
-  ctx->state = premature? EXP100_FAILED : EXP100_SEND_DATA;
+  ctx->state = premature ? EXP100_FAILED : EXP100_SEND_DATA;
   data->req.keepon &= ~KEEP_SEND_TIMED;
   Curl_expire_done(data, EXPIRE_100_TIMEOUT);
 }
@@ -4545,7 +4386,7 @@
 bool Curl_http_exp100_is_selected(struct Curl_easy *data)
 {
   struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
-  return r? TRUE : FALSE;
+  return !!r;
 }
 
 #endif /* CURL_DISABLE_HTTP */
diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h
index bb5974d..7056e8a 100644
--- a/Utilities/cmcurl/lib/http.h
+++ b/Utilities/cmcurl/lib/http.h
@@ -89,9 +89,6 @@
                                  void *headers
 #endif
   );
-CURLcode Curl_dynhds_add_custom(struct Curl_easy *data,
-                                bool is_connect,
-                                struct dynhds *hds);
 
 void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
                       const char **method, Curl_HttpReq *);
diff --git a/Utilities/cmcurl/lib/http1.c b/Utilities/cmcurl/lib/http1.c
index d7e21fd..f135b20 100644
--- a/Utilities/cmcurl/lib/http1.c
+++ b/Utilities/cmcurl/lib/http1.c
@@ -128,7 +128,7 @@
   else if(*err == CURLE_AGAIN) {
     /* no line end in `buf`, add it to our scratch */
     *err = Curl_dyn_addn(&parser->scratch, (const unsigned char *)buf, buflen);
-    nread = (*err)? -1 : (ssize_t)buflen;
+    nread = (*err) ? -1 : (ssize_t)buflen;
   }
   return nread;
 }
@@ -325,10 +325,10 @@
 
   result = Curl_dyn_addf(dbuf, "%s %s%s%s%s HTTP/1.%d\r\n",
                          req->method,
-                         req->scheme? req->scheme : "",
-                         req->scheme? "://" : "",
-                         req->authority? req->authority : "",
-                         req->path? req->path : "",
+                         req->scheme ? req->scheme : "",
+                         req->scheme ? "://" : "",
+                         req->authority ? req->authority : "",
+                         req->path ? req->path : "",
                          http_minor);
   if(result)
     goto out;
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c
index df3e6f0..dbe6f1a 100644
--- a/Utilities/cmcurl/lib/http2.c
+++ b/Utilities/cmcurl/lib/http2.c
@@ -254,7 +254,7 @@
 static void free_push_headers(struct h2_stream_ctx *stream)
 {
   size_t i;
-  for(i = 0; i<stream->push_headers_used; i++)
+  for(i = 0; i < stream->push_headers_used; i++)
     free(stream->push_headers[i]);
   Curl_safefree(stream->push_headers);
   stream->push_headers_used = 0;
@@ -299,7 +299,7 @@
   int32_t dwsize;
   int rv;
 
-  dwsize = paused? 0 : cf_h2_get_desired_local_win(cf, data);
+  dwsize = paused ? 0 : cf_h2_get_desired_local_win(cf, data);
   if(dwsize != stream->local_window_size) {
     int32_t wsize = nghttp2_session_get_stream_effective_local_window_size(
                       ctx->h2, stream->id);
@@ -433,6 +433,8 @@
 {
   struct cf_h2_ctx *ctx = cf->ctx;
   nghttp2_option *o;
+  nghttp2_mem mem = {NULL, Curl_nghttp2_malloc, Curl_nghttp2_free,
+                     Curl_nghttp2_calloc, Curl_nghttp2_realloc};
 
   int rc = nghttp2_option_new(&o);
   if(rc)
@@ -445,7 +447,7 @@
      HTTP field value. */
   nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1);
 #endif
-  rc = nghttp2_session_client_new2(&ctx->h2, cbs, cf, o);
+  rc = nghttp2_session_client_new3(&ctx->h2, cbs, cf, o, &mem);
   nghttp2_option_del(o);
   return rc;
 }
@@ -498,9 +500,10 @@
                      const uint8_t *value, size_t valuelen,
                      uint8_t flags,
                      void *userp);
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
 static int error_callback(nghttp2_session *session, const char *msg,
                           size_t len, void *userp);
-
+#endif
 static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
                                struct Curl_easy *data)
 {
@@ -530,7 +533,9 @@
   nghttp2_session_callbacks_set_on_begin_headers_callback(
     cbs, on_begin_headers);
   nghttp2_session_callbacks_set_on_header_callback(cbs, on_header);
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
   nghttp2_session_callbacks_set_error_callback(cbs, error_callback);
+#endif
 
   /* The nghttp2 session is not yet setup, do it */
   rc = h2_client_new(cf, cbs);
@@ -606,7 +611,7 @@
   /* all set, traffic will be send on connect */
   result = CURLE_OK;
   CURL_TRC_CF(data, cf, "[0] created h2 session%s",
-              ctx->via_h1_upgrade? " (via h1 upgrade)" : "");
+              ctx->via_h1_upgrade ? " (via h1 upgrade)" : "");
 
 out:
   if(cbs)
@@ -764,7 +769,7 @@
     }
     return result;
   }
-  return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN;
+  return Curl_bufq_is_empty(&ctx->outbufq) ? CURLE_OK : CURLE_AGAIN;
 }
 
 /*
@@ -786,8 +791,11 @@
   (void)flags;
   DEBUGASSERT(data);
 
-  nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
-                                  nw_out_writer, cf, &result);
+  if(!cf->connected)
+    nwritten = Curl_bufq_write(&ctx->outbufq, buf, blen, &result);
+  else
+    nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
+                                    nw_out_writer, cf, &result);
   if(nwritten < 0) {
     if(result == CURLE_AGAIN) {
       ctx->nw_out_blocked = 1;
@@ -852,7 +860,7 @@
     return NULL;
 
   len = strlen(header);
-  for(i = 0; i<stream->push_headers_used; i++) {
+  for(i = 0; i < stream->push_headers_used; i++) {
     if(!strncmp(header, stream->push_headers[i], len)) {
       /* sub-match, make sure that it is followed by a colon */
       if(stream->push_headers[i][len] != ':')
@@ -990,11 +998,11 @@
     }
     DEBUGASSERT(stream);
 
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     rv = data->multi->push_cb(data, newhandle,
                               stream->push_headers_used, &heads,
                               data->multi->push_userp);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
 
     /* free the headers again */
     free_push_headers(stream);
@@ -1113,9 +1121,6 @@
         return CURLE_RECV_ERROR;
       }
     }
-    if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
-      drain_stream(cf, data, stream);
-    }
     break;
   case NGHTTP2_HEADERS:
     if(stream->bodystarted) {
@@ -1131,10 +1136,10 @@
       return CURLE_RECV_ERROR;
 
     /* Only final status code signals the end of header */
-    if(stream->status_code / 100 != 1) {
+    if(stream->status_code / 100 != 1)
       stream->bodystarted = TRUE;
+    else
       stream->status_code = -1;
-    }
 
     h2_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);
 
@@ -1181,6 +1186,22 @@
   default:
     break;
   }
+
+  if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
+    if(!stream->closed && !stream->body_eos &&
+       ((stream->status_code >= 400) || (stream->status_code < 200))) {
+      /* The server did not give us a positive response and we are not
+       * done uploading the request body. We need to stop doing that and
+       * also inform the server that we aborted our side. */
+      CURL_TRC_CF(data, cf, "[%d] EOS frame with unfinished upload and "
+                  "HTTP status %d, abort upload by RST",
+                  stream_id, stream->status_code);
+      nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
+                                stream->id, NGHTTP2_STREAM_CLOSED);
+      stream->closed = TRUE;
+    }
+    drain_stream(cf, data, stream);
+  }
   return CURLE_OK;
 }
 
@@ -1235,14 +1256,14 @@
     case NGHTTP2_GOAWAY: {
       char scratch[128];
       size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
-        size_t len = (frame->goaway.opaque_data_len < s_len)?
-                      frame->goaway.opaque_data_len : s_len-1;
-        if(len)
-          memcpy(scratch, frame->goaway.opaque_data, len);
-        scratch[len] = '\0';
-        return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', "
-                         "last_stream=%d]", frame->goaway.error_code,
-                         scratch, frame->goaway.last_stream_id);
+      size_t len = (frame->goaway.opaque_data_len < s_len) ?
+        frame->goaway.opaque_data_len : s_len-1;
+      if(len)
+        memcpy(scratch, frame->goaway.opaque_data, len);
+      scratch[len] = '\0';
+      return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', "
+                       "last_stream=%d]", frame->goaway.error_code,
+                       scratch, frame->goaway.last_stream_id);
     }
     case NGHTTP2_WINDOW_UPDATE: {
       return msnprintf(buffer, blen,
@@ -1350,7 +1371,7 @@
     return 0;
   }
 
-  return on_stream_frame(cf, data_s, frame)? NGHTTP2_ERR_CALLBACK_FAILURE : 0;
+  return on_stream_frame(cf, data_s, frame) ? NGHTTP2_ERR_CALLBACK_FAILURE : 0;
 }
 
 static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
@@ -1402,8 +1423,8 @@
 
   DEBUGASSERT(call_data);
   /* stream id 0 is the connection, do not look there for streams. */
-  data_s = stream_id?
-             nghttp2_session_get_stream_user_data(session, stream_id) : NULL;
+  data_s = stream_id ?
+    nghttp2_session_get_stream_user_data(session, stream_id) : NULL;
   if(!data_s) {
     CURL_TRC_CF(call_data, cf,
                 "[%d] on_stream_close, no easy set on stream", stream_id);
@@ -1683,7 +1704,7 @@
     *data_flags = NGHTTP2_DATA_FLAG_EOF;
     return nread;
   }
-  return (nread == 0)? NGHTTP2_ERR_DEFERRED : nread;
+  return (nread == 0) ? NGHTTP2_ERR_DEFERRED : nread;
 }
 
 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
@@ -1773,7 +1794,7 @@
   }
   else if(stream->reset) {
     failf(data, "HTTP/2 stream %u was reset", stream->id);
-    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP2;
+    *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
     return -1;
   }
 
@@ -1826,14 +1847,14 @@
 static int sweight_wanted(const struct Curl_easy *data)
 {
   /* 0 weight is not set by user and we take the nghttp2 default one */
-  return data->set.priority.weight?
+  return data->set.priority.weight ?
     data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT;
 }
 
 static int sweight_in_effect(const struct Curl_easy *data)
 {
   /* 0 weight is not set by user and we take the nghttp2 default one */
-  return data->state.priority.weight?
+  return data->state.priority.weight ?
     data->state.priority.weight : NGHTTP2_DEFAULT_WEIGHT;
 }
 
@@ -1849,7 +1870,7 @@
 {
   struct Curl_data_priority *prio = &data->set.priority;
   struct h2_stream_ctx *depstream = H2_STREAM_CTX(ctx, prio->parent);
-  int32_t depstream_id = depstream? depstream->id:0;
+  int32_t depstream_id = depstream ? depstream->id : 0;
   nghttp2_priority_spec_init(pri_spec, depstream_id,
                              sweight_wanted(data),
                              data->set.priority.exclusive);
@@ -1895,6 +1916,11 @@
                 nghttp2_strerror(rv), rv);
     return CURLE_SEND_ERROR;
   }
+  /* Defer flushing during the connect phase so that the SETTINGS and
+   * other initial frames are sent together with the first request.
+   * Unless we are 'connect_only' where the request will never come. */
+  if(!cf->connected && !cf->conn->connect_only)
+    return CURLE_OK;
   return nw_out_flush(cf, data);
 }
 
@@ -1920,7 +1946,7 @@
           (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
           (ctx->rcvd_goaway && ctx->remote_max_sid < stream->id)) {
     CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id);
-    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP2;
+    *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
     nread = -1;
   }
 
@@ -1978,8 +2004,8 @@
     }
     else {
       CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes", nread);
-      data_max_bytes = (data_max_bytes > (size_t)nread)?
-                        (data_max_bytes - (size_t)nread) : 0;
+      data_max_bytes = (data_max_bytes > (size_t)nread) ?
+        (data_max_bytes - (size_t)nread) : 0;
     }
 
     if(h2_process_pending_input(cf, data, &result))
@@ -2244,7 +2270,7 @@
 
 out:
   CURL_TRC_CF(data, cf, "[%d] submit -> %zd, %d",
-              stream? stream->id : -1, nwritten, *err);
+              stream ? stream->id : -1, nwritten, *err);
   Curl_safefree(nva);
   *pstream = stream;
   Curl_dynhds_free(&h2_headers);
@@ -2436,6 +2462,7 @@
   struct cf_h2_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
   struct cf_call_data save;
+  bool first_time = FALSE;
 
   if(cf->connected) {
     *done = TRUE;
@@ -2457,11 +2484,14 @@
     result = cf_h2_ctx_open(cf, data);
     if(result)
       goto out;
+    first_time = TRUE;
   }
 
-  result = h2_progress_ingress(cf, data, H2_CHUNK_SIZE);
-  if(result)
-    goto out;
+  if(!first_time) {
+    result = h2_progress_ingress(cf, data, H2_CHUNK_SIZE);
+    if(result)
+      goto out;
+  }
 
   /* Send out our SETTINGS and ACKs and such. If that blocks, we
    * have it buffered and  can count this filter as being connected */
@@ -2584,7 +2614,7 @@
       Curl_expire(data, 0, EXPIRE_RUN_NOW);
     }
     CURL_TRC_CF(data, cf, "[%d] stream now %spaused", stream->id,
-                pause? "" : "un");
+                pause ? "" : "un");
   }
   return CURLE_OK;
 }
@@ -2630,7 +2660,7 @@
   if(ctx && (!Curl_bufq_is_empty(&ctx->inbufq)
             || (stream && !Curl_bufq_is_empty(&stream->sendbuf))))
     return TRUE;
-  return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
+  return cf->next ? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
 }
 
 static bool cf_h2_is_alive(struct Curl_cfilter *cf,
@@ -2681,12 +2711,12 @@
     else {
       effective_max = ctx->max_concurrent_streams;
     }
-    *pres1 = (effective_max > INT_MAX)? INT_MAX : (int)effective_max;
+    *pres1 = (effective_max > INT_MAX) ? INT_MAX : (int)effective_max;
     CF_DATA_RESTORE(cf, save);
     return CURLE_OK;
   case CF_QUERY_STREAM_ERROR: {
     struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
-    *pres1 = stream? (int)stream->error : 0;
+    *pres1 = stream ? (int)stream->error : 0;
     return CURLE_OK;
   }
   case CF_QUERY_NEED_FLUSH: {
@@ -2701,7 +2731,7 @@
   default:
     break;
   }
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
@@ -2751,7 +2781,7 @@
 out:
   if(result)
     cf_h2_ctx_free(ctx);
-  *pcf = result? NULL : cf;
+  *pcf = result ? NULL : cf;
   return result;
 }
 
@@ -2782,8 +2812,8 @@
   return result;
 }
 
-static bool Curl_cf_is_http2(struct Curl_cfilter *cf,
-                             const struct Curl_easy *data)
+static bool cf_is_http2(struct Curl_cfilter *cf,
+                        const struct Curl_easy *data)
 {
   (void)data;
   for(; cf; cf = cf->next) {
@@ -2799,7 +2829,7 @@
                         const struct connectdata *conn,
                         int sockindex)
 {
-  return conn? Curl_cf_is_http2(conn->cfilter[sockindex], data) : FALSE;
+  return conn ? cf_is_http2(conn->cfilter[sockindex], data) : FALSE;
 }
 
 bool Curl_http2_may_switch(struct Curl_easy *data,
@@ -2851,7 +2881,7 @@
   struct Curl_cfilter *cf_h2;
   CURLcode result;
 
-  DEBUGASSERT(!Curl_cf_is_http2(cf, data));
+  DEBUGASSERT(!cf_is_http2(cf, data));
 
   result = http2_cfilter_insert_after(cf, data, FALSE);
   if(result)
@@ -2932,6 +2962,30 @@
   return FALSE;
 }
 
+void *Curl_nghttp2_malloc(size_t size, void *user_data)
+{
+  (void)user_data;
+  return Curl_cmalloc(size);
+}
+
+void Curl_nghttp2_free(void *ptr, void *user_data)
+{
+  (void)user_data;
+  Curl_cfree(ptr);
+}
+
+void *Curl_nghttp2_calloc(size_t nmemb, size_t size, void *user_data)
+{
+  (void)user_data;
+  return Curl_ccalloc(nmemb, size);
+}
+
+void *Curl_nghttp2_realloc(void *ptr, size_t size, void *user_data)
+{
+  (void)user_data;
+  return Curl_crealloc(ptr, size);
+}
+
 #else /* !USE_NGHTTP2 */
 
 /* Satisfy external references even if http2 is not compiled in. */
diff --git a/Utilities/cmcurl/lib/http2.h b/Utilities/cmcurl/lib/http2.h
index 80e1834..dbb1784 100644
--- a/Utilities/cmcurl/lib/http2.h
+++ b/Utilities/cmcurl/lib/http2.h
@@ -60,6 +60,11 @@
                             struct connectdata *conn, int sockindex,
                             const char *ptr, size_t nread);
 
+void *Curl_nghttp2_malloc(size_t size, void *user_data);
+void Curl_nghttp2_free(void *ptr, void *user_data);
+void *Curl_nghttp2_calloc(size_t nmemb, size_t size, void *user_data);
+void *Curl_nghttp2_realloc(void *ptr, size_t size, void *user_data);
+
 extern struct Curl_cftype Curl_cft_nghttp2;
 
 #else /* USE_NGHTTP2 */
diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c
index 3874993..5d4848f 100644
--- a/Utilities/cmcurl/lib/http_aws_sigv4.c
+++ b/Utilities/cmcurl/lib/http_aws_sigv4.c
@@ -47,7 +47,7 @@
 
 #define HMAC_SHA256(k, kl, d, dl, o)           \
   do {                                         \
-    result = Curl_hmacit(Curl_HMAC_SHA256,     \
+    result = Curl_hmacit(&Curl_HMAC_SHA256,    \
                          (unsigned char *)k,   \
                          kl,                   \
                          (unsigned char *)d,   \
@@ -122,10 +122,6 @@
 
 #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)
 
@@ -176,7 +172,7 @@
   struct curl_slist *tmp_head = NULL;
   CURLcode ret = CURLE_OUT_OF_MEMORY;
   struct curl_slist *l;
-  int again = 1;
+  bool again = TRUE;
 
   /* provider1 mid */
   Curl_strntolower(provider1, provider1, strlen(provider1));
@@ -190,31 +186,22 @@
             "x-%s-date:%s", provider1, timestamp);
 
   if(!Curl_checkheaders(data, STRCONST("Host"))) {
-    char full_host[FULL_HOST_LEN + 1];
+    char *fullhost;
 
     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;
+      size_t pos = strcspn(data->state.aptr.host, "\n\r");
+      fullhost = Curl_memdup0(data->state.aptr.host, pos);
     }
-    else {
-      if(strlen(hostname) > MAX_HOST_LEN) {
-        ret = CURLE_URL_MALFORMAT;
-        goto fail;
-      }
-      msnprintf(full_host, FULL_HOST_LEN, "host:%s", hostname);
-    }
+    else
+      fullhost = aprintf("host:%s", hostname);
 
-    head = curl_slist_append(NULL, full_host);
-    if(!head)
+    if(fullhost)
+      head = Curl_slist_append_nodup(NULL, fullhost);
+    if(!head) {
+      free(fullhost);
       goto fail;
+    }
   }
 
 
@@ -300,7 +287,7 @@
 
   /* alpha-sort by header name in a case sensitive manner */
   do {
-    again = 0;
+    again = FALSE;
     for(l = head; l; l = l->next) {
       struct curl_slist *next = l->next;
 
@@ -309,7 +296,7 @@
 
         l->data = next->data;
         next->data = tmp;
-        again = 1;
+        again = TRUE;
       }
     }
   } while(again);
@@ -507,12 +494,12 @@
           /* allowed as-is */
           if(*q == '=') {
             result = Curl_dyn_addn(dq, q, 1);
-            *found_equals = true;
+            *found_equals = TRUE;
             break;
           }
         }
         /* URL encode */
-        out[1] = hex[((unsigned char)*q)>>4];
+        out[1] = hex[((unsigned char)*q) >> 4];
         out[2] = hex[*q & 0xf];
         result = Curl_dyn_addn(dq, out, 3);
         break;
@@ -562,7 +549,7 @@
   ap = &array[0];
   for(i = 0; !result && (i < entry); i++, ap++) {
     const char *q = ap->p;
-    bool found_equals = false;
+    bool found_equals = FALSE;
     if(!ap->len)
       continue;
     result = canon_string(q, ap->len, dq, &found_equals);
@@ -589,7 +576,7 @@
   char provider1[MAX_SIGV4_LEN + 1]="";
   char region[MAX_SIGV4_LEN + 1]="";
   char service[MAX_SIGV4_LEN + 1]="";
-  bool sign_as_s3 = false;
+  bool sign_as_s3 = FALSE;
   const char *hostname = conn->host.name;
   time_t clock;
   struct tm tm;
diff --git a/Utilities/cmcurl/lib/http_chunks.c b/Utilities/cmcurl/lib/http_chunks.c
index c228eb4..aea84be 100644
--- a/Utilities/cmcurl/lib/http_chunks.c
+++ b/Utilities/cmcurl/lib/http_chunks.c
@@ -516,9 +516,9 @@
   if(result)
     goto out;
 
-  Curl_set_in_callback(data, true);
+  Curl_set_in_callback(data, TRUE);
   rc = data->set.trailer_callback(&trailers, data->set.trailer_data);
-  Curl_set_in_callback(data, false);
+  Curl_set_in_callback(data, FALSE);
 
   if(rc != CURL_TRAILERFUNC_OK) {
     failf(data, "operation aborted by trailing headers callback");
diff --git a/Utilities/cmcurl/lib/http_digest.c b/Utilities/cmcurl/lib/http_digest.c
index 2db3125..a3ba17a 100644
--- a/Utilities/cmcurl/lib/http_digest.c
+++ b/Utilities/cmcurl/lib/http_digest.c
@@ -121,9 +121,9 @@
     passwdp = "";
 
 #if defined(USE_WINDOWS_SSPI)
-  have_chlg = digest->input_token ? TRUE : FALSE;
+  have_chlg = !!digest->input_token;
 #else
-  have_chlg = digest->nonce ? TRUE : FALSE;
+  have_chlg = !!digest->nonce;
 #endif
 
   if(!have_chlg) {
diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c
index 26e475c..5d76bdd 100644
--- a/Utilities/cmcurl/lib/http_negotiate.c
+++ b/Utilities/cmcurl/lib/http_negotiate.c
@@ -108,9 +108,9 @@
   neg_ctx->sslContext = conn->sslContext;
 #endif
   /* Check if the connection is using SSL and get the channel binding data */
-#ifdef HAVE_GSSAPI
+#if defined(USE_SSL) && defined(HAVE_GSSAPI)
   if(conn->handler->flags & PROTOPT_SSL) {
-    Curl_dyn_init(&neg_ctx->channel_binding_data, SSL_CB_MAX_SIZE);
+    Curl_dyn_init(&neg_ctx->channel_binding_data, SSL_CB_MAX_SIZE + 1);
     result = Curl_ssl_get_channel_binding(
       data, FIRSTSOCKET, &neg_ctx->channel_binding_data);
     if(result) {
@@ -124,7 +124,7 @@
   result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
                                            host, header, neg_ctx);
 
-#ifdef HAVE_GSSAPI
+#if defined(USE_SSL) && defined(HAVE_GSSAPI)
   Curl_dyn_free(&neg_ctx->channel_binding_data);
 #endif
 
diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c
index a5f27f5..b1dbe98 100644
--- a/Utilities/cmcurl/lib/http_proxy.c
+++ b/Utilities/cmcurl/lib/http_proxy.c
@@ -45,12 +45,155 @@
 #include "vtls/vtls.h"
 #include "transfer.h"
 #include "multiif.h"
+#include "vauth/vauth.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
+static bool hd_name_eq(const char *n1, size_t n1len,
+                       const char *n2, size_t n2len)
+{
+  return (n1len == n2len) ? strncasecompare(n1, n2, n1len) : FALSE;
+}
+
+static CURLcode dynhds_add_custom(struct Curl_easy *data,
+                                  bool is_connect,
+                                  struct dynhds *hds)
+{
+  struct connectdata *conn = data->conn;
+  char *ptr;
+  struct curl_slist *h[2];
+  struct curl_slist *headers;
+  int numlists = 1; /* by default */
+  int i;
+
+  enum Curl_proxy_use proxy;
+
+  if(is_connect)
+    proxy = HEADER_CONNECT;
+  else
+    proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy ?
+      HEADER_PROXY : HEADER_SERVER;
+
+  switch(proxy) {
+  case HEADER_SERVER:
+    h[0] = data->set.headers;
+    break;
+  case HEADER_PROXY:
+    h[0] = data->set.headers;
+    if(data->set.sep_headers) {
+      h[1] = data->set.proxyheaders;
+      numlists++;
+    }
+    break;
+  case HEADER_CONNECT:
+    if(data->set.sep_headers)
+      h[0] = data->set.proxyheaders;
+    else
+      h[0] = data->set.headers;
+    break;
+  }
+
+  /* loop through one or two lists */
+  for(i = 0; i < numlists; i++) {
+    for(headers = h[i]; headers; headers = headers->next) {
+      const char *name, *value;
+      size_t namelen, valuelen;
+
+      /* There are 2 quirks in place for custom headers:
+       * 1. setting only 'name:' to suppress a header from being sent
+       * 2. setting only 'name;' to send an empty (illegal) header
+       */
+      ptr = strchr(headers->data, ':');
+      if(ptr) {
+        name = headers->data;
+        namelen = ptr - headers->data;
+        ptr++; /* pass the colon */
+        while(*ptr && ISSPACE(*ptr))
+          ptr++;
+        if(*ptr) {
+          value = ptr;
+          valuelen = strlen(value);
+        }
+        else {
+          /* quirk #1, suppress this header */
+          continue;
+        }
+      }
+      else {
+        ptr = strchr(headers->data, ';');
+
+        if(!ptr) {
+          /* neither : nor ; in provided header value. We seem
+           * to ignore this silently */
+          continue;
+        }
+
+        name = headers->data;
+        namelen = ptr - headers->data;
+        ptr++; /* pass the semicolon */
+        while(*ptr && ISSPACE(*ptr))
+          ptr++;
+        if(!*ptr) {
+          /* quirk #2, send an empty header */
+          value = "";
+          valuelen = 0;
+        }
+        else {
+          /* this may be used for something else in the future,
+           * ignore this for now */
+          continue;
+        }
+      }
+
+      DEBUGASSERT(name && value);
+      if(data->state.aptr.host &&
+         /* a Host: header was sent already, do not pass on any custom Host:
+            header as that will produce *two* in the same request! */
+         hd_name_eq(name, namelen, STRCONST("Host:")))
+        ;
+      else if(data->state.httpreq == HTTPREQ_POST_FORM &&
+              /* this header (extended by formdata.c) is sent later */
+              hd_name_eq(name, namelen, STRCONST("Content-Type:")))
+        ;
+      else if(data->state.httpreq == HTTPREQ_POST_MIME &&
+              /* this header is sent later */
+              hd_name_eq(name, namelen, STRCONST("Content-Type:")))
+        ;
+      else if(data->req.authneg &&
+              /* while doing auth neg, do not allow the custom length since
+                 we will force length zero then */
+              hd_name_eq(name, namelen, STRCONST("Content-Length:")))
+        ;
+      else if(data->state.aptr.te &&
+              /* when asking for Transfer-Encoding, do not pass on a custom
+                 Connection: */
+              hd_name_eq(name, namelen, STRCONST("Connection:")))
+        ;
+      else if((conn->httpversion >= 20) &&
+              hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:")))
+        /* HTTP/2 does not support chunked requests */
+        ;
+      else if((hd_name_eq(name, namelen, STRCONST("Authorization:")) ||
+               hd_name_eq(name, namelen, STRCONST("Cookie:"))) &&
+              /* be careful of sending this potentially sensitive header to
+                 other hosts */
+              !Curl_auth_allowed_to_host(data))
+        ;
+      else {
+        CURLcode result;
+
+        result = Curl_dynhds_add(hds, name, namelen, value, valuelen);
+        if(result)
+          return result;
+      }
+    }
+  }
+
+  return CURLE_OK;
+}
 
 CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf,
                                          const char **phostname,
@@ -97,8 +240,8 @@
   if(result)
     goto out;
 
-  authority = aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname,
-                      ipv6_ip?"]":"", port);
+  authority = aprintf("%s%s%s:%d", ipv6_ip ? "[" : "", hostname,
+                      ipv6_ip ?"]" : "", port);
   if(!authority) {
     result = CURLE_OUT_OF_MEMORY;
     goto out;
@@ -146,7 +289,7 @@
       goto out;
   }
 
-  result = Curl_dynhds_add_custom(data, TRUE, &req->headers);
+  result = dynhds_add_custom(data, TRUE, &req->headers);
 
 out:
   if(result && req) {
@@ -185,7 +328,7 @@
   *done = FALSE;
   if(!ctx->cf_protocol) {
     struct Curl_cfilter *cf_protocol = NULL;
-    int alpn = Curl_conn_cf_is_ssl(cf->next)?
+    int alpn = Curl_conn_cf_is_ssl(cf->next) ?
       cf->conn->proxy_alpn : CURL_HTTP_VERSION_1_1;
 
     /* First time call after the subchain connected */
@@ -195,7 +338,7 @@
     case CURL_HTTP_VERSION_1_1:
       CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.1");
       infof(data, "CONNECT tunnel: HTTP/1.%d negotiated",
-            (alpn == CURL_HTTP_VERSION_1_0)? 0 : 1);
+            (alpn == CURL_HTTP_VERSION_1_0) ? 0 : 1);
       result = Curl_cf_h1_proxy_insert_after(cf, data);
       if(result)
         goto out;
diff --git a/Utilities/cmcurl/lib/http_proxy.h b/Utilities/cmcurl/lib/http_proxy.h
index 2b5f7ae..2e91ff2 100644
--- a/Utilities/cmcurl/lib/http_proxy.h
+++ b/Utilities/cmcurl/lib/http_proxy.h
@@ -30,6 +30,12 @@
 
 #include "urldata.h"
 
+enum Curl_proxy_use {
+  HEADER_SERVER,  /* direct to server */
+  HEADER_PROXY,   /* regular request to proxy */
+  HEADER_CONNECT  /* sending CONNECT to a proxy */
+};
+
 CURLcode Curl_http_proxy_get_destination(struct Curl_cfilter *cf,
                                          const char **phostname,
                                          int *pport, bool *pipv6_ip);
diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c
index 4979a18..e424cdb 100644
--- a/Utilities/cmcurl/lib/imap.c
+++ b/Utilities/cmcurl/lib/imap.c
@@ -520,8 +520,8 @@
   }
 
   /* Make sure the username and password are in the correct atom format */
-  user = imap_atom(conn->user, false);
-  passwd = imap_atom(conn->passwd, false);
+  user = imap_atom(conn->user, FALSE);
+  passwd = imap_atom(conn->passwd, FALSE);
 
   /* Send the LOGIN command */
   result = imap_sendf(data, "LOGIN %s %s", user ? user : "",
@@ -655,7 +655,7 @@
                         imap->custom_params ? imap->custom_params : "");
   else {
     /* Make sure the mailbox is in the correct atom format if necessary */
-    char *mailbox = imap->mailbox ? imap_atom(imap->mailbox, true)
+    char *mailbox = imap->mailbox ? imap_atom(imap->mailbox, TRUE)
                                   : strdup("");
     if(!mailbox)
       return CURLE_OUT_OF_MEMORY;
@@ -697,7 +697,7 @@
   }
 
   /* Make sure the mailbox is in the correct atom format */
-  mailbox = imap_atom(imap->mailbox, false);
+  mailbox = imap_atom(imap->mailbox, FALSE);
   if(!mailbox)
     return CURLE_OUT_OF_MEMORY;
 
@@ -809,7 +809,7 @@
   }
 
   /* Make sure the mailbox is in the correct atom format */
-  mailbox = imap_atom(imap->mailbox, false);
+  mailbox = imap_atom(imap->mailbox, FALSE);
   if(!mailbox)
     return CURLE_OUT_OF_MEMORY;
 
@@ -1399,7 +1399,7 @@
   }
 
   result = Curl_pp_statemach(data, &imapc->pp, FALSE, FALSE);
-  *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
+  *done = (imapc->state == IMAP_STOP);
 
   return result;
 }
@@ -1859,7 +1859,7 @@
   /* Performing the alnum check with this macro is faster because of ASCII
      arithmetic */
   if(ISALNUM(ch))
-    return true;
+    return TRUE;
 
   switch(ch) {
     /* bchar */
@@ -1873,10 +1873,10 @@
     case '+': case ',':
     /* bchar -> achar -> uchar -> pct-encoded */
     case '%': /* HEXDIG chars are already included above */
-      return true;
+      return TRUE;
 
     default:
-      return false;
+      return FALSE;
   }
 }
 
@@ -1891,7 +1891,7 @@
   CURLcode result = CURLE_OK;
   struct imap_conn *imapc = &conn->proto.imapc;
   const char *ptr = conn->options;
-  bool prefer_login = false;
+  bool prefer_login = FALSE;
 
   while(!result && ptr && *ptr) {
     const char *key = ptr;
@@ -1907,16 +1907,16 @@
 
     if(strncasecompare(key, "AUTH=+LOGIN", 11)) {
       /* User prefers plaintext LOGIN over any SASL, including SASL LOGIN */
-      prefer_login = true;
+      prefer_login = TRUE;
       imapc->sasl.prefmech = SASL_AUTH_NONE;
     }
     else if(strncasecompare(key, "AUTH=", 5)) {
-      prefer_login = false;
+      prefer_login = FALSE;
       result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
                                                value, ptr - value);
     }
     else {
-      prefer_login = false;
+      prefer_login = FALSE;
       result = CURLE_URL_MALFORMAT;
     }
 
diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c
index f3649cd..e310a1b 100644
--- a/Utilities/cmcurl/lib/krb5.c
+++ b/Utilities/cmcurl/lib/krb5.c
@@ -202,14 +202,15 @@
                         data->set.str[STRING_SERVICE_NAME] :
                         "ftp";
   const char *srv_host = "host";
-  gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp;
+  gss_buffer_desc input_buffer, output_buffer, *gssresp;
+  gss_buffer_desc _gssresp = GSS_C_EMPTY_BUFFER;
   OM_uint32 maj, min;
   gss_name_t gssname;
   gss_ctx_id_t *context = app_data;
   struct gss_channel_bindings_struct chan;
   size_t base64_sz = 0;
   struct sockaddr_in *remote_addr =
-    (struct sockaddr_in *)(void *)&conn->remote_addr->sa_addr;
+    (struct sockaddr_in *)(void *)&conn->remote_addr->curl_sa_addr;
   char *stringp;
 
   if(getsockname(conn->sock[FIRSTSOCKET],
@@ -363,7 +364,7 @@
       free(_gssresp.value);
 
     if(ret == AUTH_OK || service == srv_host)
-      return ret;
+      break;
 
     service = srv_host;
   }
@@ -372,13 +373,13 @@
 
 static void krb5_end(void *app_data)
 {
-    OM_uint32 min;
-    gss_ctx_id_t *context = app_data;
-    if(*context != GSS_C_NO_CONTEXT) {
-      OM_uint32 maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER);
-      (void)maj;
-      DEBUGASSERT(maj == GSS_S_COMPLETE);
-    }
+  OM_uint32 min;
+  gss_ctx_id_t *context = app_data;
+  if(*context != GSS_C_NO_CONTEXT) {
+    OM_uint32 maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER);
+    (void)maj;
+    DEBUGASSERT(maj == GSS_S_COMPLETE);
+  }
 }
 
 static const struct Curl_sec_client_mech Curl_krb5_client_mech = {
@@ -612,10 +613,10 @@
   return total_read;
 }
 
-/* Send |length| bytes from |from| to the |fd| socket taking care of encoding
-   and negotiating with the server. |from| can be NULL. */
+/* Send |length| bytes from |from| to the |sockindex| socket taking care of
+   encoding and negotiating with the server. |from| can be NULL. */
 static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
-                        curl_socket_t fd, const char *from, int length)
+                        int sockindex, const char *from, int length)
 {
   int bytes, htonl_bytes; /* 32-bit integers for htonl */
   char *buffer = NULL;
@@ -623,7 +624,7 @@
   size_t cmd_size = 0;
   CURLcode error;
   enum protection_level prot_level = conn->data_prot;
-  bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE;
+  bool iscmd = (prot_level == PROT_CMD);
 
   DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST);
 
@@ -649,27 +650,27 @@
       static const char *enc = "ENC ";
       static const char *mic = "MIC ";
       if(prot_level == PROT_PRIVATE)
-        socket_write(data, fd, enc, 4);
+        socket_write(data, sockindex, enc, 4);
       else
-        socket_write(data, fd, mic, 4);
+        socket_write(data, sockindex, mic, 4);
 
-      socket_write(data, fd, cmd_buffer, cmd_size);
-      socket_write(data, fd, "\r\n", 2);
-      infof(data, "Send: %s%s", prot_level == PROT_PRIVATE?enc:mic,
+      socket_write(data, sockindex, cmd_buffer, cmd_size);
+      socket_write(data, sockindex, "\r\n", 2);
+      infof(data, "Send: %s%s", prot_level == PROT_PRIVATE ? enc : mic,
             cmd_buffer);
       free(cmd_buffer);
     }
   }
   else {
     htonl_bytes = (int)htonl((OM_uint32)bytes);
-    socket_write(data, fd, &htonl_bytes, sizeof(htonl_bytes));
-    socket_write(data, fd, buffer, curlx_sitouz(bytes));
+    socket_write(data, sockindex, &htonl_bytes, sizeof(htonl_bytes));
+    socket_write(data, sockindex, buffer, curlx_sitouz(bytes));
   }
   free(buffer);
 }
 
 static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
-                         curl_socket_t fd, const char *buffer, size_t length)
+                         int sockindex, const char *buffer, size_t length)
 {
   ssize_t tx = 0, len = conn->buffer_size;
 
@@ -679,7 +680,7 @@
     if(length < (size_t)len)
       len = length;
 
-    do_sec_send(data, conn, fd, buffer, curlx_sztosi(len));
+    do_sec_send(data, conn, sockindex, buffer, curlx_sztosi(len));
     length -= len;
     buffer += len;
     tx += len;
@@ -693,10 +694,9 @@
                         CURLcode *err)
 {
   struct connectdata *conn = data->conn;
-  curl_socket_t fd = conn->sock[sockindex];
   (void)eos; /* unused */
   *err = CURLE_OK;
-  return sec_write(data, conn, fd, buffer, len);
+  return sec_write(data, conn, sockindex, buffer, len);
 }
 
 int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c
index 01429ba..2cbdb9c 100644
--- a/Utilities/cmcurl/lib/ldap.c
+++ b/Utilities/cmcurl/lib/ldap.c
@@ -825,8 +825,8 @@
   if(!res)
     return FALSE;
 
-  for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items;
-      s = strtok_r(NULL, ",", &lasts), i++)
+  for(i = 0, s = Curl_strtok_r(str, ",", &lasts); s && i < items;
+      s = Curl_strtok_r(NULL, ",", &lasts), i++)
     res[i] = s;
 
   *out = res;
diff --git a/Utilities/cmcurl/lib/llist.c b/Utilities/cmcurl/lib/llist.c
index 7e19cd5..e5c65fb 100644
--- a/Utilities/cmcurl/lib/llist.c
+++ b/Utilities/cmcurl/lib/llist.c
@@ -96,7 +96,7 @@
   }
   else {
     /* if 'e' is NULL here, we insert the new element first in the list */
-    ne->_next = e?e->_next:list->_head;
+    ne->_next = e ? e->_next : list->_head;
     ne->_prev = e;
     if(!e) {
       list->_head->_prev = ne;
diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c
index f006bdc..8a3c884 100644
--- a/Utilities/cmcurl/lib/md4.c
+++ b/Utilities/cmcurl/lib/md4.c
@@ -115,6 +115,13 @@
 
 #elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4)
 
+#ifdef OPENSSL_COEXIST
+  #define MD4_CTX WOLFSSL_MD4_CTX
+  #define MD4_Init wolfSSL_MD4_Init
+  #define MD4_Update wolfSSL_MD4_Update
+  #define MD4_Final wolfSSL_MD4_Final
+#endif
+
 #elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
 
 #elif defined(AN_APPLE_OS)
diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c
index 7b51429..1cf1231 100644
--- a/Utilities/cmcurl/lib/md5.c
+++ b/Utilities/cmcurl/lib/md5.c
@@ -88,29 +88,30 @@
 
 typedef struct md5_ctx my_md5_ctx;
 
-static CURLcode my_md5_init(my_md5_ctx *ctx)
+static CURLcode my_md5_init(void *ctx)
 {
   md5_init(ctx);
   return CURLE_OK;
 }
 
-static void my_md5_update(my_md5_ctx *ctx,
+static void my_md5_update(void *ctx,
                           const unsigned char *input,
                           unsigned int inputLen)
 {
   md5_update(ctx, inputLen, input);
 }
 
-static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+static void my_md5_final(unsigned char *digest, void *ctx)
 {
   md5_digest(ctx, 16, digest);
 }
 
-#elif defined(USE_OPENSSL_MD5) || defined(USE_WOLFSSL_MD5)
+#elif defined(USE_OPENSSL_MD5) || \
+  (defined(USE_WOLFSSL_MD5) && !defined(OPENSSL_COEXIST))
 
 typedef MD5_CTX my_md5_ctx;
 
-static CURLcode my_md5_init(my_md5_ctx *ctx)
+static CURLcode my_md5_init(void *ctx)
 {
   if(!MD5_Init(ctx))
     return CURLE_OUT_OF_MEMORY;
@@ -118,23 +119,47 @@
   return CURLE_OK;
 }
 
-static void my_md5_update(my_md5_ctx *ctx,
+static void my_md5_update(void *ctx,
                           const unsigned char *input,
                           unsigned int len)
 {
   (void)MD5_Update(ctx, input, len);
 }
 
-static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+static void my_md5_final(unsigned char *digest, void *ctx)
 {
   (void)MD5_Final(digest, ctx);
 }
 
+#elif defined(USE_WOLFSSL_MD5)
+
+typedef WOLFSSL_MD5_CTX my_md5_ctx;
+
+static CURLcode my_md5_init(void *ctx)
+{
+  if(!wolfSSL_MD5_Init(ctx))
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+static void my_md5_update(void *ctx,
+                          const unsigned char *input,
+                          unsigned int len)
+{
+  (void)wolfSSL_MD5_Update(ctx, input, len);
+}
+
+static void my_md5_final(unsigned char *digest, void *ctx)
+{
+  (void)wolfSSL_MD5_Final(digest, ctx);
+}
+
 #elif defined(USE_MBEDTLS)
 
 typedef mbedtls_md5_context my_md5_ctx;
 
-static CURLcode my_md5_init(my_md5_ctx *ctx)
+static CURLcode my_md5_init(void *ctx)
 {
 #if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
   if(mbedtls_md5_starts(ctx))
@@ -148,7 +173,7 @@
   return CURLE_OK;
 }
 
-static void my_md5_update(my_md5_ctx *ctx,
+static void my_md5_update(void *ctx,
                           const unsigned char *data,
                           unsigned int length)
 {
@@ -159,7 +184,7 @@
 #endif
 }
 
-static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+static void my_md5_final(unsigned char *digest, void *ctx)
 {
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
   (void) mbedtls_md5_finish(ctx, digest);
@@ -178,7 +203,7 @@
    reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
 #  define my_md5_ctx CC_MD5_CTX
 
-static CURLcode my_md5_init(my_md5_ctx *ctx)
+static CURLcode my_md5_init(void *ctx)
 {
   if(!CC_MD5_Init(ctx))
     return CURLE_OUT_OF_MEMORY;
@@ -186,14 +211,14 @@
   return CURLE_OK;
 }
 
-static void my_md5_update(my_md5_ctx *ctx,
+static void my_md5_update(void *ctx,
                           const unsigned char *input,
                           unsigned int inputLen)
 {
   CC_MD5_Update(ctx, input, inputLen);
 }
 
-static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+static void my_md5_final(unsigned char *digest, void *ctx)
 {
   CC_MD5_Final(digest, ctx);
 }
@@ -206,8 +231,9 @@
 };
 typedef struct md5_ctx my_md5_ctx;
 
-static CURLcode my_md5_init(my_md5_ctx *ctx)
+static CURLcode my_md5_init(void *in)
 {
+  my_md5_ctx *ctx = (my_md5_ctx *)in;
   if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
     return CURLE_OUT_OF_MEMORY;
@@ -221,15 +247,17 @@
   return CURLE_OK;
 }
 
-static void my_md5_update(my_md5_ctx *ctx,
+static void my_md5_update(void *in,
                           const unsigned char *input,
                           unsigned int inputLen)
 {
+  my_md5_ctx *ctx = in;
   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
 }
 
-static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+static void my_md5_final(unsigned char *digest, void *in)
 {
+  my_md5_ctx *ctx = (my_md5_ctx *)in;
   unsigned long length = 0;
   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
   if(length == 16)
@@ -292,10 +320,10 @@
 };
 typedef struct md5_ctx my_md5_ctx;
 
-static CURLcode my_md5_init(my_md5_ctx *ctx);
-static void my_md5_update(my_md5_ctx *ctx, const void *data,
-                          unsigned long size);
-static void my_md5_final(unsigned char *result, my_md5_ctx *ctx);
+static CURLcode my_md5_init(void *ctx);
+static void my_md5_update(void *ctx, const unsigned char *data,
+                          unsigned int size);
+static void my_md5_final(unsigned char *result, void *ctx);
 
 /*
  * The basic MD5 functions.
@@ -455,8 +483,9 @@
   return ptr;
 }
 
-static CURLcode my_md5_init(my_md5_ctx *ctx)
+static CURLcode my_md5_init(void *in)
 {
+  my_md5_ctx *ctx = (my_md5_ctx *)in;
   ctx->a = 0x67452301;
   ctx->b = 0xefcdab89;
   ctx->c = 0x98badcfe;
@@ -468,11 +497,12 @@
   return CURLE_OK;
 }
 
-static void my_md5_update(my_md5_ctx *ctx, const void *data,
-                          unsigned long size)
+static void my_md5_update(void *in, const unsigned char *data,
+                          unsigned int size)
 {
   MD5_u32plus saved_lo;
-  unsigned long used;
+  unsigned int used;
+  my_md5_ctx *ctx = (my_md5_ctx *)in;
 
   saved_lo = ctx->lo;
   ctx->lo = (saved_lo + size) & 0x1fffffff;
@@ -483,7 +513,7 @@
   used = saved_lo & 0x3f;
 
   if(used) {
-    unsigned long available = 64 - used;
+    unsigned int available = 64 - used;
 
     if(size < available) {
       memcpy(&ctx->buffer[used], data, size);
@@ -504,9 +534,10 @@
   memcpy(ctx->buffer, data, size);
 }
 
-static void my_md5_final(unsigned char *result, my_md5_ctx *ctx)
+static void my_md5_final(unsigned char *result, void *in)
 {
-  unsigned long used, available;
+  unsigned int used, available;
+  my_md5_ctx *ctx = (my_md5_ctx *)in;
 
   used = ctx->lo & 0x3f;
 
@@ -557,36 +588,21 @@
 
 #endif /* CRYPTO LIBS */
 
-const struct HMAC_params Curl_HMAC_MD5[] = {
-  {
-    /* Hash initialization function. */
-    CURLX_FUNCTION_CAST(HMAC_hinit_func, my_md5_init),
-    /* Hash update function. */
-    CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_md5_update),
-    /* Hash computation end function. */
-    CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_md5_final),
-    /* Size of hash context structure. */
-    sizeof(my_md5_ctx),
-    /* Maximum key length. */
-    64,
-    /* Result size. */
-    16
-  }
+const struct HMAC_params Curl_HMAC_MD5 = {
+  my_md5_init,        /* Hash initialization function. */
+  my_md5_update,      /* Hash update function. */
+  my_md5_final,       /* Hash computation end function. */
+  sizeof(my_md5_ctx), /* Size of hash context structure. */
+  64,                 /* Maximum key length. */
+  16                  /* Result size. */
 };
 
-const struct MD5_params Curl_DIGEST_MD5[] = {
-  {
-    /* Digest initialization function */
-    CURLX_FUNCTION_CAST(Curl_MD5_init_func, my_md5_init),
-    /* Digest update function */
-    CURLX_FUNCTION_CAST(Curl_MD5_update_func, my_md5_update),
-    /* Digest computation end function */
-    CURLX_FUNCTION_CAST(Curl_MD5_final_func, my_md5_final),
-    /* Size of digest context struct */
-    sizeof(my_md5_ctx),
-    /* Result size */
-    16
-  }
+const struct MD5_params Curl_DIGEST_MD5 = {
+  my_md5_init,        /* Digest initialization function */
+  my_md5_update,      /* Digest update function */
+  my_md5_final,       /* Digest computation end function */
+  sizeof(my_md5_ctx), /* Size of digest context struct */
+  16                  /* Result size */
 };
 
 /*
diff --git a/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c
index bc83d3e..02612c2 100644
--- a/Utilities/cmcurl/lib/memdebug.c
+++ b/Utilities/cmcurl/lib/memdebug.c
@@ -49,9 +49,9 @@
 };
 
 /*
- * Note that these debug functions are very simple and they are meant to
- * remain so. For advanced analysis, record a log file and write perl scripts
- * to analyze them!
+ * Note that these debug functions are simple and they are meant to remain so.
+ * For advanced analysis, record a log file and write perl scripts to analyze
+ * them!
  *
  * Do not use these with multithreaded test programs!
  */
diff --git a/Utilities/cmcurl/lib/memdebug.h b/Utilities/cmcurl/lib/memdebug.h
index cabadbc..80f3374 100644
--- a/Utilities/cmcurl/lib/memdebug.h
+++ b/Utilities/cmcurl/lib/memdebug.h
@@ -153,6 +153,7 @@
                      __LINE__, __FILE__)
 #endif
 
+#ifndef CURL_NO_GETADDRINFO_OVERRIDE
 #ifdef HAVE_GETADDRINFO
 #if defined(getaddrinfo) && defined(__osf__)
 /* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define
@@ -172,6 +173,7 @@
 #define freeaddrinfo(data) \
   curl_dbg_freeaddrinfo(data, __LINE__, __FILE__)
 #endif /* HAVE_FREEADDRINFO */
+#endif /* !CURL_NO_GETADDRINFO_OVERRIDE */
 
 /* sclose is probably already defined, redefine it! */
 #undef sclose
diff --git a/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c
index 885eca6..21c40b0 100644
--- a/Utilities/cmcurl/lib/mime.c
+++ b/Utilities/cmcurl/lib/mime.c
@@ -26,6 +26,8 @@
 
 #include <curl/curl.h>
 
+struct Curl_easy;
+
 #include "mime.h"
 #include "warnless.h"
 #include "urldata.h"
@@ -259,7 +261,7 @@
   s2 = strrchr(path, '\\');
 
   if(s1 && s2) {
-    path = (s1 > s2? s1 : s2) + 1;
+    path = (s1 > s2 ? s1 : s2) + 1;
   }
   else if(s1)
     path = s1 + 1;
@@ -424,7 +426,7 @@
   for(cursize = 0; cursize < size; cursize++) {
     *buffer = st->buf[st->bufbeg];
     if(*buffer++ & 0x80)
-      return cursize? cursize: READ_ERROR;
+      return cursize ? cursize : READ_ERROR;
     st->bufbeg++;
   }
 
@@ -538,7 +540,7 @@
   if(n >= st->bufend && ateof)
     return 1;
   if(n + 2 > st->bufend)
-    return ateof? 0: -1;
+    return ateof ? 0 : -1;
   if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
      qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
     return 1;
@@ -651,7 +653,7 @@
 {
   /* Determining the size can only be done by reading the data: unless the
      data size is 0, we return it as unknown (-1). */
-  return part->datasize? -1: 0;
+  return part->datasize ? -1 : 0;
 }
 
 
@@ -711,7 +713,7 @@
   if(part->fp)
     return 0;
   part->fp = fopen_read(part->data, "rb");
-  return part->fp? 0: -1;
+  return part->fp ? 0 : -1;
 }
 
 static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
@@ -738,8 +740,8 @@
   if(mime_open_file(part))
     return CURL_SEEKFUNC_FAIL;
 
-  return fseek(part->fp, (long) offset, whence)?
-               CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
+  return fseek(part->fp, (long) offset, whence) ?
+    CURL_SEEKFUNC_CANTSEEK : CURL_SEEKFUNC_OK;
 }
 
 static void mime_file_free(void *ptr)
@@ -871,7 +873,7 @@
         break;
       case READ_ERROR:
       case STOP_FILLING:
-        return cursize? cursize: sz;
+        return cursize ? cursize : sz;
       default:
         cursize += sz;
         buffer += sz;
@@ -890,7 +892,7 @@
       st->bufend = len;
     }
     if(st->bufend >= sizeof(st->buf))
-      return cursize? cursize: READ_ERROR;    /* Buffer full. */
+      return cursize ? cursize : READ_ERROR;    /* Buffer full. */
     sz = read_part_content(part, st->buf + st->bufend,
                            sizeof(st->buf) - st->bufend, hasread);
     switch(sz) {
@@ -901,7 +903,7 @@
     case CURL_READFUNC_PAUSE:
     case READ_ERROR:
     case STOP_FILLING:
-      return cursize? cursize: sz;
+      return cursize ? cursize : sz;
     default:
       st->bufend += sz;
       break;
@@ -925,8 +927,8 @@
     switch(part->state.state) {
     case MIMESTATE_BEGIN:
       mimesetstate(&part->state,
-                   (part->flags & MIME_BODY_ONLY)?
-                     MIMESTATE_BODY: MIMESTATE_CURLHEADERS,
+                   (part->flags & MIME_BODY_ONLY) ?
+                   MIMESTATE_BODY : MIMESTATE_CURLHEADERS,
                    part->curlheaders);
       break;
     case MIMESTATE_USERHEADERS:
@@ -977,7 +979,7 @@
       case CURL_READFUNC_PAUSE:
       case READ_ERROR:
       case STOP_FILLING:
-        return cursize? cursize: sz;
+        return cursize ? cursize : sz;
       }
       break;
     case MIMESTATE_END:
@@ -1043,7 +1045,7 @@
       case CURL_READFUNC_PAUSE:
       case READ_ERROR:
       case STOP_FILLING:
-        return cursize? cursize: sz;
+        return cursize ? cursize : sz;
       case 0:
         mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
         break;
@@ -1228,12 +1230,12 @@
     /* No one knows about the cloned subparts, thus always attach ownership
        to the part. */
     mime = curl_mime_init(data);
-    res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY;
+    res = mime ? curl_mime_subparts(dst, mime) : CURLE_OUT_OF_MEMORY;
 
     /* Duplicate subparts. */
     for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) {
       d = curl_mime_addpart(mime);
-      res = d? Curl_mime_duppart(data, d, s): CURLE_OUT_OF_MEMORY;
+      res = d ? Curl_mime_duppart(data, d, s) : CURLE_OUT_OF_MEMORY;
     }
     break;
   default:  /* Invalid kind: should not occur. */
@@ -1279,7 +1281,7 @@
  */
 
 /* Create a mime handle. */
-curl_mime *curl_mime_init(struct Curl_easy *easy)
+curl_mime *curl_mime_init(void *easy)
 {
   curl_mime *mime;
 
@@ -1562,7 +1564,8 @@
     subparts->parent = part;
     /* Subparts are processed internally: no read callback. */
     part->seekfunc = mime_subparts_seek;
-    part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
+    part->freefunc = take_ownership ? mime_subparts_free :
+      mime_subparts_unbind;
     part->arg = subparts;
     part->datasize = -1;
     part->kind = MIMEKIND_MULTIPART;
@@ -1606,8 +1609,8 @@
 /* Rewind mime stream. */
 static CURLcode mime_rewind(curl_mimepart *part)
 {
-  return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
-         CURLE_OK: CURLE_SEND_FAIL_REWIND;
+  return mime_part_rewind(part) == CURL_SEEKFUNC_OK ?
+         CURLE_OK : CURLE_SEND_FAIL_REWIND;
 }
 
 /* Compute header list size. */
@@ -1691,7 +1694,7 @@
       free(s);
   }
 
-  return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
+  return hdr ? CURLE_OK : CURLE_OUT_OF_MEMORY;
 }
 
 /* Add a content type header. */
@@ -1699,8 +1702,8 @@
                                  const char *type, const char *boundary)
 {
   return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
-                              boundary? "; boundary=": "",
-                              boundary? boundary: "");
+                              boundary ? "; boundary=" : "",
+                              boundary ? boundary : "");
 }
 
 const char *Curl_mime_contenttype(const char *filename)
@@ -1840,12 +1843,12 @@
         ret = Curl_mime_add_header(&part->curlheaders,
                                    "Content-Disposition: %s%s%s%s%s%s%s",
                                    disposition,
-                                   name? "; name=\"": "",
-                                   name? name: "",
-                                   name? "\"": "",
-                                   filename? "; filename=\"": "",
-                                   filename? filename: "",
-                                   filename? "\"": "");
+                                   name ? "; name=\"" : "",
+                                   name ? name : "",
+                                   name ? "\"" : "",
+                                   filename ? "; filename=\"" : "",
+                                   filename ? filename : "",
+                                   filename ? "\"" : "");
       Curl_safefree(name);
       Curl_safefree(filename);
       if(ret)
@@ -1923,6 +1926,7 @@
   curl_off_t total_len;
   curl_off_t read_len;
   CURLcode error_result;
+  struct bufq tmpbuf;
   BIT(seen_eos);
   BIT(errored);
 };
@@ -1934,9 +1938,18 @@
   (void)data;
   ctx->total_len = -1;
   ctx->read_len = 0;
+  Curl_bufq_init2(&ctx->tmpbuf, 1024, 1, BUFQ_OPT_NO_SPARES);
   return CURLE_OK;
 }
 
+static void cr_mime_close(struct Curl_easy *data,
+                          struct Curl_creader *reader)
+{
+  struct cr_mime_ctx *ctx = reader->ctx;
+  (void)data;
+  Curl_bufq_free(&ctx->tmpbuf);
+}
+
 /* Real client reader to installed client callbacks. */
 static CURLcode cr_mime_read(struct Curl_easy *data,
                              struct Curl_creader *reader,
@@ -1945,6 +1958,7 @@
 {
   struct cr_mime_ctx *ctx = reader->ctx;
   size_t nread;
+  char tmp[256];
 
 
   /* Once we have errored, we will return the same error forever */
@@ -1970,18 +1984,46 @@
       blen = (size_t)remain;
   }
 
-  if(blen <= 4) {
-    /* TODO: Curl_mime_read() may go into an infinite loop when reading
-     * such small lengths. Returning 0 bytes read is a fix that only works
-     * as request upload buffers will get flushed eventually and larger
-     * reads will happen again. */
-    CURL_TRC_READ(data, "cr_mime_read(len=%zu), too small, return", blen);
-    *pnread = 0;
-    *peos = FALSE;
-    goto out;
+  if(!Curl_bufq_is_empty(&ctx->tmpbuf)) {
+    CURLcode result = CURLE_OK;
+    ssize_t n = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen,
+                               &result);
+    if(n < 0) {
+      ctx->errored = TRUE;
+      ctx->error_result = result;
+      return result;
+    }
+    nread = (size_t)n;
   }
+  else if(blen <= 4) {
+    /* Curl_mime_read() may go into an infinite loop when reading
+     * via a base64 encoder, as it stalls when the read buffer is too small
+     * to contain a complete 3 byte encoding. Read into a larger buffer
+     * and use that until empty. */
+    CURL_TRC_READ(data, "cr_mime_read(len=%zu), small read, using tmp", blen);
+    nread = Curl_mime_read(tmp, 1, sizeof(tmp), ctx->part);
+    if(nread <= sizeof(tmp)) {
+      CURLcode result = CURLE_OK;
+      ssize_t n = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread,
+                                  &result);
+      if(n < 0) {
+        ctx->errored = TRUE;
+        ctx->error_result = result;
+        return result;
+      }
+      /* stored it, read again */
+      n = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &result);
+      if(n < 0) {
+        ctx->errored = TRUE;
+        ctx->error_result = result;
+        return result;
+      }
+      nread = (size_t)n;
+    }
+  }
+  else
+    nread = Curl_mime_read(buf, 1, blen, ctx->part);
 
-  nread = Curl_mime_read(buf, 1, blen, ctx->part);
   CURL_TRC_READ(data, "cr_mime_read(len=%zu), mime_read() -> %zd",
                 blen, nread);
 
@@ -2041,7 +2083,6 @@
     break;
   }
 
-out:
   CURL_TRC_READ(data, "cr_mime_read(len=%zu, total=%" FMT_OFF_T
                 ", read=%"FMT_OFF_T") -> %d, %zu, %d",
                 blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos);
@@ -2137,7 +2178,7 @@
   "cr-mime",
   cr_mime_init,
   cr_mime_read,
-  Curl_creader_def_close,
+  cr_mime_close,
   cr_mime_needs_rewind,
   cr_mime_total_length,
   cr_mime_resume_from,
diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c
index 42993c7..35e40e3 100644
--- a/Utilities/cmcurl/lib/mprintf.c
+++ b/Utilities/cmcurl/lib/mprintf.c
@@ -101,27 +101,27 @@
 
 /* conversion and display flags */
 enum {
-  FLAGS_SPACE      = 1<<0,
-  FLAGS_SHOWSIGN   = 1<<1,
-  FLAGS_LEFT       = 1<<2,
-  FLAGS_ALT        = 1<<3,
-  FLAGS_SHORT      = 1<<4,
-  FLAGS_LONG       = 1<<5,
-  FLAGS_LONGLONG   = 1<<6,
-  FLAGS_LONGDOUBLE = 1<<7,
-  FLAGS_PAD_NIL    = 1<<8,
-  FLAGS_UNSIGNED   = 1<<9,
-  FLAGS_OCTAL      = 1<<10,
-  FLAGS_HEX        = 1<<11,
-  FLAGS_UPPER      = 1<<12,
-  FLAGS_WIDTH      = 1<<13, /* '*' or '*<num>$' used */
-  FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */
-  FLAGS_PREC       = 1<<15, /* precision was specified */
-  FLAGS_PRECPARAM  = 1<<16, /* precision PARAMETER was specified */
-  FLAGS_CHAR       = 1<<17, /* %c story */
-  FLAGS_FLOATE     = 1<<18, /* %e or %E */
-  FLAGS_FLOATG     = 1<<19, /* %g or %G */
-  FLAGS_SUBSTR     = 1<<20  /* no input, only substring */
+  FLAGS_SPACE      = 1 << 0,
+  FLAGS_SHOWSIGN   = 1 << 1,
+  FLAGS_LEFT       = 1 << 2,
+  FLAGS_ALT        = 1 << 3,
+  FLAGS_SHORT      = 1 << 4,
+  FLAGS_LONG       = 1 << 5,
+  FLAGS_LONGLONG   = 1 << 6,
+  FLAGS_LONGDOUBLE = 1 << 7,
+  FLAGS_PAD_NIL    = 1 << 8,
+  FLAGS_UNSIGNED   = 1 << 9,
+  FLAGS_OCTAL      = 1 << 10,
+  FLAGS_HEX        = 1 << 11,
+  FLAGS_UPPER      = 1 << 12,
+  FLAGS_WIDTH      = 1 << 13, /* '*' or '*<num>$' used */
+  FLAGS_WIDTHPARAM = 1 << 14, /* width PARAMETER was specified */
+  FLAGS_PREC       = 1 << 15, /* precision was specified */
+  FLAGS_PRECPARAM  = 1 << 16, /* precision PARAMETER was specified */
+  FLAGS_CHAR       = 1 << 17, /* %c story */
+  FLAGS_FLOATE     = 1 << 18, /* %e or %E */
+  FLAGS_FLOATG     = 1 << 19, /* %g or %G */
+  FLAGS_SUBSTR     = 1 << 20  /* no input, only substring */
 };
 
 enum {
@@ -321,10 +321,10 @@
               fmt++;
             }
             while(ISDIGIT(*fmt)) {
-              if(precision > INT_MAX/10)
+              int n = *fmt - '0';
+              if(precision > (INT_MAX - n) / 10)
                 return PFMT_PREC;
-              precision *= 10;
-              precision += *fmt - '0';
+              precision = precision * 10 + n;
               fmt++;
             }
             if(is_neg)
@@ -397,10 +397,10 @@
           width = 0;
           fmt--;
           do {
-            if(width > INT_MAX/10)
+            int n = *fmt - '0';
+            if(width > (INT_MAX - n) / 10)
               return PFMT_WIDTH;
-            width *= 10;
-            width += *fmt - '0';
+            width = width * 10 + n;
             fmt++;
           } while(ISDIGIT(*fmt));
           break;
@@ -455,15 +455,30 @@
         flags |= FLAGS_UNSIGNED;
         break;
       case 'o':
-        type = FORMAT_INT;
-        flags |= FLAGS_OCTAL;
+        if(flags & FLAGS_LONGLONG)
+          type = FORMAT_LONGLONGU;
+        else if(flags & FLAGS_LONG)
+          type = FORMAT_LONGU;
+        else
+          type = FORMAT_INTU;
+        flags |= FLAGS_OCTAL|FLAGS_UNSIGNED;
         break;
       case 'x':
-        type = FORMAT_INTU;
+        if(flags & FLAGS_LONGLONG)
+          type = FORMAT_LONGLONGU;
+        else if(flags & FLAGS_LONG)
+          type = FORMAT_LONGU;
+        else
+          type = FORMAT_INTU;
         flags |= FLAGS_HEX|FLAGS_UNSIGNED;
         break;
       case 'X':
-        type = FORMAT_INTU;
+        if(flags & FLAGS_LONGLONG)
+          type = FORMAT_LONGLONGU;
+        else if(flags & FLAGS_LONG)
+          type = FORMAT_LONGU;
+        else
+          type = FORMAT_INTU;
         flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
         break;
       case 'c':
@@ -668,7 +683,7 @@
   char work[BUFFSIZE];
 
   /* 'workend' points to the final buffer byte position, but with an extra
-     byte as margin to avoid the (false?) warning Coverity gives us
+     byte as margin to avoid the (FALSE?) warning Coverity gives us
      otherwise */
   char *workend = &work[sizeof(work) - 2];
 
@@ -760,7 +775,7 @@
       }
       else if(flags & FLAGS_HEX) {
         /* Hexadecimal unsigned integer */
-        digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits;
+        digits = (flags & FLAGS_UPPER) ? upper_digits : lower_digits;
         base = 16;
         is_neg = FALSE;
       }
@@ -906,7 +921,7 @@
       if(iptr->val.ptr) {
         /* If the pointer is not NULL, write it as a %#x spec.  */
         base = 16;
-        digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits;
+        digits = (flags & FLAGS_UPPER) ? upper_digits : lower_digits;
         is_alt = TRUE;
         num = (size_t) iptr->val.ptr;
         is_neg = FALSE;
@@ -984,7 +999,7 @@
         *fptr++ = 'l';
 
       if(flags & FLAGS_FLOATE)
-        *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E':'e');
+        *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E' : 'e');
       else if(flags & FLAGS_FLOATG)
         *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g');
       else
diff --git a/Utilities/cmcurl/lib/mqtt.c b/Utilities/cmcurl/lib/mqtt.c
index 22d354a..69eaf34 100644
--- a/Utilities/cmcurl/lib/mqtt.c
+++ b/Utilities/cmcurl/lib/mqtt.c
@@ -156,7 +156,7 @@
 {
   int i;
 
-  for(i = 0; (len > 0) && (i<4); i++) {
+  for(i = 0; (len > 0) && (i < 4); i++) {
     unsigned char encoded;
     encoded = len % 0x80;
     len /= 0x80;
@@ -375,7 +375,7 @@
       return CURLE_OUT_OF_MEMORY;
     rlen = Curl_dyn_len(&mq->recvbuf);
   }
-  return (rlen >= nbytes)? CURLE_OK : CURLE_AGAIN;
+  return (rlen >= nbytes) ? CURLE_OK : CURLE_AGAIN;
 }
 
 static void mqtt_recv_consume(struct Curl_easy *data, size_t nbytes)
@@ -610,7 +610,7 @@
   infof(data, "%s (from %s) (next is %s)",
         statenames[state],
         statenames[mqtt->state],
-        (state == MQTT_FIRST)? statenames[nextstate] : "");
+        (state == MQTT_FIRST) ? statenames[nextstate] : "");
 #endif
   mqtt->state = state;
   if(state == MQTT_FIRST)
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index 78e5c0a..1851dc7 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -50,6 +50,7 @@
 #include "http2.h"
 #include "socketpair.h"
 #include "socks.h"
+#include "urlapi-int.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -79,7 +80,7 @@
  * are not NULL, but no longer have the MAGIC touch. This gives
  * us early warning on things only discovered by valgrind otherwise. */
 #define GOOD_MULTI_HANDLE(x) \
-  (((x) && (x)->magic == CURL_MULTI_HANDLE)? TRUE: \
+  (((x) && (x)->magic == CURL_MULTI_HANDLE)? TRUE:      \
   (DEBUGASSERT(!(x)), FALSE))
 #else
 #define GOOD_MULTI_HANDLE(x) \
@@ -98,10 +99,10 @@
                                long *timeout_ms);
 static void process_pending_handles(struct Curl_multi *multi);
 static void multi_xfer_bufs_free(struct Curl_multi *multi);
-static void Curl_expire_ex(struct Curl_easy *data, const struct curltime *nowp,
-                           timediff_t milli, expire_id id);
+static void expire_ex(struct Curl_easy *data, const struct curltime *nowp,
+                      timediff_t milli, expire_id id);
 
-#ifdef DEBUGBUILD
+#if defined( DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
 static const char * const multi_statename[]={
   "INIT",
   "PENDING",
@@ -240,12 +241,13 @@
 }
 
 #define TRHASH_SIZE 13
+
+/* the given key here is a struct Curl_easy pointer */
 static size_t trhash(void *key, size_t key_length, size_t slots_num)
 {
-  size_t keyval = (size_t)*(struct Curl_easy **)key;
-  (void) key_length;
-
-  return (keyval % slots_num);
+  unsigned char bytes = ((unsigned char *)key)[key_length - 1] ^
+    ((unsigned char *)key)[0];
+  return (bytes % slots_num);
 }
 
 static size_t trhash_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
@@ -449,7 +451,7 @@
   return NULL;
 }
 
-struct Curl_multi *curl_multi_init(void)
+CURLM *curl_multi_init(void)
 {
   return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
                            CURL_CONNECTION_HASH_SIZE,
@@ -463,17 +465,18 @@
     infof(data, "!!! WARNING !!!");
     infof(data, "This is a debug build of libcurl, "
           "do not use in production.");
-    multi->warned = true;
+    multi->warned = TRUE;
   }
 }
 #else
 #define multi_warn_debug(x,y) Curl_nop_stmt
 #endif
 
-CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
-                                struct Curl_easy *data)
+CURLMcode curl_multi_add_handle(CURLM *m, CURL *d)
 {
   CURLMcode rc;
+  struct Curl_multi *multi = m;
+  struct Curl_easy *data = d;
   /* First, make some basic checks that the CURLM handle is a good handle */
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
@@ -755,6 +758,8 @@
   mdctx.premature = premature;
   Curl_cpool_do_locked(data, data->conn, multi_done_locked, &mdctx);
 
+  /* flush the netrc cache */
+  Curl_netrc_cleanup(&data->state.netrc);
   return result;
 }
 
@@ -768,10 +773,10 @@
     connclose(conn, "Removing connect-only easy handle");
 }
 
-CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
-                                   struct Curl_easy *data)
+CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d)
 {
-  struct Curl_easy *easy = data;
+  struct Curl_multi *multi = m;
+  struct Curl_easy *data = d;
   bool premature;
   struct Curl_llist_node *e;
   CURLMcode rc;
@@ -796,7 +801,7 @@
   if(multi->in_callback)
     return CURLM_RECURSIVE_API_CALL;
 
-  premature = (data->mstate < MSTATE_COMPLETED) ? TRUE : FALSE;
+  premature = (data->mstate < MSTATE_COMPLETED);
 
   /* If the 'state' is not INIT or COMPLETED, we might need to do something
      nice to put the easy_handle in a good known state when this returns. */
@@ -846,7 +851,7 @@
 
   /* This ignores the return code even in case of problems because there is
      nothing more to do about that, here */
-  (void)singlesocket(multi, easy); /* to let the application know what sockets
+  (void)singlesocket(multi, data); /* to let the application know what sockets
                                       that vanish with this handle */
 
   /* Remove the association between the connection and the handle */
@@ -886,7 +891,7 @@
   for(e = Curl_llist_head(&multi->msglist); e; e = Curl_node_next(e)) {
     struct Curl_message *msg = Curl_node_elem(e);
 
-    if(msg->extmsg.easy_handle == easy) {
+    if(msg->extmsg.easy_handle == data) {
       Curl_node_remove(e);
       /* there can only be one from this specific handle */
       break;
@@ -1125,14 +1130,19 @@
   }
 
   if(expect_sockets && !ps->num &&
-     !(data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) &&
+     !Curl_llist_count(&data->state.timeoutlist) &&
+     !Curl_cwriter_is_paused(data) && !Curl_creader_is_paused(data) &&
      Curl_conn_is_ip_connected(data, FIRSTSOCKET)) {
-    infof(data, "WARNING: no socket in pollset, transfer may stall!");
+    /* We expected sockets for POLL monitoring, but none are set.
+     * We are not waiting on any timer.
+     * None of the READ/WRITE directions are paused.
+     * We are connected to the server on IP level, at least. */
+    infof(data, "WARNING: no socket in pollset or timer, transfer may stall!");
     DEBUGASSERT(0);
   }
 }
 
-CURLMcode curl_multi_fdset(struct Curl_multi *multi,
+CURLMcode curl_multi_fdset(CURLM *m,
                            fd_set *read_fd_set, fd_set *write_fd_set,
                            fd_set *exc_fd_set, int *max_fd)
 {
@@ -1141,6 +1151,7 @@
      and then we must make sure that is done. */
   int this_max_fd = -1;
   struct Curl_llist_node *e;
+  struct Curl_multi *multi = m;
   (void)exc_fd_set; /* not used */
 
   if(!GOOD_MULTI_HANDLE(multi))
@@ -1173,7 +1184,7 @@
   return CURLM_OK;
 }
 
-CURLMcode curl_multi_waitfds(struct Curl_multi *multi,
+CURLMcode curl_multi_waitfds(CURLM *m,
                              struct curl_waitfd *ufds,
                              unsigned int size,
                              unsigned int *fd_count)
@@ -1181,6 +1192,7 @@
   struct curl_waitfds cwfds;
   CURLMcode result = CURLM_OK;
   struct Curl_llist_node *e;
+  struct Curl_multi *multi = m;
 
   if(!ufds)
     return CURLM_BAD_FUNCTION_ARGUMENT;
@@ -1478,7 +1490,7 @@
   return result;
 }
 
-CURLMcode curl_multi_wait(struct Curl_multi *multi,
+CURLMcode curl_multi_wait(CURLM *multi,
                           struct curl_waitfd extra_fds[],
                           unsigned int extra_nfds,
                           int timeout_ms,
@@ -1488,7 +1500,7 @@
                     FALSE);
 }
 
-CURLMcode curl_multi_poll(struct Curl_multi *multi,
+CURLMcode curl_multi_poll(CURLM *multi,
                           struct curl_waitfd extra_fds[],
                           unsigned int extra_nfds,
                           int timeout_ms,
@@ -1498,11 +1510,12 @@
                     TRUE);
 }
 
-CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
+CURLMcode curl_multi_wakeup(CURLM *m)
 {
   /* this function is usually called from another thread,
      it has to be careful only to access parts of the
      Curl_multi struct that are constant */
+  struct Curl_multi *multi = m;
 
 #if defined(ENABLE_WAKEUP) && !defined(USE_WINSOCK)
 #ifdef USE_EVENTFD
@@ -1528,6 +1541,9 @@
   if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) {
 #ifdef USE_EVENTFD
     buf = &val;
+    /* eventfd has a stringent rule of requiring the 8-byte buffer when
+       calling write(2) on it, which makes the sizeof(buf) below fine since
+       this is only used on 64-bit systems and then the pointer is 64-bit */
 #else
     buf[0] = 1;
 #endif
@@ -1657,9 +1673,9 @@
 static bool multi_handle_timeout(struct Curl_easy *data,
                                  struct curltime *now,
                                  bool *stream_error,
-                                 CURLcode *result,
-                                 bool connect_timeout)
+                                 CURLcode *result)
 {
+  bool connect_timeout = data->mstate < MSTATE_DO;
   timediff_t timeout_ms = Curl_timeleft(data, now, connect_timeout);
   if(timeout_ms < 0) {
     /* Handle timed out */
@@ -1811,19 +1827,781 @@
 #endif
 }
 
+/*
+ * multi_follow() handles the URL redirect magic. Pass in the 'newurl' string
+ * as given by the remote server and set up the new URL to request.
+ *
+ * This function DOES NOT FREE the given url.
+ */
+static CURLcode multi_follow(struct Curl_easy *data,
+                             char *newurl,    /* the Location: string */
+                             followtype type) /* see transfer.h */
+{
+#ifdef CURL_DISABLE_HTTP
+  (void)data;
+  (void)newurl;
+  (void)type;
+  /* Location: following will not happen when HTTP is disabled */
+  return CURLE_TOO_MANY_REDIRECTS;
+#else
+
+  /* Location: redirect */
+  bool disallowport = FALSE;
+  bool reachedmax = FALSE;
+  CURLUcode uc;
+
+  DEBUGASSERT(type != FOLLOW_NONE);
+
+  if(type != FOLLOW_FAKE)
+    data->state.requests++; /* count all real follows */
+  if(type == FOLLOW_REDIR) {
+    if((data->set.maxredirs != -1) &&
+       (data->state.followlocation >= data->set.maxredirs)) {
+      reachedmax = TRUE;
+      type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected
+                             to URL */
+    }
+    else {
+      data->state.followlocation++; /* count redirect-followings, including
+                                       auth reloads */
+
+      if(data->set.http_auto_referer) {
+        CURLU *u;
+        char *referer = NULL;
+
+        /* We are asked to automatically set the previous URL as the referer
+           when we get the next URL. We pick the ->url field, which may or may
+           not be 100% correct */
+
+        if(data->state.referer_alloc) {
+          Curl_safefree(data->state.referer);
+          data->state.referer_alloc = FALSE;
+        }
+
+        /* Make a copy of the URL without credentials and fragment */
+        u = curl_url();
+        if(!u)
+          return CURLE_OUT_OF_MEMORY;
+
+        uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0);
+        if(!uc)
+          uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0);
+        if(!uc)
+          uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
+        if(!uc)
+          uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
+        if(!uc)
+          uc = curl_url_get(u, CURLUPART_URL, &referer, 0);
+
+        curl_url_cleanup(u);
+
+        if(uc || !referer)
+          return CURLE_OUT_OF_MEMORY;
+
+        data->state.referer = referer;
+        data->state.referer_alloc = TRUE; /* yes, free this later */
+      }
+    }
+  }
+
+  if((type != FOLLOW_RETRY) &&
+     (data->req.httpcode != 401) && (data->req.httpcode != 407) &&
+     Curl_is_absolute_url(newurl, NULL, 0, FALSE)) {
+    /* If this is not redirect due to a 401 or 407 response and an absolute
+       URL: do not allow a custom port number */
+    disallowport = TRUE;
+  }
+
+  DEBUGASSERT(data->state.uh);
+  uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, (unsigned int)
+                    ((type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
+                     ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
+                     CURLU_ALLOW_SPACE |
+                     (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
+  if(uc) {
+    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 */
+    newurl = strdup(newurl);
+    if(!newurl)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  else {
+    uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
+    if(uc)
+      return Curl_uc_to_curlcode(uc);
+
+    /* Clear auth if this redirects to a different port number or protocol,
+       unless permitted */
+    if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) {
+      char *portnum;
+      int port;
+      bool clear = FALSE;
+
+      if(data->set.use_port && data->state.allow_port)
+        /* a custom port is used */
+        port = (int)data->set.use_port;
+      else {
+        uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum,
+                          CURLU_DEFAULT_PORT);
+        if(uc) {
+          free(newurl);
+          return Curl_uc_to_curlcode(uc);
+        }
+        port = atoi(portnum);
+        free(portnum);
+      }
+      if(port != data->info.conn_remote_port) {
+        infof(data, "Clear auth, redirects to port from %u to %u",
+              data->info.conn_remote_port, port);
+        clear = TRUE;
+      }
+      else {
+        char *scheme;
+        const struct Curl_handler *p;
+        uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0);
+        if(uc) {
+          free(newurl);
+          return Curl_uc_to_curlcode(uc);
+        }
+
+        p = Curl_get_scheme_handler(scheme);
+        if(p && (p->protocol != data->info.conn_protocol)) {
+          infof(data, "Clear auth, redirects scheme from %s to %s",
+                data->info.conn_scheme, scheme);
+          clear = TRUE;
+        }
+        free(scheme);
+      }
+      if(clear) {
+        Curl_safefree(data->state.aptr.user);
+        Curl_safefree(data->state.aptr.passwd);
+      }
+    }
+  }
+
+  if(type == FOLLOW_FAKE) {
+    /* we are only figuring out the new URL if we would have followed locations
+       but now we are done so we can get out! */
+    data->info.wouldredirect = newurl;
+
+    if(reachedmax) {
+      failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
+      return CURLE_TOO_MANY_REDIRECTS;
+    }
+    return CURLE_OK;
+  }
+
+  if(disallowport)
+    data->state.allow_port = FALSE;
+
+  if(data->state.url_alloc)
+    Curl_safefree(data->state.url);
+
+  data->state.url = newurl;
+  data->state.url_alloc = TRUE;
+  Curl_req_soft_reset(&data->req, data);
+  infof(data, "Issue another request to this URL: '%s'", data->state.url);
+
+  /*
+   * We get here when the HTTP code is 300-399 (and 401). We need to perform
+   * differently based on exactly what return code there was.
+   *
+   * News from 7.10.6: we can also get here on a 401 or 407, in case we act on
+   * an HTTP (proxy-) authentication scheme other than Basic.
+   */
+  switch(data->info.httpcode) {
+    /* 401 - Act on a WWW-Authenticate, we keep on moving and do the
+       Authorization: XXXX header in the HTTP request code snippet */
+    /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
+       Proxy-Authorization: XXXX header in the HTTP request code snippet */
+    /* 300 - Multiple Choices */
+    /* 306 - Not used */
+    /* 307 - Temporary Redirect */
+  default:  /* for all above (and the unknown ones) */
+    /* Some codes are explicitly mentioned since I have checked RFC2616 and
+     * they seem to be OK to POST to.
+     */
+    break;
+  case 301: /* Moved Permanently */
+    /* (quote from RFC7231, section 6.4.2)
+     *
+     * Note: For historical reasons, a user agent MAY change the request
+     * method from POST to GET for the subsequent request. If this
+     * behavior is undesired, the 307 (Temporary Redirect) status code
+     * can be used instead.
+     *
+     * ----
+     *
+     * Many webservers expect this, so these servers often answers to a POST
+     * request with an error page. To be sure that libcurl gets the page that
+     * most user agents would get, libcurl has to force GET.
+     *
+     * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
+     * can be overridden with CURLOPT_POSTREDIR.
+     */
+    if((data->state.httpreq == HTTPREQ_POST
+        || data->state.httpreq == HTTPREQ_POST_FORM
+        || data->state.httpreq == HTTPREQ_POST_MIME)
+       && !(data->set.keep_post & CURL_REDIR_POST_301)) {
+      infof(data, "Switch from POST to GET");
+      data->state.httpreq = HTTPREQ_GET;
+      Curl_creader_set_rewind(data, FALSE);
+    }
+    break;
+  case 302: /* Found */
+    /* (quote from RFC7231, section 6.4.3)
+     *
+     * Note: For historical reasons, a user agent MAY change the request
+     * method from POST to GET for the subsequent request. If this
+     * behavior is undesired, the 307 (Temporary Redirect) status code
+     * can be used instead.
+     *
+     * ----
+     *
+     * Many webservers expect this, so these servers often answers to a POST
+     * request with an error page. To be sure that libcurl gets the page that
+     * most user agents would get, libcurl has to force GET.
+     *
+     * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
+     * can be overridden with CURLOPT_POSTREDIR.
+     */
+    if((data->state.httpreq == HTTPREQ_POST
+        || data->state.httpreq == HTTPREQ_POST_FORM
+        || data->state.httpreq == HTTPREQ_POST_MIME)
+       && !(data->set.keep_post & CURL_REDIR_POST_302)) {
+      infof(data, "Switch from POST to GET");
+      data->state.httpreq = HTTPREQ_GET;
+      Curl_creader_set_rewind(data, FALSE);
+    }
+    break;
+
+  case 303: /* See Other */
+    /* 'See Other' location is not the resource but a substitute for the
+     * resource. In this case we switch the method to GET/HEAD, unless the
+     * method is POST and the user specified to keep it as POST.
+     * https://github.com/curl/curl/issues/5237#issuecomment-614641049
+     */
+    if(data->state.httpreq != HTTPREQ_GET &&
+       ((data->state.httpreq != HTTPREQ_POST &&
+         data->state.httpreq != HTTPREQ_POST_FORM &&
+         data->state.httpreq != HTTPREQ_POST_MIME) ||
+        !(data->set.keep_post & CURL_REDIR_POST_303))) {
+      data->state.httpreq = HTTPREQ_GET;
+      infof(data, "Switch to %s",
+            data->req.no_body ? "HEAD" : "GET");
+    }
+    break;
+  case 304: /* Not Modified */
+    /* 304 means we did a conditional request and it was "Not modified".
+     * We should not get any Location: header in this response!
+     */
+    break;
+  case 305: /* Use Proxy */
+    /* (quote from RFC2616, section 10.3.6):
+     * "The requested resource MUST be accessed through the proxy given
+     * by the Location field. The Location field gives the URI of the
+     * proxy. The recipient is expected to repeat this single request
+     * via the proxy. 305 responses MUST only be generated by origin
+     * servers."
+     */
+    break;
+  }
+  Curl_pgrsTime(data, TIMER_REDIRECT);
+  Curl_pgrsResetTransferSizes(data);
+
+  return CURLE_OK;
+#endif /* CURL_DISABLE_HTTP */
+}
+
+static CURLMcode state_performing(struct Curl_easy *data,
+                                  struct curltime *nowp,
+                                  bool *stream_errorp,
+                                  CURLcode *resultp)
+{
+  char *newurl = NULL;
+  bool retry = FALSE;
+  timediff_t recv_timeout_ms = 0;
+  timediff_t send_timeout_ms = 0;
+  CURLMcode rc = CURLM_OK;
+  CURLcode result = *resultp = CURLE_OK;
+  *stream_errorp = FALSE;
+
+  /* check if over send speed */
+  if(data->set.max_send_speed)
+    send_timeout_ms = Curl_pgrsLimitWaitTime(&data->progress.ul,
+                                             data->set.max_send_speed,
+                                             *nowp);
+
+  /* check if over recv speed */
+  if(data->set.max_recv_speed)
+    recv_timeout_ms = Curl_pgrsLimitWaitTime(&data->progress.dl,
+                                             data->set.max_recv_speed,
+                                             *nowp);
+
+  if(send_timeout_ms || recv_timeout_ms) {
+    Curl_ratelimit(data, *nowp);
+    multistate(data, MSTATE_RATELIMITING);
+    if(send_timeout_ms >= recv_timeout_ms)
+      Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
+    else
+      Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
+    return CURLM_OK;
+  }
+
+  /* read/write data if it is ready to do so */
+  result = Curl_sendrecv(data, nowp);
+
+  if(data->req.done || (result == CURLE_RECV_ERROR)) {
+    /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
+     * condition and the server closed the reused connection exactly when we
+     * wanted to use it, so figure out if that is indeed the case.
+     */
+    CURLcode ret = Curl_retry_request(data, &newurl);
+    if(!ret)
+      retry = !!newurl;
+    else if(!result)
+      result = ret;
+
+    if(retry) {
+      /* if we are to retry, set the result to OK and consider the
+         request as done */
+      result = CURLE_OK;
+      data->req.done = TRUE;
+    }
+  }
+  else if((CURLE_HTTP2_STREAM == result) &&
+          Curl_h2_http_1_1_error(data)) {
+    CURLcode ret = Curl_retry_request(data, &newurl);
+
+    if(!ret) {
+      infof(data, "Downgrades to HTTP/1.1");
+      streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
+      data->state.httpwant = CURL_HTTP_VERSION_1_1;
+      /* clear the error message bit too as we ignore the one we got */
+      data->state.errorbuf = FALSE;
+      if(!newurl)
+        /* typically for HTTP_1_1_REQUIRED error on first flight */
+        newurl = strdup(data->state.url);
+      /* if we are to retry, set the result to OK and consider the request
+         as done */
+      retry = TRUE;
+      result = CURLE_OK;
+      data->req.done = TRUE;
+    }
+    else
+      result = ret;
+  }
+
+  if(result) {
+    /*
+     * The transfer phase returned error, we mark the connection to get closed
+     * to prevent being reused. This is because we cannot possibly know if the
+     * connection is in a good shape or not now. Unless it is a protocol which
+     * uses two "channels" like FTP, as then the error happened in the data
+     * connection.
+     */
+
+    if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
+       result != CURLE_HTTP2_STREAM)
+      streamclose(data->conn, "Transfer returned error");
+
+    multi_posttransfer(data);
+    multi_done(data, result, TRUE);
+  }
+  else if(data->req.done && !Curl_cwriter_is_paused(data)) {
+
+    /* call this even if the readwrite function returned error */
+    multi_posttransfer(data);
+
+    /* When we follow redirects or is set to retry the connection, we must to
+       go back to the CONNECT state */
+    if(data->req.newurl || retry) {
+      followtype follow = FOLLOW_NONE;
+      if(!retry) {
+        /* if the URL is a follow-location and not just a retried request then
+           figure out the URL here */
+        free(newurl);
+        newurl = data->req.newurl;
+        data->req.newurl = NULL;
+        follow = FOLLOW_REDIR;
+      }
+      else
+        follow = FOLLOW_RETRY;
+      (void)multi_done(data, CURLE_OK, FALSE);
+      /* multi_done() might return CURLE_GOT_NOTHING */
+      result = multi_follow(data, newurl, follow);
+      if(!result) {
+        multistate(data, MSTATE_SETUP);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+    }
+    else {
+      /* after the transfer is done, go DONE */
+
+      /* but first check to see if we got a location info even though we are
+         not following redirects */
+      if(data->req.location) {
+        free(newurl);
+        newurl = data->req.location;
+        data->req.location = NULL;
+        result = multi_follow(data, newurl, FOLLOW_FAKE);
+        if(result) {
+          *stream_errorp = TRUE;
+          result = multi_done(data, result, TRUE);
+        }
+      }
+
+      if(!result) {
+        multistate(data, MSTATE_DONE);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+    }
+  }
+  else if(data->state.select_bits && !Curl_xfer_is_blocked(data)) {
+    /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer does
+       not get stuck on this transfer at the expense of other concurrent
+       transfers */
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+  }
+  free(newurl);
+  *resultp = result;
+  return rc;
+}
+
+static CURLMcode state_do(struct Curl_easy *data,
+                          bool *stream_errorp,
+                          CURLcode *resultp)
+{
+  CURLMcode rc = CURLM_OK;
+  CURLcode result = CURLE_OK;
+  if(data->set.fprereq) {
+    int prereq_rc;
+
+    /* call the prerequest callback function */
+    Curl_set_in_callback(data, TRUE);
+    prereq_rc = data->set.fprereq(data->set.prereq_userp,
+                                  data->info.primary.remote_ip,
+                                  data->info.primary.local_ip,
+                                  data->info.primary.remote_port,
+                                  data->info.primary.local_port);
+    Curl_set_in_callback(data, FALSE);
+    if(prereq_rc != CURL_PREREQFUNC_OK) {
+      failf(data, "operation aborted by pre-request callback");
+      /* failure in pre-request callback - do not do any other processing */
+      result = CURLE_ABORTED_BY_CALLBACK;
+      multi_posttransfer(data);
+      multi_done(data, result, FALSE);
+      *stream_errorp = TRUE;
+      goto end;
+    }
+  }
+
+  if(data->set.connect_only == 1) {
+    /* keep connection open for application to use the socket */
+    connkeep(data->conn, "CONNECT_ONLY");
+    multistate(data, MSTATE_DONE);
+    rc = CURLM_CALL_MULTI_PERFORM;
+  }
+  else {
+    bool dophase_done = FALSE;
+    /* Perform the protocol's DO action */
+    result = multi_do(data, &dophase_done);
+
+    /* When multi_do() returns failure, data->conn might be NULL! */
+
+    if(!result) {
+      if(!dophase_done) {
+#ifndef CURL_DISABLE_FTP
+        /* some steps needed for wildcard matching */
+        if(data->state.wildcardmatch) {
+          struct WildcardData *wc = data->wildcard;
+          if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
+            /* skip some states if it is important */
+            multi_done(data, CURLE_OK, FALSE);
+
+            /* if there is no connection left, skip the DONE state */
+            multistate(data, data->conn ?
+                       MSTATE_DONE : MSTATE_COMPLETED);
+            rc = CURLM_CALL_MULTI_PERFORM;
+            goto end;
+          }
+        }
+#endif
+        /* DO was not completed in one function call, we must continue
+           DOING... */
+        multistate(data, MSTATE_DOING);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+
+      /* after DO, go DO_DONE... or DO_MORE */
+      else if(data->conn->bits.do_more) {
+        /* we are supposed to do more, but we need to sit down, relax and wait
+           a little while first */
+        multistate(data, MSTATE_DOING_MORE);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+      else {
+        /* we are done with the DO, now DID */
+        multistate(data, MSTATE_DID);
+        rc = CURLM_CALL_MULTI_PERFORM;
+      }
+    }
+    else if((CURLE_SEND_ERROR == result) &&
+            data->conn->bits.reuse) {
+      /*
+       * In this situation, a connection that we were trying to use may have
+       * unexpectedly died. If possible, send the connection back to the
+       * CONNECT phase so we can try again.
+       */
+      char *newurl = NULL;
+      followtype follow = FOLLOW_NONE;
+      CURLcode drc;
+
+      drc = Curl_retry_request(data, &newurl);
+      if(drc) {
+        /* a failure here pretty much implies an out of memory */
+        result = drc;
+        *stream_errorp = TRUE;
+      }
+
+      multi_posttransfer(data);
+      drc = multi_done(data, result, FALSE);
+
+      /* When set to retry the connection, we must go back to the CONNECT
+       * state */
+      if(newurl) {
+        if(!drc || (drc == CURLE_SEND_ERROR)) {
+          follow = FOLLOW_RETRY;
+          drc = multi_follow(data, newurl, follow);
+          if(!drc) {
+            multistate(data, MSTATE_SETUP);
+            rc = CURLM_CALL_MULTI_PERFORM;
+            result = CURLE_OK;
+          }
+          else {
+            /* Follow failed */
+            result = drc;
+          }
+        }
+        else {
+          /* done did not return OK or SEND_ERROR */
+          result = drc;
+        }
+      }
+      else {
+        /* Have error handler disconnect conn if we cannot retry */
+        *stream_errorp = TRUE;
+      }
+      free(newurl);
+    }
+    else {
+      /* failure detected */
+      multi_posttransfer(data);
+      if(data->conn)
+        multi_done(data, result, FALSE);
+      *stream_errorp = TRUE;
+    }
+  }
+end:
+  *resultp = result;
+  return rc;
+}
+
+static CURLMcode state_ratelimiting(struct Curl_easy *data,
+                                    struct curltime *nowp,
+                                    CURLcode *resultp)
+{
+  CURLcode result = CURLE_OK;
+  CURLMcode rc = CURLM_OK;
+  DEBUGASSERT(data->conn);
+  /* if both rates are within spec, resume transfer */
+  if(Curl_pgrsUpdate(data))
+    result = CURLE_ABORTED_BY_CALLBACK;
+  else
+    result = Curl_speedcheck(data, *nowp);
+
+  if(result) {
+    if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
+       result != CURLE_HTTP2_STREAM)
+      streamclose(data->conn, "Transfer returned error");
+
+    multi_posttransfer(data);
+    multi_done(data, result, TRUE);
+  }
+  else {
+    timediff_t recv_timeout_ms = 0;
+    timediff_t send_timeout_ms = 0;
+    if(data->set.max_send_speed)
+      send_timeout_ms =
+        Curl_pgrsLimitWaitTime(&data->progress.ul,
+                               data->set.max_send_speed,
+                               *nowp);
+
+    if(data->set.max_recv_speed)
+      recv_timeout_ms =
+        Curl_pgrsLimitWaitTime(&data->progress.dl,
+                               data->set.max_recv_speed,
+                               *nowp);
+
+    if(!send_timeout_ms && !recv_timeout_ms) {
+      multistate(data, MSTATE_PERFORMING);
+      Curl_ratelimit(data, *nowp);
+      /* start performing again right away */
+      rc = CURLM_CALL_MULTI_PERFORM;
+    }
+    else if(send_timeout_ms >= recv_timeout_ms)
+      Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
+    else
+      Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
+  }
+  *resultp = result;
+  return rc;
+}
+
+static CURLMcode state_resolving(struct Curl_multi *multi,
+                                 struct Curl_easy *data,
+                                 bool *stream_errorp,
+                                 CURLcode *resultp)
+{
+  struct Curl_dns_entry *dns = NULL;
+  struct connectdata *conn = data->conn;
+  const char *hostname;
+  CURLcode result = CURLE_OK;
+  CURLMcode rc = CURLM_OK;
+
+  DEBUGASSERT(conn);
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.httpproxy)
+    hostname = conn->http_proxy.host.name;
+  else
+#endif
+    if(conn->bits.conn_to_host)
+      hostname = conn->conn_to_host.name;
+    else
+      hostname = conn->host.name;
+
+  /* check if we have the name resolved by now */
+  dns = Curl_fetch_addr(data, hostname, conn->primary.remote_port);
+
+  if(dns) {
+#ifdef CURLRES_ASYNCH
+    data->state.async.dns = dns;
+    data->state.async.done = TRUE;
+#endif
+    result = CURLE_OK;
+    infof(data, "Hostname '%s' was found in DNS cache", hostname);
+  }
+
+  if(!dns)
+    result = Curl_resolv_check(data, &dns);
+
+  /* Update sockets here, because the socket(s) may have been closed and the
+     application thus needs to be told, even if it is likely that the same
+     socket(s) will again be used further down. If the name has not yet been
+     resolved, it is likely that new sockets have been opened in an attempt to
+     contact another resolver. */
+  rc = singlesocket(multi, data);
+  if(rc)
+    return rc;
+
+  if(dns) {
+    bool connected;
+    /* Perform the next step in the connection phase, and then move on to the
+       WAITCONNECT state */
+    result = Curl_once_resolved(data, &connected);
+
+    if(result)
+      /* if Curl_once_resolved() returns failure, the connection struct is
+         already freed and gone */
+      data->conn = NULL; /* no more connection */
+    else {
+      /* call again please so that we get the next socket setup */
+      rc = CURLM_CALL_MULTI_PERFORM;
+      if(connected)
+        multistate(data, MSTATE_PROTOCONNECT);
+      else {
+        multistate(data, MSTATE_CONNECTING);
+      }
+    }
+  }
+
+  if(result)
+    /* failure detected */
+    *stream_errorp = TRUE;
+
+  *resultp = result;
+  return rc;
+}
+
+static CURLMcode state_connect(struct Curl_multi *multi,
+                               struct Curl_easy *data,
+                               struct curltime *nowp,
+                               CURLcode *resultp)
+{
+  /* Connect. We want to get a connection identifier filled in. This state can
+     be entered from SETUP and from PENDING. */
+  bool connected;
+  bool async;
+  CURLMcode rc = CURLM_OK;
+  CURLcode result = Curl_connect(data, &async, &connected);
+  if(CURLE_NO_CONNECTION_AVAILABLE == result) {
+    /* There was no connection available. We will go to the pending state and
+       wait for an available connection. */
+    multistate(data, MSTATE_PENDING);
+    /* unlink from process list */
+    Curl_node_remove(&data->multi_queue);
+    /* add handle to pending list */
+    Curl_llist_append(&multi->pending, data, &data->multi_queue);
+    *resultp = CURLE_OK;
+    return rc;
+  }
+  else
+    process_pending_handles(data->multi);
+
+  if(!result) {
+    *nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
+    if(async)
+      /* We are now waiting for an asynchronous name lookup */
+      multistate(data, MSTATE_RESOLVING);
+    else {
+      /* after the connect has been sent off, go WAITCONNECT unless the
+         protocol connect is already done and we can go directly to WAITDO or
+         DO! */
+      rc = CURLM_CALL_MULTI_PERFORM;
+
+      if(connected) {
+        if(!data->conn->bits.reuse &&
+           Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
+          /* new connection, can multiplex, wake pending handles */
+          process_pending_handles(data->multi);
+        }
+        multistate(data, MSTATE_PROTOCONNECT);
+      }
+      else {
+        multistate(data, MSTATE_CONNECTING);
+      }
+    }
+  }
+  *resultp = result;
+  return rc;
+}
+
 static CURLMcode multi_runsingle(struct Curl_multi *multi,
                                  struct curltime *nowp,
                                  struct Curl_easy *data)
 {
   struct Curl_message *msg = NULL;
   bool connected;
-  bool async;
   bool protocol_connected = FALSE;
   bool dophase_done = FALSE;
   CURLMcode rc;
   CURLcode result = CURLE_OK;
-  timediff_t recv_timeout_ms;
-  timediff_t send_timeout_ms;
   int control;
 
   if(!GOOD_EASY_HANDLE(data))
@@ -1862,14 +2640,14 @@
     /* Wait for the connect state as only then is the start time stored, but
        we must not check already completed handles */
     if((data->mstate >= MSTATE_CONNECT) && (data->mstate < MSTATE_COMPLETED) &&
-       multi_handle_timeout(data, nowp, &stream_error, &result, FALSE))
+       multi_handle_timeout(data, nowp, &stream_error, &result))
       /* Skip the statemachine and go directly to error handling section. */
       goto statemachine_end;
 
     switch(data->mstate) {
     case MSTATE_INIT:
-      /* Transitional state. init this transfer. A handle never comes
-         back to this state. */
+      /* Transitional state. init this transfer. A handle never comes back to
+         this state. */
       result = Curl_pretransfer(data);
       if(result)
         break;
@@ -1895,119 +2673,13 @@
       FALLTHROUGH();
 
     case MSTATE_CONNECT:
-      /* Connect. We want to get a connection identifier filled in. This state
-         can be entered from SETUP and from PENDING. */
-      result = Curl_connect(data, &async, &connected);
-      if(CURLE_NO_CONNECTION_AVAILABLE == result) {
-        /* There was no connection available. We will go to the pending
-           state and wait for an available connection. */
-        multistate(data, MSTATE_PENDING);
-        /* unlink from process list */
-        Curl_node_remove(&data->multi_queue);
-        /* add handle to pending list */
-        Curl_llist_append(&multi->pending, data, &data->multi_queue);
-        result = CURLE_OK;
-        break;
-      }
-      else
-        process_pending_handles(data->multi);
-
-      if(!result) {
-        *nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
-        if(async)
-          /* We are now waiting for an asynchronous name lookup */
-          multistate(data, MSTATE_RESOLVING);
-        else {
-          /* after the connect has been sent off, go WAITCONNECT unless the
-             protocol connect is already done and we can go directly to
-             WAITDO or DO! */
-          rc = CURLM_CALL_MULTI_PERFORM;
-
-          if(connected) {
-            if(!data->conn->bits.reuse &&
-               Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
-              /* new connection, can multiplex, wake pending handles */
-              process_pending_handles(data->multi);
-            }
-            multistate(data, MSTATE_PROTOCONNECT);
-          }
-          else {
-            multistate(data, MSTATE_CONNECTING);
-          }
-        }
-      }
+      rc = state_connect(multi, data, nowp, &result);
       break;
 
     case MSTATE_RESOLVING:
       /* awaiting an asynch name resolve to complete */
-    {
-      struct Curl_dns_entry *dns = NULL;
-      struct connectdata *conn = data->conn;
-      const char *hostname;
-
-      DEBUGASSERT(conn);
-#ifndef CURL_DISABLE_PROXY
-      if(conn->bits.httpproxy)
-        hostname = conn->http_proxy.host.name;
-      else
-#endif
-        if(conn->bits.conn_to_host)
-          hostname = conn->conn_to_host.name;
-      else
-        hostname = conn->host.name;
-
-      /* check if we have the name resolved by now */
-      dns = Curl_fetch_addr(data, hostname, conn->primary.remote_port);
-
-      if(dns) {
-#ifdef CURLRES_ASYNCH
-        data->state.async.dns = dns;
-        data->state.async.done = TRUE;
-#endif
-        result = CURLE_OK;
-        infof(data, "Hostname '%s' was found in DNS cache", hostname);
-      }
-
-      if(!dns)
-        result = Curl_resolv_check(data, &dns);
-
-      /* Update sockets here, because the socket(s) may have been
-         closed and the application thus needs to be told, even if it
-         is likely that the same socket(s) will again be used further
-         down. If the name has not yet been resolved, it is likely
-         that new sockets have been opened in an attempt to contact
-         another resolver. */
-      rc = singlesocket(multi, data);
-      if(rc)
-        return rc;
-
-      if(dns) {
-        /* Perform the next step in the connection phase, and then move on
-           to the WAITCONNECT state */
-        result = Curl_once_resolved(data, &connected);
-
-        if(result)
-          /* if Curl_once_resolved() returns failure, the connection struct
-             is already freed and gone */
-          data->conn = NULL; /* no more connection */
-        else {
-          /* call again please so that we get the next socket setup */
-          rc = CURLM_CALL_MULTI_PERFORM;
-          if(connected)
-            multistate(data, MSTATE_PROTOCONNECT);
-          else {
-            multistate(data, MSTATE_CONNECTING);
-          }
-        }
-      }
-
-      if(result) {
-        /* failure detected */
-        stream_error = TRUE;
-        break;
-      }
-    }
-    break;
+      rc = state_resolving(multi, data, &stream_error, &result);
+      break;
 
 #ifndef CURL_DISABLE_HTTP
     case MSTATE_TUNNELING:
@@ -2048,9 +2720,10 @@
 
     case MSTATE_PROTOCONNECT:
       if(!result && data->conn->bits.reuse) {
-        /* ftp seems to hang when protoconnect on reused connection
-         * since we handle PROTOCONNECT in general inside the filers, it
-         * seems wrong to restart this on a reused connection. */
+        /* ftp seems to hang when protoconnect on reused connection since we
+         * handle PROTOCONNECT in general inside the filers, it seems wrong to
+         * restart this on a reused connection.
+         */
         multistate(data, MSTATE_DO);
         rc = CURLM_CALL_MULTI_PERFORM;
         break;
@@ -2092,135 +2765,7 @@
       break;
 
     case MSTATE_DO:
-      if(data->set.fprereq) {
-        int prereq_rc;
-
-        /* call the prerequest callback function */
-        Curl_set_in_callback(data, true);
-        prereq_rc = data->set.fprereq(data->set.prereq_userp,
-                                      data->info.primary.remote_ip,
-                                      data->info.primary.local_ip,
-                                      data->info.primary.remote_port,
-                                      data->info.primary.local_port);
-        Curl_set_in_callback(data, false);
-        if(prereq_rc != CURL_PREREQFUNC_OK) {
-          failf(data, "operation aborted by pre-request callback");
-          /* failure in pre-request callback - do not do any other
-             processing */
-          result = CURLE_ABORTED_BY_CALLBACK;
-          multi_posttransfer(data);
-          multi_done(data, result, FALSE);
-          stream_error = TRUE;
-          break;
-        }
-      }
-
-      if(data->set.connect_only == 1) {
-        /* keep connection open for application to use the socket */
-        connkeep(data->conn, "CONNECT_ONLY");
-        multistate(data, MSTATE_DONE);
-        result = CURLE_OK;
-        rc = CURLM_CALL_MULTI_PERFORM;
-      }
-      else {
-        /* Perform the protocol's DO action */
-        result = multi_do(data, &dophase_done);
-
-        /* When multi_do() returns failure, data->conn might be NULL! */
-
-        if(!result) {
-          if(!dophase_done) {
-#ifndef CURL_DISABLE_FTP
-            /* some steps needed for wildcard matching */
-            if(data->state.wildcardmatch) {
-              struct WildcardData *wc = data->wildcard;
-              if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
-                /* skip some states if it is important */
-                multi_done(data, CURLE_OK, FALSE);
-
-                /* if there is no connection left, skip the DONE state */
-                multistate(data, data->conn ?
-                           MSTATE_DONE : MSTATE_COMPLETED);
-                rc = CURLM_CALL_MULTI_PERFORM;
-                break;
-              }
-            }
-#endif
-            /* DO was not completed in one function call, we must continue
-               DOING... */
-            multistate(data, MSTATE_DOING);
-            rc = CURLM_CALL_MULTI_PERFORM;
-          }
-
-          /* after DO, go DO_DONE... or DO_MORE */
-          else if(data->conn->bits.do_more) {
-            /* we are supposed to do more, but we need to sit down, relax
-               and wait a little while first */
-            multistate(data, MSTATE_DOING_MORE);
-            rc = CURLM_CALL_MULTI_PERFORM;
-          }
-          else {
-            /* we are done with the DO, now DID */
-            multistate(data, MSTATE_DID);
-            rc = CURLM_CALL_MULTI_PERFORM;
-          }
-        }
-        else if((CURLE_SEND_ERROR == result) &&
-                data->conn->bits.reuse) {
-          /*
-           * In this situation, a connection that we were trying to use
-           * may have unexpectedly died. If possible, send the connection
-           * back to the CONNECT phase so we can try again.
-           */
-          char *newurl = NULL;
-          followtype follow = FOLLOW_NONE;
-          CURLcode drc;
-
-          drc = Curl_retry_request(data, &newurl);
-          if(drc) {
-            /* a failure here pretty much implies an out of memory */
-            result = drc;
-            stream_error = TRUE;
-          }
-
-          multi_posttransfer(data);
-          drc = multi_done(data, result, FALSE);
-
-          /* When set to retry the connection, we must go back to the CONNECT
-           * state */
-          if(newurl) {
-            if(!drc || (drc == CURLE_SEND_ERROR)) {
-              follow = FOLLOW_RETRY;
-              drc = Curl_follow(data, newurl, follow);
-              if(!drc) {
-                multistate(data, MSTATE_SETUP);
-                rc = CURLM_CALL_MULTI_PERFORM;
-                result = CURLE_OK;
-              }
-              else {
-                /* Follow failed */
-                result = drc;
-              }
-            }
-            else {
-              /* done did not return OK or SEND_ERROR */
-              result = drc;
-            }
-          }
-          else {
-            /* Have error handler disconnect conn if we cannot retry */
-            stream_error = TRUE;
-          }
-          free(newurl);
-        }
-        else {
-          /* failure detected */
-          multi_posttransfer(data);
-          if(data->conn)
-            multi_done(data, result, FALSE);
-          stream_error = TRUE;
-        }
-      }
+      rc = state_do(data, &stream_error, &result);
       break;
 
     case MSTATE_DOING:
@@ -2230,7 +2775,7 @@
       if(!result) {
         if(dophase_done) {
           /* after DO, go DO_DONE or DO_MORE */
-          multistate(data, data->conn->bits.do_more?
+          multistate(data, data->conn->bits.do_more ?
                      MSTATE_DOING_MORE : MSTATE_DID);
           rc = CURLM_CALL_MULTI_PERFORM;
         } /* dophase_done */
@@ -2254,7 +2799,7 @@
         if(control) {
           /* if positive, advance to DO_DONE
              if negative, go back to DOING */
-          multistate(data, control == 1?
+          multistate(data, control == 1 ?
                      MSTATE_DID : MSTATE_DOING);
           rc = CURLM_CALL_MULTI_PERFORM;
         }
@@ -2293,195 +2838,12 @@
       break;
 
     case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */
-      DEBUGASSERT(data->conn);
-      /* if both rates are within spec, resume transfer */
-      if(Curl_pgrsUpdate(data))
-        result = CURLE_ABORTED_BY_CALLBACK;
-      else
-        result = Curl_speedcheck(data, *nowp);
-
-      if(result) {
-        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
-           result != CURLE_HTTP2_STREAM)
-          streamclose(data->conn, "Transfer returned error");
-
-        multi_posttransfer(data);
-        multi_done(data, result, TRUE);
-      }
-      else {
-        send_timeout_ms = 0;
-        if(data->set.max_send_speed)
-          send_timeout_ms =
-            Curl_pgrsLimitWaitTime(&data->progress.ul,
-                                   data->set.max_send_speed,
-                                   *nowp);
-
-        recv_timeout_ms = 0;
-        if(data->set.max_recv_speed)
-          recv_timeout_ms =
-            Curl_pgrsLimitWaitTime(&data->progress.dl,
-                                   data->set.max_recv_speed,
-                                   *nowp);
-
-        if(!send_timeout_ms && !recv_timeout_ms) {
-          multistate(data, MSTATE_PERFORMING);
-          Curl_ratelimit(data, *nowp);
-          /* start performing again right away */
-          rc = CURLM_CALL_MULTI_PERFORM;
-        }
-        else if(send_timeout_ms >= recv_timeout_ms)
-          Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
-        else
-          Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
-      }
+      rc = state_ratelimiting(data, nowp, &result);
       break;
 
     case MSTATE_PERFORMING:
-    {
-      char *newurl = NULL;
-      bool retry = FALSE;
-      /* check if over send speed */
-      send_timeout_ms = 0;
-      if(data->set.max_send_speed)
-        send_timeout_ms = Curl_pgrsLimitWaitTime(&data->progress.ul,
-                                                 data->set.max_send_speed,
-                                                 *nowp);
-
-      /* check if over recv speed */
-      recv_timeout_ms = 0;
-      if(data->set.max_recv_speed)
-        recv_timeout_ms = Curl_pgrsLimitWaitTime(&data->progress.dl,
-                                                 data->set.max_recv_speed,
-                                                 *nowp);
-
-      if(send_timeout_ms || recv_timeout_ms) {
-        Curl_ratelimit(data, *nowp);
-        multistate(data, MSTATE_RATELIMITING);
-        if(send_timeout_ms >= recv_timeout_ms)
-          Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
-        else
-          Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
-        break;
-      }
-
-      /* read/write data if it is ready to do so */
-      result = Curl_sendrecv(data, nowp);
-
-      if(data->req.done || (result == CURLE_RECV_ERROR)) {
-        /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
-         * condition and the server closed the reused connection exactly when
-         * we wanted to use it, so figure out if that is indeed the case.
-         */
-        CURLcode ret = Curl_retry_request(data, &newurl);
-        if(!ret)
-          retry = (newurl)?TRUE:FALSE;
-        else if(!result)
-          result = ret;
-
-        if(retry) {
-          /* if we are to retry, set the result to OK and consider the
-             request as done */
-          result = CURLE_OK;
-          data->req.done = TRUE;
-        }
-      }
-      else if((CURLE_HTTP2_STREAM == result) &&
-              Curl_h2_http_1_1_error(data)) {
-        CURLcode ret = Curl_retry_request(data, &newurl);
-
-        if(!ret) {
-          infof(data, "Downgrades to HTTP/1.1");
-          streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
-          data->state.httpwant = CURL_HTTP_VERSION_1_1;
-          /* clear the error message bit too as we ignore the one we got */
-          data->state.errorbuf = FALSE;
-          if(!newurl)
-            /* typically for HTTP_1_1_REQUIRED error on first flight */
-            newurl = strdup(data->state.url);
-          /* if we are to retry, set the result to OK and consider the request
-             as done */
-          retry = TRUE;
-          result = CURLE_OK;
-          data->req.done = TRUE;
-        }
-        else
-          result = ret;
-      }
-
-      if(result) {
-        /*
-         * The transfer phase returned error, we mark the connection to get
-         * closed to prevent being reused. This is because we cannot possibly
-         * know if the connection is in a good shape or not now. Unless it is
-         * a protocol which uses two "channels" like FTP, as then the error
-         * happened in the data connection.
-         */
-
-        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
-           result != CURLE_HTTP2_STREAM)
-          streamclose(data->conn, "Transfer returned error");
-
-        multi_posttransfer(data);
-        multi_done(data, result, TRUE);
-      }
-      else if(data->req.done && !Curl_cwriter_is_paused(data)) {
-
-        /* call this even if the readwrite function returned error */
-        multi_posttransfer(data);
-
-        /* When we follow redirects or is set to retry the connection, we must
-           to go back to the CONNECT state */
-        if(data->req.newurl || retry) {
-          followtype follow = FOLLOW_NONE;
-          if(!retry) {
-            /* if the URL is a follow-location and not just a retried request
-               then figure out the URL here */
-            free(newurl);
-            newurl = data->req.newurl;
-            data->req.newurl = NULL;
-            follow = FOLLOW_REDIR;
-          }
-          else
-            follow = FOLLOW_RETRY;
-          (void)multi_done(data, CURLE_OK, FALSE);
-          /* multi_done() might return CURLE_GOT_NOTHING */
-          result = Curl_follow(data, newurl, follow);
-          if(!result) {
-            multistate(data, MSTATE_SETUP);
-            rc = CURLM_CALL_MULTI_PERFORM;
-          }
-        }
-        else {
-          /* after the transfer is done, go DONE */
-
-          /* but first check to see if we got a location info even though we
-             are not following redirects */
-          if(data->req.location) {
-            free(newurl);
-            newurl = data->req.location;
-            data->req.location = NULL;
-            result = Curl_follow(data, newurl, FOLLOW_FAKE);
-            if(result) {
-              stream_error = TRUE;
-              result = multi_done(data, result, TRUE);
-            }
-          }
-
-          if(!result) {
-            multistate(data, MSTATE_DONE);
-            rc = CURLM_CALL_MULTI_PERFORM;
-          }
-        }
-      }
-      else if(data->state.select_bits && !Curl_xfer_is_blocked(data)) {
-        /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer
-           will not get stuck on this transfer at the expense of other
-           concurrent transfers */
-        Curl_expire(data, 0, EXPIRE_RUN_NOW);
-      }
-      free(newurl);
+      rc = state_performing(data, nowp, &stream_error, &result);
       break;
-    }
 
     case MSTATE_DONE:
       /* this state is highly transient, so run another loop after this */
@@ -2529,14 +2891,14 @@
     if(data->mstate >= MSTATE_CONNECT &&
        data->mstate < MSTATE_DO &&
        rc != CURLM_CALL_MULTI_PERFORM &&
-       !multi_ischanged(multi, false)) {
+       !multi_ischanged(multi, FALSE)) {
       /* We now handle stream timeouts if and only if this will be the last
        * loop iteration. We only check this on the last iteration to ensure
        * that if we know we have additional work to do immediately
        * (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
        * declaring the connection timed out as we may almost have a completed
        * connection. */
-      multi_handle_timeout(data, nowp, &stream_error, &result, FALSE);
+      multi_handle_timeout(data, nowp, &stream_error, &result);
     }
 
 statemachine_end:
@@ -2584,8 +2946,8 @@
         streamclose(data->conn, "Aborted by callback");
 
         /* if not yet in DONE state, go there, otherwise COMPLETED */
-        multistate(data, (data->mstate < MSTATE_DONE)?
-                   MSTATE_DONE: MSTATE_COMPLETED);
+        multistate(data, (data->mstate < MSTATE_DONE) ?
+                   MSTATE_DONE : MSTATE_COMPLETED);
         rc = CURLM_CALL_MULTI_PERFORM;
       }
     }
@@ -2621,13 +2983,14 @@
 }
 
 
-CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
+CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
 {
   CURLMcode returncode = CURLM_OK;
   struct Curl_tree *t = NULL;
   struct curltime now = Curl_now();
   struct Curl_llist_node *e;
   struct Curl_llist_node *n = NULL;
+  struct Curl_multi *multi = m;
   SIGPIPE_VARIABLE(pipe_st);
 
   if(!GOOD_MULTI_HANDLE(multi))
@@ -2679,8 +3042,7 @@
       if(data->mstate == MSTATE_PENDING) {
         bool stream_unused;
         CURLcode result_unused;
-        if(multi_handle_timeout(data, &now, &stream_unused, &result_unused,
-                                FALSE)) {
+        if(multi_handle_timeout(data, &now, &stream_unused, &result_unused)) {
           infof(data, "PENDING handle timeout");
           move_pending_to_connect(multi, data);
         }
@@ -2714,16 +3076,15 @@
   }
 }
 
-CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
+CURLMcode curl_multi_cleanup(CURLM *m)
 {
+  struct Curl_multi *multi = m;
   if(GOOD_MULTI_HANDLE(multi)) {
     struct Curl_llist_node *e;
     struct Curl_llist_node *n;
     if(multi->in_callback)
       return CURLM_RECURSIVE_API_CALL;
 
-    multi->magic = 0; /* not good anymore */
-
     /* move the pending and msgsent entries back to process
        so that there is just one list to iterate over */
     unlink_all_msgsent_handles(multi);
@@ -2757,6 +3118,8 @@
 
     Curl_cpool_destroy(&multi->cpool);
 
+    multi->magic = 0; /* not good anymore */
+
     sockhash_destroy(&multi->sockhash);
     Curl_hash_destroy(&multi->proto_hash);
     Curl_hash_destroy(&multi->hostcache);
@@ -2791,9 +3154,10 @@
  * beyond. The current design is fully O(1).
  */
 
-CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
+CURLMsg *curl_multi_info_read(CURLM *m, int *msgs_in_queue)
 {
   struct Curl_message *msg;
+  struct Curl_multi *multi = m;
 
   *msgs_in_queue = 0; /* default to none */
 
@@ -2866,7 +3230,7 @@
     if(entry) {
       /* check if new for this transfer */
       unsigned int j;
-      for(j = 0; j< last_ps->num; j++) {
+      for(j = 0; j < last_ps->num; j++) {
         if(s == last_ps->sockets[j]) {
           last_action = last_ps->actions[j];
           break;
@@ -3220,11 +3584,19 @@
         else {
           /* Expire with out current now, so we will get it below when
            * asking the splaytree for expired transfers. */
-          Curl_expire_ex(data, &mrc.now, 0, EXPIRE_RUN_NOW);
+          expire_ex(data, &mrc.now, 0, EXPIRE_RUN_NOW);
         }
       }
     }
   }
+  else {
+    /* Asked to run due to time-out. Clear the 'last_expire_ts' variable to
+       force Curl_update_timer() to trigger a callback to the app again even
+       if the same timeout is still the one to run after this call. That
+       handles the case when the application asks libcurl to run the timeout
+       prematurely. */
+    memset(&multi->last_expire_ts, 0, sizeof(multi->last_expire_ts));
+  }
 
   result = multi_run_expired(&mrc);
   if(result)
@@ -3256,12 +3628,13 @@
 }
 
 #undef curl_multi_setopt
-CURLMcode curl_multi_setopt(struct Curl_multi *multi,
+CURLMcode curl_multi_setopt(CURLM *m,
                             CURLMoption option, ...)
 {
   CURLMcode res = CURLM_OK;
   va_list param;
   unsigned long uarg;
+  struct Curl_multi *multi = m;
 
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
@@ -3337,24 +3710,26 @@
 /* we define curl_multi_socket() in the public multi.h header */
 #undef curl_multi_socket
 
-CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
-                            int *running_handles)
+CURLMcode curl_multi_socket(CURLM *m, curl_socket_t s, int *running_handles)
 {
+  struct Curl_multi *multi = m;
   if(multi->in_callback)
     return CURLM_RECURSIVE_API_CALL;
   return multi_socket(multi, FALSE, s, 0, running_handles);
 }
 
-CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
+CURLMcode curl_multi_socket_action(CURLM *m, curl_socket_t s,
                                    int ev_bitmask, int *running_handles)
 {
+  struct Curl_multi *multi = m;
   if(multi->in_callback)
     return CURLM_RECURSIVE_API_CALL;
   return multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
 }
 
-CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
+CURLMcode curl_multi_socket_all(CURLM *m, int *running_handles)
 {
+  struct Curl_multi *multi = m;
   if(multi->in_callback)
     return CURLM_RECURSIVE_API_CALL;
   return multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
@@ -3379,7 +3754,7 @@
     multi->timetree = Curl_splay(tv_zero, multi->timetree);
     /* this will not return NULL from a non-emtpy tree, but some compilers
      * are not convinced of that. Analyzers are hard. */
-    *expire_time = multi->timetree? multi->timetree->key : tv_zero;
+    *expire_time = multi->timetree ? multi->timetree->key : tv_zero;
 
     /* 'multi->timetree' will be non-NULL here but the compilers sometimes
        yell at us if we assume so */
@@ -3404,10 +3779,11 @@
   return CURLM_OK;
 }
 
-CURLMcode curl_multi_timeout(struct Curl_multi *multi,
+CURLMcode curl_multi_timeout(CURLM *m,
                              long *timeout_ms)
 {
   struct curltime expire_time;
+  struct Curl_multi *multi = m;
 
   /* First, make some basic checks that the CURLM handle is a good handle */
   if(!GOOD_MULTI_HANDLE(multi))
@@ -3556,20 +3932,9 @@
   return CURLM_OK;
 }
 
-/*
- * Curl_expire()
- *
- * given a number of milliseconds from now to use to set the 'act before
- * this'-time for the transfer, to be extracted by curl_multi_timeout()
- *
- * The timeout will be added to a queue of timeouts if it defines a moment in
- * time that is later than the current head of queue.
- *
- * Expire replaces a former timeout using the same id if already set.
- */
-static void Curl_expire_ex(struct Curl_easy *data,
-                           const struct curltime *nowp,
-                           timediff_t milli, expire_id id)
+static void expire_ex(struct Curl_easy *data,
+                      const struct curltime *nowp,
+                      timediff_t milli, expire_id id)
 {
   struct Curl_multi *multi = data->multi;
   struct curltime *curr_expire = &data->state.expiretime;
@@ -3627,10 +3992,21 @@
                                      &data->state.timenode);
 }
 
+/*
+ * Curl_expire()
+ *
+ * given a number of milliseconds from now to use to set the 'act before
+ * this'-time for the transfer, to be extracted by curl_multi_timeout()
+ *
+ * The timeout will be added to a queue of timeouts if it defines a moment in
+ * time that is later than the current head of queue.
+ *
+ * Expire replaces a former timeout using the same id if already set.
+ */
 void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
 {
   struct curltime now = Curl_now();
-  Curl_expire_ex(data, &now, milli, id);
+  expire_ex(data, &now, milli, id);
 }
 
 /*
@@ -3684,10 +4060,11 @@
   return FALSE;
 }
 
-CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
+CURLMcode curl_multi_assign(CURLM *m, curl_socket_t s,
                             void *hashp)
 {
   struct Curl_sh_entry *there = NULL;
+  struct Curl_multi *multi = m;
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
 
@@ -3758,10 +4135,10 @@
   return multi->max_concurrent_streams;
 }
 
-struct Curl_easy **curl_multi_get_handles(struct Curl_multi *multi)
+CURL **curl_multi_get_handles(CURLM *m)
 {
-  struct Curl_easy **a = malloc(sizeof(struct Curl_easy *) *
-                                (multi->num_easy + 1));
+  struct Curl_multi *multi = m;
+  CURL **a = malloc(sizeof(struct Curl_easy *) * (multi->num_easy + 1));
   if(a) {
     unsigned int i = 0;
     struct Curl_llist_node *e;
@@ -3882,6 +4259,51 @@
   data->multi->xfer_ulbuf_borrowed = FALSE;
 }
 
+CURLcode Curl_multi_xfer_sockbuf_borrow(struct Curl_easy *data,
+                                        size_t blen, char **pbuf)
+{
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->multi);
+  *pbuf = NULL;
+  if(!data->multi) {
+    failf(data, "transfer has no multi handle");
+    return CURLE_FAILED_INIT;
+  }
+  if(data->multi->xfer_sockbuf_borrowed) {
+    failf(data, "attempt to borrow xfer_sockbuf when already borrowed");
+    return CURLE_AGAIN;
+  }
+
+  if(data->multi->xfer_sockbuf && blen > data->multi->xfer_sockbuf_len) {
+    /* not large enough, get a new one */
+    free(data->multi->xfer_sockbuf);
+    data->multi->xfer_sockbuf = NULL;
+    data->multi->xfer_sockbuf_len = 0;
+  }
+
+  if(!data->multi->xfer_sockbuf) {
+    data->multi->xfer_sockbuf = malloc(blen);
+    if(!data->multi->xfer_sockbuf) {
+      failf(data, "could not allocate xfer_sockbuf of %zu bytes", blen);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    data->multi->xfer_sockbuf_len = blen;
+  }
+
+  data->multi->xfer_sockbuf_borrowed = TRUE;
+  *pbuf = data->multi->xfer_sockbuf;
+  return CURLE_OK;
+}
+
+void Curl_multi_xfer_sockbuf_release(struct Curl_easy *data, char *buf)
+{
+  (void)buf;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->multi);
+  DEBUGASSERT(!buf || data->multi->xfer_sockbuf == buf);
+  data->multi->xfer_sockbuf_borrowed = FALSE;
+}
+
 static void multi_xfer_bufs_free(struct Curl_multi *multi)
 {
   DEBUGASSERT(multi);
@@ -3891,6 +4313,9 @@
   Curl_safefree(multi->xfer_ulbuf);
   multi->xfer_ulbuf_len = 0;
   multi->xfer_ulbuf_borrowed = FALSE;
+  Curl_safefree(multi->xfer_sockbuf);
+  multi->xfer_sockbuf_len = 0;
+  multi->xfer_sockbuf_borrowed = FALSE;
 }
 
 struct Curl_easy *Curl_multi_get_handle(struct Curl_multi *multi,
diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h
index fef117c..9225d2d 100644
--- a/Utilities/cmcurl/lib/multihandle.h
+++ b/Utilities/cmcurl/lib/multihandle.h
@@ -124,6 +124,9 @@
   /* buffer used for upload data, lazy initialized */
   char *xfer_ulbuf; /* the actual buffer */
   size_t xfer_ulbuf_len;      /* the allocated length */
+  /* buffer used for socket I/O operations, lazy initialized */
+  char *xfer_sockbuf; /* the actual buffer */
+  size_t xfer_sockbuf_len; /* the allocated length */
 
   /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
      the pluralis form, there can be more than one easy handle waiting on the
@@ -181,6 +184,7 @@
                 burn */
   BIT(xfer_buf_borrowed);      /* xfer_buf is currently being borrowed */
   BIT(xfer_ulbuf_borrowed);    /* xfer_ulbuf is currently being borrowed */
+  BIT(xfer_sockbuf_borrowed);  /* xfer_sockbuf is currently being borrowed */
 #ifdef DEBUGBUILD
   BIT(warned);                 /* true after user warned of DEBUGBUILD */
 #endif
diff --git a/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h
index e5872cd..fd0e215 100644
--- a/Utilities/cmcurl/lib/multiif.h
+++ b/Utilities/cmcurl/lib/multiif.h
@@ -145,6 +145,30 @@
 void Curl_multi_xfer_ulbuf_release(struct Curl_easy *data, char *buf);
 
 /**
+ * Borrow the socket scratch buffer from the multi, suitable
+ * for the given transfer `data`. The buffer may only be used for
+ * direct socket I/O operation by one connection at a time and MUST be
+ * returned to the multi before the I/O call returns.
+ * Pointers into the buffer remain only valid as long as it is borrowed.
+ *
+ * @param data    the easy handle
+ * @param blen    requested length of the buffer
+ * @param pbuf    on return, the buffer to use or NULL on error
+ * @return CURLE_OK when buffer is available and is returned.
+ *         CURLE_OUT_OF_MEMORy on failure to allocate the buffer,
+ *         CURLE_FAILED_INIT if the easy handle is without multi.
+ *         CURLE_AGAIN if the buffer is borrowed already.
+ */
+CURLcode Curl_multi_xfer_sockbuf_borrow(struct Curl_easy *data,
+                                        size_t blen, char **pbuf);
+/**
+ * Release the borrowed buffer. All references into the buffer become
+ * invalid after this.
+ * @param buf the buffer pointer borrowed for coding error checks.
+ */
+void Curl_multi_xfer_sockbuf_release(struct Curl_easy *data, char *buf);
+
+/**
  * Get the transfer handle for the given id. Returns NULL if not found.
  */
 struct Curl_easy *Curl_multi_get_handle(struct Curl_multi *multi,
diff --git a/Utilities/cmcurl/lib/netrc.c b/Utilities/cmcurl/lib/netrc.c
index 490efb6..d5ee3c0 100644
--- a/Utilities/cmcurl/lib/netrc.c
+++ b/Utilities/cmcurl/lib/netrc.c
@@ -31,7 +31,6 @@
 
 #include <curl/curl.h>
 #include "netrc.h"
-#include "strtok.h"
 #include "strcase.h"
 #include "curl_get_line.h"
 
@@ -49,226 +48,284 @@
   MACDEF
 };
 
+enum found_state {
+  NONE,
+  LOGIN,
+  PASSWORD
+};
+
+#define FOUND_LOGIN    1
+#define FOUND_PASSWORD 2
+
 #define NETRC_FILE_MISSING 1
 #define NETRC_FAILED -1
 #define NETRC_SUCCESS 0
 
-#define MAX_NETRC_LINE 4096
+#define MAX_NETRC_LINE 16384
+#define MAX_NETRC_FILE (128*1024)
+#define MAX_NETRC_TOKEN 4096
+
+static CURLcode file2memory(const char *filename, struct dynbuf *filebuf)
+{
+  CURLcode result = CURLE_OK;
+  FILE *file = fopen(filename, FOPEN_READTEXT);
+  struct dynbuf linebuf;
+  Curl_dyn_init(&linebuf, MAX_NETRC_LINE);
+
+  if(file) {
+    while(Curl_get_line(&linebuf, file)) {
+      const char *line = Curl_dyn_ptr(&linebuf);
+      /* skip comments on load */
+      while(ISBLANK(*line))
+        line++;
+      if(*line == '#')
+        continue;
+      result = Curl_dyn_add(filebuf, line);
+      if(result)
+        goto done;
+    }
+  }
+done:
+  Curl_dyn_free(&linebuf);
+  if(file)
+    fclose(file);
+  return result;
+}
 
 /*
  * Returns zero on success.
  */
-static int parsenetrc(const char *host,
-                      char **loginp,
+static int parsenetrc(struct store_netrc *store,
+                      const char *host,
+                      char **loginp, /* might point to a username */
                       char **passwordp,
-                      char *netrcfile)
+                      const char *netrcfile)
 {
-  FILE *file;
   int retcode = NETRC_FILE_MISSING;
   char *login = *loginp;
-  char *password = *passwordp;
-  bool specific_login = (login && *login != 0);
-  bool login_alloc = FALSE;
-  bool password_alloc = FALSE;
+  char *password = NULL;
+  bool specific_login = !!login; /* points to something */
   enum host_lookup_state state = NOTHING;
+  enum found_state keyword = NONE;
+  unsigned char found = 0; /* login + password found bits, as they can come in
+                              any order */
+  bool our_login = FALSE;  /* found our login name */
+  bool done = FALSE;
+  char *netrcbuffer;
+  struct dynbuf token;
+  struct dynbuf *filebuf = &store->filebuf;
+  DEBUGASSERT(!*passwordp);
+  Curl_dyn_init(&token, MAX_NETRC_TOKEN);
 
-  char state_login = 0;      /* Found a login keyword */
-  char state_password = 0;   /* Found a password keyword */
-  int state_our_login = TRUE;  /* With specific_login, found *our* login
-                                  name (or login-less line) */
+  if(!store->loaded) {
+    if(file2memory(netrcfile, filebuf))
+      return NETRC_FAILED;
+    store->loaded = TRUE;
+  }
 
-  DEBUGASSERT(netrcfile);
+  netrcbuffer = Curl_dyn_ptr(filebuf);
 
-  file = fopen(netrcfile, FOPEN_READTEXT);
-  if(file) {
-    bool done = FALSE;
-    struct dynbuf buf;
-    Curl_dyn_init(&buf, MAX_NETRC_LINE);
-
-    while(!done && Curl_get_line(&buf, file)) {
-      char *tok;
+  while(!done) {
+    char *tok = netrcbuffer;
+    while(tok && !done) {
       char *tok_end;
       bool quoted;
-      char *netrcbuffer = Curl_dyn_ptr(&buf);
+      Curl_dyn_reset(&token);
+      while(ISBLANK(*tok))
+        tok++;
+      /* tok is first non-space letter */
       if(state == MACDEF) {
-        if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r'))
-          state = NOTHING;
-        else
-          continue;
+        if((*tok == '\n') || (*tok == '\r'))
+          state = NOTHING; /* end of macro definition */
       }
-      tok = netrcbuffer;
-      while(tok) {
-        while(ISBLANK(*tok))
-          tok++;
-        /* tok is first non-space letter */
-        if(!*tok || (*tok == '#'))
-          /* end of line or the rest is a comment */
-          break;
 
-        /* leading double-quote means quoted string */
-        quoted = (*tok == '\"');
+      if(!*tok || (*tok == '\n'))
+        /* end of line  */
+        break;
 
-        tok_end = tok;
-        if(!quoted) {
-          while(!ISSPACE(*tok_end))
-            tok_end++;
-          *tok_end = 0;
+      /* leading double-quote means quoted string */
+      quoted = (*tok == '\"');
+
+      tok_end = tok;
+      if(!quoted) {
+        size_t len = 0;
+        while(!ISSPACE(*tok_end)) {
+          tok_end++;
+          len++;
         }
-        else {
-          bool escape = FALSE;
-          bool endquote = FALSE;
-          char *store = tok;
-          tok_end++; /* pass the leading quote */
-          while(*tok_end) {
-            char s = *tok_end;
-            if(escape) {
-              escape = FALSE;
-              switch(s) {
-              case 'n':
-                s = '\n';
-                break;
-              case 'r':
-                s = '\r';
-                break;
-              case 't':
-                s = '\t';
-                break;
-              }
-            }
-            else if(s == '\\') {
-              escape = TRUE;
-              tok_end++;
-              continue;
-            }
-            else if(s == '\"') {
-              tok_end++; /* pass the ending quote */
-              endquote = TRUE;
+        if(!len || Curl_dyn_addn(&token, tok, len)) {
+          retcode = NETRC_FAILED;
+          goto out;
+        }
+      }
+      else {
+        bool escape = FALSE;
+        bool endquote = FALSE;
+        tok_end++; /* pass the leading quote */
+        while(*tok_end) {
+          char s = *tok_end;
+          if(escape) {
+            escape = FALSE;
+            switch(s) {
+            case 'n':
+              s = '\n';
+              break;
+            case 'r':
+              s = '\r';
+              break;
+            case 't':
+              s = '\t';
               break;
             }
-            *store++ = s;
-            tok_end++;
           }
-          *store = 0;
-          if(escape || !endquote) {
-            /* bad syntax, get out */
+          else if(s == '\\') {
+            escape = TRUE;
+            tok_end++;
+            continue;
+          }
+          else if(s == '\"') {
+            tok_end++; /* pass the ending quote */
+            endquote = TRUE;
+            break;
+          }
+          if(Curl_dyn_addn(&token, &s, 1)) {
             retcode = NETRC_FAILED;
             goto out;
           }
+          tok_end++;
         }
+        if(escape || !endquote) {
+          /* bad syntax, get out */
+          retcode = NETRC_FAILED;
+          goto out;
+        }
+      }
 
-        if((login && *login) && (password && *password)) {
+      tok = Curl_dyn_ptr(&token);
+
+      switch(state) {
+      case NOTHING:
+        if(strcasecompare("macdef", tok))
+          /* Define a macro. A macro is defined with the specified name; its
+             contents begin with the next .netrc line and continue until a
+             null line (consecutive new-line characters) is encountered. */
+          state = MACDEF;
+        else if(strcasecompare("machine", tok)) {
+          /* the next tok is the machine name, this is in itself the delimiter
+             that starts the stuff entered for this machine, after this we
+             need to search for 'login' and 'password'. */
+          state = HOSTFOUND;
+          keyword = NONE;
+          found = 0;
+          our_login = FALSE;
+          Curl_safefree(password);
+          if(!specific_login)
+            Curl_safefree(login);
+        }
+        else if(strcasecompare("default", tok)) {
+          state = HOSTVALID;
+          retcode = NETRC_SUCCESS; /* we did find our host */
+        }
+        break;
+      case MACDEF:
+        if(!*tok)
+          state = NOTHING;
+        break;
+      case HOSTFOUND:
+        if(strcasecompare(host, tok)) {
+          /* and yes, this is our host! */
+          state = HOSTVALID;
+          retcode = NETRC_SUCCESS; /* we did find our host */
+        }
+        else
+          /* not our host */
+          state = NOTHING;
+        break;
+      case HOSTVALID:
+        /* we are now parsing sub-keywords concerning "our" host */
+        if(keyword == LOGIN) {
+          if(specific_login)
+            our_login = !Curl_timestrcmp(login, tok);
+          else {
+            our_login = TRUE;
+            free(login);
+            login = strdup(tok);
+            if(!login) {
+              retcode = NETRC_FAILED; /* allocation failed */
+              goto out;
+            }
+          }
+          found |= FOUND_LOGIN;
+          keyword = NONE;
+        }
+        else if(keyword == PASSWORD) {
+          free(password);
+          password = strdup(tok);
+          if(!password) {
+            retcode = NETRC_FAILED; /* allocation failed */
+            goto out;
+          }
+          found |= FOUND_PASSWORD;
+          keyword = NONE;
+        }
+        else if(strcasecompare("login", tok))
+          keyword = LOGIN;
+        else if(strcasecompare("password", tok))
+          keyword = PASSWORD;
+        else if(strcasecompare("machine", tok)) {
+          /* a new machine here */
+          state = HOSTFOUND;
+          keyword = NONE;
+          found = 0;
+          Curl_safefree(password);
+          if(!specific_login)
+            Curl_safefree(login);
+        }
+        else if(strcasecompare("default", tok)) {
+          state = HOSTVALID;
+          retcode = NETRC_SUCCESS; /* we did find our host */
+          Curl_safefree(password);
+          if(!specific_login)
+            Curl_safefree(login);
+        }
+        if((found == (FOUND_PASSWORD|FOUND_LOGIN)) && our_login) {
           done = TRUE;
           break;
         }
-
-        switch(state) {
-        case NOTHING:
-          if(strcasecompare("macdef", tok)) {
-            /* Define a macro. A macro is defined with the specified name; its
-               contents begin with the next .netrc line and continue until a
-               null line (consecutive new-line characters) is encountered. */
-            state = MACDEF;
-          }
-          else if(strcasecompare("machine", tok)) {
-            /* the next tok is the machine name, this is in itself the
-               delimiter that starts the stuff entered for this machine,
-               after this we need to search for 'login' and
-               'password'. */
-            state = HOSTFOUND;
-          }
-          else if(strcasecompare("default", tok)) {
-            state = HOSTVALID;
-            retcode = NETRC_SUCCESS; /* we did find our host */
-          }
-          break;
-        case MACDEF:
-          if(!strlen(tok)) {
-            state = NOTHING;
-          }
-          break;
-        case HOSTFOUND:
-          if(strcasecompare(host, tok)) {
-            /* and yes, this is our host! */
-            state = HOSTVALID;
-            retcode = NETRC_SUCCESS; /* we did find our host */
-          }
-          else
-            /* not our host */
-            state = NOTHING;
-          break;
-        case HOSTVALID:
-          /* we are now parsing sub-keywords concerning "our" host */
-          if(state_login) {
-            if(specific_login) {
-              state_our_login = !Curl_timestrcmp(login, tok);
-            }
-            else if(!login || Curl_timestrcmp(login, tok)) {
-              if(login_alloc) {
-                free(login);
-                login_alloc = FALSE;
-              }
-              login = strdup(tok);
-              if(!login) {
-                retcode = NETRC_FAILED; /* allocation failed */
-                goto out;
-              }
-              login_alloc = TRUE;
-            }
-            state_login = 0;
-          }
-          else if(state_password) {
-            if((state_our_login || !specific_login)
-               && (!password || Curl_timestrcmp(password, tok))) {
-              if(password_alloc) {
-                free(password);
-                password_alloc = FALSE;
-              }
-              password = strdup(tok);
-              if(!password) {
-                retcode = NETRC_FAILED; /* allocation failed */
-                goto out;
-              }
-              password_alloc = TRUE;
-            }
-            state_password = 0;
-          }
-          else if(strcasecompare("login", tok))
-            state_login = 1;
-          else if(strcasecompare("password", tok))
-            state_password = 1;
-          else if(strcasecompare("machine", tok)) {
-            /* ok, there is machine here go => */
-            state = HOSTFOUND;
-            state_our_login = FALSE;
-          }
-          break;
-        } /* switch (state) */
-        tok = ++tok_end;
-      }
-    } /* while Curl_get_line() */
+        break;
+      } /* switch (state) */
+      tok = ++tok_end;
+    }
+    if(!done) {
+      char *nl = NULL;
+      if(tok)
+        nl = strchr(tok, '\n');
+      if(!nl)
+        break;
+      /* point to next line */
+      netrcbuffer = &nl[1];
+    }
+  } /* while !done */
 
 out:
-    Curl_dyn_free(&buf);
-    if(!retcode) {
-      /* success */
-      if(login_alloc) {
-        if(*loginp)
-          free(*loginp);
-        *loginp = login;
-      }
-      if(password_alloc) {
-        if(*passwordp)
-          free(*passwordp);
-        *passwordp = password;
-      }
-    }
-    else {
-      if(login_alloc)
-        free(login);
-      if(password_alloc)
-        free(password);
-    }
-    fclose(file);
+  Curl_dyn_free(&token);
+  if(!retcode && !password && our_login) {
+    /* success without a password, set a blank one */
+    password = strdup("");
+    if(!password)
+      retcode = 1; /* out of memory */
+  }
+  if(!retcode) {
+    /* success */
+    if(!specific_login)
+      *loginp = login;
+    *passwordp = password;
+  }
+  else {
+    Curl_dyn_free(filebuf);
+    if(!specific_login)
+      free(login);
+    free(password);
   }
 
   return retcode;
@@ -280,7 +337,8 @@
  * *loginp and *passwordp MUST be allocated if they are not NULL when passed
  * in.
  */
-int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
+int Curl_parsenetrc(struct store_netrc *store, const char *host,
+                    char **loginp, char **passwordp,
                     char *netrcfile)
 {
   int retcode = 1;
@@ -329,7 +387,7 @@
       free(homea);
       return -1;
     }
-    retcode = parsenetrc(host, loginp, passwordp, filealloc);
+    retcode = parsenetrc(store, host, loginp, passwordp, filealloc);
     free(filealloc);
 #ifdef _WIN32
     if(retcode == NETRC_FILE_MISSING) {
@@ -339,15 +397,25 @@
         free(homea);
         return -1;
       }
-      retcode = parsenetrc(host, loginp, passwordp, filealloc);
+      retcode = parsenetrc(store, host, loginp, passwordp, filealloc);
       free(filealloc);
     }
 #endif
     free(homea);
   }
   else
-    retcode = parsenetrc(host, loginp, passwordp, netrcfile);
+    retcode = parsenetrc(store, host, loginp, passwordp, netrcfile);
   return retcode;
 }
 
+void Curl_netrc_init(struct store_netrc *s)
+{
+  Curl_dyn_init(&s->filebuf, MAX_NETRC_FILE);
+  s->loaded = FALSE;
+}
+void Curl_netrc_cleanup(struct store_netrc *s)
+{
+  Curl_dyn_free(&s->filebuf);
+  s->loaded = FALSE;
+}
 #endif
diff --git a/Utilities/cmcurl/lib/netrc.h b/Utilities/cmcurl/lib/netrc.h
index 37c95db..0ef9ff7 100644
--- a/Utilities/cmcurl/lib/netrc.h
+++ b/Utilities/cmcurl/lib/netrc.h
@@ -26,9 +26,19 @@
 
 #include "curl_setup.h"
 #ifndef CURL_DISABLE_NETRC
+#include "dynbuf.h"
+
+struct store_netrc {
+  struct dynbuf filebuf;
+  char *filename;
+  BIT(loaded);
+};
+
+void Curl_netrc_init(struct store_netrc *s);
+void Curl_netrc_cleanup(struct store_netrc *s);
 
 /* returns -1 on failure, 0 if the host is found, 1 is the host is not found */
-int Curl_parsenetrc(const char *host, char **loginp,
+int Curl_parsenetrc(struct store_netrc *s, 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
@@ -38,6 +48,8 @@
 #else
 /* disabled */
 #define Curl_parsenetrc(a,b,c,d,e,f) 1
+#define Curl_netrc_init(x)
+#define Curl_netrc_cleanup(x)
 #endif
 
 #endif /* HEADER_CURL_NETRC_H */
diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c
index f3e13ed..8c4af22 100644
--- a/Utilities/cmcurl/lib/openldap.c
+++ b/Utilities/cmcurl/lib/openldap.c
@@ -236,17 +236,13 @@
 {
   switch(rc) {
   case LDAP_NO_MEMORY:
-    result = CURLE_OUT_OF_MEMORY;
-    break;
+    return CURLE_OUT_OF_MEMORY;
   case LDAP_INVALID_CREDENTIALS:
-    result = CURLE_LOGIN_DENIED;
-    break;
+    return CURLE_LOGIN_DENIED;
   case LDAP_PROTOCOL_ERROR:
-    result = CURLE_UNSUPPORTED_PROTOCOL;
-    break;
+    return CURLE_UNSUPPORTED_PROTOCOL;
   case LDAP_INSUFFICIENT_ACCESS:
-    result = CURLE_REMOTE_ACCESS_DENIED;
-    break;
+    return CURLE_REMOTE_ACCESS_DENIED;
   }
   return result;
 }
@@ -276,7 +272,8 @@
   if(rc != LDAP_URL_SUCCESS) {
     const char *msg = "url parsing problem";
 
-    result = rc == LDAP_URL_ERR_MEM? CURLE_OUT_OF_MEMORY: CURLE_URL_MALFORMAT;
+    result = rc == LDAP_URL_ERR_MEM ? CURLE_OUT_OF_MEMORY :
+      CURLE_URL_MALFORMAT;
     rc -= LDAP_URL_SUCCESS;
     if((size_t) rc < sizeof(url_errs) / sizeof(url_errs[0]))
       msg = url_errs[rc];
@@ -313,7 +310,7 @@
       ptr++;
   }
 
-  return result == CURLE_URL_MALFORMAT? CURLE_SETOPT_OPTION_SYNTAX: result;
+  return result == CURLE_URL_MALFORMAT ? CURLE_SETOPT_OPTION_SYNTAX : result;
 }
 
 static CURLcode oldap_setup_connection(struct Curl_easy *data,
@@ -351,7 +348,6 @@
 {
   struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
-  CURLcode result = CURLE_OK;
   struct berval cred;
   struct berval *pcred = &cred;
   int rc;
@@ -362,8 +358,8 @@
     pcred = NULL;
   rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
   if(rc != LDAP_SUCCESS)
-    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
-  return result;
+    return oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
+  return CURLE_OK;
 }
 
 /*
@@ -374,7 +370,6 @@
 {
   struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
-  CURLcode result = CURLE_OK;
   struct berval cred;
   struct berval *pcred = &cred;
   int rc;
@@ -385,8 +380,8 @@
     pcred = NULL;
   rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
   if(rc != LDAP_SUCCESS)
-    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
-  return result;
+    return oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
+  return CURLE_OK;
 }
 
 /*
@@ -395,20 +390,18 @@
 static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech)
 {
   struct ldapconninfo *li = data->conn->proto.ldapc;
-  CURLcode result = CURLE_OK;
   int rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL,
                           &li->msgid);
 
   (void)mech;
   if(rc != LDAP_SUCCESS)
-    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
-  return result;
+    return oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
+  return CURLE_OK;
 }
 
 /* Starts LDAP simple bind. */
 static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
 {
-  CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   char *binddn = NULL;
@@ -426,19 +419,17 @@
 
   rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
                       NULL, NULL, &li->msgid);
-  if(rc == LDAP_SUCCESS)
-    oldap_state(data, newstate);
-  else
-    result = oldap_map_error(rc,
-                             data->state.aptr.user?
-                             CURLE_LOGIN_DENIED: CURLE_LDAP_CANNOT_BIND);
-  return result;
+  if(rc != LDAP_SUCCESS)
+    return oldap_map_error(rc,
+                           data->state.aptr.user ?
+                           CURLE_LOGIN_DENIED : CURLE_LDAP_CANNOT_BIND);
+  oldap_state(data, newstate);
+  return CURLE_OK;
 }
 
 /* Query the supported SASL authentication mechanisms. */
 static CURLcode oldap_perform_mechs(struct Curl_easy *data)
 {
-  CURLcode result = CURLE_OK;
   struct ldapconninfo *li = data->conn->proto.ldapc;
   int rc;
   static const char * const supportedSASLMechanisms[] = {
@@ -449,11 +440,10 @@
   rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
                        (char **) supportedSASLMechanisms, 0,
                        NULL, NULL, NULL, 0, &li->msgid);
-  if(rc == LDAP_SUCCESS)
-    oldap_state(data, OLDAP_MECHS);
-  else
-    result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
-  return result;
+  if(rc != LDAP_SUCCESS)
+    return oldap_map_error(rc, CURLE_LOGIN_DENIED);
+  oldap_state(data, OLDAP_MECHS);
+  return CURLE_OK;
 }
 
 /* Starts SASL bind. */
@@ -479,12 +469,10 @@
 
 static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate)
 {
-  CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
-  bool ssldone = 0;
-
-  result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
+  bool ssldone = FALSE;
+  CURLcode result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
   if(!result) {
     oldap_state(data, newstate);
 
@@ -505,15 +493,13 @@
 /* Send the STARTTLS request */
 static CURLcode oldap_perform_starttls(struct Curl_easy *data)
 {
-  CURLcode result = CURLE_OK;
   struct ldapconninfo *li = data->conn->proto.ldapc;
   int rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid);
 
-  if(rc == LDAP_SUCCESS)
-    oldap_state(data, OLDAP_STARTTLS);
-  else
-    result = oldap_map_error(rc, CURLE_USE_SSL_FAILED);
-  return result;
+  if(rc != LDAP_SUCCESS)
+    return oldap_map_error(rc, CURLE_USE_SSL_FAILED);
+  oldap_state(data, OLDAP_STARTTLS);
+  return CURLE_OK;
 }
 #endif
 
@@ -552,9 +538,9 @@
 
   hosturl = aprintf("%s://%s%s%s:%d",
                     conn->handler->scheme,
-                    conn->bits.ipv6_ip? "[": "",
+                    conn->bits.ipv6_ip ? "[" : "",
                     conn->host.name,
-                    conn->bits.ipv6_ip? "]": "",
+                    conn->bits.ipv6_ip ? "]" : "",
                     conn->remote_port);
   if(!hosturl)
     return CURLE_OUT_OF_MEMORY;
@@ -986,7 +972,7 @@
   BerElement *ber = NULL;
   struct timeval tv = {0, 0};
   struct berval bv, *bvals;
-  int binary = 0;
+  bool binary = FALSE;
   CURLcode result = CURLE_AGAIN;
   int code;
   char *info = NULL;
@@ -1069,10 +1055,10 @@
       }
 
       binary = bv.bv_len > 7 &&
-               !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7);
+        !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7);
 
       for(i = 0; bvals[i].bv_val != NULL; i++) {
-        int binval = 0;
+        bool binval = FALSE;
 
         result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
                               STRCONST(":"));
@@ -1083,13 +1069,13 @@
           /* check for leading or trailing whitespace */
           if(ISBLANK(bvals[i].bv_val[0]) ||
              ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))
-            binval = 1;
+            binval = TRUE;
           else {
             /* check for unprintable characters */
             unsigned int j;
             for(j = 0; j < bvals[i].bv_len; j++)
               if(!ISPRINT(bvals[i].bv_val[j])) {
-                binval = 1;
+                binval = TRUE;
                 break;
               }
           }
@@ -1134,7 +1120,7 @@
 
   ldap_msgfree(msg);
   *err = result;
-  return result? -1: 0;
+  return result ? -1 : 0;
 }
 
 #ifdef USE_SSL
diff --git a/Utilities/cmcurl/lib/parsedate.c b/Utilities/cmcurl/lib/parsedate.c
index d35b58b..4d0a221 100644
--- a/Utilities/cmcurl/lib/parsedate.c
+++ b/Utilities/cmcurl/lib/parsedate.c
@@ -218,7 +218,7 @@
     what = &Curl_wkday[0];
   else
     return -1; /* too short */
-  for(i = 0; i<7; i++) {
+  for(i = 0; i < 7; i++) {
     size_t ilen = strlen(what[0]);
     if((ilen == len) &&
        strncasecompare(check, what[0], len))
@@ -235,7 +235,7 @@
   if(len != 3)
     return -1; /* not a month */
 
-  for(i = 0; i<12; i++) {
+  for(i = 0; i < 12; i++) {
     if(strncasecompare(check, what[0], 3))
       return i;
     what++;
@@ -253,7 +253,7 @@
   if(len > 4) /* longer than any valid timezone */
     return -1;
 
-  for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
+  for(i = 0; i < sizeof(tz)/sizeof(tz[0]); i++) {
     size_t ilen = strlen(what->name);
     if((ilen == len) &&
        strncasecompare(check, what->name, len))
@@ -441,7 +441,7 @@
         if((tzoff == -1) &&
            ((end - date) == 4) &&
            (val <= 1400) &&
-           (indate< date) &&
+           (indate < date) &&
            ((date[-1] == '+' || date[-1] == '-'))) {
           /* four digits and a value less than or equal to 1400 (to take into
              account all sorts of funny time zone diffs) and it is preceded
@@ -456,7 +456,7 @@
 
           /* the + and - prefix indicates the local time compared to GMT,
              this we need their reversed math to get what we want */
-          tzoff = date[-1]=='+'?-tzoff:tzoff;
+          tzoff = date[-1]=='+' ? -tzoff : tzoff;
         }
 
         if(((end - date) == 8) &&
@@ -471,7 +471,7 @@
         }
 
         if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) {
-          if((val > 0) && (val<32)) {
+          if((val > 0) && (val < 32)) {
             mdaynum = val;
             found = TRUE;
           }
diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c
index 817e3f6..bd0d3e3 100644
--- a/Utilities/cmcurl/lib/pingpong.c
+++ b/Utilities/cmcurl/lib/pingpong.c
@@ -52,8 +52,8 @@
 {
   struct connectdata *conn = data->conn;
   timediff_t timeout_ms; /* in milliseconds */
-  timediff_t response_time = (data->set.server_response_timeout)?
-    data->set.server_response_timeout: pp->response_time;
+  timediff_t response_time = (data->set.server_response_timeout) ?
+    data->set.server_response_timeout : pp->response_time;
 
   /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
      remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is
@@ -113,9 +113,9 @@
     /* We are receiving and there is data ready in the SSL library */
     rc = 1;
   else
-    rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
+    rc = Curl_socket_check(pp->sendleft ? CURL_SOCKET_BAD : sock, /* reading */
                            CURL_SOCKET_BAD,
-                           pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
+                           pp->sendleft ? sock : CURL_SOCKET_BAD, /* writing */
                            interval_ms);
 
   if(block) {
diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c
index 1f5334d..db6ec04 100644
--- a/Utilities/cmcurl/lib/pop3.c
+++ b/Utilities/cmcurl/lib/pop3.c
@@ -504,7 +504,7 @@
   }
 
   /* Create the digest */
-  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
   if(!ctxt)
     return CURLE_OUT_OF_MEMORY;
 
@@ -1119,7 +1119,7 @@
   }
 
   result = Curl_pp_statemach(data, &pop3c->pp, FALSE, FALSE);
-  *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
+  *done = (pop3c->state == POP3_STOP);
 
   return result;
 }
diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c
index cb9829c..d3a1b9a 100644
--- a/Utilities/cmcurl/lib/progress.c
+++ b/Utilities/cmcurl/lib/progress.c
@@ -174,7 +174,7 @@
   case TIMER_STARTSINGLE:
     /* This is set at the start of each single transfer */
     data->progress.t_startsingle = timestamp;
-    data->progress.is_t_startransfer_set = false;
+    data->progress.is_t_startransfer_set = FALSE;
     break;
   case TIMER_POSTQUEUE:
     /* Set when the transfer starts (after potentially having been brought
@@ -211,7 +211,7 @@
       return;
     }
     else {
-      data->progress.is_t_startransfer_set = true;
+      data->progress.is_t_startransfer_set = TRUE;
       break;
     }
   case TIMER_POSTRANSFER:
@@ -249,7 +249,7 @@
 {
   data->progress.speeder_c = 0; /* reset the progress meter display */
   data->progress.start = Curl_now();
-  data->progress.is_t_startransfer_set = false;
+  data->progress.is_t_startransfer_set = FALSE;
   data->progress.ul.limit.start = data->progress.start;
   data->progress.dl.limit.start = data->progress.start;
   data->progress.ul.limit.start_size = 0;
@@ -381,6 +381,11 @@
   }
 }
 
+void Curl_pgrsEarlyData(struct Curl_easy *data, curl_off_t sent)
+{
+    data->progress.earlydata_sent = sent;
+}
+
 /* returns the average speed in bytes / second */
 static curl_off_t trspeed(curl_off_t size, /* number of bytes */
                           curl_off_t us)   /* microseconds */
@@ -428,7 +433,7 @@
        array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
        transfer. Imagine, after one second we have filled in two entries,
        after two seconds we have filled in three entries etc. */
-    countindex = ((p->speeder_c >= CURR_TIME)? CURR_TIME:p->speeder_c) - 1;
+    countindex = ((p->speeder_c >= CURR_TIME) ? CURR_TIME : p->speeder_c) - 1;
 
     /* first of all, we do not do this if there is no counted seconds yet */
     if(countindex) {
@@ -439,7 +444,7 @@
       /* Get the index position to compare with the 'nowindex' position.
          Get the oldest entry possible. While we have less than CURR_TIME
          entries, the first entry will remain the oldest. */
-      checkindex = (p->speeder_c >= CURR_TIME)? p->speeder_c%CURR_TIME:0;
+      checkindex = (p->speeder_c >= CURR_TIME) ? p->speeder_c%CURR_TIME : 0;
 
       /* Figure out the exact time for the time span */
       span_ms = Curl_timediff(now, p->speeder_time[checkindex]);
@@ -530,14 +535,14 @@
   /* Since both happen at the same time, total expected duration is max. */
   total_estm.secs = CURLMAX(ul_estm.secs, dl_estm.secs);
   /* create the three time strings */
-  time2str(time_left, total_estm.secs > 0?(total_estm.secs - cur_secs):0);
+  time2str(time_left, total_estm.secs > 0 ? (total_estm.secs - cur_secs) : 0);
   time2str(time_total, total_estm.secs);
   time2str(time_spent, cur_secs);
 
   /* Get the total amount of data expected to get transferred */
   total_expected_size =
-    ((p->flags & PGRS_UL_SIZE_KNOWN)? p->ul.total_size:p->ul.cur_size) +
-    ((p->flags & PGRS_DL_SIZE_KNOWN)? p->dl.total_size:p->dl.cur_size);
+    ((p->flags & PGRS_UL_SIZE_KNOWN) ? p->ul.total_size : p->ul.cur_size) +
+    ((p->flags & PGRS_DL_SIZE_KNOWN) ? p->dl.total_size : p->dl.cur_size);
 
   /* We have transferred this much so far */
   total_cur_size = p->dl.cur_size + p->ul.cur_size;
@@ -583,13 +588,13 @@
     if(data->set.fxferinfo) {
       int result;
       /* There is a callback set, call that */
-      Curl_set_in_callback(data, true);
+      Curl_set_in_callback(data, TRUE);
       result = data->set.fxferinfo(data->set.progress_client,
                                    data->progress.dl.total_size,
                                    data->progress.dl.cur_size,
                                    data->progress.ul.total_size,
                                    data->progress.ul.cur_size);
-      Curl_set_in_callback(data, false);
+      Curl_set_in_callback(data, FALSE);
       if(result != CURL_PROGRESSFUNC_CONTINUE) {
         if(result)
           failf(data, "Callback aborted");
@@ -599,13 +604,13 @@
     else if(data->set.fprogress) {
       int result;
       /* The older deprecated callback is set, call that */
-      Curl_set_in_callback(data, true);
+      Curl_set_in_callback(data, TRUE);
       result = data->set.fprogress(data->set.progress_client,
                                    (double)data->progress.dl.total_size,
                                    (double)data->progress.dl.cur_size,
                                    (double)data->progress.ul.total_size,
                                    (double)data->progress.ul.cur_size);
-      Curl_set_in_callback(data, false);
+      Curl_set_in_callback(data, FALSE);
       if(result != CURL_PROGRESSFUNC_CONTINUE) {
         if(result)
           failf(data, "Callback aborted");
diff --git a/Utilities/cmcurl/lib/progress.h b/Utilities/cmcurl/lib/progress.h
index 04a8f5b..326271e 100644
--- a/Utilities/cmcurl/lib/progress.h
+++ b/Utilities/cmcurl/lib/progress.h
@@ -69,6 +69,8 @@
 void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
                       struct curltime timestamp);
 
+void Curl_pgrsEarlyData(struct Curl_easy *data, curl_off_t sent);
+
 #define PGRS_HIDE    (1<<4)
 #define PGRS_UL_SIZE_KNOWN (1<<5)
 #define PGRS_DL_SIZE_KNOWN (1<<6)
diff --git a/Utilities/cmcurl/lib/psl.c b/Utilities/cmcurl/lib/psl.c
index 626a203..0b88b05 100644
--- a/Utilities/cmcurl/lib/psl.c
+++ b/Utilities/cmcurl/lib/psl.c
@@ -81,7 +81,7 @@
       psl = psl_latest(NULL);
       dynamic = psl != NULL;
       /* Take care of possible time computation overflow. */
-      expires = now < TIME_T_MAX - PSL_TTL? now + PSL_TTL: TIME_T_MAX;
+      expires = now < TIME_T_MAX - PSL_TTL ? now + PSL_TTL : TIME_T_MAX;
 
       /* Only get the built-in PSL if we do not already have the "latest". */
       if(!psl && !pslcache->dynamic)
diff --git a/Utilities/cmcurl/lib/psl.h b/Utilities/cmcurl/lib/psl.h
index 23cfa92..dd5bee2 100644
--- a/Utilities/cmcurl/lib/psl.h
+++ b/Utilities/cmcurl/lib/psl.h
@@ -27,6 +27,8 @@
 #ifdef USE_LIBPSL
 #include <libpsl.h>
 
+struct Curl_easy;
+
 #define PSL_TTL (72 * 3600)     /* PSL time to live before a refresh. */
 
 struct PslCache {
diff --git a/Utilities/cmcurl/lib/rand.c b/Utilities/cmcurl/lib/rand.c
index 63aebdc..8d55e26 100644
--- a/Utilities/cmcurl/lib/rand.c
+++ b/Utilities/cmcurl/lib/rand.c
@@ -49,7 +49,7 @@
 #ifdef _WIN32
 
 #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 && \
-  !defined(CURL_WINDOWS_APP)
+  !defined(CURL_WINDOWS_UWP)
 #  define HAVE_WIN_BCRYPTGENRANDOM
 #  include <bcrypt.h>
 #  ifdef _MSC_VER
diff --git a/Utilities/cmcurl/lib/request.c b/Utilities/cmcurl/lib/request.c
index 1ddbdc9..310e4ea 100644
--- a/Utilities/cmcurl/lib/request.c
+++ b/Utilities/cmcurl/lib/request.c
@@ -283,9 +283,9 @@
           data->req.writebytecount);
   else if(!data->req.download_done) {
     DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf));
-    infof(data, Curl_creader_total_length(data)?
-                "We are completely uploaded and fine" :
-                "Request completely sent off");
+    infof(data, Curl_creader_total_length(data) ?
+          "We are completely uploaded and fine" :
+          "Request completely sent off");
   }
 
   return Curl_xfer_send_close(data);
@@ -327,6 +327,13 @@
     if(data->req.shutdown) {
       bool done;
       result = Curl_xfer_send_shutdown(data, &done);
+      if(result && data->req.shutdown_err_ignore) {
+        infof(data, "Shutdown send direction error: %d. Broken server? "
+              "Proceeding as if everything is ok.", result);
+        result = CURLE_OK;
+        done = TRUE;
+      }
+
       if(result)
         return result;
       if(!done)
diff --git a/Utilities/cmcurl/lib/request.h b/Utilities/cmcurl/lib/request.h
index c53c3eb..bb72247 100644
--- a/Utilities/cmcurl/lib/request.h
+++ b/Utilities/cmcurl/lib/request.h
@@ -151,6 +151,7 @@
                         negotiation. */
   BIT(sendbuf_init); /* sendbuf is initialized */
   BIT(shutdown);     /* request end will shutdown connection */
+  BIT(shutdown_err_ignore); /* errors in shutdown will not fail request */
 #ifdef USE_HYPER
   BIT(bodywritten);
 #endif
diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c
index c9b1bc0..ecefd13 100644
--- a/Utilities/cmcurl/lib/rtsp.c
+++ b/Utilities/cmcurl/lib/rtsp.c
@@ -213,6 +213,11 @@
        (data->conn->proto.rtspc.rtp_channel == -1)) {
       infof(data, "Got an RTP Receive with a CSeq of %ld", CSeq_recv);
     }
+    if(data->set.rtspreq == RTSPREQ_RECEIVE &&
+       data->req.eos_written) {
+      failf(data, "Server prematurely closed the RTSP connection.");
+      return CURLE_RECV_ERROR;
+    }
   }
 
   return httpStatus;
@@ -359,8 +364,8 @@
   /* Accept Headers for DESCRIBE requests */
   if(rtspreq == RTSPREQ_DESCRIBE) {
     /* Accept Header */
-    p_accept = Curl_checkheaders(data, STRCONST("Accept"))?
-      NULL:"Accept: application/sdp\r\n";
+    p_accept = Curl_checkheaders(data, STRCONST("Accept")) ?
+      NULL : "Accept: application/sdp\r\n";
 
     /* Accept-Encoding header */
     if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
@@ -615,7 +620,7 @@
   in_body = (data->req.headerline && !rtspc->in_header) &&
             (data->req.size >= 0) &&
             (data->req.bytecount < data->req.size);
-  body_remain = in_body? (data->req.size - data->req.bytecount) : 0;
+  body_remain = in_body ? (data->req.size - data->req.bytecount) : 0;
   DEBUGASSERT(body_remain >= 0);
   if(body_remain) {
     if((curl_off_t)blen > body_remain)
@@ -858,7 +863,7 @@
                data->req.size));
   if(!result && (is_eos || blen)) {
     result = Curl_client_write(data, CLIENTWRITE_BODY|
-                               (is_eos? CLIENTWRITE_EOS:0),
+                               (is_eos ? CLIENTWRITE_EOS : 0),
                                (char *)buf, blen);
   }
 
@@ -898,9 +903,9 @@
     user_ptr = data->set.out;
   }
 
-  Curl_set_in_callback(data, true);
+  Curl_set_in_callback(data, TRUE);
   wrote = writeit((char *)ptr, 1, len, user_ptr);
-  Curl_set_in_callback(data, false);
+  Curl_set_in_callback(data, FALSE);
 
   if(CURL_WRITEFUNC_PAUSE == wrote) {
     failf(data, "Cannot pause RTP");
diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c
index dae736b..c1779ad 100644
--- a/Utilities/cmcurl/lib/select.c
+++ b/Utilities/cmcurl/lib/select.c
@@ -24,6 +24,10 @@
 
 #include "curl_setup.h"
 
+#if !defined(HAVE_SELECT) && !defined(HAVE_POLL)
+#error "We cannot compile without select() or poll() support."
+#endif
+
 #include <limits.h>
 
 #ifdef HAVE_SYS_SELECT_H
@@ -32,10 +36,6 @@
 #include <unistd.h>
 #endif
 
-#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
-#error "We cannot compile without select() or poll() support."
-#endif
-
 #ifdef MSDOS
 #include <dos.h>  /* delay() */
 #endif
@@ -53,16 +53,15 @@
 #include "memdebug.h"
 
 /*
- * Internal function used for waiting a specific amount of ms
- * in Curl_socket_check() and Curl_poll() when no file descriptor
- * is provided to wait on, just being used to delay execution.
- * Winsock select() and poll() timeout mechanisms need a valid
- * socket descriptor in a not null file descriptor set to work.
- * Waiting indefinitely with this function is not allowed, a
- * zero or negative timeout value will return immediately.
- * Timeout resolution, accuracy, as well as maximum supported
- * value is system dependent, neither factor is a critical issue
- * for the intended use of this function in the library.
+ * Internal function used for waiting a specific amount of ms in
+ * Curl_socket_check() and Curl_poll() when no file descriptor is provided to
+ * wait on, just being used to delay execution. Winsock select() and poll()
+ * timeout mechanisms need a valid socket descriptor in a not null file
+ * descriptor set to work. Waiting indefinitely with this function is not
+ * allowed, a zero or negative timeout value will return immediately. Timeout
+ * resolution, accuracy, as well as maximum supported value is system
+ * dependent, neither factor is a critical issue for the intended use of this
+ * function in the library.
  *
  * Return values:
  *   -1 = system call error, or invalid timeout value
@@ -89,20 +88,13 @@
 #endif
   Sleep((ULONG)timeout_ms);
 #else
-#if defined(HAVE_POLL_FINE)
-  /* prevent overflow, timeout_ms is typecast to int. */
-#if TIMEDIFF_T_MAX > INT_MAX
-  if(timeout_ms > INT_MAX)
-    timeout_ms = INT_MAX;
-#endif
-  r = poll(NULL, 0, (int)timeout_ms);
-#else
+  /* avoid using poll() for this since it behaves incorrectly with no sockets
+     on Apple operating systems */
   {
     struct timeval pending_tv;
     r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms));
   }
-#endif /* HAVE_POLL_FINE */
-#endif /* USE_WINSOCK */
+#endif /* _WIN32 */
   if(r) {
     if((r == -1) && (SOCKERRNO == EINTR))
       /* make EINTR from select or poll not a "lethal" error */
@@ -113,12 +105,12 @@
   return r;
 }
 
-#ifndef HAVE_POLL_FINE
+#ifndef HAVE_POLL
 /*
- * This is a wrapper around select() to aid in Windows compatibility.
- * A negative timeout value makes this function wait indefinitely,
- * unless no valid file descriptor is given, when this happens the
- * negative timeout is ignored and the function times out immediately.
+ * This is a wrapper around select() to aid in Windows compatibility. A
+ * negative timeout value makes this function wait indefinitely, unless no
+ * valid file descriptor is given, when this happens the negative timeout is
+ * ignored and the function times out immediately.
  *
  * Return values:
  *   -1 = system call error or fd >= FD_SETSIZE
@@ -172,13 +164,13 @@
 
 /*
  * Wait for read or write events on a set of file descriptors. It uses poll()
- * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
+ * when poll() is available, in order to avoid limits with FD_SETSIZE,
  * otherwise select() is used. An error is returned if select() is being used
  * and a file descriptor is too large for FD_SETSIZE.
  *
- * A negative timeout value makes this function wait indefinitely,
- * unless no valid file descriptor is given, when this happens the
- * negative timeout is ignored and the function times out immediately.
+ * A negative timeout value makes this function wait indefinitely, unless no
+ * valid file descriptor is given, when this happens the negative timeout is
+ * ignored and the function times out immediately.
  *
  * Return values:
  *   -1 = system call error or fd >= FD_SETSIZE
@@ -275,7 +267,7 @@
  */
 int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
 {
-#ifdef HAVE_POLL_FINE
+#ifdef HAVE_POLL
   int pending_ms;
 #else
   fd_set fds_read;
@@ -305,7 +297,7 @@
      when function is called with a zero timeout or a negative timeout
      value indicating a blocking call should be performed. */
 
-#ifdef HAVE_POLL_FINE
+#ifdef HAVE_POLL
 
   /* prevent overflow, timeout_ms is typecast to int. */
 #if TIMEDIFF_T_MAX > INT_MAX
@@ -335,7 +327,7 @@
       ufds[i].revents |= POLLIN|POLLOUT;
   }
 
-#else  /* HAVE_POLL_FINE */
+#else  /* HAVE_POLL */
 
   FD_ZERO(&fds_read);
   FD_ZERO(&fds_write);
@@ -401,7 +393,7 @@
       r++;
   }
 
-#endif  /* HAVE_POLL_FINE */
+#endif  /* HAVE_POLL */
 
   return r;
 }
diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c
index 6f56662..30a3517 100644
--- a/Utilities/cmcurl/lib/sendf.c
+++ b/Utilities/cmcurl/lib/sendf.c
@@ -300,7 +300,7 @@
 
   /* Error on too large filesize is handled below, after writing
    * the permitted bytes */
-  if(data->set.max_filesize) {
+  if(data->set.max_filesize && !data->req.ignorebody) {
     size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
     if(nwrite > wmax) {
       nwrite = wmax;
@@ -398,7 +398,7 @@
   result = cwt->do_init(data, writer);
 
 out:
-  *pwriter = result? NULL : writer;
+  *pwriter = result ? NULL : writer;
   if(result)
     free(writer);
   return result;
@@ -575,7 +575,7 @@
 curl_off_t Curl_creader_def_total_length(struct Curl_easy *data,
                                          struct Curl_creader *reader)
 {
-  return reader->next?
+  return reader->next ?
          reader->next->crt->total_length(data, reader->next) : -1;
 }
 
@@ -677,9 +677,9 @@
   }
   nread = 0;
   if(ctx->read_cb && blen) {
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     nread = ctx->read_cb(buf, 1, blen, ctx->cb_user_data);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
     ctx->has_used_cb = TRUE;
   }
 
@@ -773,9 +773,9 @@
     return CURLE_READ_ERROR;
 
   if(data->set.seek_func) {
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     seekerr = data->set.seek_func(data->set.seek_client, offset, SEEK_SET);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
   }
 
   if(seekerr != CURL_SEEKFUNC_OK) {
@@ -794,10 +794,10 @@
         curlx_sotouz(offset - passed);
       size_t actuallyread;
 
-      Curl_set_in_callback(data, true);
+      Curl_set_in_callback(data, TRUE);
       actuallyread = ctx->read_cb(scratch, 1, readthisamountnow,
                                   ctx->cb_user_data);
-      Curl_set_in_callback(data, false);
+      Curl_set_in_callback(data, FALSE);
 
       passed += actuallyread;
       if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
@@ -835,9 +835,9 @@
   if(data->set.seek_func) {
     int err;
 
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
     CURL_TRC_READ(data, "cr_in, rewind via set.seek_func -> %d", err);
     if(err) {
       failf(data, "seek callback returned error %d", (int)err);
@@ -847,10 +847,10 @@
   else if(data->set.ioctl_func) {
     curlioerr err;
 
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
                                  data->set.ioctl_client);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
     CURL_TRC_READ(data, "cr_in, rewind via set.ioctl_func -> %d", (int)err);
     if(err) {
       failf(data, "ioctl callback returned error %d", (int)err);
@@ -930,7 +930,7 @@
   result = crt->do_init(data, reader);
 
 out:
-  *preader = result? NULL : reader;
+  *preader = result ? NULL : reader;
   if(result)
     free(reader);
   return result;
@@ -1014,7 +1014,7 @@
         ctx->prev_cr = (buf[i] == '\r');
         continue;
       }
-      ctx->prev_cr = false;
+      ctx->prev_cr = FALSE;
       /* on a soft limit bufq, we do not need to check length */
       result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
       if(!result)
@@ -1376,7 +1376,7 @@
 curl_off_t Curl_creader_total_length(struct Curl_easy *data)
 {
   struct Curl_creader *r = data->req.reader_stack;
-  return r? r->crt->total_length(data, r) : -1;
+  return r ? r->crt->total_length(data, r) : -1;
 }
 
 curl_off_t Curl_creader_client_length(struct Curl_easy *data)
@@ -1384,7 +1384,7 @@
   struct Curl_creader *r = data->req.reader_stack;
   while(r && r->phase != CURL_CR_CLIENT)
     r = r->next;
-  return r? r->crt->total_length(data, r) : -1;
+  return r ? r->crt->total_length(data, r) : -1;
 }
 
 CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset)
@@ -1392,7 +1392,7 @@
   struct Curl_creader *r = data->req.reader_stack;
   while(r && r->phase != CURL_CR_CLIENT)
     r = r->next;
-  return r? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
+  return r ? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
 }
 
 CURLcode Curl_creader_unpause(struct Curl_easy *data)
diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c
index 5b9a4cb..0bae6ba 100644
--- a/Utilities/cmcurl/lib/setopt.c
+++ b/Utilities/cmcurl/lib/setopt.c
@@ -193,7 +193,7 @@
     size_t tlen;
 
     str = strchr(str, ',');
-    tlen = str? (size_t) (str - token): strlen(token);
+    tlen = str ? (size_t) (str - token) : strlen(token);
     if(tlen) {
       const struct Curl_handler *h = Curl_getn_scheme_handler(token, tlen);
 
@@ -210,21 +210,58 @@
   return CURLE_OK;
 }
 
-/*
- * Do not make Curl_vsetopt() static: it is called from
- * packages/OS400/ccsidcurl.c.
- */
-CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
+static CURLcode httpauth(struct Curl_easy *data, bool proxy,
+                         unsigned long auth)
 {
-  char *argptr;
-  CURLcode result = CURLE_OK;
-  long arg;
-  unsigned long uarg;
-  curl_off_t bigsize;
+  if(auth != CURLAUTH_NONE) {
+    int bitcheck = 0;
+    bool authbits = FALSE;
+    /* the DIGEST_IE bit is only used to set a special marker, for all the
+       rest we need to handle it as normal DIGEST */
+    bool iestyle = !!(auth & CURLAUTH_DIGEST_IE);
+    if(proxy)
+      data->state.authproxy.iestyle = iestyle;
+    else
+      data->state.authhost.iestyle = iestyle;
 
+    if(auth & CURLAUTH_DIGEST_IE) {
+      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+    }
+
+    /* switch off bits we cannot support */
+#ifndef USE_NTLM
+    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
+#endif
+#ifndef USE_SPNEGO
+    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without GSS-API
+                                    or SSPI */
+#endif
+
+    /* check if any auth bit lower than CURLAUTH_ONLY is still set */
+    while(bitcheck < 31) {
+      if(auth & (1UL << bitcheck++)) {
+        authbits = TRUE;
+        break;
+      }
+    }
+    if(!authbits)
+      return CURLE_NOT_BUILT_IN; /* no supported types left! */
+  }
+  if(proxy)
+    data->set.proxyauth = auth;
+  else
+    data->set.httpauth = auth;
+  return CURLE_OK;
+}
+
+static CURLcode setopt_long(struct Curl_easy *data, CURLoption option,
+                            long arg)
+{
+  bool enabled = (0 != arg);
+  unsigned long uarg = (unsigned long)arg;
   switch(option) {
   case CURLOPT_DNS_CACHE_TIMEOUT:
-    arg = va_arg(param, long);
     if(arg < -1)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     else if(arg > INT_MAX)
@@ -234,7 +271,6 @@
     break;
   case CURLOPT_CA_CACHE_TIMEOUT:
     if(Curl_ssl_supports(data, SSLSUPP_CA_CACHE)) {
-      arg = va_arg(param, long);
       if(arg < -1)
         return CURLE_BAD_FUNCTION_ARGUMENT;
       else if(arg > INT_MAX)
@@ -245,95 +281,47 @@
     else
       return CURLE_NOT_BUILT_IN;
     break;
-  case CURLOPT_DNS_USE_GLOBAL_CACHE:
-    /* deprecated */
-    break;
-  case CURLOPT_SSL_CIPHER_LIST:
-    if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) {
-      /* set a list of cipher we want to use in the SSL connection */
-      result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],
-                              va_arg(param, char *));
-    }
-    else
-      return CURLE_NOT_BUILT_IN;
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_SSL_CIPHER_LIST:
-    if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) {
-      /* set a list of cipher we want to use in the SSL connection for proxy */
-      result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
-                              va_arg(param, char *));
-    }
-    else
-      return CURLE_NOT_BUILT_IN;
-    break;
-#endif
-  case CURLOPT_TLS13_CIPHERS:
-    if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) {
-      /* set preferred list of TLS 1.3 cipher suites */
-      result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST],
-                              va_arg(param, char *));
-    }
-    else
-      return CURLE_NOT_BUILT_IN;
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_TLS13_CIPHERS:
-    if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) {
-      /* set preferred list of TLS 1.3 cipher suites for proxy */
-      result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_PROXY],
-                              va_arg(param, char *));
-    }
-    else
-      return CURLE_NOT_BUILT_IN;
-    break;
-#endif
-  case CURLOPT_RANDOM_FILE:
-    break;
-  case CURLOPT_EGDSOCKET:
-    break;
   case CURLOPT_MAXCONNECTS:
     /*
      * Set the absolute number of maximum simultaneous alive connection that
      * libcurl is allowed to have.
      */
-    uarg = va_arg(param, unsigned long);
     if(uarg > UINT_MAX)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.maxconnects = (unsigned int)uarg;
     break;
-  case CURLOPT_FORBID_REUSE:
+   case CURLOPT_FORBID_REUSE:
     /*
      * When this transfer is done, it must not be left to be reused by a
      * subsequent transfer but shall be closed immediately.
      */
-    data->set.reuse_forbid = (0 != va_arg(param, long));
+    data->set.reuse_forbid = enabled;
     break;
   case CURLOPT_FRESH_CONNECT:
     /*
      * This transfer shall not use a previously cached connection but
      * should be made with a fresh new connect!
      */
-    data->set.reuse_fresh = (0 != va_arg(param, long));
+    data->set.reuse_fresh = enabled;
     break;
   case CURLOPT_VERBOSE:
     /*
      * Verbose means infof() calls that give a lot of information about
      * the connection and transfer procedures as well as internal choices.
      */
-    data->set.verbose = (0 != va_arg(param, long));
+    data->set.verbose = enabled;
     break;
   case CURLOPT_HEADER:
     /*
      * Set to include the header in the general data output stream.
      */
-    data->set.include_header = (0 != va_arg(param, long));
+    data->set.include_header = enabled;
     break;
   case CURLOPT_NOPROGRESS:
     /*
      * Shut off the internal supported progress meter
      */
-    data->set.hide_progress = (0 != va_arg(param, long));
+    data->set.hide_progress = enabled;
     if(data->set.hide_progress)
       data->progress.flags |= PGRS_HIDE;
     else
@@ -343,7 +331,7 @@
     /*
      * Do not include the body part in the output data stream.
      */
-    data->set.opt_no_body = (0 != va_arg(param, long));
+    data->set.opt_no_body = enabled;
 #ifndef CURL_DISABLE_HTTP
     if(data->set.opt_no_body)
       /* in HTTP lingo, no body means using the HEAD request... */
@@ -357,10 +345,10 @@
      * Do not output the >=400 error code HTML-page, but instead only
      * return error.
      */
-    data->set.http_fail_on_error = (0 != va_arg(param, long));
+    data->set.http_fail_on_error = enabled;
     break;
   case CURLOPT_KEEP_SENDING_ON_ERROR:
-    data->set.http_keep_sending_on_error = (0 != va_arg(param, long));
+    data->set.http_keep_sending_on_error = enabled;
     break;
   case CURLOPT_UPLOAD:
   case CURLOPT_PUT:
@@ -368,7 +356,6 @@
      * We want to sent data to the remote host. If this is HTTP, that equals
      * using the PUT request.
      */
-    arg = va_arg(param, long);
     if(arg) {
       /* If this is HTTP, PUT is what's needed to "upload" */
       data->set.method = HTTPREQ_PUT;
@@ -379,23 +366,18 @@
          then this can be changed to HEAD later on) */
       data->set.method = HTTPREQ_GET;
     break;
-  case CURLOPT_REQUEST_TARGET:
-    result = Curl_setstropt(&data->set.str[STRING_TARGET],
-                            va_arg(param, char *));
-    break;
   case CURLOPT_FILETIME:
     /*
      * Try to get the file time of the remote document. The time will
      * later (possibly) become available using curl_easy_getinfo().
      */
-    data->set.get_filetime = (0 != va_arg(param, long));
+    data->set.get_filetime = enabled;
     break;
   case CURLOPT_SERVER_RESPONSE_TIMEOUT:
     /*
      * Option that specifies how quickly a server response must be obtained
      * before it is considered failure. For pingpong protocols.
      */
-    arg = va_arg(param, long);
     if((arg >= 0) && (arg <= (INT_MAX/1000)))
       data->set.server_response_timeout = (unsigned int)arg * 1000;
     else
@@ -406,7 +388,6 @@
      * Option that specifies how quickly a server response must be obtained
      * before it is considered failure. For pingpong protocols.
      */
-    arg = va_arg(param, long);
     if((arg >= 0) && (arg <= INT_MAX))
       data->set.server_response_timeout = (unsigned int)arg;
     else
@@ -418,13 +399,12 @@
      * Option that prevents libcurl from sending TFTP option requests to the
      * server.
      */
-    data->set.tftp_no_options = va_arg(param, long) != 0;
+    data->set.tftp_no_options = enabled;
     break;
   case CURLOPT_TFTP_BLKSIZE:
     /*
      * TFTP option that specifies the block size to use for data transmission.
      */
-    arg = va_arg(param, long);
     if(arg < TFTP_BLKSIZE_MIN)
       arg = 512;
     else if(arg > TFTP_BLKSIZE_MAX)
@@ -437,18 +417,10 @@
     /*
      * Parse the $HOME/.netrc file
      */
-    arg = va_arg(param, long);
     if((arg < CURL_NETRC_IGNORED) || (arg >= CURL_NETRC_LAST))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.use_netrc = (unsigned char)arg;
     break;
-  case CURLOPT_NETRC_FILE:
-    /*
-     * Use this file instead of the $HOME/.netrc file
-     */
-    result = Curl_setstropt(&data->set.str[STRING_NETRC_FILE],
-                            va_arg(param, char *));
-    break;
 #endif
   case CURLOPT_TRANSFERTEXT:
     /*
@@ -457,14 +429,13 @@
      *
      * Transfer using ASCII (instead of BINARY).
      */
-    data->set.prefer_ascii = (0 != va_arg(param, long));
+    data->set.prefer_ascii = enabled;
     break;
   case CURLOPT_TIMECONDITION:
     /*
      * Set HTTP time condition. This must be one of the defines in the
      * curl/curl.h header file.
      */
-    arg = va_arg(param, long);
     if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.timecondition = (unsigned char)(curl_TimeCond)arg;
@@ -474,17 +445,8 @@
      * This is the value to compare with the remote document with the
      * method set with CURLOPT_TIMECONDITION
      */
-    data->set.timevalue = (time_t)va_arg(param, long);
+    data->set.timevalue = (time_t)arg;
     break;
-
-  case CURLOPT_TIMEVALUE_LARGE:
-    /*
-     * This is the value to compare with the remote document with the
-     * method set with CURLOPT_TIMECONDITION
-     */
-    data->set.timevalue = (time_t)va_arg(param, curl_off_t);
-    break;
-
   case CURLOPT_SSLVERSION:
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_SSLVERSION:
@@ -501,9 +463,6 @@
       if(option != CURLOPT_SSLVERSION)
         primary = &data->set.proxy_ssl.primary;
 #endif
-
-      arg = va_arg(param, long);
-
       version = C_SSLVERSION_VALUE(arg);
       version_max = (long)C_SSLVERSION_MAX_VALUE(arg);
 
@@ -519,136 +478,54 @@
       primary->version_max = (unsigned int)version_max;
     }
 #else
-    result = CURLE_NOT_BUILT_IN;
+    return CURLE_NOT_BUILT_IN;
 #endif
     break;
-
-    /* MQTT "borrows" some of the HTTP options */
-#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT)
-  case CURLOPT_COPYPOSTFIELDS:
-    /*
-     * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
-     * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to
-     *  CURLOPT_COPYPOSTFIELDS and not altered later.
-     */
-    argptr = va_arg(param, char *);
-
-    if(!argptr || data->set.postfieldsize == -1)
-      result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr);
-    else {
-      /*
-       *  Check that requested length does not overflow the size_t type.
-       */
-
-      if((data->set.postfieldsize < 0) ||
-         ((sizeof(curl_off_t) != sizeof(size_t)) &&
-          (data->set.postfieldsize > (curl_off_t)((size_t)-1))))
-        result = CURLE_OUT_OF_MEMORY;
-      else {
-        /* Allocate even when size == 0. This satisfies the need of possible
-           later address compare to detect the COPYPOSTFIELDS mode, and to
-           mark that postfields is used rather than read function or form
-           data.
-        */
-        char *p = Curl_memdup0(argptr, (size_t)data->set.postfieldsize);
-        if(!p)
-          result = CURLE_OUT_OF_MEMORY;
-        else {
-          free(data->set.str[STRING_COPYPOSTFIELDS]);
-          data->set.str[STRING_COPYPOSTFIELDS] = p;
-        }
-      }
-    }
-
-    data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
-    data->set.method = HTTPREQ_POST;
-    break;
-
-  case CURLOPT_POSTFIELDS:
-    /*
-     * Like above, but use static data instead of copying it.
-     */
-    data->set.postfields = va_arg(param, void *);
-    /* Release old copied data. */
-    Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
-    data->set.method = HTTPREQ_POST;
-    break;
-
   case CURLOPT_POSTFIELDSIZE:
     /*
      * The size of the POSTFIELD data to prevent libcurl to do strlen() to
      * figure it out. Enables binary posts.
      */
-    bigsize = va_arg(param, long);
-    if(bigsize < -1)
+    if(arg < -1)
       return CURLE_BAD_FUNCTION_ARGUMENT;
 
-    if(data->set.postfieldsize < bigsize &&
+    if(data->set.postfieldsize < arg &&
        data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
       /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
       Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
       data->set.postfields = NULL;
     }
 
-    data->set.postfieldsize = bigsize;
+    data->set.postfieldsize = arg;
     break;
-
-  case CURLOPT_POSTFIELDSIZE_LARGE:
+#ifndef CURL_DISABLE_HTTP
+#if !defined(CURL_DISABLE_COOKIES)
+  case CURLOPT_COOKIESESSION:
     /*
-     * The size of the POSTFIELD data to prevent libcurl to do strlen() to
-     * figure it out. Enables binary posts.
+     * Set this option to TRUE to start a new "cookie session". It will
+     * prevent the forthcoming read-cookies-from-file actions to accept
+     * cookies that are marked as being session cookies, as they belong to a
+     * previous session.
      */
-    bigsize = va_arg(param, curl_off_t);
-    if(bigsize < -1)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-
-    if(data->set.postfieldsize < bigsize &&
-       data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
-      /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
-      Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
-      data->set.postfields = NULL;
-    }
-
-    data->set.postfieldsize = bigsize;
+    data->set.cookiesession = enabled;
     break;
 #endif
-#ifndef CURL_DISABLE_HTTP
   case CURLOPT_AUTOREFERER:
     /*
      * Switch on automatic referer that gets set if curl follows locations.
      */
-    data->set.http_auto_referer = (0 != va_arg(param, long));
-    break;
-
-  case CURLOPT_ACCEPT_ENCODING:
-    /*
-     * String to use at the value of Accept-Encoding header.
-     *
-     * If the encoding is set to "" we use an Accept-Encoding header that
-     * encompasses all the encodings we support.
-     * If the encoding is set to NULL we do not send an Accept-Encoding header
-     * and ignore an received Content-Encoding header.
-     *
-     */
-    argptr = va_arg(param, char *);
-    if(argptr && !*argptr) {
-      char all[256];
-      Curl_all_content_encodings(all, sizeof(all));
-      result = Curl_setstropt(&data->set.str[STRING_ENCODING], all);
-    }
-    else
-      result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
+    data->set.http_auto_referer = enabled;
     break;
 
   case CURLOPT_TRANSFER_ENCODING:
-    data->set.http_transfer_encoding = (0 != va_arg(param, long));
+    data->set.http_transfer_encoding = enabled;
     break;
 
   case CURLOPT_FOLLOWLOCATION:
     /*
      * Follow Location: header hints on an HTTP-server.
      */
-    data->set.http_follow_location = (0 != va_arg(param, long));
+    data->set.http_follow_location = enabled;
     break;
 
   case CURLOPT_UNRESTRICTED_AUTH:
@@ -656,7 +533,7 @@
      * Send authentication (user+password) when following locations, even when
      * hostname changed.
      */
-    data->set.allow_auth_to_other_hosts = (0 != va_arg(param, long));
+    data->set.allow_auth_to_other_hosts = enabled;
     break;
 
   case CURLOPT_MAXREDIRS:
@@ -664,7 +541,6 @@
      * The maximum amount of hops you allow curl to follow Location:
      * headers. This should mostly be used to detect never-ending loops.
      */
-    arg = va_arg(param, long);
     if(arg < -1)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.maxredirs = arg;
@@ -680,7 +556,6 @@
      * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
      * other - POST is kept as POST after 301 and 302
      */
-    arg = va_arg(param, long);
     if(arg < CURL_REDIR_GET_ALL)
       /* no return error on too high numbers since the bitmask could be
          extended in a future */
@@ -692,228 +567,27 @@
     /* Does this option serve a purpose anymore? Yes it does, when
        CURLOPT_POSTFIELDS is not used and the POST data is read off the
        callback! */
-    if(va_arg(param, long)) {
+    if(arg) {
       data->set.method = HTTPREQ_POST;
       data->set.opt_no_body = FALSE; /* this is implied */
     }
     else
       data->set.method = HTTPREQ_GET;
     break;
-
-#ifndef CURL_DISABLE_FORM_API
-  case CURLOPT_HTTPPOST:
-    /*
-     * Set to make us do HTTP POST. Legacy API-style.
-     */
-    data->set.httppost = va_arg(param, struct curl_httppost *);
-    data->set.method = HTTPREQ_POST_FORM;
-    data->set.opt_no_body = FALSE; /* this is implied */
-    Curl_mime_cleanpart(data->state.formp);
-    Curl_safefree(data->state.formp);
-    data->state.mimepost = NULL;
-    break;
-#endif
-
-#if !defined(CURL_DISABLE_AWS)
-  case CURLOPT_AWS_SIGV4:
-    /*
-     * String that is merged to some authentication
-     * parameters are used by the algorithm.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_AWS_SIGV4],
-                            va_arg(param, char *));
-    /*
-     * Basic been set by default it need to be unset here
-     */
-    if(data->set.str[STRING_AWS_SIGV4])
-      data->set.httpauth = CURLAUTH_AWS_SIGV4;
-    break;
-#endif
-
-  case CURLOPT_REFERER:
-    /*
-     * String to set in the HTTP Referer: field.
-     */
-    if(data->state.referer_alloc) {
-      Curl_safefree(data->state.referer);
-      data->state.referer_alloc = FALSE;
-    }
-    result = Curl_setstropt(&data->set.str[STRING_SET_REFERER],
-                            va_arg(param, char *));
-    data->state.referer = data->set.str[STRING_SET_REFERER];
-    break;
-
-  case CURLOPT_USERAGENT:
-    /*
-     * String to use in the HTTP User-Agent field
-     */
-    result = Curl_setstropt(&data->set.str[STRING_USERAGENT],
-                            va_arg(param, char *));
-    break;
-
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXYHEADER:
-    /*
-     * Set a list with proxy headers to use (or replace internals with)
-     *
-     * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a
-     * long time we remain doing it this way until CURLOPT_PROXYHEADER is
-     * used. As soon as this option has been used, if set to anything but
-     * NULL, custom headers for proxies are only picked from this list.
-     *
-     * Set this option to NULL to restore the previous behavior.
-     */
-    data->set.proxyheaders = va_arg(param, struct curl_slist *);
-    break;
-#endif
   case CURLOPT_HEADEROPT:
     /*
      * Set header option.
      */
-    arg = va_arg(param, long);
     data->set.sep_headers = !!(arg & CURLHEADER_SEPARATE);
     break;
-
-#if !defined(CURL_DISABLE_COOKIES)
-  case CURLOPT_COOKIE:
-    /*
-     * Cookie string to send to the remote server in the request.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_COOKIE],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_COOKIEFILE:
-    /*
-     * Set cookie file to read and parse. Can be used multiple times.
-     */
-    argptr = (char *)va_arg(param, void *);
-    if(argptr) {
-      struct curl_slist *cl;
-      /* general protection against mistakes and abuse */
-      if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
-        return CURLE_BAD_FUNCTION_ARGUMENT;
-      /* append the cookie filename to the list of filenames, and deal with
-         them later */
-      cl = curl_slist_append(data->state.cookielist, argptr);
-      if(!cl) {
-        curl_slist_free_all(data->state.cookielist);
-        data->state.cookielist = NULL;
-        return CURLE_OUT_OF_MEMORY;
-      }
-      data->state.cookielist = cl; /* store the list for later use */
-    }
-    else {
-      /* clear the list of cookie files */
-      curl_slist_free_all(data->state.cookielist);
-      data->state.cookielist = NULL;
-
-      if(!data->share || !data->share->cookies) {
-        /* throw away all existing cookies if this is not a shared cookie
-           container */
-        Curl_cookie_clearall(data->cookies);
-        Curl_cookie_cleanup(data->cookies);
-      }
-      /* disable the cookie engine */
-      data->cookies = NULL;
-    }
-    break;
-
-  case CURLOPT_COOKIEJAR:
-    /*
-     * Set cookie filename to dump all cookies to when we are done.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR],
-                            va_arg(param, char *));
-    if(!result) {
-      /*
-       * Activate the cookie parser. This may or may not already
-       * have been made.
-       */
-      struct CookieInfo *newcookies =
-        Curl_cookie_init(data, NULL, data->cookies, data->set.cookiesession);
-      if(!newcookies)
-        result = CURLE_OUT_OF_MEMORY;
-      data->cookies = newcookies;
-    }
-    break;
-
-  case CURLOPT_COOKIESESSION:
-    /*
-     * Set this option to TRUE to start a new "cookie session". It will
-     * prevent the forthcoming read-cookies-from-file actions to accept
-     * cookies that are marked as being session cookies, as they belong to a
-     * previous session.
-     */
-    data->set.cookiesession = (0 != va_arg(param, long));
-    break;
-
-  case CURLOPT_COOKIELIST:
-    argptr = va_arg(param, char *);
-
-    if(!argptr)
-      break;
-
-    if(strcasecompare(argptr, "ALL")) {
-      /* clear all cookies */
-      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
-      Curl_cookie_clearall(data->cookies);
-      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
-    }
-    else if(strcasecompare(argptr, "SESS")) {
-      /* clear session cookies */
-      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
-      Curl_cookie_clearsess(data->cookies);
-      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
-    }
-    else if(strcasecompare(argptr, "FLUSH")) {
-      /* flush cookies to file, takes care of the locking */
-      Curl_flush_cookies(data, FALSE);
-    }
-    else if(strcasecompare(argptr, "RELOAD")) {
-      /* reload cookies from file */
-      Curl_cookie_loadfiles(data);
-      break;
-    }
-    else {
-      if(!data->cookies)
-        /* if cookie engine was not running, activate it */
-        data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
-
-      /* general protection against mistakes and abuse */
-      if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
-        return CURLE_BAD_FUNCTION_ARGUMENT;
-      argptr = strdup(argptr);
-      if(!argptr || !data->cookies) {
-        result = CURLE_OUT_OF_MEMORY;
-        free(argptr);
-      }
-      else {
-        Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
-
-        if(checkprefix("Set-Cookie:", argptr))
-          /* HTTP Header format line */
-          Curl_cookie_add(data, data->cookies, TRUE, FALSE, argptr + 11, NULL,
-                          NULL, TRUE);
-
-        else
-          /* Netscape format line */
-          Curl_cookie_add(data, data->cookies, FALSE, FALSE, argptr, NULL,
-                          NULL, TRUE);
-
-        Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
-        free(argptr);
-      }
-    }
-
-    break;
-#endif /* !CURL_DISABLE_COOKIES */
+  case CURLOPT_HTTPAUTH:
+    return httpauth(data, FALSE, uarg);
 
   case CURLOPT_HTTPGET:
     /*
      * Set to force us do HTTP GET
      */
-    if(va_arg(param, long)) {
+    if(enabled) {
       data->set.method = HTTPREQ_GET;
       data->set.opt_no_body = FALSE; /* this is implied */
     }
@@ -924,7 +598,6 @@
      * This sets a requested HTTP version to be used. The value is one of
      * the listed enums in curl/curl.h.
      */
-    arg = va_arg(param, long);
     switch(arg) {
     case CURL_HTTP_VERSION_NONE:
 #ifdef USE_HTTP2
@@ -965,226 +638,51 @@
      * Time to wait for a response to an HTTP request containing an
      * Expect: 100-continue header before sending the data anyway.
      */
-    arg = va_arg(param, long);
     if(arg < 0)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.expect_100_timeout = arg;
     break;
 
   case CURLOPT_HTTP09_ALLOWED:
-    arg = (long)va_arg(param, unsigned long);
-    if(arg > 1L)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
 #ifdef USE_HYPER
     /* Hyper does not support HTTP/0.9 */
-    if(arg)
+    if(enabled)
       return CURLE_BAD_FUNCTION_ARGUMENT;
 #else
-    data->set.http09_allowed = !!arg;
+    data->set.http09_allowed = enabled;
 #endif
     break;
+#endif /* ! CURL_DISABLE_HTTP */
 
-  case CURLOPT_HTTP200ALIASES:
-    /*
-     * Set a list of aliases for HTTP 200 in response header
-     */
-    data->set.http200aliases = va_arg(param, struct curl_slist *);
-    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 */
-#ifndef CURL_DISABLE_FORM_API
-      Curl_mime_cleanpart(data->state.formp);
-      Curl_safefree(data->state.formp);
-      data->state.mimepost = NULL;
-#endif
-    }
-    break;
-
+#ifndef CURL_DISABLE_MIME
   case CURLOPT_MIME_OPTIONS:
-    arg = va_arg(param, long);
     data->set.mime_formescape = !!(arg & CURLMIMEOPT_FORMESCAPE);
-  break;
-# endif
-#endif
-
-  case CURLOPT_HTTPAUTH:
-    /*
-     * Set HTTP Authentication type BITMASK.
-     */
-  {
-    int bitcheck;
-    bool authbits;
-    unsigned long auth = va_arg(param, unsigned long);
-
-    if(auth == CURLAUTH_NONE) {
-      data->set.httpauth = auth;
-      break;
-    }
-
-    /* the DIGEST_IE bit is only used to set a special marker, for all the
-       rest we need to handle it as normal DIGEST */
-    data->state.authhost.iestyle = !!(auth & CURLAUTH_DIGEST_IE);
-
-    if(auth & CURLAUTH_DIGEST_IE) {
-      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
-      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
-    }
-
-    /* switch off bits we cannot support */
-#ifndef USE_NTLM
-    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
-#endif
-#ifndef USE_SPNEGO
-    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
-                                    GSS-API or SSPI */
-#endif
-
-    /* check if any auth bit lower than CURLAUTH_ONLY is still set */
-    bitcheck = 0;
-    authbits = FALSE;
-    while(bitcheck < 31) {
-      if(auth & (1UL << bitcheck++)) {
-        authbits = TRUE;
-        break;
-      }
-    }
-    if(!authbits)
-      return CURLE_NOT_BUILT_IN; /* no supported types left! */
-
-    data->set.httpauth = auth;
-  }
-  break;
-
-  case CURLOPT_CUSTOMREQUEST:
-    /*
-     * Set a custom string to use as request
-     */
-    result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST],
-                            va_arg(param, char *));
-
-    /* we do not set
-       data->set.method = HTTPREQ_CUSTOM;
-       here, we continue as if we were using the already set type
-       and this just changes the actual request keyword */
     break;
-
+#endif
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_HTTPPROXYTUNNEL:
     /*
      * Tunnel operations through the proxy instead of normal proxy use
      */
-    data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long));
+    data->set.tunnel_thru_httpproxy = enabled;
     break;
 
   case CURLOPT_PROXYPORT:
     /*
      * Explicitly set HTTP proxy port number.
      */
-    arg = va_arg(param, long);
     if((arg < 0) || (arg > 65535))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.proxyport = (unsigned short)arg;
     break;
 
   case CURLOPT_PROXYAUTH:
-    /*
-     * Set HTTP Authentication type BITMASK.
-     */
-  {
-    int bitcheck;
-    bool authbits;
-    unsigned long auth = va_arg(param, unsigned long);
-
-    if(auth == CURLAUTH_NONE) {
-      data->set.proxyauth = auth;
-      break;
-    }
-
-    /* the DIGEST_IE bit is only used to set a special marker, for all the
-       rest we need to handle it as normal DIGEST */
-    data->state.authproxy.iestyle = !!(auth & CURLAUTH_DIGEST_IE);
-
-    if(auth & CURLAUTH_DIGEST_IE) {
-      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
-      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
-    }
-    /* switch off bits we cannot support */
-#ifndef USE_NTLM
-    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
-#endif
-#ifndef USE_SPNEGO
-    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
-                                    GSS-API or SSPI */
-#endif
-
-    /* check if any auth bit lower than CURLAUTH_ONLY is still set */
-    bitcheck = 0;
-    authbits = FALSE;
-    while(bitcheck < 31) {
-      if(auth & (1UL << bitcheck++)) {
-        authbits = TRUE;
-        break;
-      }
-    }
-    if(!authbits)
-      return CURLE_NOT_BUILT_IN; /* no supported types left! */
-
-    data->set.proxyauth = auth;
-  }
-  break;
-
-  case CURLOPT_PROXY:
-    /*
-     * Set proxy server:port to use as proxy.
-     *
-     * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL)
-     * we explicitly say that we do not want to use a proxy
-     * (even though there might be environment variables saying so).
-     *
-     * Setting it to NULL, means no proxy but allows the environment variables
-     * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL).
-     */
-    result = Curl_setstropt(&data->set.str[STRING_PROXY],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_PRE_PROXY:
-    /*
-     * Set proxy server:port to use as SOCKS proxy.
-     *
-     * If the proxy is set to "" or NULL we explicitly say that we do not want
-     * to use the socks proxy.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY],
-                            va_arg(param, char *));
-    break;
+    return httpauth(data, TRUE, uarg);
 
   case CURLOPT_PROXYTYPE:
     /*
      * Set proxy type.
      */
-    arg = va_arg(param, long);
     if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.proxytype = (unsigned char)(curl_proxytype)arg;
@@ -1194,81 +692,57 @@
     /*
      * set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy
      */
-    switch(va_arg(param, long)) {
-    case 0:
-      data->set.proxy_transfer_mode = FALSE;
-      break;
-    case 1:
-      data->set.proxy_transfer_mode = TRUE;
-      break;
-    default:
+    if(uarg > 1)
       /* reserve other values for future use */
-      result = CURLE_BAD_FUNCTION_ARGUMENT;
-      break;
-    }
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.proxy_transfer_mode = (bool)uarg;
     break;
-
   case CURLOPT_SOCKS5_AUTH:
-    data->set.socks5auth = (unsigned char)va_arg(param, unsigned long);
     if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
-      result = CURLE_NOT_BUILT_IN;
+      return CURLE_NOT_BUILT_IN;
+    data->set.socks5auth = (unsigned char)uarg;
     break;
-#endif   /* CURL_DISABLE_PROXY */
+  case CURLOPT_HAPROXYPROTOCOL:
+    /*
+     * Set to send the HAProxy Proxy Protocol header
+     */
+    data->set.haproxyprotocol = enabled;
+    break;
+  case CURLOPT_PROXY_SSL_VERIFYPEER:
+    /*
+     * Enable peer SSL verifying for proxy.
+     */
+    data->set.proxy_ssl.primary.verifypeer = enabled;
+
+    /* Update the current connection proxy_ssl_config. */
+    Curl_ssl_conn_config_update(data, TRUE);
+    break;
+  case CURLOPT_PROXY_SSL_VERIFYHOST:
+    /*
+     * Enable verification of the hostname in the peer certificate for proxy
+     */
+    data->set.proxy_ssl.primary.verifyhost = enabled;
+
+    /* Update the current connection proxy_ssl_config. */
+    Curl_ssl_conn_config_update(data, TRUE);
+    break;
+#endif /* ! CURL_DISABLE_PROXY */
 
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
   case CURLOPT_SOCKS5_GSSAPI_NEC:
     /*
      * Set flag for NEC SOCK5 support
      */
-    data->set.socks5_gssapi_nec = (0 != va_arg(param, long));
+    data->set.socks5_gssapi_nec = enabled;
     break;
 #endif
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_SOCKS5_GSSAPI_SERVICE:
-  case CURLOPT_PROXY_SERVICE_NAME:
-    /*
-     * Set proxy authentication service name for Kerberos 5 and SPNEGO
-     */
-    result = Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME],
-                            va_arg(param, char *));
-    break;
-#endif
-  case CURLOPT_SERVICE_NAME:
-    /*
-     * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SERVICE_NAME],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_HEADERDATA:
-    /*
-     * Custom pointer to pass the header write callback function
-     */
-    data->set.writeheader = (void *)va_arg(param, void *);
-    break;
-  case CURLOPT_ERRORBUFFER:
-    /*
-     * Error buffer provided by the caller to get the human readable
-     * error string in.
-     */
-    data->set.errorbuffer = va_arg(param, char *);
-    break;
-  case CURLOPT_WRITEDATA:
-    /*
-     * FILE pointer to write to. Or possibly
-     * used as argument to the write callback.
-     */
-    data->set.out = va_arg(param, void *);
-    break;
-
 #ifdef CURL_LIST_ONLY_PROTOCOL
   case CURLOPT_DIRLISTONLY:
     /*
      * An option that changes the command to one that asks for a list only, no
      * file info details. Used for FTP, POP3 and SFTP.
      */
-    data->set.list_only = (0 != va_arg(param, long));
+    data->set.list_only = enabled;
     break;
 #endif
   case CURLOPT_APPEND:
@@ -1276,7 +750,7 @@
      * We want to upload and append to an existing file. Used for FTP and
      * SFTP.
      */
-    data->set.remote_append = (0 != va_arg(param, long));
+    data->set.remote_append = enabled;
     break;
 
 #ifndef CURL_DISABLE_FTP
@@ -1284,34 +758,23 @@
     /*
      * How do access files over FTP.
      */
-    arg = va_arg(param, long);
     if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.ftp_filemethod = (unsigned char)arg;
     break;
-  case CURLOPT_FTPPORT:
-    /*
-     * Use FTP PORT, this also specifies which IP address to use
-     */
-    result = Curl_setstropt(&data->set.str[STRING_FTPPORT],
-                            va_arg(param, char *));
-    data->set.ftp_use_port = !!(data->set.str[STRING_FTPPORT]);
-    break;
-
   case CURLOPT_FTP_USE_EPRT:
-    data->set.ftp_use_eprt = (0 != va_arg(param, long));
+    data->set.ftp_use_eprt = enabled;
     break;
 
   case CURLOPT_FTP_USE_EPSV:
-    data->set.ftp_use_epsv = (0 != va_arg(param, long));
+    data->set.ftp_use_epsv = enabled;
     break;
 
   case CURLOPT_FTP_USE_PRET:
-    data->set.ftp_use_pret = (0 != va_arg(param, long));
+    data->set.ftp_use_pret = enabled;
     break;
 
   case CURLOPT_FTP_SSL_CCC:
-    arg = va_arg(param, long);
     if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.ftp_ccc = (unsigned char)arg;
@@ -1322,164 +785,72 @@
      * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
      * bypass of the IP address in PASV responses.
      */
-    data->set.ftp_skip_ip = (0 != va_arg(param, long));
-    break;
-
-  case CURLOPT_FTP_ACCOUNT:
-    result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_FTP_ALTERNATIVE_TO_USER:
-    result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
-                            va_arg(param, char *));
+    data->set.ftp_skip_ip = enabled;
     break;
 
   case CURLOPT_FTPSSLAUTH:
     /*
      * Set a specific auth for FTP-SSL transfers.
      */
-    arg = va_arg(param, long);
     if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.ftpsslauth = (unsigned char)(curl_ftpauth)arg;
     break;
-#ifdef HAVE_GSSAPI
-  case CURLOPT_KRBLEVEL:
+  case CURLOPT_ACCEPTTIMEOUT_MS:
     /*
-     * A string that defines the kerberos security level.
+     * The maximum time for curl to wait for FTP server connect
      */
-    result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL],
-                            va_arg(param, char *));
-    data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]);
+    if(uarg > UINT_MAX)
+      uarg = UINT_MAX;
+    data->set.accepttimeout = (unsigned int)uarg;
     break;
-#endif
-#endif
+  case CURLOPT_WILDCARDMATCH:
+    data->set.wildcard_enabled = enabled;
+    break;
+#endif /* ! CURL_DISABLE_FTP */
 #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
   case CURLOPT_FTP_CREATE_MISSING_DIRS:
     /*
      * An FTP/SFTP option that modifies an upload to create missing
      * directories on the server.
      */
-    arg = va_arg(param, long);
     /* reserve other values for future use */
-    if((arg < CURLFTP_CREATE_DIR_NONE) ||
-       (arg > CURLFTP_CREATE_DIR_RETRY))
-      result = CURLE_BAD_FUNCTION_ARGUMENT;
-    else
-      data->set.ftp_create_missing_dirs = (unsigned char)arg;
+    if((arg < CURLFTP_CREATE_DIR_NONE) || (arg > CURLFTP_CREATE_DIR_RETRY))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.ftp_create_missing_dirs = (unsigned char)arg;
     break;
-
-  case CURLOPT_POSTQUOTE:
-    /*
-     * List of RAW FTP commands to use after a transfer
-     */
-    data->set.postquote = va_arg(param, struct curl_slist *);
-    break;
-  case CURLOPT_PREQUOTE:
-    /*
-     * List of RAW FTP commands to use prior to RETR (Wesley Laxton)
-     */
-    data->set.prequote = va_arg(param, struct curl_slist *);
-    break;
-  case CURLOPT_QUOTE:
-    /*
-     * List of RAW FTP commands to use before a transfer
-     */
-    data->set.quote = va_arg(param, struct curl_slist *);
-    break;
-#endif
-  case CURLOPT_READDATA:
-    /*
-     * FILE pointer to read the file to be uploaded from. Or possibly
-     * used as argument to the read callback.
-     */
-    data->set.in_set = va_arg(param, void *);
-    break;
+#endif /* ! CURL_DISABLE_FTP || USE_SSH */
   case CURLOPT_INFILESIZE:
     /*
      * If known, this should inform curl about the file size of the
      * to-be-uploaded file.
      */
-    arg = va_arg(param, long);
     if(arg < -1)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.filesize = arg;
     break;
-  case CURLOPT_INFILESIZE_LARGE:
-    /*
-     * If known, this should inform curl about the file size of the
-     * to-be-uploaded file.
-     */
-    bigsize = va_arg(param, curl_off_t);
-    if(bigsize < -1)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.filesize = bigsize;
-    break;
   case CURLOPT_LOW_SPEED_LIMIT:
     /*
      * The low speed limit that if transfers are below this for
      * CURLOPT_LOW_SPEED_TIME, the transfer is aborted.
      */
-    arg = va_arg(param, long);
     if(arg < 0)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.low_speed_limit = arg;
     break;
-  case CURLOPT_MAX_SEND_SPEED_LARGE:
-    /*
-     * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE
-     * bytes per second the transfer is throttled..
-     */
-    bigsize = va_arg(param, curl_off_t);
-    if(bigsize < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.max_send_speed = bigsize;
-    break;
-  case CURLOPT_MAX_RECV_SPEED_LARGE:
-    /*
-     * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per
-     * second the transfer is throttled..
-     */
-    bigsize = va_arg(param, curl_off_t);
-    if(bigsize < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.max_recv_speed = bigsize;
-    break;
   case CURLOPT_LOW_SPEED_TIME:
     /*
      * The low speed time that if transfers are below the set
      * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted.
      */
-    arg = va_arg(param, long);
     if(arg < 0)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.low_speed_time = arg;
     break;
-  case CURLOPT_CURLU:
-    /*
-     * pass CURLU to set URL
-     */
-    data->set.uh = va_arg(param, CURLU *);
-    break;
-  case CURLOPT_URL:
-    /*
-     * The URL to fetch.
-     */
-    if(data->state.url_alloc) {
-      /* the already set URL is allocated, free it first! */
-      Curl_safefree(data->state.url);
-      data->state.url_alloc = FALSE;
-    }
-    result = Curl_setstropt(&data->set.str[STRING_SET_URL],
-                            va_arg(param, char *));
-    data->state.url = data->set.str[STRING_SET_URL];
-    break;
   case CURLOPT_PORT:
     /*
      * The port number to use when getting the URL. 0 disables it.
      */
-    arg = va_arg(param, long);
     if((arg < 0) || (arg > 65535))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.use_port = (unsigned short)arg;
@@ -1489,7 +860,6 @@
      * The maximum time you allow curl to use for a single transfer
      * operation.
      */
-    arg = va_arg(param, long);
     if((arg >= 0) && (arg <= (INT_MAX/1000)))
       data->set.timeout = (unsigned int)arg * 1000;
     else
@@ -1497,7 +867,6 @@
     break;
 
   case CURLOPT_TIMEOUT_MS:
-    uarg = va_arg(param, unsigned long);
     if(uarg > UINT_MAX)
       uarg = UINT_MAX;
     data->set.timeout = (unsigned int)uarg;
@@ -1507,7 +876,6 @@
     /*
      * The maximum time you allow curl to use to connect.
      */
-    arg = va_arg(param, long);
     if((arg >= 0) && (arg <= (INT_MAX/1000)))
       data->set.connecttimeout = (unsigned int)arg * 1000;
     else
@@ -1515,423 +883,32 @@
     break;
 
   case CURLOPT_CONNECTTIMEOUT_MS:
-    uarg = va_arg(param, unsigned long);
     if(uarg > UINT_MAX)
       uarg = UINT_MAX;
     data->set.connecttimeout = (unsigned int)uarg;
     break;
 
-#ifndef CURL_DISABLE_FTP
-  case CURLOPT_ACCEPTTIMEOUT_MS:
-    /*
-     * The maximum time for curl to wait for FTP server connect
-     */
-    uarg = va_arg(param, unsigned long);
-    if(uarg > UINT_MAX)
-      uarg = UINT_MAX;
-    data->set.accepttimeout = (unsigned int)uarg;
-    break;
-#endif
-
-  case CURLOPT_USERPWD:
-    /*
-     * user:password to use in the operation
-     */
-    result = setstropt_userpwd(va_arg(param, char *),
-                               &data->set.str[STRING_USERNAME],
-                               &data->set.str[STRING_PASSWORD]);
-    break;
-
-  case CURLOPT_USERNAME:
-    /*
-     * authentication username to use in the operation
-     */
-    result = Curl_setstropt(&data->set.str[STRING_USERNAME],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_PASSWORD:
-    /*
-     * authentication password to use in the operation
-     */
-    result = Curl_setstropt(&data->set.str[STRING_PASSWORD],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_LOGIN_OPTIONS:
-    /*
-     * authentication options to use in the operation
-     */
-    result = Curl_setstropt(&data->set.str[STRING_OPTIONS],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_XOAUTH2_BEARER:
-    /*
-     * OAuth 2.0 bearer token to use in the operation
-     */
-    result = Curl_setstropt(&data->set.str[STRING_BEARER],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_RESOLVE:
-    /*
-     * List of HOST:PORT:[addresses] strings to populate the DNS cache with
-     * Entries added this way will remain in the cache until explicitly
-     * removed or the handle is cleaned up.
-     *
-     * Prefix the HOST with plus sign (+) to have the entry expire just like
-     * automatically added entries.
-     *
-     * Prefix the HOST with dash (-) to _remove_ the entry from the cache.
-     *
-     * This API can remove any entry from the DNS cache, but only entries
-     * that are not actually in use right now will be pruned immediately.
-     */
-    data->set.resolve = va_arg(param, struct curl_slist *);
-    data->state.resolve = data->set.resolve;
-    break;
-  case CURLOPT_PROGRESSFUNCTION:
-    /*
-     * Progress callback function
-     */
-    data->set.fprogress = va_arg(param, curl_progress_callback);
-    if(data->set.fprogress)
-      data->progress.callback = TRUE; /* no longer internal */
-    else
-      data->progress.callback = FALSE; /* NULL enforces internal */
-    break;
-
-  case CURLOPT_XFERINFOFUNCTION:
-    /*
-     * Transfer info callback function
-     */
-    data->set.fxferinfo = va_arg(param, curl_xferinfo_callback);
-    if(data->set.fxferinfo)
-      data->progress.callback = TRUE; /* no longer internal */
-    else
-      data->progress.callback = FALSE; /* NULL enforces internal */
-
-    break;
-
-  case CURLOPT_PROGRESSDATA:
-    /*
-     * Custom client data to pass to the progress callback
-     */
-    data->set.progress_client = va_arg(param, void *);
-    break;
-
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXYUSERPWD: {
-    /*
-     * user:password needed to use the proxy
-     */
-    char *u = NULL;
-    char *p = NULL;
-    result = setstropt_userpwd(va_arg(param, char *), &u, &p);
-
-    /* URL decode the components */
-    if(!result && u)
-      result = Curl_urldecode(u, 0, &data->set.str[STRING_PROXYUSERNAME], NULL,
-                              REJECT_ZERO);
-    if(!result && p)
-      result = Curl_urldecode(p, 0, &data->set.str[STRING_PROXYPASSWORD], NULL,
-                              REJECT_ZERO);
-    free(u);
-    free(p);
-  }
-    break;
-  case CURLOPT_PROXYUSERNAME:
-    /*
-     * authentication username to use in the operation
-     */
-    result = Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_PROXYPASSWORD:
-    /*
-     * authentication password to use in the operation
-     */
-    result = Curl_setstropt(&data->set.str[STRING_PROXYPASSWORD],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_NOPROXY:
-    /*
-     * proxy exception list
-     */
-    result = Curl_setstropt(&data->set.str[STRING_NOPROXY],
-                            va_arg(param, char *));
-    break;
-#endif
-
-  case CURLOPT_RANGE:
-    /*
-     * What range of the file you want to transfer
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SET_RANGE],
-                            va_arg(param, char *));
-    break;
   case CURLOPT_RESUME_FROM:
     /*
      * Resume transfer at the given file position
      */
-    arg = va_arg(param, long);
     if(arg < -1)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.set_resume_from = arg;
     break;
-  case CURLOPT_RESUME_FROM_LARGE:
-    /*
-     * Resume transfer at the given file position
-     */
-    bigsize = va_arg(param, curl_off_t);
-    if(bigsize < -1)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.set_resume_from = bigsize;
-    break;
-  case CURLOPT_DEBUGFUNCTION:
-    /*
-     * stderr write callback.
-     */
-    data->set.fdebug = va_arg(param, curl_debug_callback);
-    /*
-     * if the callback provided is NULL, it will use the default callback
-     */
-    break;
-  case CURLOPT_DEBUGDATA:
-    /*
-     * Set to a void * that should receive all error writes. This
-     * defaults to CURLOPT_STDERR for normal operations.
-     */
-    data->set.debugdata = va_arg(param, void *);
-    break;
-  case CURLOPT_STDERR:
-    /*
-     * Set to a FILE * that should receive all error writes. This
-     * defaults to stderr for normal operations.
-     */
-    data->set.err = va_arg(param, FILE *);
-    if(!data->set.err)
-      data->set.err = stderr;
-    break;
-  case CURLOPT_HEADERFUNCTION:
-    /*
-     * Set header write callback
-     */
-    data->set.fwrite_header = va_arg(param, curl_write_callback);
-    break;
-  case CURLOPT_WRITEFUNCTION:
-    /*
-     * Set data write callback
-     */
-    data->set.fwrite_func = va_arg(param, curl_write_callback);
-    if(!data->set.fwrite_func)
-      /* When set to NULL, reset to our internal default function */
-      data->set.fwrite_func = (curl_write_callback)fwrite;
-    break;
-  case CURLOPT_READFUNCTION:
-    /*
-     * Read data callback
-     */
-    data->set.fread_func_set = va_arg(param, curl_read_callback);
-    if(!data->set.fread_func_set) {
-      data->set.is_fread_set = 0;
-      /* When set to NULL, reset to our internal default function */
-      data->set.fread_func_set = (curl_read_callback)fread;
-    }
-    else
-      data->set.is_fread_set = 1;
-    break;
-  case CURLOPT_SEEKFUNCTION:
-    /*
-     * Seek callback. Might be NULL.
-     */
-    data->set.seek_func = va_arg(param, curl_seek_callback);
-    break;
-  case CURLOPT_SEEKDATA:
-    /*
-     * Seek control callback. Might be NULL.
-     */
-    data->set.seek_client = va_arg(param, void *);
-    break;
-  case CURLOPT_IOCTLFUNCTION:
-    /*
-     * I/O control callback. Might be NULL.
-     */
-    data->set.ioctl_func = va_arg(param, curl_ioctl_callback);
-    break;
-  case CURLOPT_IOCTLDATA:
-    /*
-     * I/O control data pointer. Might be NULL.
-     */
-    data->set.ioctl_client = va_arg(param, void *);
-    break;
-  case CURLOPT_SSLCERT:
-    /*
-     * String that holds filename of the SSL certificate to use
-     */
-    result = Curl_setstropt(&data->set.str[STRING_CERT],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_SSLCERT_BLOB:
-    /*
-     * Blob that holds file content of the SSL certificate to use
-     */
-    result = Curl_setblobopt(&data->set.blobs[BLOB_CERT],
-                             va_arg(param, struct curl_blob *));
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_SSLCERT:
-    /*
-     * String that holds filename of the SSL certificate to use for proxy
-     */
-    result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_SSLCERT_BLOB:
-    /*
-     * Blob that holds file content of the SSL certificate to use for proxy
-     */
-    result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY],
-                             va_arg(param, struct curl_blob *));
-    break;
-#endif
-  case CURLOPT_SSLCERTTYPE:
-    /*
-     * String that holds file type of the SSL certificate to use
-     */
-    result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE],
-                            va_arg(param, char *));
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_SSLCERTTYPE:
-    /*
-     * String that holds file type of the SSL certificate to use for proxy
-     */
-    result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY],
-                            va_arg(param, char *));
-    break;
-#endif
-  case CURLOPT_SSLKEY:
-    /*
-     * String that holds filename of the SSL key to use
-     */
-    result = Curl_setstropt(&data->set.str[STRING_KEY],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_SSLKEY_BLOB:
-    /*
-     * Blob that holds file content of the SSL key to use
-     */
-    result = Curl_setblobopt(&data->set.blobs[BLOB_KEY],
-                             va_arg(param, struct curl_blob *));
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_SSLKEY:
-    /*
-     * String that holds filename of the SSL key to use for proxy
-     */
-    result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_SSLKEY_BLOB:
-    /*
-     * Blob that holds file content of the SSL key to use for proxy
-     */
-    result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY],
-                             va_arg(param, struct curl_blob *));
-    break;
-#endif
-  case CURLOPT_SSLKEYTYPE:
-    /*
-     * String that holds file type of the SSL key to use
-     */
-    result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE],
-                            va_arg(param, char *));
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_SSLKEYTYPE:
-    /*
-     * String that holds file type of the SSL key to use for proxy
-     */
-    result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY],
-                            va_arg(param, char *));
-    break;
-#endif
-  case CURLOPT_KEYPASSWD:
-    /*
-     * String that holds the SSL or SSH private key password.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD],
-                            va_arg(param, char *));
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_KEYPASSWD:
-    /*
-     * String that holds the SSL private key password for proxy.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY],
-                            va_arg(param, char *));
-    break;
-#endif
-  case CURLOPT_SSLENGINE:
-    /*
-     * String that holds the SSL crypto engine.
-     */
-    argptr = va_arg(param, char *);
-    if(argptr && argptr[0]) {
-      result = Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], argptr);
-      if(!result) {
-        result = Curl_ssl_set_engine(data, argptr);
-      }
-    }
-    break;
 
-  case CURLOPT_SSLENGINE_DEFAULT:
-    /*
-     * flag to set engine as default.
-     */
-    Curl_safefree(data->set.str[STRING_SSL_ENGINE]);
-    result = Curl_ssl_set_engine_default(data);
-    break;
   case CURLOPT_CRLF:
     /*
      * Kludgy option to enable CRLF conversions. Subject for removal.
      */
-    data->set.crlf = (0 != va_arg(param, long));
+    data->set.crlf = enabled;
     break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_HAPROXYPROTOCOL:
-    /*
-     * Set to send the HAProxy Proxy Protocol header
-     */
-    data->set.haproxyprotocol = (0 != va_arg(param, long));
-    break;
-  case CURLOPT_HAPROXY_CLIENT_IP:
-    /*
-     * Set the client IP to send through HAProxy PROXY protocol
-     */
-    result = Curl_setstropt(&data->set.str[STRING_HAPROXY_CLIENT_IP],
-                            va_arg(param, char *));
-    /* We enable implicitly the HAProxy protocol if we use this flag. */
-    data->set.haproxyprotocol = TRUE;
-    break;
-#endif
-  case CURLOPT_INTERFACE:
-    /*
-     * Set what interface or address/hostname to bind the socket to when
-     * performing an operation and thus what from-IP your connection will use.
-     */
-    result = setstropt_interface(va_arg(param, char *),
-                                 &data->set.str[STRING_DEVICE],
-                                 &data->set.str[STRING_INTERFACE],
-                                 &data->set.str[STRING_BINDHOST]);
-    break;
+
 #ifndef CURL_DISABLE_BINDLOCAL
   case CURLOPT_LOCALPORT:
     /*
      * Set what local port to bind the socket to when performing an operation.
      */
-    arg = va_arg(param, long);
     if((arg < 0) || (arg > 65535))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.localport = curlx_sltous(arg);
@@ -1940,17 +917,16 @@
     /*
      * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
      */
-    arg = va_arg(param, long);
     if((arg < 0) || (arg > 65535))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.localportrange = curlx_sltous(arg);
     break;
 #endif
+
   case CURLOPT_GSSAPI_DELEGATION:
     /*
      * GSS-API credential delegation bitmask
      */
-    uarg = va_arg(param, unsigned long);
     data->set.gssapi_delegation = (unsigned char)uarg&
       (CURLGSSAPI_DELEGATION_POLICY_FLAG|CURLGSSAPI_DELEGATION_FLAG);
     break;
@@ -1958,7 +934,7 @@
     /*
      * Enable peer SSL verifying.
      */
-    data->set.ssl.primary.verifypeer = (0 != va_arg(param, long));
+    data->set.ssl.primary.verifypeer = enabled;
 
     /* Update the current connection ssl_config. */
     Curl_ssl_conn_config_update(data, FALSE);
@@ -1968,295 +944,71 @@
     /*
      * Enable peer SSL verifying for DoH.
      */
-    data->set.doh_verifypeer = (0 != va_arg(param, long));
+    data->set.doh_verifypeer = enabled;
     break;
-#endif
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_SSL_VERIFYPEER:
-    /*
-     * Enable peer SSL verifying for proxy.
-     */
-    data->set.proxy_ssl.primary.verifypeer =
-      (0 != va_arg(param, long));
-
-    /* Update the current connection proxy_ssl_config. */
-    Curl_ssl_conn_config_update(data, TRUE);
-    break;
-#endif
-  case CURLOPT_SSL_VERIFYHOST:
-    /*
-     * Enable verification of the hostname in the peer certificate
-     */
-    arg = va_arg(param, long);
-
-    /* Obviously people are not reading documentation and too many thought
-       this argument took a boolean when it was not and misused it.
-       Treat 1 and 2 the same */
-    data->set.ssl.primary.verifyhost = !!(arg & 3);
-
-    /* Update the current connection ssl_config. */
-    Curl_ssl_conn_config_update(data, FALSE);
-    break;
-#ifndef CURL_DISABLE_DOH
   case CURLOPT_DOH_SSL_VERIFYHOST:
     /*
      * Enable verification of the hostname in the peer certificate for DoH
      */
-    arg = va_arg(param, long);
-
-    /* Treat both 1 and 2 as TRUE */
-    data->set.doh_verifyhost = !!(arg & 3);
+    data->set.doh_verifyhost = enabled;
     break;
-#endif
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_SSL_VERIFYHOST:
-    /*
-     * Enable verification of the hostname in the peer certificate for proxy
-     */
-    arg = va_arg(param, long);
-
-    /* Treat both 1 and 2 as TRUE */
-    data->set.proxy_ssl.primary.verifyhost = !!(arg & 3);
-    /* Update the current connection proxy_ssl_config. */
-    Curl_ssl_conn_config_update(data, TRUE);
-    break;
-#endif
-  case CURLOPT_SSL_VERIFYSTATUS:
-    /*
-     * Enable certificate status verifying.
-     */
-    if(!Curl_ssl_cert_status_request()) {
-      result = CURLE_NOT_BUILT_IN;
-      break;
-    }
-
-    data->set.ssl.primary.verifystatus = (0 != va_arg(param, long));
-
-    /* Update the current connection ssl_config. */
-    Curl_ssl_conn_config_update(data, FALSE);
-    break;
-#ifndef CURL_DISABLE_DOH
   case CURLOPT_DOH_SSL_VERIFYSTATUS:
     /*
      * Enable certificate status verifying for DoH.
      */
-    if(!Curl_ssl_cert_status_request()) {
-      result = CURLE_NOT_BUILT_IN;
-      break;
-    }
+    if(!Curl_ssl_cert_status_request())
+      return CURLE_NOT_BUILT_IN;
 
-    data->set.doh_verifystatus = (0 != va_arg(param, long));
+    data->set.doh_verifystatus = enabled;
     break;
-#endif
-  case CURLOPT_SSL_CTX_FUNCTION:
+#endif /* ! CURL_DISABLE_DOH */
+  case CURLOPT_SSL_VERIFYHOST:
     /*
-     * Set a SSL_CTX callback
+     * Enable verification of the hostname in the peer certificate
      */
-#ifdef USE_SSL
-    if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
-      data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
+
+    /* Obviously people are not reading documentation and too many thought
+       this argument took a boolean when it was not and misused it.
+       Treat 1 and 2 the same */
+    data->set.ssl.primary.verifyhost = enabled;
+
+    /* Update the current connection ssl_config. */
+    Curl_ssl_conn_config_update(data, FALSE);
     break;
-  case CURLOPT_SSL_CTX_DATA:
+  case CURLOPT_SSL_VERIFYSTATUS:
     /*
-     * Set a SSL_CTX callback parameter pointer
+     * Enable certificate status verifying.
      */
-#ifdef USE_SSL
-    if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
-      data->set.ssl.fsslctxp = va_arg(param, void *);
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
+    if(!Curl_ssl_cert_status_request())
+      return CURLE_NOT_BUILT_IN;
+
+    data->set.ssl.primary.verifystatus = enabled;
+
+    /* Update the current connection ssl_config. */
+    Curl_ssl_conn_config_update(data, FALSE);
     break;
   case CURLOPT_SSL_FALSESTART:
     /*
      * Enable TLS false start.
      */
-    if(!Curl_ssl_false_start(data)) {
-      result = CURLE_NOT_BUILT_IN;
-      break;
-    }
+    if(!Curl_ssl_false_start(data))
+      return CURLE_NOT_BUILT_IN;
 
-    data->set.ssl.falsestart = (0 != va_arg(param, long));
+    data->set.ssl.falsestart = enabled;
     break;
   case CURLOPT_CERTINFO:
 #ifdef USE_SSL
     if(Curl_ssl_supports(data, SSLSUPP_CERTINFO))
-      data->set.ssl.certinfo = (0 != va_arg(param, long));
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-  case CURLOPT_PINNEDPUBLICKEY:
-    /*
-     * Set pinned public key for SSL connection.
-     * Specify filename of the public key in DER format.
-     */
-#ifdef USE_SSL
-    if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
-      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY],
-                              va_arg(param, char *));
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_PINNEDPUBLICKEY:
-    /*
-     * Set pinned public key for SSL connection.
-     * Specify filename of the public key in DER format.
-     */
-#ifdef USE_SSL
-    if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
-      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
-                              va_arg(param, char *));
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-#endif
-  case CURLOPT_CAINFO:
-    /*
-     * Set CA info for SSL connection. Specify filename of the CA certificate
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_CAINFO_BLOB:
-    /*
-     * Blob that holds CA info for SSL connection.
-     * Specify entire PEM of the CA certificate
-     */
-#ifdef USE_SSL
-    if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) {
-      result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO],
-                               va_arg(param, struct curl_blob *));
-      break;
-    }
+      data->set.ssl.certinfo = enabled;
     else
 #endif
       return CURLE_NOT_BUILT_IN;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_CAINFO:
-    /*
-     * Set CA info SSL connection for proxy. Specify filename of the
-     * CA certificate
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
-                            va_arg(param, char *));
     break;
-  case CURLOPT_PROXY_CAINFO_BLOB:
-    /*
-     * Blob that holds CA info for SSL connection proxy.
-     * Specify entire PEM of the CA certificate
-     */
-#ifdef USE_SSL
-    if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) {
-      result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY],
-                               va_arg(param, struct curl_blob *));
-      break;
-    }
-    else
-#endif
-      return CURLE_NOT_BUILT_IN;
-#endif
-  case CURLOPT_CAPATH:
-    /*
-     * Set CA path info for SSL connection. Specify directory name of the CA
-     * certificates which have been prepared using openssl c_rehash utility.
-     */
-#ifdef USE_SSL
-    if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
-      /* This does not work on Windows. */
-      result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH],
-                              va_arg(param, char *));
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_CAPATH:
-    /*
-     * Set CA path info for SSL connection proxy. Specify directory name of the
-     * CA certificates which have been prepared using openssl c_rehash utility.
-     */
-#ifdef USE_SSL
-    if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
-      /* This does not work on Windows. */
-      result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY],
-                              va_arg(param, char *));
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-#endif
-  case CURLOPT_CRLFILE:
-    /*
-     * Set CRL file info for SSL connection. Specify filename of the CRL
-     * to check certificates revocation
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE],
-                            va_arg(param, char *));
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_CRLFILE:
-    /*
-     * Set CRL file info for SSL connection for proxy. Specify filename of the
-     * CRL to check certificates revocation
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
-                            va_arg(param, char *));
-    break;
-#endif
-  case CURLOPT_ISSUERCERT:
-    /*
-     * Set Issuer certificate file
-     * to check certificates issuer
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_ISSUERCERT_BLOB:
-    /*
-     * Blob that holds Issuer certificate to check certificates issuer
-     */
-    result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT],
-                             va_arg(param, struct curl_blob *));
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_ISSUERCERT:
-    /*
-     * Set Issuer certificate file
-     * to check certificates issuer
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_ISSUERCERT_BLOB:
-    /*
-     * Blob that holds Issuer certificate to check certificates issuer
-     */
-    result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY],
-                             va_arg(param, struct curl_blob *));
-    break;
-#endif
-#ifndef CURL_DISABLE_TELNET
-  case CURLOPT_TELNETOPTIONS:
-    /*
-     * Set a linked list of telnet options
-     */
-    data->set.telnet_options = va_arg(param, struct curl_slist *);
-    break;
-#endif
   case CURLOPT_BUFFERSIZE:
     /*
      * The application kindly asks for a differently sized receive buffer.
      * If it seems reasonable, we will use it.
      */
-    arg = va_arg(param, long);
-
     if(arg > READBUFFER_MAX)
       arg = READBUFFER_MAX;
     else if(arg < 1)
@@ -2272,8 +1024,6 @@
      * The application kindly asks for a differently sized upload buffer.
      * Cap it to sensible.
      */
-    arg = va_arg(param, long);
-
     if(arg > UPLOADBUFFER_MAX)
       arg = UPLOADBUFFER_MAX;
     else if(arg < UPLOADBUFFER_MIN)
@@ -2287,106 +1037,12 @@
      * The application asks not to set any signal() or alarm() handlers,
      * even when using a timeout.
      */
-    data->set.no_signal = (0 != va_arg(param, long));
+    data->set.no_signal = enabled;
     break;
-
-  case CURLOPT_SHARE:
-  {
-    struct Curl_share *set;
-    set = va_arg(param, struct Curl_share *);
-
-    /* disconnect from old share, if any */
-    if(data->share) {
-      Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
-
-      if(data->dns.hostcachetype == HCACHE_SHARED) {
-        data->dns.hostcache = NULL;
-        data->dns.hostcachetype = HCACHE_NONE;
-      }
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
-      if(data->share->cookies == data->cookies)
-        data->cookies = NULL;
-#endif
-
-#ifndef CURL_DISABLE_HSTS
-      if(data->share->hsts == data->hsts)
-        data->hsts = NULL;
-#endif
-#ifdef USE_SSL
-      if(data->share->sslsession == data->state.session)
-        data->state.session = NULL;
-#endif
-#ifdef USE_LIBPSL
-      if(data->psl == &data->share->psl)
-        data->psl = data->multi? &data->multi->psl: NULL;
-#endif
-
-      data->share->dirty--;
-
-      Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
-      data->share = NULL;
-    }
-
-    if(GOOD_SHARE_HANDLE(set))
-      /* use new share if it set */
-      data->share = set;
-    if(data->share) {
-
-      Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
-
-      data->share->dirty++;
-
-      if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) {
-        /* use shared host cache */
-        data->dns.hostcache = &data->share->hostcache;
-        data->dns.hostcachetype = HCACHE_SHARED;
-      }
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
-      if(data->share->cookies) {
-        /* use shared cookie list, first free own one if any */
-        Curl_cookie_cleanup(data->cookies);
-        /* enable cookies since we now use a share that uses cookies! */
-        data->cookies = data->share->cookies;
-      }
-#endif   /* CURL_DISABLE_HTTP */
-#ifndef CURL_DISABLE_HSTS
-      if(data->share->hsts) {
-        /* first free the private one if any */
-        Curl_hsts_cleanup(&data->hsts);
-        data->hsts = data->share->hsts;
-      }
-#endif
-#ifdef USE_SSL
-      if(data->share->sslsession) {
-        data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
-        data->state.session = data->share->sslsession;
-      }
-#endif
-#ifdef USE_LIBPSL
-      if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL))
-        data->psl = &data->share->psl;
-#endif
-
-      Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
-    }
-    /* check for host cache not needed,
-     * it will be done by curl_easy_perform */
-  }
-  break;
-
-  case CURLOPT_PRIVATE:
-    /*
-     * Set private data pointer.
-     */
-    data->set.private_data = va_arg(param, void *);
-    break;
-
   case CURLOPT_MAXFILESIZE:
     /*
      * Set the maximum size of a file to download.
      */
-    arg = va_arg(param, long);
     if(arg < 0)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.max_filesize = arg;
@@ -2397,14 +1053,11 @@
     /*
      * Make transfers attempt to use SSL/TLS.
      */
-    arg = va_arg(param, long);
     if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.use_ssl = (unsigned char)arg;
     break;
-
   case CURLOPT_SSL_OPTIONS:
-    arg = va_arg(param, long);
     data->set.ssl.primary.ssl_options = (unsigned char)(arg & 0xff);
     data->set.ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST);
     data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
@@ -2412,13 +1065,13 @@
     data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
     data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
     data->set.ssl.auto_client_cert = !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
+    data->set.ssl.earlydata = !!(arg & CURLSSLOPT_EARLYDATA);
     /* If a setting is added here it should also be added in dohprobe()
        which sets its own CURLOPT_SSL_OPTIONS based on these settings. */
     break;
 
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_SSL_OPTIONS:
-    arg = va_arg(param, long);
     data->set.proxy_ssl.primary.ssl_options = (unsigned char)(arg & 0xff);
     data->set.proxy_ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST);
     data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
@@ -2431,42 +1084,22 @@
     break;
 #endif
 
-  case CURLOPT_SSL_EC_CURVES:
-    /*
-     * Set accepted curves in SSL connection setup.
-     * Specify colon-delimited list of curve algorithm names.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES],
-                            va_arg(param, char *));
-    break;
-#endif
+#endif /* USE_SSL */
   case CURLOPT_IPRESOLVE:
-    arg = va_arg(param, long);
     if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.ipver = (unsigned char) arg;
     break;
-
-  case CURLOPT_MAXFILESIZE_LARGE:
-    /*
-     * Set the maximum size of a file to download.
-     */
-    bigsize = va_arg(param, curl_off_t);
-    if(bigsize < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.max_filesize = bigsize;
-    break;
-
   case CURLOPT_TCP_NODELAY:
     /*
      * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
      * algorithm
      */
-    data->set.tcp_nodelay = (0 != va_arg(param, long));
+    data->set.tcp_nodelay = enabled;
     break;
 
   case CURLOPT_IGNORE_CONTENT_LENGTH:
-    data->set.ignorecl = (0 != va_arg(param, long));
+    data->set.ignorecl = enabled;
     break;
 
   case CURLOPT_CONNECT_ONLY:
@@ -2475,73 +1108,13 @@
      * (1) - only do connection
      * (2) - do first get request but get no content
      */
-    arg = va_arg(param, long);
     if(arg > 2)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.connect_only = (unsigned char)arg;
     break;
 
-  case CURLOPT_SOCKOPTFUNCTION:
-    /*
-     * socket callback function: called after socket() but before connect()
-     */
-    data->set.fsockopt = va_arg(param, curl_sockopt_callback);
-    break;
-
-  case CURLOPT_SOCKOPTDATA:
-    /*
-     * socket callback data pointer. Might be NULL.
-     */
-    data->set.sockopt_client = va_arg(param, void *);
-    break;
-
-  case CURLOPT_OPENSOCKETFUNCTION:
-    /*
-     * open/create socket callback function: called instead of socket(),
-     * before connect()
-     */
-    data->set.fopensocket = va_arg(param, curl_opensocket_callback);
-    break;
-
-  case CURLOPT_OPENSOCKETDATA:
-    /*
-     * socket callback data pointer. Might be NULL.
-     */
-    data->set.opensocket_client = va_arg(param, void *);
-    break;
-
-  case CURLOPT_CLOSESOCKETFUNCTION:
-    /*
-     * close socket callback function: called instead of close()
-     * when shutting down a connection
-     */
-    data->set.fclosesocket = va_arg(param, curl_closesocket_callback);
-    break;
-
-  case CURLOPT_RESOLVER_START_FUNCTION:
-    /*
-     * resolver start callback function: called before a new resolver request
-     * is started
-     */
-    data->set.resolver_start = va_arg(param, curl_resolver_start_callback);
-    break;
-
-  case CURLOPT_RESOLVER_START_DATA:
-    /*
-     * resolver start callback data pointer. Might be NULL.
-     */
-    data->set.resolver_start_client = va_arg(param, void *);
-    break;
-
-  case CURLOPT_CLOSESOCKETDATA:
-    /*
-     * socket callback data pointer. Might be NULL.
-     */
-    data->set.closesocket_client = va_arg(param, void *);
-    break;
-
   case CURLOPT_SSL_SESSIONID_CACHE:
-    data->set.ssl.primary.cache_session = (0 != va_arg(param, long));
+    data->set.ssl.primary.cache_session = enabled;
 #ifndef CURL_DISABLE_PROXY
     data->set.proxy_ssl.primary.cache_session =
       data->set.ssl.primary.cache_session;
@@ -2551,87 +1124,19 @@
 #ifdef USE_SSH
     /* we only include SSH options if explicitly built to support SSH */
   case CURLOPT_SSH_AUTH_TYPES:
-    data->set.ssh_auth_types = (int)va_arg(param, long);
+    data->set.ssh_auth_types = (int)arg;
     break;
-
-  case CURLOPT_SSH_PUBLIC_KEYFILE:
-    /*
-     * Use this file instead of the $HOME/.ssh/id_dsa.pub file
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_SSH_PRIVATE_KEYFILE:
-    /*
-     * Use this file instead of the $HOME/.ssh/id_dsa file
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
-    /*
-     * Option to allow for the MD5 of the host public key to be checked
-     * for validation purposes.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_SSH_KNOWNHOSTS:
-    /*
-     * Store the filename to read known hosts from.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
-                            va_arg(param, char *));
-    break;
-#ifdef USE_LIBSSH2
-  case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
-    /*
-     * Option to allow for the SHA256 of the host public key to be checked
-     * for validation purposes.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_SSH_HOSTKEYFUNCTION:
-    /* the callback to check the hostkey without the knownhost file */
-    data->set.ssh_hostkeyfunc = va_arg(param, curl_sshhostkeycallback);
-    break;
-
-  case CURLOPT_SSH_HOSTKEYDATA:
-    /*
-     * Custom client data to pass to the SSH keyfunc callback
-     */
-    data->set.ssh_hostkeyfunc_userp = va_arg(param, void *);
+  case CURLOPT_SSH_COMPRESSION:
+    data->set.ssh_compression = enabled;
     break;
 #endif
 
-  case CURLOPT_SSH_KEYFUNCTION:
-    /* setting to NULL is fine since the ssh.c functions themselves will
-       then revert to use the internal default */
-    data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback);
-    break;
-
-  case CURLOPT_SSH_KEYDATA:
-    /*
-     * Custom client data to pass to the SSH keyfunc callback
-     */
-    data->set.ssh_keyfunc_userp = va_arg(param, void *);
-    break;
-
-  case CURLOPT_SSH_COMPRESSION:
-    data->set.ssh_compression = (0 != va_arg(param, long));
-    break;
-#endif /* USE_SSH */
-
   case CURLOPT_HTTP_TRANSFER_DECODING:
     /*
      * disable libcurl transfer encoding is used
      */
 #ifndef USE_HYPER
-    data->set.http_te_skip = (0 == va_arg(param, long));
+    data->set.http_te_skip = !enabled; /* reversed */
     break;
 #else
     return CURLE_NOT_BUILT_IN; /* hyper does not support */
@@ -2641,7 +1146,7 @@
     /*
      * raw data passed to the application when content encoding is used
      */
-    data->set.http_ce_skip = (0 == va_arg(param, long));
+    data->set.http_ce_skip = !enabled; /* reversed */
     break;
 
 #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
@@ -2649,7 +1154,6 @@
     /*
      * Uses these permissions instead of 0644
      */
-    arg = va_arg(param, long);
     if((arg < 0) || (arg > 0777))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.new_file_perms = (unsigned int)arg;
@@ -2660,13 +1164,11 @@
     /*
      * Uses these permissions instead of 0755
      */
-    arg = va_arg(param, long);
     if((arg < 0) || (arg > 0777))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.new_directory_perms = (unsigned int)arg;
     break;
 #endif
-
 #ifdef USE_IPV6
   case CURLOPT_ADDRESS_SCOPE:
     /*
@@ -2674,7 +1176,6 @@
      * We always get longs when passed plain numericals so we should check
      * that the value fits into an unsigned 32-bit integer.
      */
-    uarg = va_arg(param, unsigned long);
 #if SIZEOF_LONG > 4
     if(uarg > UINT_MAX)
       return CURLE_BAD_FUNCTION_ARGUMENT;
@@ -2682,85 +1183,30 @@
     data->set.scope_id = (unsigned int)uarg;
     break;
 #endif
-
   case CURLOPT_PROTOCOLS:
     /* set the bitmask for the protocols that are allowed to be used for the
        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_prot_t)va_arg(param, long);
+       external inputs and want to restrict what protocol(s) to deal with.
+       Defaults to CURLPROTO_ALL. */
+    data->set.allowed_protocols = (curl_prot_t)arg;
     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_prot_t)va_arg(param, long);
+       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_prot_t)arg;
     break;
 
-  case CURLOPT_PROTOCOLS_STR: {
-    argptr = va_arg(param, char *);
-    if(argptr) {
-      result = protocol2num(argptr, &data->set.allowed_protocols);
-      if(result)
-        return result;
-    }
-    else
-      /* make a NULL argument reset to default */
-      data->set.allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
-    break;
-  }
-
-  case CURLOPT_REDIR_PROTOCOLS_STR: {
-    argptr = va_arg(param, char *);
-    if(argptr) {
-      result = protocol2num(argptr, &data->set.redir_protocols);
-      if(result)
-        return result;
-    }
-    else
-      /* make a NULL argument reset to default */
-      data->set.redir_protocols = (curl_prot_t) CURLPROTO_REDIR;
-    break;
-  }
-
-  case CURLOPT_DEFAULT_PROTOCOL:
-    /* Set the protocol to use when the URL does not include any protocol */
-    result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
-                            va_arg(param, char *));
-    break;
 #ifndef CURL_DISABLE_SMTP
-  case CURLOPT_MAIL_FROM:
-    /* Set the SMTP mail originator */
-    result = Curl_setstropt(&data->set.str[STRING_MAIL_FROM],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_MAIL_AUTH:
-    /* Set the SMTP auth originator */
-    result = Curl_setstropt(&data->set.str[STRING_MAIL_AUTH],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_MAIL_RCPT:
-    /* Set the list of mail recipients */
-    data->set.mail_rcpt = va_arg(param, struct curl_slist *);
-    break;
   case CURLOPT_MAIL_RCPT_ALLOWFAILS:
     /* allow RCPT TO command to fail for some recipients */
-    data->set.mail_rcpt_allowfails = (0 != va_arg(param, long));
+    data->set.mail_rcpt_allowfails = enabled;
     break;
-#endif
-
-  case CURLOPT_SASL_AUTHZID:
-    /* Authorization identity (identity to act as) */
-    result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID],
-                            va_arg(param, char *));
-    break;
-
+#endif /* !CURL_DISABLE_SMTP */
   case CURLOPT_SASL_IR:
     /* Enable/disable SASL initial response */
-    data->set.sasl_ir = (0 != va_arg(param, long));
+    data->set.sasl_ir = enabled;
     break;
 #ifndef CURL_DISABLE_RTSP
   case CURLOPT_RTSP_REQUEST:
@@ -2769,9 +1215,8 @@
      * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
      * Would this be better if the RTSPREQ_* were just moved into here?
      */
-    long in_rtspreq = va_arg(param, long);
     Curl_RtspReq rtspreq = RTSPREQ_NONE;
-    switch(in_rtspreq) {
+    switch(arg) {
     case CURL_RTSPREQ_OPTIONS:
       rtspreq = RTSPREQ_OPTIONS;
       break;
@@ -2816,151 +1261,32 @@
       rtspreq = RTSPREQ_RECEIVE;
       break;
     default:
-      rtspreq = RTSPREQ_NONE;
+      return CURLE_BAD_FUNCTION_ARGUMENT;
     }
 
     data->set.rtspreq = rtspreq;
     break;
   }
-
-
-  case CURLOPT_RTSP_SESSION_ID:
-    /*
-     * Set the RTSP Session ID manually. Useful if the application is
-     * resuming a previously established RTSP session
-     */
-    result = Curl_setstropt(&data->set.str[STRING_RTSP_SESSION_ID],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_RTSP_STREAM_URI:
-    /*
-     * Set the Stream URI for the RTSP request. Unless the request is
-     * for generic server options, the application will need to set this.
-     */
-    result = Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
-                            va_arg(param, char *));
-    break;
-
-  case CURLOPT_RTSP_TRANSPORT:
-    /*
-     * The content of the Transport: header for the RTSP request
-     */
-    result = Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
-                            va_arg(param, char *));
-    break;
-
   case CURLOPT_RTSP_CLIENT_CSEQ:
     /*
      * Set the CSEQ number to issue for the next RTSP request. Useful if the
      * application is resuming a previously broken connection. The CSEQ
      * will increment from this new number henceforth.
      */
-    data->state.rtsp_next_client_CSeq = va_arg(param, long);
+    data->state.rtsp_next_client_CSeq = arg;
     break;
 
   case CURLOPT_RTSP_SERVER_CSEQ:
     /* Same as the above, but for server-initiated requests */
-    data->state.rtsp_next_server_CSeq = va_arg(param, long);
+    data->state.rtsp_next_server_CSeq = arg;
     break;
 
-  case CURLOPT_INTERLEAVEDATA:
-    data->set.rtp_out = va_arg(param, void *);
-    break;
-  case CURLOPT_INTERLEAVEFUNCTION:
-    /* Set the user defined RTP write function */
-    data->set.fwrite_rtp = va_arg(param, curl_write_callback);
-    break;
-#endif
-#ifndef CURL_DISABLE_FTP
-  case CURLOPT_WILDCARDMATCH:
-    data->set.wildcard_enabled = (0 != va_arg(param, long));
-    break;
-  case CURLOPT_CHUNK_BGN_FUNCTION:
-    data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback);
-    break;
-  case CURLOPT_CHUNK_END_FUNCTION:
-    data->set.chunk_end = va_arg(param, curl_chunk_end_callback);
-    break;
-  case CURLOPT_FNMATCH_FUNCTION:
-    data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
-    break;
-  case CURLOPT_CHUNK_DATA:
-    data->set.wildcardptr = va_arg(param, void *);
-    break;
-  case CURLOPT_FNMATCH_DATA:
-    data->set.fnmatch_data = va_arg(param, void *);
-    break;
-#endif
-#ifdef USE_TLS_SRP
-  case CURLOPT_TLSAUTH_USERNAME:
-    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME],
-                            va_arg(param, char *));
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_TLSAUTH_USERNAME:
-    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY],
-                            va_arg(param, char *));
-    break;
-#endif
-  case CURLOPT_TLSAUTH_PASSWORD:
-    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD],
-                            va_arg(param, char *));
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_TLSAUTH_PASSWORD:
-    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY],
-                            va_arg(param, char *));
-    break;
-#endif
-  case CURLOPT_TLSAUTH_TYPE:
-    argptr = va_arg(param, char *);
-    if(argptr && !strcasecompare(argptr, "SRP"))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    break;
-#ifndef CURL_DISABLE_PROXY
-  case CURLOPT_PROXY_TLSAUTH_TYPE:
-    argptr = va_arg(param, char *);
-    if(argptr && !strcasecompare(argptr, "SRP"))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    break;
-#endif
-#endif
-#ifdef USE_ARES
-  case CURLOPT_DNS_SERVERS:
-    result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS],
-                            va_arg(param, char *));
-    if(result)
-      return result;
-    result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]);
-    break;
-  case CURLOPT_DNS_INTERFACE:
-    result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE],
-                            va_arg(param, char *));
-    if(result)
-      return result;
-    result = Curl_set_dns_interface(data, data->set.str[STRING_DNS_INTERFACE]);
-    break;
-  case CURLOPT_DNS_LOCAL_IP4:
-    result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4],
-                            va_arg(param, char *));
-    if(result)
-      return result;
-    result = Curl_set_dns_local_ip4(data, data->set.str[STRING_DNS_LOCAL_IP4]);
-    break;
-  case CURLOPT_DNS_LOCAL_IP6:
-    result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6],
-                            va_arg(param, char *));
-    if(result)
-      return result;
-    result = Curl_set_dns_local_ip6(data, data->set.str[STRING_DNS_LOCAL_IP6]);
-    break;
-#endif
+#endif /* ! CURL_DISABLE_RTSP */
+
   case CURLOPT_TCP_KEEPALIVE:
-    data->set.tcp_keepalive = (0 != va_arg(param, long));
+    data->set.tcp_keepalive = enabled;
     break;
   case CURLOPT_TCP_KEEPIDLE:
-    arg = va_arg(param, long);
     if(arg < 0)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     else if(arg > INT_MAX)
@@ -2968,7 +1294,6 @@
     data->set.tcp_keepidle = (int)arg;
     break;
   case CURLOPT_TCP_KEEPINTVL:
-    arg = va_arg(param, long);
     if(arg < 0)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     else if(arg > INT_MAX)
@@ -2976,7 +1301,6 @@
     data->set.tcp_keepintvl = (int)arg;
     break;
   case CURLOPT_TCP_KEEPCNT:
-    arg = va_arg(param, long);
     if(arg < 0)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     else if(arg > INT_MAX)
@@ -2984,123 +1308,1300 @@
     data->set.tcp_keepcnt = (int)arg;
     break;
   case CURLOPT_TCP_FASTOPEN:
-#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \
-   defined(TCP_FASTOPEN_CONNECT)
-    data->set.tcp_fastopen = (0 != va_arg(param, long));
+#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) ||        \
+  defined(TCP_FASTOPEN_CONNECT)
+    data->set.tcp_fastopen = enabled;
 #else
-    result = CURLE_NOT_BUILT_IN;
+    return CURLE_NOT_BUILT_IN;
 #endif
     break;
   case CURLOPT_SSL_ENABLE_NPN:
     break;
   case CURLOPT_SSL_ENABLE_ALPN:
-    data->set.ssl_enable_alpn = (0 != va_arg(param, long));
+    data->set.ssl_enable_alpn = enabled;
     break;
-#ifdef USE_UNIX_SOCKETS
-  case CURLOPT_UNIX_SOCKET_PATH:
-    data->set.abstract_unix_socket = FALSE;
-    result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
-                            va_arg(param, char *));
-    break;
-  case CURLOPT_ABSTRACT_UNIX_SOCKET:
-    data->set.abstract_unix_socket = TRUE;
-    result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
-                            va_arg(param, char *));
-    break;
-#endif
-
   case CURLOPT_PATH_AS_IS:
-    data->set.path_as_is = (0 != va_arg(param, long));
+    data->set.path_as_is = enabled;
     break;
   case CURLOPT_PIPEWAIT:
-    data->set.pipewait = (0 != va_arg(param, long));
+    data->set.pipewait = enabled;
     break;
   case CURLOPT_STREAM_WEIGHT:
 #if defined(USE_HTTP2) || defined(USE_HTTP3)
-    arg = va_arg(param, long);
     if((arg >= 1) && (arg <= 256))
       data->set.priority.weight = (int)arg;
     break;
 #else
     return CURLE_NOT_BUILT_IN;
 #endif
-  case CURLOPT_STREAM_DEPENDS:
-  case CURLOPT_STREAM_DEPENDS_E:
-  {
-    struct Curl_easy *dep = va_arg(param, struct Curl_easy *);
-    if(!dep || GOOD_EASY_HANDLE(dep)) {
-      return Curl_data_priority_add_child(dep, data,
-                                          option == CURLOPT_STREAM_DEPENDS_E);
-    }
-    break;
-  }
-  case CURLOPT_CONNECT_TO:
-    data->set.connect_to = va_arg(param, struct curl_slist *);
-    break;
   case CURLOPT_SUPPRESS_CONNECT_HEADERS:
-    data->set.suppress_connect_headers = (0 != va_arg(param, long));
+    data->set.suppress_connect_headers = enabled;
     break;
   case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS:
-    uarg = va_arg(param, unsigned long);
     if(uarg > UINT_MAX)
       uarg = UINT_MAX;
     data->set.happy_eyeballs_timeout = (unsigned int)uarg;
     break;
 #ifndef CURL_DISABLE_SHUFFLE_DNS
   case CURLOPT_DNS_SHUFFLE_ADDRESSES:
-    data->set.dns_shuffle_addresses = (0 != va_arg(param, long));
+    data->set.dns_shuffle_addresses = enabled;
     break;
 #endif
   case CURLOPT_DISALLOW_USERNAME_IN_URL:
-    data->set.disallow_username_in_url = (0 != va_arg(param, long));
+    data->set.disallow_username_in_url = enabled;
     break;
-#ifndef CURL_DISABLE_DOH
-  case CURLOPT_DOH_URL:
-    result = Curl_setstropt(&data->set.str[STRING_DOH],
-                            va_arg(param, char *));
-    data->set.doh = !!(data->set.str[STRING_DOH]);
-    break;
-#endif
+
   case CURLOPT_UPKEEP_INTERVAL_MS:
-    arg = va_arg(param, long);
     if(arg < 0)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.upkeep_interval_ms = arg;
     break;
   case CURLOPT_MAXAGE_CONN:
-    arg = va_arg(param, long);
     if(arg < 0)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.maxage_conn = arg;
     break;
   case CURLOPT_MAXLIFETIME_CONN:
-    arg = va_arg(param, long);
     if(arg < 0)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.maxlifetime_conn = arg;
     break;
-  case CURLOPT_TRAILERFUNCTION:
-#ifndef CURL_DISABLE_HTTP
-    data->set.trailer_callback = va_arg(param, curl_trailer_callback);
+#ifndef CURL_DISABLE_HSTS
+  case CURLOPT_HSTS_CTRL:
+    if(arg & CURLHSTS_ENABLE) {
+      if(!data->hsts) {
+        data->hsts = Curl_hsts_init();
+        if(!data->hsts)
+          return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    else
+      Curl_hsts_cleanup(&data->hsts);
+    break;
+#endif /* ! CURL_DISABLE_HSTS */
+#ifndef CURL_DISABLE_ALTSVC
+  case CURLOPT_ALTSVC_CTRL:
+    if(!arg) {
+      DEBUGF(infof(data, "bad CURLOPT_ALTSVC_CTRL input"));
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+    if(!data->asi) {
+      data->asi = Curl_altsvc_init();
+      if(!data->asi)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    return Curl_altsvc_ctrl(data->asi, arg);
+#endif /* ! CURL_DISABLE_ALTSVC */
+#ifndef CURL_DISABLE_WEBSOCKETS
+  case CURLOPT_WS_OPTIONS:
+    data->set.ws_raw_mode =  (bool)(arg & CURLWS_RAW_MODE);
+    break;
 #endif
+  case CURLOPT_QUICK_EXIT:
+    data->set.quick_exit = enabled;
+    break;
+  case CURLOPT_DNS_USE_GLOBAL_CACHE:
+    /* deprecated */
+    break;
+  case CURLOPT_SSLENGINE_DEFAULT:
+    /*
+     * flag to set engine as default.
+     */
+    Curl_safefree(data->set.str[STRING_SSL_ENGINE]);
+    return Curl_ssl_set_engine_default(data);
+
+  default:
+    /* unknown option */
+    return CURLE_UNKNOWN_OPTION;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode setopt_slist(struct Curl_easy *data, CURLoption option,
+                             struct curl_slist *slist)
+{
+  CURLcode result = CURLE_OK;
+  switch(option) {
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXYHEADER:
+    /*
+     * Set a list with proxy headers to use (or replace internals with)
+     *
+     * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a
+     * long time we remain doing it this way until CURLOPT_PROXYHEADER is
+     * used. As soon as this option has been used, if set to anything but
+     * NULL, custom headers for proxies are only picked from this list.
+     *
+     * Set this option to NULL to restore the previous behavior.
+     */
+    data->set.proxyheaders = slist;
+    break;
+#endif
+#ifndef CURL_DISABLE_HTTP
+  case CURLOPT_HTTP200ALIASES:
+    /*
+     * Set a list of aliases for HTTP 200 in response header
+     */
+    data->set.http200aliases = slist;
+    break;
+#endif
+#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
+  case CURLOPT_POSTQUOTE:
+    /*
+     * List of RAW FTP commands to use after a transfer
+     */
+    data->set.postquote = slist;
+    break;
+  case CURLOPT_PREQUOTE:
+    /*
+     * List of RAW FTP commands to use prior to RETR (Wesley Laxton)
+     */
+    data->set.prequote = slist;
+    break;
+  case CURLOPT_QUOTE:
+    /*
+     * List of RAW FTP commands to use before a transfer
+     */
+    data->set.quote = slist;
+    break;
+#endif
+  case CURLOPT_RESOLVE:
+    /*
+     * List of HOST:PORT:[addresses] strings to populate the DNS cache with
+     * Entries added this way will remain in the cache until explicitly
+     * removed or the handle is cleaned up.
+     *
+     * Prefix the HOST with plus sign (+) to have the entry expire just like
+     * automatically added entries.
+     *
+     * Prefix the HOST with dash (-) to _remove_ the entry from the cache.
+     *
+     * This API can remove any entry from the DNS cache, but only entries
+     * that are not actually in use right now will be pruned immediately.
+     */
+    data->set.resolve = slist;
+    data->state.resolve = data->set.resolve;
+    break;
+#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 = slist;
+    break;
+#endif
+#ifndef CURL_DISABLE_TELNET
+  case CURLOPT_TELNETOPTIONS:
+    /*
+     * Set a linked list of telnet options
+     */
+    data->set.telnet_options = slist;
+    break;
+#endif
+#ifndef CURL_DISABLE_SMTP
+  case CURLOPT_MAIL_RCPT:
+    /* Set the list of mail recipients */
+    data->set.mail_rcpt = slist;
+    break;
+#endif
+  case CURLOPT_CONNECT_TO:
+    data->set.connect_to = slist;
+    break;
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+  return result;
+}
+
+/* assorted pointer type arguments */
+static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option,
+                                va_list param)
+{
+  CURLcode result = CURLE_OK;
+  switch(option) {
+#ifndef CURL_DISABLE_HTTP
+#ifndef CURL_DISABLE_FORM_API
+  case CURLOPT_HTTPPOST:
+    /*
+     * Set to make us do HTTP POST. Legacy API-style.
+     */
+    data->set.httppost = va_arg(param, struct curl_httppost *);
+    data->set.method = HTTPREQ_POST_FORM;
+    data->set.opt_no_body = FALSE; /* this is implied */
+    Curl_mime_cleanpart(data->state.formp);
+    Curl_safefree(data->state.formp);
+    data->state.mimepost = NULL;
+    break;
+#endif /* ! CURL_DISABLE_FORM_API */
+#endif /* ! CURL_DISABLE_HTTP */
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) ||       \
+    !defined(CURL_DISABLE_IMAP)
+# 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 */
+#ifndef CURL_DISABLE_FORM_API
+      Curl_mime_cleanpart(data->state.formp);
+      Curl_safefree(data->state.formp);
+      data->state.mimepost = NULL;
+#endif
+    }
+    break;
+#endif /* ! CURL_DISABLE_MIME */
+#endif /* ! disabled HTTP, SMTP or IMAP */
+  case CURLOPT_STDERR:
+    /*
+     * Set to a FILE * that should receive all error writes. This
+     * defaults to stderr for normal operations.
+     */
+    data->set.err = va_arg(param, FILE *);
+    if(!data->set.err)
+      data->set.err = stderr;
+    break;
+  case CURLOPT_SHARE:
+  {
+    struct Curl_share *set = va_arg(param, struct Curl_share *);
+
+    /* disconnect from old share, if any */
+    if(data->share) {
+      Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+      if(data->dns.hostcachetype == HCACHE_SHARED) {
+        data->dns.hostcache = NULL;
+        data->dns.hostcachetype = HCACHE_NONE;
+      }
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+      if(data->share->cookies == data->cookies)
+        data->cookies = NULL;
+#endif
+
+#ifndef CURL_DISABLE_HSTS
+      if(data->share->hsts == data->hsts)
+        data->hsts = NULL;
+#endif
+#ifdef USE_SSL
+      if(data->share->sslsession == data->state.session)
+        data->state.session = NULL;
+#endif
+#ifdef USE_LIBPSL
+      if(data->psl == &data->share->psl)
+        data->psl = data->multi ? &data->multi->psl : NULL;
+#endif
+
+      data->share->dirty--;
+
+      Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+      data->share = NULL;
+    }
+
+    if(GOOD_SHARE_HANDLE(set))
+      /* use new share if it set */
+      data->share = set;
+    if(data->share) {
+
+      Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+      data->share->dirty++;
+
+      if(data->share->specifier & (1 << CURL_LOCK_DATA_DNS)) {
+        /* use shared host cache */
+        data->dns.hostcache = &data->share->hostcache;
+        data->dns.hostcachetype = HCACHE_SHARED;
+      }
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+      if(data->share->cookies) {
+        /* use shared cookie list, first free own one if any */
+        Curl_cookie_cleanup(data->cookies);
+        /* enable cookies since we now use a share that uses cookies! */
+        data->cookies = data->share->cookies;
+      }
+#endif   /* CURL_DISABLE_HTTP */
+#ifndef CURL_DISABLE_HSTS
+      if(data->share->hsts) {
+        /* first free the private one if any */
+        Curl_hsts_cleanup(&data->hsts);
+        data->hsts = data->share->hsts;
+      }
+#endif
+#ifdef USE_SSL
+      if(data->share->sslsession) {
+        data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
+        data->state.session = data->share->sslsession;
+      }
+#endif
+#ifdef USE_LIBPSL
+      if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL))
+        data->psl = &data->share->psl;
+#endif
+
+      Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+    }
+    /* check for host cache not needed,
+     * it will be done by curl_easy_perform */
+  }
+  break;
+
+#ifdef USE_HTTP2
+  case CURLOPT_STREAM_DEPENDS:
+  case CURLOPT_STREAM_DEPENDS_E: {
+    struct Curl_easy *dep = va_arg(param, struct Curl_easy *);
+    if(!dep || GOOD_EASY_HANDLE(dep))
+      return Curl_data_priority_add_child(dep, data,
+                                          option == CURLOPT_STREAM_DEPENDS_E);
+    break;
+  }
+#endif
+
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+  return result;
+}
+
+static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
+                            char *ptr)
+{
+  CURLcode result = CURLE_OK;
+  switch(option) {
+  case CURLOPT_SSL_CIPHER_LIST:
+    if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST))
+      /* set a list of cipher we want to use in the SSL connection */
+      return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST], ptr);
+    return CURLE_NOT_BUILT_IN;
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSL_CIPHER_LIST:
+    if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) {
+      /* set a list of cipher we want to use in the SSL connection for proxy */
+      return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
+                            ptr);
+    }
+    else
+      return CURLE_NOT_BUILT_IN;
+    break;
+#endif
+  case CURLOPT_TLS13_CIPHERS:
+    if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) {
+      /* set preferred list of TLS 1.3 cipher suites */
+      return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST], ptr);
+    }
+    else
+      return CURLE_NOT_BUILT_IN;
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_TLS13_CIPHERS:
+    if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES))
+      /* set preferred list of TLS 1.3 cipher suites for proxy */
+      return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_PROXY],
+                            ptr);
+    else
+      return CURLE_NOT_BUILT_IN;
+    break;
+#endif
+  case CURLOPT_RANDOM_FILE:
+    break;
+  case CURLOPT_EGDSOCKET:
+    break;
+  case CURLOPT_REQUEST_TARGET:
+    return Curl_setstropt(&data->set.str[STRING_TARGET], ptr);
+#ifndef CURL_DISABLE_NETRC
+  case CURLOPT_NETRC_FILE:
+    /*
+     * Use this file instead of the $HOME/.netrc file
+     */
+    return Curl_setstropt(&data->set.str[STRING_NETRC_FILE], ptr);
+#endif
+
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT)
+  case CURLOPT_COPYPOSTFIELDS:
+    /*
+     * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
+     * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to
+     *  CURLOPT_COPYPOSTFIELDS and not altered later.
+     */
+    if(!ptr || data->set.postfieldsize == -1)
+      result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], ptr);
+    else {
+      if(data->set.postfieldsize < 0)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
+      /*
+       *  Check that requested length does not overflow the size_t type.
+       */
+      else if(data->set.postfieldsize > SIZE_T_MAX)
+        return CURLE_OUT_OF_MEMORY;
+#endif
+      else {
+        /* Allocate even when size == 0. This satisfies the need of possible
+           later address compare to detect the COPYPOSTFIELDS mode, and to
+           mark that postfields is used rather than read function or form
+           data.
+        */
+        char *p = Curl_memdup0(ptr, (size_t)data->set.postfieldsize);
+        if(!p)
+          return CURLE_OUT_OF_MEMORY;
+        else {
+          free(data->set.str[STRING_COPYPOSTFIELDS]);
+          data->set.str[STRING_COPYPOSTFIELDS] = p;
+        }
+      }
+    }
+
+    data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
+    data->set.method = HTTPREQ_POST;
+    break;
+
+  case CURLOPT_POSTFIELDS:
+    /*
+     * Like above, but use static data instead of copying it.
+     */
+    data->set.postfields = ptr;
+    /* Release old copied data. */
+    Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
+    data->set.method = HTTPREQ_POST;
+    break;
+#endif /* ! CURL_DISABLE_HTTP || ! CURL_DISABLE_MQTT */
+
+#ifndef CURL_DISABLE_HTTP
+  case CURLOPT_ACCEPT_ENCODING:
+    /*
+     * String to use at the value of Accept-Encoding header.
+     *
+     * If the encoding is set to "" we use an Accept-Encoding header that
+     * encompasses all the encodings we support.
+     * If the encoding is set to NULL we do not send an Accept-Encoding header
+     * and ignore an received Content-Encoding header.
+     *
+     */
+    if(ptr && !*ptr) {
+      char all[256];
+      Curl_all_content_encodings(all, sizeof(all));
+      return Curl_setstropt(&data->set.str[STRING_ENCODING], all);
+    }
+    return Curl_setstropt(&data->set.str[STRING_ENCODING], ptr);
+
+#if !defined(CURL_DISABLE_AWS)
+  case CURLOPT_AWS_SIGV4:
+    /*
+     * String that is merged to some authentication
+     * parameters are used by the algorithm.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_AWS_SIGV4], ptr);
+    /*
+     * Basic been set by default it need to be unset here
+     */
+    if(data->set.str[STRING_AWS_SIGV4])
+      data->set.httpauth = CURLAUTH_AWS_SIGV4;
+    break;
+#endif
+  case CURLOPT_REFERER:
+    /*
+     * String to set in the HTTP Referer: field.
+     */
+    if(data->state.referer_alloc) {
+      Curl_safefree(data->state.referer);
+      data->state.referer_alloc = FALSE;
+    }
+    result = Curl_setstropt(&data->set.str[STRING_SET_REFERER], ptr);
+    data->state.referer = data->set.str[STRING_SET_REFERER];
+    break;
+
+  case CURLOPT_USERAGENT:
+    /*
+     * String to use in the HTTP User-Agent field
+     */
+    return Curl_setstropt(&data->set.str[STRING_USERAGENT], ptr);
+
+#if !defined(CURL_DISABLE_COOKIES)
+  case CURLOPT_COOKIE:
+    /*
+     * Cookie string to send to the remote server in the request.
+     */
+    return Curl_setstropt(&data->set.str[STRING_COOKIE], ptr);
+
+  case CURLOPT_COOKIEFILE:
+    /*
+     * Set cookie file to read and parse. Can be used multiple times.
+     */
+    if(ptr) {
+      struct curl_slist *cl;
+      /* general protection against mistakes and abuse */
+      if(strlen(ptr) > CURL_MAX_INPUT_LENGTH)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+      /* append the cookie filename to the list of filenames, and deal with
+         them later */
+      cl = curl_slist_append(data->state.cookielist, ptr);
+      if(!cl) {
+        curl_slist_free_all(data->state.cookielist);
+        data->state.cookielist = NULL;
+        return CURLE_OUT_OF_MEMORY;
+      }
+      data->state.cookielist = cl; /* store the list for later use */
+    }
+    else {
+      /* clear the list of cookie files */
+      curl_slist_free_all(data->state.cookielist);
+      data->state.cookielist = NULL;
+
+      if(!data->share || !data->share->cookies) {
+        /* throw away all existing cookies if this is not a shared cookie
+           container */
+        Curl_cookie_clearall(data->cookies);
+        Curl_cookie_cleanup(data->cookies);
+      }
+      /* disable the cookie engine */
+      data->cookies = NULL;
+    }
+    break;
+
+  case CURLOPT_COOKIEJAR:
+    /*
+     * Set cookie filename to dump all cookies to when we are done.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR], ptr);
+    if(!result) {
+      /*
+       * Activate the cookie parser. This may or may not already
+       * have been made.
+       */
+      struct CookieInfo *newcookies =
+        Curl_cookie_init(data, NULL, data->cookies, data->set.cookiesession);
+      if(!newcookies)
+        result = CURLE_OUT_OF_MEMORY;
+      data->cookies = newcookies;
+    }
+    break;
+
+  case CURLOPT_COOKIELIST:
+    if(!ptr)
+      break;
+
+    if(strcasecompare(ptr, "ALL")) {
+      /* clear all cookies */
+      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+      Curl_cookie_clearall(data->cookies);
+      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+    }
+    else if(strcasecompare(ptr, "SESS")) {
+      /* clear session cookies */
+      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+      Curl_cookie_clearsess(data->cookies);
+      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+    }
+    else if(strcasecompare(ptr, "FLUSH")) {
+      /* flush cookies to file, takes care of the locking */
+      Curl_flush_cookies(data, FALSE);
+    }
+    else if(strcasecompare(ptr, "RELOAD")) {
+      /* reload cookies from file */
+      Curl_cookie_loadfiles(data);
+      break;
+    }
+    else {
+      if(!data->cookies) {
+        /* if cookie engine was not running, activate it */
+        data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
+        if(!data->cookies)
+          return CURLE_OUT_OF_MEMORY;
+      }
+
+      /* general protection against mistakes and abuse */
+      if(strlen(ptr) > CURL_MAX_INPUT_LENGTH)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+
+      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+      if(checkprefix("Set-Cookie:", ptr))
+        /* HTTP Header format line */
+        Curl_cookie_add(data, data->cookies, TRUE, FALSE, ptr + 11, NULL,
+                        NULL, TRUE);
+      else
+        /* Netscape format line */
+        Curl_cookie_add(data, data->cookies, FALSE, FALSE, ptr, NULL,
+                        NULL, TRUE);
+      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+    }
+    break;
+#endif /* !CURL_DISABLE_COOKIES */
+
+#endif /* ! CURL_DISABLE_HTTP */
+
+  case CURLOPT_CUSTOMREQUEST:
+    /*
+     * Set a custom string to use as request
+     */
+    return Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST], ptr);
+
+    /* we do not set
+       data->set.method = HTTPREQ_CUSTOM;
+       here, we continue as if we were using the already set type
+       and this just changes the actual request keyword */
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY:
+    /*
+     * Set proxy server:port to use as proxy.
+     *
+     * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL)
+     * we explicitly say that we do not want to use a proxy
+     * (even though there might be environment variables saying so).
+     *
+     * Setting it to NULL, means no proxy but allows the environment variables
+     * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL).
+     */
+    return Curl_setstropt(&data->set.str[STRING_PROXY], ptr);
+    break;
+
+  case CURLOPT_PRE_PROXY:
+    /*
+     * Set proxy server:port to use as SOCKS proxy.
+     *
+     * If the proxy is set to "" or NULL we explicitly say that we do not want
+     * to use the socks proxy.
+     */
+    return Curl_setstropt(&data->set.str[STRING_PRE_PROXY], ptr);
+#endif   /* CURL_DISABLE_PROXY */
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_SOCKS5_GSSAPI_SERVICE:
+  case CURLOPT_PROXY_SERVICE_NAME:
+    /*
+     * Set proxy authentication service name for Kerberos 5 and SPNEGO
+     */
+    return Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], ptr);
+#endif
+  case CURLOPT_SERVICE_NAME:
+    /*
+     * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
+     */
+    return Curl_setstropt(&data->set.str[STRING_SERVICE_NAME], ptr);
+    break;
+
+  case CURLOPT_HEADERDATA:
+    /*
+     * Custom pointer to pass the header write callback function
+     */
+    data->set.writeheader = (void *)ptr;
+    break;
+  case CURLOPT_READDATA:
+    /*
+     * FILE pointer to read the file to be uploaded from. Or possibly used as
+     * argument to the read callback.
+     */
+    data->set.in_set = (void *)ptr;
+    break;
+  case CURLOPT_WRITEDATA:
+    /*
+     * FILE pointer to write to. Or possibly used as argument to the write
+     * callback.
+     */
+    data->set.out = (void *)ptr;
+    break;
+  case CURLOPT_DEBUGDATA:
+    /*
+     * Set to a void * that should receive all error writes. This
+     * defaults to CURLOPT_STDERR for normal operations.
+     */
+    data->set.debugdata = (void *)ptr;
+    break;
+  case CURLOPT_PROGRESSDATA:
+    /*
+     * Custom client data to pass to the progress callback
+     */
+    data->set.progress_client = (void *)ptr;
+    break;
+  case CURLOPT_SEEKDATA:
+    /*
+     * Seek control callback. Might be NULL.
+     */
+    data->set.seek_client = (void *)ptr;
+    break;
+  case CURLOPT_IOCTLDATA:
+    /*
+     * I/O control data pointer. Might be NULL.
+     */
+    data->set.ioctl_client = (void *)ptr;
+    break;
+  case CURLOPT_SSL_CTX_DATA:
+    /*
+     * Set a SSL_CTX callback parameter pointer
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
+      data->set.ssl.fsslctxp = (void *)ptr;
+    else
+#endif
+      return CURLE_NOT_BUILT_IN;
+    break;
+  case CURLOPT_SOCKOPTDATA:
+    /*
+     * socket callback data pointer. Might be NULL.
+     */
+    data->set.sockopt_client = (void *)ptr;
+    break;
+  case CURLOPT_OPENSOCKETDATA:
+    /*
+     * socket callback data pointer. Might be NULL.
+     */
+    data->set.opensocket_client = (void *)ptr;
+    break;
+  case CURLOPT_RESOLVER_START_DATA:
+    /*
+     * resolver start callback data pointer. Might be NULL.
+     */
+    data->set.resolver_start_client = (void *)ptr;
+    break;
+  case CURLOPT_CLOSESOCKETDATA:
+    /*
+     * socket callback data pointer. Might be NULL.
+     */
+    data->set.closesocket_client = (void *)ptr;
     break;
   case CURLOPT_TRAILERDATA:
 #ifndef CURL_DISABLE_HTTP
-    data->set.trailer_data = va_arg(param, void *);
+    data->set.trailer_data = (void *)ptr;
 #endif
     break;
+  case CURLOPT_PREREQDATA:
+    data->set.prereq_userp = (void *)ptr;
+    break;
+
+  case CURLOPT_ERRORBUFFER:
+    /*
+     * Error buffer provided by the caller to get the human readable error
+     * string in.
+     */
+    data->set.errorbuffer = ptr;
+    break;
+
+#ifndef CURL_DISABLE_FTP
+  case CURLOPT_FTPPORT:
+    /*
+     * Use FTP PORT, this also specifies which IP address to use
+     */
+    result = Curl_setstropt(&data->set.str[STRING_FTPPORT], ptr);
+    data->set.ftp_use_port = !!(data->set.str[STRING_FTPPORT]);
+    break;
+
+  case CURLOPT_FTP_ACCOUNT:
+    return Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT], ptr);
+
+  case CURLOPT_FTP_ALTERNATIVE_TO_USER:
+    return Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER], ptr);
+
+#ifdef HAVE_GSSAPI
+  case CURLOPT_KRBLEVEL:
+    /*
+     * A string that defines the kerberos security level.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL], ptr);
+    data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]);
+    break;
+#endif
+#endif
+  case CURLOPT_URL:
+    /*
+     * The URL to fetch.
+     */
+    if(data->state.url_alloc) {
+      /* the already set URL is allocated, free it first! */
+      Curl_safefree(data->state.url);
+      data->state.url_alloc = FALSE;
+    }
+    result = Curl_setstropt(&data->set.str[STRING_SET_URL], ptr);
+    data->state.url = data->set.str[STRING_SET_URL];
+    break;
+
+  case CURLOPT_USERPWD:
+    /*
+     * user:password to use in the operation
+     */
+    return setstropt_userpwd(ptr, &data->set.str[STRING_USERNAME],
+                             &data->set.str[STRING_PASSWORD]);
+
+  case CURLOPT_USERNAME:
+    /*
+     * authentication username to use in the operation
+     */
+    return Curl_setstropt(&data->set.str[STRING_USERNAME], ptr);
+
+  case CURLOPT_PASSWORD:
+    /*
+     * authentication password to use in the operation
+     */
+    return Curl_setstropt(&data->set.str[STRING_PASSWORD], ptr);
+
+  case CURLOPT_LOGIN_OPTIONS:
+    /*
+     * authentication options to use in the operation
+     */
+    return Curl_setstropt(&data->set.str[STRING_OPTIONS], ptr);
+
+  case CURLOPT_XOAUTH2_BEARER:
+    /*
+     * OAuth 2.0 bearer token to use in the operation
+     */
+    return Curl_setstropt(&data->set.str[STRING_BEARER], ptr);
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXYUSERPWD: {
+    /*
+     * user:password needed to use the proxy
+     */
+    char *u = NULL;
+    char *p = NULL;
+    result = setstropt_userpwd(ptr, &u, &p);
+
+    /* URL decode the components */
+    if(!result && u)
+      result = Curl_urldecode(u, 0, &data->set.str[STRING_PROXYUSERNAME], NULL,
+                              REJECT_ZERO);
+    if(!result && p)
+      result = Curl_urldecode(p, 0, &data->set.str[STRING_PROXYPASSWORD], NULL,
+                              REJECT_ZERO);
+    free(u);
+    free(p);
+  }
+    break;
+  case CURLOPT_PROXYUSERNAME:
+    /*
+     * authentication username to use in the operation
+     */
+    return Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME], ptr);
+
+  case CURLOPT_PROXYPASSWORD:
+    /*
+     * authentication password to use in the operation
+     */
+    return Curl_setstropt(&data->set.str[STRING_PROXYPASSWORD], ptr);
+
+  case CURLOPT_NOPROXY:
+    /*
+     * proxy exception list
+     */
+    return Curl_setstropt(&data->set.str[STRING_NOPROXY], ptr);
+#endif /* ! CURL_DISABLE_PROXY */
+
+  case CURLOPT_RANGE:
+    /*
+     * What range of the file you want to transfer
+     */
+    return Curl_setstropt(&data->set.str[STRING_SET_RANGE], ptr);
+
+  case CURLOPT_CURLU:
+    /*
+     * pass CURLU to set URL
+     */
+    data->set.uh = (CURLU *)ptr;
+    break;
+  case CURLOPT_SSLCERT:
+    /*
+     * String that holds filename of the SSL certificate to use
+     */
+    return Curl_setstropt(&data->set.str[STRING_CERT], ptr);
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSLCERT:
+    /*
+     * String that holds filename of the SSL certificate to use for proxy
+     */
+    return Curl_setstropt(&data->set.str[STRING_CERT_PROXY], ptr);
+
+#endif
+  case CURLOPT_SSLCERTTYPE:
+    /*
+     * String that holds file type of the SSL certificate to use
+     */
+    return Curl_setstropt(&data->set.str[STRING_CERT_TYPE], ptr);
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSLCERTTYPE:
+    /*
+     * String that holds file type of the SSL certificate to use for proxy
+     */
+    return Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY], ptr);
+#endif
+  case CURLOPT_SSLKEY:
+    /*
+     * String that holds filename of the SSL key to use
+     */
+    return Curl_setstropt(&data->set.str[STRING_KEY], ptr);
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSLKEY:
+    /*
+     * String that holds filename of the SSL key to use for proxy
+     */
+    return Curl_setstropt(&data->set.str[STRING_KEY_PROXY], ptr);
+
+#endif
+  case CURLOPT_SSLKEYTYPE:
+    /*
+     * String that holds file type of the SSL key to use
+     */
+    return Curl_setstropt(&data->set.str[STRING_KEY_TYPE], ptr);
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSLKEYTYPE:
+    /*
+     * String that holds file type of the SSL key to use for proxy
+     */
+    return Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY], ptr);
+
+#endif
+  case CURLOPT_KEYPASSWD:
+    /*
+     * String that holds the SSL or SSH private key password.
+     */
+    return Curl_setstropt(&data->set.str[STRING_KEY_PASSWD], ptr);
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_KEYPASSWD:
+    /*
+     * String that holds the SSL private key password for proxy.
+     */
+    return Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY], ptr);
+#endif
+  case CURLOPT_SSLENGINE:
+    /*
+     * String that holds the SSL crypto engine.
+     */
+    if(ptr && ptr[0]) {
+      result = Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], ptr);
+      if(!result) {
+        result = Curl_ssl_set_engine(data, ptr);
+      }
+    }
+    break;
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_HAPROXY_CLIENT_IP:
+    /*
+     * Set the client IP to send through HAProxy PROXY protocol
+     */
+    result = Curl_setstropt(&data->set.str[STRING_HAPROXY_CLIENT_IP], ptr);
+    /* enable the HAProxy protocol */
+    data->set.haproxyprotocol = TRUE;
+    break;
+#endif
+  case CURLOPT_INTERFACE:
+    /*
+     * Set what interface or address/hostname to bind the socket to when
+     * performing an operation and thus what from-IP your connection will use.
+     */
+    return setstropt_interface(ptr,
+                               &data->set.str[STRING_DEVICE],
+                               &data->set.str[STRING_INTERFACE],
+                               &data->set.str[STRING_BINDHOST]);
+
+  case CURLOPT_PINNEDPUBLICKEY:
+    /*
+     * Set pinned public key for SSL connection.
+     * Specify filename of the public key in DER format.
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
+      return Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY], ptr);
+#endif
+    return CURLE_NOT_BUILT_IN;
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_PINNEDPUBLICKEY:
+    /*
+     * Set pinned public key for SSL connection.
+     * Specify filename of the public key in DER format.
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
+      return Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
+                            ptr);
+#endif
+    return CURLE_NOT_BUILT_IN;
+#endif
+  case CURLOPT_CAINFO:
+    /*
+     * Set CA info for SSL connection. Specify filename of the CA certificate
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSL_CAFILE], ptr);
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_CAINFO:
+    /*
+     * Set CA info SSL connection for proxy. Specify filename of the
+     * CA certificate
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], ptr);
+#endif
+
+  case CURLOPT_CAPATH:
+    /*
+     * Set CA path info for SSL connection. Specify directory name of the CA
+     * certificates which have been prepared using openssl c_rehash utility.
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
+      /* This does not work on Windows. */
+      return Curl_setstropt(&data->set.str[STRING_SSL_CAPATH], ptr);
+#endif
+    return CURLE_NOT_BUILT_IN;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_CAPATH:
+    /*
+     * Set CA path info for SSL connection proxy. Specify directory name of the
+     * CA certificates which have been prepared using openssl c_rehash utility.
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
+      /* This does not work on Windows. */
+      return Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], ptr);
+#endif
+    return CURLE_NOT_BUILT_IN;
+#endif
+  case CURLOPT_CRLFILE:
+    /*
+     * Set CRL file info for SSL connection. Specify filename of the CRL
+     * to check certificates revocation
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE], ptr);
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_CRLFILE:
+    /*
+     * Set CRL file info for SSL connection for proxy. Specify filename of the
+     * CRL to check certificates revocation
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY], ptr);
+#endif
+  case CURLOPT_ISSUERCERT:
+    /*
+     * Set Issuer certificate file
+     * to check certificates issuer
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT], ptr);
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_ISSUERCERT:
+    /*
+     * Set Issuer certificate file
+     * to check certificates issuer
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY], ptr);
+
+#endif
+
+  case CURLOPT_PRIVATE:
+    /*
+     * Set private data pointer.
+     */
+    data->set.private_data = (void *)ptr;
+    break;
+
+#ifdef USE_SSL
+  case CURLOPT_SSL_EC_CURVES:
+    /*
+     * Set accepted curves in SSL connection setup.
+     * Specify colon-delimited list of curve algorithm names.
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES], ptr);
+#endif
+#ifdef USE_SSH
+  case CURLOPT_SSH_PUBLIC_KEYFILE:
+    /*
+     * Use this file instead of the $HOME/.ssh/id_dsa.pub file
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY], ptr);
+
+  case CURLOPT_SSH_PRIVATE_KEYFILE:
+    /*
+     * Use this file instead of the $HOME/.ssh/id_dsa file
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY], ptr);
+
+  case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
+    /*
+     * Option to allow for the MD5 of the host public key to be checked
+     * for validation purposes.
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], ptr);
+
+  case CURLOPT_SSH_KNOWNHOSTS:
+    /*
+     * Store the filename to read known hosts from.
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS], ptr);
+
+  case CURLOPT_SSH_KEYDATA:
+    /*
+     * Custom client data to pass to the SSH keyfunc callback
+     */
+    data->set.ssh_keyfunc_userp = (void *)ptr;
+    break;
+#ifdef USE_LIBSSH2
+  case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
+    /*
+     * Option to allow for the SHA256 of the host public key to be checked
+     * for validation purposes.
+     */
+    return Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256],
+                          ptr);
+
+  case CURLOPT_SSH_HOSTKEYDATA:
+    /*
+     * Custom client data to pass to the SSH keyfunc callback
+     */
+    data->set.ssh_hostkeyfunc_userp = (void *)ptr;
+    break;
+#endif /* USE_LIBSSH2 */
+#endif /* USE_SSH */
+  case CURLOPT_PROTOCOLS_STR:
+    if(ptr)
+      return protocol2num(ptr, &data->set.allowed_protocols);
+    /* make a NULL argument reset to default */
+    data->set.allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
+    break;
+
+  case CURLOPT_REDIR_PROTOCOLS_STR:
+    if(ptr)
+      return protocol2num(ptr, &data->set.redir_protocols);
+    /* make a NULL argument reset to default */
+    data->set.redir_protocols = (curl_prot_t) CURLPROTO_REDIR;
+    break;
+
+  case CURLOPT_DEFAULT_PROTOCOL:
+    /* Set the protocol to use when the URL does not include any protocol */
+    return Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL], ptr);
+
+#ifndef CURL_DISABLE_SMTP
+  case CURLOPT_MAIL_FROM:
+    /* Set the SMTP mail originator */
+    return Curl_setstropt(&data->set.str[STRING_MAIL_FROM], ptr);
+
+  case CURLOPT_MAIL_AUTH:
+    /* Set the SMTP auth originator */
+    return Curl_setstropt(&data->set.str[STRING_MAIL_AUTH], ptr);
+#endif
+
+  case CURLOPT_SASL_AUTHZID:
+    /* Authorization identity (identity to act as) */
+    return Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID], ptr);
+
+#ifndef CURL_DISABLE_RTSP
+  case CURLOPT_RTSP_SESSION_ID:
+    /*
+     * Set the RTSP Session ID manually. Useful if the application is
+     * resuming a previously established RTSP session
+     */
+    return Curl_setstropt(&data->set.str[STRING_RTSP_SESSION_ID], ptr);
+
+  case CURLOPT_RTSP_STREAM_URI:
+    /*
+     * Set the Stream URI for the RTSP request. Unless the request is
+     * for generic server options, the application will need to set this.
+     */
+    return Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI], ptr);
+    break;
+
+  case CURLOPT_RTSP_TRANSPORT:
+    /*
+     * The content of the Transport: header for the RTSP request
+     */
+    return Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT], ptr);
+
+  case CURLOPT_INTERLEAVEDATA:
+    data->set.rtp_out = (void *)ptr;
+    break;
+#endif /* ! CURL_DISABLE_RTSP */
+#ifndef CURL_DISABLE_FTP
+  case CURLOPT_CHUNK_DATA:
+    data->set.wildcardptr = (void *)ptr;
+    break;
+  case CURLOPT_FNMATCH_DATA:
+    data->set.fnmatch_data = (void *)ptr;
+    break;
+#endif
+#ifdef USE_TLS_SRP
+  case CURLOPT_TLSAUTH_USERNAME:
+    return Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME], ptr);
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_TLSAUTH_USERNAME:
+    return Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], ptr);
+
+#endif
+  case CURLOPT_TLSAUTH_PASSWORD:
+    return Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD], ptr);
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_TLSAUTH_PASSWORD:
+    return Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], ptr);
+#endif
+  case CURLOPT_TLSAUTH_TYPE:
+    if(ptr && !strcasecompare(ptr, "SRP"))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_TLSAUTH_TYPE:
+    if(ptr && !strcasecompare(ptr, "SRP"))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+#endif
+#endif
+#ifdef USE_ARES
+  case CURLOPT_DNS_SERVERS:
+    result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS], ptr);
+    if(result)
+      return result;
+    return Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]);
+
+  case CURLOPT_DNS_INTERFACE:
+    result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE], ptr);
+    if(result)
+      return result;
+    return Curl_set_dns_interface(data, data->set.str[STRING_DNS_INTERFACE]);
+
+  case CURLOPT_DNS_LOCAL_IP4:
+    result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4], ptr);
+    if(result)
+      return result;
+    return Curl_set_dns_local_ip4(data, data->set.str[STRING_DNS_LOCAL_IP4]);
+
+  case CURLOPT_DNS_LOCAL_IP6:
+    result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6], ptr);
+    if(result)
+      return result;
+    return Curl_set_dns_local_ip6(data, data->set.str[STRING_DNS_LOCAL_IP6]);
+
+#endif
+#ifdef USE_UNIX_SOCKETS
+  case CURLOPT_UNIX_SOCKET_PATH:
+    data->set.abstract_unix_socket = FALSE;
+    return Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], ptr);
+
+  case CURLOPT_ABSTRACT_UNIX_SOCKET:
+    data->set.abstract_unix_socket = TRUE;
+    return Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], ptr);
+
+#endif
+
+#ifndef CURL_DISABLE_DOH
+  case CURLOPT_DOH_URL:
+    result = Curl_setstropt(&data->set.str[STRING_DOH], ptr);
+    data->set.doh = !!(data->set.str[STRING_DOH]);
+    break;
+#endif
 #ifndef CURL_DISABLE_HSTS
-  case CURLOPT_HSTSREADFUNCTION:
-    data->set.hsts_read = va_arg(param, curl_hstsread_callback);
-    break;
   case CURLOPT_HSTSREADDATA:
-    data->set.hsts_read_userp = va_arg(param, void *);
-    break;
-  case CURLOPT_HSTSWRITEFUNCTION:
-    data->set.hsts_write = va_arg(param, curl_hstswrite_callback);
+    data->set.hsts_read_userp = (void *)ptr;
     break;
   case CURLOPT_HSTSWRITEDATA:
-    data->set.hsts_write_userp = va_arg(param, void *);
+    data->set.hsts_write_userp = (void *)ptr;
     break;
   case CURLOPT_HSTS: {
     struct curl_slist *h;
@@ -3109,15 +2610,14 @@
       if(!data->hsts)
         return CURLE_OUT_OF_MEMORY;
     }
-    argptr = va_arg(param, char *);
-    if(argptr) {
-      result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
+    if(ptr) {
+      result = Curl_setstropt(&data->set.str[STRING_HSTS], ptr);
       if(result)
         return result;
       /* this needs to build a list of filenames to read from, so that it can
          read them later, as we might get a shared HSTS handle to load them
          into */
-      h = curl_slist_append(data->state.hstslist, argptr);
+      h = curl_slist_append(data->state.hstslist, ptr);
       if(!h) {
         curl_slist_free_all(data->state.hstslist);
         data->state.hstslist = NULL;
@@ -3135,19 +2635,7 @@
     }
     break;
   }
-  case CURLOPT_HSTS_CTRL:
-    arg = va_arg(param, long);
-    if(arg & CURLHSTS_ENABLE) {
-      if(!data->hsts) {
-        data->hsts = Curl_hsts_init();
-        if(!data->hsts)
-          return CURLE_OUT_OF_MEMORY;
-      }
-    }
-    else
-      Curl_hsts_cleanup(&data->hsts);
-    break;
-#endif
+#endif /* ! CURL_DISABLE_HSTS */
 #ifndef CURL_DISABLE_ALTSVC
   case CURLOPT_ALTSVC:
     if(!data->asi) {
@@ -3155,96 +2643,417 @@
       if(!data->asi)
         return CURLE_OUT_OF_MEMORY;
     }
-    argptr = va_arg(param, char *);
-    result = Curl_setstropt(&data->set.str[STRING_ALTSVC], argptr);
+    result = Curl_setstropt(&data->set.str[STRING_ALTSVC], ptr);
     if(result)
       return result;
-    if(argptr)
-      (void)Curl_altsvc_load(data->asi, argptr);
+    if(ptr)
+      (void)Curl_altsvc_load(data->asi, ptr);
     break;
-  case CURLOPT_ALTSVC_CTRL:
-    if(!data->asi) {
-      data->asi = Curl_altsvc_init();
-      if(!data->asi)
-        return CURLE_OUT_OF_MEMORY;
+#endif /* ! CURL_DISABLE_ALTSVC */
+#ifdef USE_ECH
+  case CURLOPT_ECH: {
+    size_t plen = 0;
+
+    if(!ptr) {
+      data->set.tls_ech = CURLECH_DISABLE;
+      return CURLE_OK;
     }
-    arg = va_arg(param, long);
-    if(!arg) {
-      DEBUGF(infof(data, "bad CURLOPT_ALTSVC_CTRL input"));
+    plen = strlen(ptr);
+    if(plen > CURL_MAX_INPUT_LENGTH) {
+      data->set.tls_ech = CURLECH_DISABLE;
       return CURLE_BAD_FUNCTION_ARGUMENT;
     }
-    result = Curl_altsvc_ctrl(data->asi, arg);
-    if(result)
-      return result;
+    /* set tls_ech flag value, preserving CLA_CFG bit */
+    if(!strcmp(ptr, "false"))
+      data->set.tls_ech = CURLECH_DISABLE |
+        (data->set.tls_ech & CURLECH_CLA_CFG);
+    else if(!strcmp(ptr, "grease"))
+      data->set.tls_ech = CURLECH_GREASE |
+        (data->set.tls_ech & CURLECH_CLA_CFG);
+    else if(!strcmp(ptr, "true"))
+      data->set.tls_ech = CURLECH_ENABLE |
+        (data->set.tls_ech & CURLECH_CLA_CFG);
+    else if(!strcmp(ptr, "hard"))
+      data->set.tls_ech = CURLECH_HARD |
+        (data->set.tls_ech & CURLECH_CLA_CFG);
+    else if(plen > 5 && !strncmp(ptr, "ecl:", 4)) {
+      result = Curl_setstropt(&data->set.str[STRING_ECH_CONFIG], ptr + 4);
+      if(result)
+        return result;
+      data->set.tls_ech |= CURLECH_CLA_CFG;
+    }
+    else if(plen > 4 && !strncmp(ptr, "pn:", 3)) {
+      result = Curl_setstropt(&data->set.str[STRING_ECH_PUBLIC], ptr + 3);
+      if(result)
+        return result;
+    }
+    break;
+  }
+#endif
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+  return result;
+}
+
+static CURLcode setopt_func(struct Curl_easy *data, CURLoption option,
+                            va_list param)
+{
+  switch(option) {
+  case CURLOPT_PROGRESSFUNCTION:
+    /*
+     * Progress callback function
+     */
+    data->set.fprogress = va_arg(param, curl_progress_callback);
+    if(data->set.fprogress)
+      data->progress.callback = TRUE; /* no longer internal */
+    else
+      data->progress.callback = FALSE; /* NULL enforces internal */
+    break;
+
+  case CURLOPT_XFERINFOFUNCTION:
+    /*
+     * Transfer info callback function
+     */
+    data->set.fxferinfo = va_arg(param, curl_xferinfo_callback);
+    if(data->set.fxferinfo)
+      data->progress.callback = TRUE; /* no longer internal */
+    else
+      data->progress.callback = FALSE; /* NULL enforces internal */
+
+    break;
+  case CURLOPT_DEBUGFUNCTION:
+    /*
+     * stderr write callback.
+     */
+    data->set.fdebug = va_arg(param, curl_debug_callback);
+    /*
+     * if the callback provided is NULL, it will use the default callback
+     */
+    break;
+  case CURLOPT_HEADERFUNCTION:
+    /*
+     * Set header write callback
+     */
+    data->set.fwrite_header = va_arg(param, curl_write_callback);
+    break;
+  case CURLOPT_WRITEFUNCTION:
+    /*
+     * Set data write callback
+     */
+    data->set.fwrite_func = va_arg(param, curl_write_callback);
+    if(!data->set.fwrite_func)
+      /* When set to NULL, reset to our internal default function */
+      data->set.fwrite_func = (curl_write_callback)fwrite;
+    break;
+  case CURLOPT_READFUNCTION:
+    /*
+     * Read data callback
+     */
+    data->set.fread_func_set = va_arg(param, curl_read_callback);
+    if(!data->set.fread_func_set) {
+      data->set.is_fread_set = 0;
+      /* When set to NULL, reset to our internal default function */
+      data->set.fread_func_set = (curl_read_callback)fread;
+    }
+    else
+      data->set.is_fread_set = 1;
+    break;
+  case CURLOPT_SEEKFUNCTION:
+    /*
+     * Seek callback. Might be NULL.
+     */
+    data->set.seek_func = va_arg(param, curl_seek_callback);
+    break;
+  case CURLOPT_IOCTLFUNCTION:
+    /*
+     * I/O control callback. Might be NULL.
+     */
+    data->set.ioctl_func = va_arg(param, curl_ioctl_callback);
+    break;
+  case CURLOPT_SSL_CTX_FUNCTION:
+    /*
+     * Set a SSL_CTX callback
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
+      data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
+    else
+#endif
+      return CURLE_NOT_BUILT_IN;
+    break;
+
+  case CURLOPT_SOCKOPTFUNCTION:
+    /*
+     * socket callback function: called after socket() but before connect()
+     */
+    data->set.fsockopt = va_arg(param, curl_sockopt_callback);
+    break;
+
+  case CURLOPT_OPENSOCKETFUNCTION:
+    /*
+     * open/create socket callback function: called instead of socket(),
+     * before connect()
+     */
+    data->set.fopensocket = va_arg(param, curl_opensocket_callback);
+    break;
+
+  case CURLOPT_CLOSESOCKETFUNCTION:
+    /*
+     * close socket callback function: called instead of close()
+     * when shutting down a connection
+     */
+    data->set.fclosesocket = va_arg(param, curl_closesocket_callback);
+    break;
+
+  case CURLOPT_RESOLVER_START_FUNCTION:
+    /*
+     * resolver start callback function: called before a new resolver request
+     * is started
+     */
+    data->set.resolver_start = va_arg(param, curl_resolver_start_callback);
+    break;
+
+
+#ifdef USE_SSH
+#ifdef USE_LIBSSH2
+  case CURLOPT_SSH_HOSTKEYFUNCTION:
+    /* the callback to check the hostkey without the knownhost file */
+    data->set.ssh_hostkeyfunc = va_arg(param, curl_sshhostkeycallback);
+    break;
+#endif
+
+  case CURLOPT_SSH_KEYFUNCTION:
+    /* setting to NULL is fine since the ssh.c functions themselves will
+       then revert to use the internal default */
+    data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback);
+    break;
+
+#endif /* USE_SSH */
+
+#ifndef CURL_DISABLE_RTSP
+  case CURLOPT_INTERLEAVEFUNCTION:
+    /* Set the user defined RTP write function */
+    data->set.fwrite_rtp = va_arg(param, curl_write_callback);
+    break;
+#endif
+#ifndef CURL_DISABLE_FTP
+  case CURLOPT_CHUNK_BGN_FUNCTION:
+    data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback);
+    break;
+  case CURLOPT_CHUNK_END_FUNCTION:
+    data->set.chunk_end = va_arg(param, curl_chunk_end_callback);
+    break;
+  case CURLOPT_FNMATCH_FUNCTION:
+    data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
+    break;
+#endif
+#ifndef CURL_DISABLE_HTTP
+  case CURLOPT_TRAILERFUNCTION:
+    data->set.trailer_callback = va_arg(param, curl_trailer_callback);
+    break;
+#endif
+#ifndef CURL_DISABLE_HSTS
+  case CURLOPT_HSTSREADFUNCTION:
+    data->set.hsts_read = va_arg(param, curl_hstsread_callback);
+    break;
+  case CURLOPT_HSTSWRITEFUNCTION:
+    data->set.hsts_write = va_arg(param, curl_hstswrite_callback);
     break;
 #endif
   case CURLOPT_PREREQFUNCTION:
     data->set.fprereq = va_arg(param, curl_prereq_callback);
     break;
-  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
-#ifdef USE_ECH
-  case CURLOPT_ECH: {
-    size_t plen = 0;
-
-    argptr = va_arg(param, char *);
-    if(!argptr) {
-      data->set.tls_ech = CURLECH_DISABLE;
-      return CURLE_OK;
-    }
-    plen = strlen(argptr);
-    if(plen > CURL_MAX_INPUT_LENGTH) {
-      data->set.tls_ech = CURLECH_DISABLE;
-      result = CURLE_BAD_FUNCTION_ARGUMENT;
-      return result;
-    }
-    /* set tls_ech flag value, preserving CLA_CFG bit */
-    if(plen == 5 && !strcmp(argptr, "false"))
-      data->set.tls_ech = CURLECH_DISABLE
-                          | (data->set.tls_ech & CURLECH_CLA_CFG);
-    else if(plen == 6 && !strcmp(argptr, "grease"))
-      data->set.tls_ech = CURLECH_GREASE
-                          | (data->set.tls_ech & CURLECH_CLA_CFG);
-    else if(plen == 4 && !strcmp(argptr, "true"))
-      data->set.tls_ech = CURLECH_ENABLE
-                          | (data->set.tls_ech & CURLECH_CLA_CFG);
-    else if(plen == 4 && !strcmp(argptr, "hard"))
-      data->set.tls_ech = CURLECH_HARD
-                          | (data->set.tls_ech & CURLECH_CLA_CFG);
-    else if(plen > 5 && !strncmp(argptr, "ecl:", 4)) {
-      result = Curl_setstropt(&data->set.str[STRING_ECH_CONFIG], argptr + 4);
-      if(result)
-        return result;
-      data->set.tls_ech |= CURLECH_CLA_CFG;
-    }
-    else if(plen > 4 && !strncmp(argptr, "pn:", 3)) {
-      result = Curl_setstropt(&data->set.str[STRING_ECH_PUBLIC], argptr + 3);
-      if(result)
-        return result;
-    }
-    break;
-  }
-#endif
-  case CURLOPT_QUICK_EXIT:
-    data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L;
-    break;
   default:
-    /* unknown tag and its companion, just ignore: */
-    result = CURLE_UNKNOWN_OPTION;
-    break;
+    return CURLE_UNKNOWN_OPTION;
   }
+  return CURLE_OK;
+}
 
-  return result;
+static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option,
+                            curl_off_t offt)
+{
+  switch(option) {
+  case CURLOPT_TIMEVALUE_LARGE:
+    /*
+     * This is the value to compare with the remote document with the
+     * method set with CURLOPT_TIMECONDITION
+     */
+    data->set.timevalue = (time_t)offt;
+    break;
+
+    /* MQTT "borrows" some of the HTTP options */
+  case CURLOPT_POSTFIELDSIZE_LARGE:
+    /*
+     * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+     * figure it out. Enables binary posts.
+     */
+    if(offt < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+
+    if(data->set.postfieldsize < offt &&
+       data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+      /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+      Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
+      data->set.postfields = NULL;
+    }
+    data->set.postfieldsize = offt;
+    break;
+  case CURLOPT_INFILESIZE_LARGE:
+    /*
+     * If known, this should inform curl about the file size of the
+     * to-be-uploaded file.
+     */
+    if(offt < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.filesize = offt;
+    break;
+  case CURLOPT_MAX_SEND_SPEED_LARGE:
+    /*
+     * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE
+     * bytes per second the transfer is throttled..
+     */
+    if(offt < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.max_send_speed = offt;
+    break;
+  case CURLOPT_MAX_RECV_SPEED_LARGE:
+    /*
+     * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per
+     * second the transfer is throttled..
+     */
+    if(offt < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.max_recv_speed = offt;
+    break;
+  case CURLOPT_RESUME_FROM_LARGE:
+    /*
+     * Resume transfer at the given file position
+     */
+    if(offt < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.set_resume_from = offt;
+    break;
+  case CURLOPT_MAXFILESIZE_LARGE:
+    /*
+     * Set the maximum size of a file to download.
+     */
+    if(offt < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.max_filesize = offt;
+    break;
+
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode setopt_blob(struct Curl_easy *data, CURLoption option,
+                            struct curl_blob *blob)
+{
+  switch(option) {
+  case CURLOPT_SSLCERT_BLOB:
+    /*
+     * Blob that holds file content of the SSL certificate to use
+     */
+    return Curl_setblobopt(&data->set.blobs[BLOB_CERT], blob);
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXY_SSLCERT_BLOB:
+    /*
+     * Blob that holds file content of the SSL certificate to use for proxy
+     */
+    return Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY], blob);
+  case CURLOPT_PROXY_SSLKEY_BLOB:
+    /*
+     * Blob that holds file content of the SSL key to use for proxy
+     */
+    return Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY], blob);
+  case CURLOPT_PROXY_CAINFO_BLOB:
+    /*
+     * Blob that holds CA info for SSL connection proxy.
+     * Specify entire PEM of the CA certificate
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB))
+      return Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY], blob);
+#endif
+    return CURLE_NOT_BUILT_IN;
+  case CURLOPT_PROXY_ISSUERCERT_BLOB:
+    /*
+     * Blob that holds Issuer certificate to check certificates issuer
+     */
+    return Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY],
+                           blob);
+#endif
+  case CURLOPT_SSLKEY_BLOB:
+    /*
+     * Blob that holds file content of the SSL key to use
+     */
+    return Curl_setblobopt(&data->set.blobs[BLOB_KEY], blob);
+  case CURLOPT_CAINFO_BLOB:
+    /*
+     * Blob that holds CA info for SSL connection.
+     * Specify entire PEM of the CA certificate
+     */
+#ifdef USE_SSL
+    if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB))
+      return Curl_setblobopt(&data->set.blobs[BLOB_CAINFO], blob);
+#endif
+    return CURLE_NOT_BUILT_IN;
+  case CURLOPT_ISSUERCERT_BLOB:
+    /*
+     * Blob that holds Issuer certificate to check certificates issuer
+     */
+    return Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT], blob);
+
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+  /* unreachable */
+}
+
+/*
+ * Do not make Curl_vsetopt() static: it is called from
+ * packages/OS400/ccsidcurl.c.
+ */
+CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
+{
+  if(option < CURLOPTTYPE_OBJECTPOINT)
+    return setopt_long(data, option, va_arg(param, long));
+  else if(option < CURLOPTTYPE_FUNCTIONPOINT) {
+    /* unfortunately, different pointer types cannot be identified any other
+       way than being listed explicitly */
+    switch(option) {
+    case CURLOPT_HTTPHEADER:
+    case CURLOPT_QUOTE:
+    case CURLOPT_POSTQUOTE:
+    case CURLOPT_TELNETOPTIONS:
+    case CURLOPT_PREQUOTE:
+    case CURLOPT_HTTP200ALIASES:
+    case CURLOPT_MAIL_RCPT:
+    case CURLOPT_RESOLVE:
+    case CURLOPT_PROXYHEADER:
+    case CURLOPT_CONNECT_TO:
+      return setopt_slist(data, option, va_arg(param, struct curl_slist *));
+    case CURLOPT_HTTPPOST:         /* curl_httppost * */
+    case CURLOPT_MIMEPOST:         /* curl_mime * */
+    case CURLOPT_STDERR:           /* FILE * */
+    case CURLOPT_SHARE:            /* CURLSH * */
+    case CURLOPT_STREAM_DEPENDS:   /* CURL * */
+    case CURLOPT_STREAM_DEPENDS_E: /* CURL * */
+      return setopt_pointers(data, option, param);
+    default:
+      break;
+    }
+    /* the char pointer options */
+    return setopt_cptr(data, option, va_arg(param, char *));
+  }
+  else if(option < CURLOPTTYPE_OFF_T)
+    return setopt_func(data, option, param);
+  else if(option < CURLOPTTYPE_BLOB)
+    return setopt_offt(data, option, va_arg(param, curl_off_t));
+  return setopt_blob(data, option, va_arg(param, struct curl_blob *));
 }
 
 /*
@@ -3256,10 +3065,11 @@
  */
 
 #undef curl_easy_setopt
-CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
+CURLcode curl_easy_setopt(CURL *d, CURLoption tag, ...)
 {
   va_list arg;
   CURLcode result;
+  struct Curl_easy *data = d;
 
   if(!data)
     return CURLE_BAD_FUNCTION_ARGUMENT;
diff --git a/Utilities/cmcurl/lib/sha256.c b/Utilities/cmcurl/lib/sha256.c
index 91dc950..c5bb921 100644
--- a/Utilities/cmcurl/lib/sha256.c
+++ b/Utilities/cmcurl/lib/sha256.c
@@ -34,9 +34,6 @@
 
 #ifdef USE_WOLFSSL
 #include <wolfssl/options.h>
-#ifndef NO_SHA256
-#define USE_OPENSSL_SHA256
-#endif
 #endif
 
 #if defined(USE_OPENSSL)
@@ -105,8 +102,9 @@
 };
 typedef struct ossl_sha256_ctx my_sha256_ctx;
 
-static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+static CURLcode my_sha256_init(void *in)
 {
+  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
   ctx->openssl_ctx = EVP_MD_CTX_create();
   if(!ctx->openssl_ctx)
     return CURLE_OUT_OF_MEMORY;
@@ -118,15 +116,17 @@
   return CURLE_OK;
 }
 
-static void my_sha256_update(my_sha256_ctx *ctx,
+static void my_sha256_update(void *in,
                              const unsigned char *data,
                              unsigned int length)
 {
+  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
   EVP_DigestUpdate(ctx->openssl_ctx, data, length);
 }
 
-static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+static void my_sha256_final(unsigned char *digest, void *in)
 {
+  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
   EVP_DigestFinal_ex(ctx->openssl_ctx, digest, NULL);
   EVP_MD_CTX_destroy(ctx->openssl_ctx);
 }
@@ -135,20 +135,20 @@
 
 typedef struct sha256_ctx my_sha256_ctx;
 
-static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+static CURLcode my_sha256_init(void *ctx)
 {
   sha256_init(ctx);
   return CURLE_OK;
 }
 
-static void my_sha256_update(my_sha256_ctx *ctx,
+static void my_sha256_update(void *ctx,
                              const unsigned char *data,
                              unsigned int length)
 {
   sha256_update(ctx, length, data);
 }
 
-static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+static void my_sha256_final(unsigned char *digest, void *ctx)
 {
   sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
 }
@@ -157,7 +157,7 @@
 
 typedef mbedtls_sha256_context my_sha256_ctx;
 
-static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+static CURLcode my_sha256_init(void *ctx)
 {
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
   (void) mbedtls_sha256_starts(ctx, 0);
@@ -167,7 +167,7 @@
   return CURLE_OK;
 }
 
-static void my_sha256_update(my_sha256_ctx *ctx,
+static void my_sha256_update(void *ctx,
                              const unsigned char *data,
                              unsigned int length)
 {
@@ -178,7 +178,7 @@
 #endif
 }
 
-static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+static void my_sha256_final(unsigned char *digest, void *ctx)
 {
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
   (void) mbedtls_sha256_finish(ctx, digest);
@@ -190,20 +190,20 @@
 #elif defined(AN_APPLE_OS)
 typedef CC_SHA256_CTX my_sha256_ctx;
 
-static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+static CURLcode my_sha256_init(void *ctx)
 {
   (void) CC_SHA256_Init(ctx);
   return CURLE_OK;
 }
 
-static void my_sha256_update(my_sha256_ctx *ctx,
+static void my_sha256_update(void *ctx,
                              const unsigned char *data,
                              unsigned int length)
 {
   (void) CC_SHA256_Update(ctx, data, length);
 }
 
-static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+static void my_sha256_final(unsigned char *digest, void *ctx)
 {
   (void) CC_SHA256_Final(digest, ctx);
 }
@@ -220,8 +220,9 @@
 #define CALG_SHA_256 0x0000800c
 #endif
 
-static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+static CURLcode my_sha256_init(void *in)
 {
+  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
   if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES,
                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
     return CURLE_OUT_OF_MEMORY;
@@ -235,15 +236,17 @@
   return CURLE_OK;
 }
 
-static void my_sha256_update(my_sha256_ctx *ctx,
+static void my_sha256_update(void *in,
                              const unsigned char *data,
                              unsigned int length)
 {
+  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
   CryptHashData(ctx->hHash, (unsigned char *) data, length, 0);
 }
 
-static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+static void my_sha256_final(unsigned char *digest, void *in)
 {
+  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
   unsigned long length = 0;
 
   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
@@ -388,8 +391,9 @@
 }
 
 /* Initialize the hash state */
-static CURLcode my_sha256_init(struct sha256_state *md)
+static CURLcode my_sha256_init(void *in)
 {
+  struct sha256_state *md = (struct sha256_state *)in;
   md->curlen = 0;
   md->length = 0;
   md->state[0] = 0x6A09E667UL;
@@ -409,41 +413,39 @@
    @param md     The hash state
    @param in     The data to hash
    @param inlen  The length of the data (octets)
-   @return 0 if successful
 */
-static int my_sha256_update(struct sha256_state *md,
-                            const unsigned char *in,
-                            unsigned long inlen)
+static void my_sha256_update(void *ctx,
+                             const unsigned char *in,
+                             unsigned int len)
 {
+  unsigned long inlen = len;
   unsigned long n;
-
-#define block_size 64
+  struct sha256_state *md = (struct sha256_state *)ctx;
+#define CURL_SHA256_BLOCK_SIZE 64
   if(md->curlen > sizeof(md->buf))
-    return -1;
+    return;
   while(inlen > 0) {
-    if(md->curlen == 0 && inlen >= block_size) {
+    if(md->curlen == 0 && inlen >= CURL_SHA256_BLOCK_SIZE) {
       if(sha256_compress(md, (unsigned char *)in) < 0)
-        return -1;
-      md->length += block_size * 8;
-      in += block_size;
-      inlen -= block_size;
+        return;
+      md->length += CURL_SHA256_BLOCK_SIZE * 8;
+      in += CURL_SHA256_BLOCK_SIZE;
+      inlen -= CURL_SHA256_BLOCK_SIZE;
     }
     else {
-      n = CURLMIN(inlen, (block_size - md->curlen));
+      n = CURLMIN(inlen, (CURL_SHA256_BLOCK_SIZE - md->curlen));
       memcpy(md->buf + md->curlen, in, n);
       md->curlen += n;
       in += n;
       inlen -= n;
-      if(md->curlen == block_size) {
+      if(md->curlen == CURL_SHA256_BLOCK_SIZE) {
         if(sha256_compress(md, md->buf) < 0)
-          return -1;
-        md->length += 8 * block_size;
+          return;
+        md->length += 8 * CURL_SHA256_BLOCK_SIZE;
         md->curlen = 0;
       }
     }
   }
-
-  return 0;
 }
 
 /*
@@ -452,13 +454,13 @@
    @param out [out] The destination of the hash (32 bytes)
    @return 0 if successful
 */
-static int my_sha256_final(unsigned char *out,
-                           struct sha256_state *md)
+static void my_sha256_final(unsigned char *out, void *ctx)
 {
+  struct sha256_state *md = ctx;
   int i;
 
   if(md->curlen >= sizeof(md->buf))
-    return -1;
+    return;
 
   /* Increase the length of the message */
   md->length += md->curlen * 8;
@@ -490,8 +492,6 @@
   /* Copy output */
   for(i = 0; i < 8; i++)
     WPA_PUT_BE32(out + (4 * i), md->state[i]);
-
-  return 0;
 }
 
 #endif /* CRYPTO LIBS */
@@ -510,7 +510,7 @@
  * Returns CURLE_OK on success.
  */
 CURLcode Curl_sha256it(unsigned char *output, const unsigned char *input,
-                   const size_t length)
+                       const size_t length)
 {
   CURLcode result;
   my_sha256_ctx ctx;
@@ -524,21 +524,13 @@
 }
 
 
-const struct HMAC_params Curl_HMAC_SHA256[] = {
-  {
-    /* Hash initialization function. */
-    CURLX_FUNCTION_CAST(HMAC_hinit_func, my_sha256_init),
-    /* Hash update function. */
-    CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_sha256_update),
-    /* Hash computation end function. */
-    CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_sha256_final),
-    /* Size of hash context structure. */
-    sizeof(my_sha256_ctx),
-    /* Maximum key length. */
-    64,
-    /* Result size. */
-    32
-  }
+const struct HMAC_params Curl_HMAC_SHA256 = {
+  my_sha256_init,        /* Hash initialization function. */
+  my_sha256_update,      /* Hash update function. */
+  my_sha256_final,       /* Hash computation end function. */
+  sizeof(my_sha256_ctx), /* Size of hash context structure. */
+  64,                    /* Maximum key length. */
+  32                     /* Result size. */
 };
 
 
diff --git a/Utilities/cmcurl/lib/share.c b/Utilities/cmcurl/lib/share.c
index 2ddaba6..6cdba18 100644
--- a/Utilities/cmcurl/lib/share.c
+++ b/Utilities/cmcurl/lib/share.c
@@ -38,13 +38,13 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-struct Curl_share *
+CURLSH *
 curl_share_init(void)
 {
   struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
   if(share) {
     share->magic = CURL_GOOD_SHARE;
-    share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
+    share->specifier |= (1 << CURL_LOCK_DATA_SHARE);
     Curl_init_dnscache(&share->hostcache, 23);
   }
 
@@ -53,7 +53,7 @@
 
 #undef curl_share_setopt
 CURLSHcode
-curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
+curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
 {
   va_list param;
   int type;
@@ -61,6 +61,7 @@
   curl_unlock_function unlockfunc;
   void *ptr;
   CURLSHcode res = CURLSHE_OK;
+  struct Curl_share *share = sh;
 
   if(!GOOD_SHARE_HANDLE(share))
     return CURLSHE_INVALID;
@@ -139,13 +140,13 @@
       res = CURLSHE_BAD_OPTION;
     }
     if(!res)
-      share->specifier |= (unsigned int)(1<<type);
+      share->specifier |= (unsigned int)(1 << type);
     break;
 
   case CURLSHOPT_UNSHARE:
     /* this is a type this share will no longer share */
     type = va_arg(param, int);
-    share->specifier &= ~(unsigned int)(1<<type);
+    share->specifier &= ~(unsigned int)(1 << type);
     switch(type) {
     case CURL_LOCK_DATA_DNS:
       break;
@@ -214,8 +215,9 @@
 }
 
 CURLSHcode
-curl_share_cleanup(struct Curl_share *share)
+curl_share_cleanup(CURLSH *sh)
 {
+  struct Curl_share *share = sh;
   if(!GOOD_SHARE_HANDLE(share))
     return CURLSHE_INVALID;
 
@@ -271,7 +273,7 @@
   if(!share)
     return CURLSHE_INVALID;
 
-  if(share->specifier & (unsigned int)(1<<type)) {
+  if(share->specifier & (unsigned int)(1 << type)) {
     if(share->lockfunc) /* only call this if set! */
       share->lockfunc(data, type, accesstype, share->clientdata);
   }
@@ -288,7 +290,7 @@
   if(!share)
     return CURLSHE_INVALID;
 
-  if(share->specifier & (unsigned int)(1<<type)) {
+  if(share->specifier & (unsigned int)(1 << type)) {
     if(share->unlockfunc) /* only call this if set! */
       share->unlockfunc (data, type, share->clientdata);
   }
diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c
index f4fff9e..a72ece6 100644
--- a/Utilities/cmcurl/lib/smb.c
+++ b/Utilities/cmcurl/lib/smb.c
@@ -27,10 +27,6 @@
 
 #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE)
 
-#ifdef _WIN32
-#define getpid GetCurrentProcessId
-#endif
-
 #include "smb.h"
 #include "urldata.h"
 #include "sendf.h"
@@ -44,7 +40,8 @@
 #include "escape.h"
 #include "curl_endian.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"
 
@@ -316,20 +313,6 @@
 #define CLIENTNAME        "curl"
 #define SERVICENAME       "?????"
 
-/* Append a string to an SMB message */
-#define MSGCAT(str)                             \
-  do {                                          \
-    strcpy(p, (str));                           \
-    p += strlen(str);                           \
-  } while(0)
-
-/* Append a null-terminated string to an SMB message */
-#define MSGCATNULL(str)                         \
-  do {                                          \
-    strcpy(p, (str));                           \
-    p += strlen(str) + 1;                       \
-  } while(0)
-
 /* SMB is mostly little endian */
 #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
   defined(__OS400__)
@@ -559,7 +542,7 @@
   h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME);
   h->uid = smb_swap16(smbc->uid);
   h->tid = smb_swap16(req->tid);
-  pid = (unsigned int)getpid();
+  pid = (unsigned int)Curl_getpid();
   h->pid_high = smb_swap16((unsigned short)(pid >> 16));
   h->pid = smb_swap16((unsigned short) pid);
 }
@@ -644,7 +627,7 @@
 
   const size_t byte_count = sizeof(lm) + sizeof(nt) +
     strlen(smbc->user) + strlen(smbc->domain) +
-    strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */
+    strlen(CURL_OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */
   if(byte_count > sizeof(msg.bytes))
     return CURLE_FILESIZE_EXCEEDED;
 
@@ -667,10 +650,13 @@
   p += sizeof(lm);
   memcpy(p, nt, sizeof(nt));
   p += sizeof(nt);
-  MSGCATNULL(smbc->user);
-  MSGCATNULL(smbc->domain);
-  MSGCATNULL(OS);
-  MSGCATNULL(CLIENTNAME);
+  p += msnprintf(p, byte_count - sizeof(nt) - sizeof(lm),
+                 "%s%c"  /* user */
+                 "%s%c"  /* domain */
+                 "%s%c"  /* OS */
+                 "%s", /* client name */
+                 smbc->user, 0, smbc->domain, 0, CURL_OS, 0, CLIENTNAME);
+  p++; /* count the final null termination */
   DEBUGASSERT(byte_count == (size_t)(p - msg.bytes));
   msg.byte_count = smb_swap16((unsigned short)byte_count);
 
@@ -694,11 +680,13 @@
   msg.word_count = SMB_WC_TREE_CONNECT_ANDX;
   msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
   msg.pw_len = 0;
-  MSGCAT("\\\\");
-  MSGCAT(conn->host.name);
-  MSGCAT("\\");
-  MSGCATNULL(smbc->share);
-  MSGCATNULL(SERVICENAME); /* Match any type of service */
+
+  p += msnprintf(p, byte_count,
+                 "\\\\%s\\"  /* hostname */
+                 "%s%c"      /* share */
+                 "%s",       /* service */
+                 conn->host.name, smbc->share, 0, SERVICENAME);
+  p++; /* count the final null termination */
   DEBUGASSERT(byte_count == (size_t)(p - msg.bytes));
   msg.byte_count = smb_swap16((unsigned short)byte_count);
 
@@ -908,7 +896,7 @@
     }
     smbc->uid = smb_swap16(h->uid);
     conn_state(data, SMB_CONNECTED);
-    *done = true;
+    *done = TRUE;
     break;
 
   default:
@@ -1108,7 +1096,7 @@
 
   case SMB_DONE:
     result = req->result;
-    *done = true;
+    *done = TRUE;
     break;
 
   default:
diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c
index 3c58932..d854d36 100644
--- a/Utilities/cmcurl/lib/smtp.c
+++ b/Utilities/cmcurl/lib/smtp.c
@@ -1100,12 +1100,11 @@
 
   (void)instate; /* no use for this yet */
 
-  is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE;
+  is_smtp_err = (smtpcode/100 != 2);
 
   /* If there is multiple RCPT TO to be issued, it is possible to ignore errors
      and proceed with only the valid addresses. */
-  is_smtp_blocking_err =
-    (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE;
+  is_smtp_blocking_err = (is_smtp_err && !data->set.mail_rcpt_allowfails);
 
   if(is_smtp_err) {
     /* Remembering the last failure which we can report if all "RCPT TO" have
@@ -1296,7 +1295,7 @@
   }
 
   result = Curl_pp_statemach(data, &smtpc->pp, FALSE, FALSE);
-  *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
+  *done = (smtpc->state == SMTP_STOP);
 
   return result;
 }
diff --git a/Utilities/cmcurl/lib/socketpair.h b/Utilities/cmcurl/lib/socketpair.h
index 3044f11..ed69c5a 100644
--- a/Utilities/cmcurl/lib/socketpair.h
+++ b/Utilities/cmcurl/lib/socketpair.h
@@ -27,14 +27,14 @@
 #include "curl_setup.h"
 
 #if defined(HAVE_EVENTFD) && \
-    defined(__x86_64__) && \
-    defined(__aarch64__) && \
-    defined(__ia64__) && \
-    defined(__ppc64__) && \
-    defined(__mips64) && \
-    defined(__sparc64__) && \
-    defined(__riscv_64e) && \
-    defined(__s390x__)
+    (defined(__x86_64__) || \
+     defined(__aarch64__) || \
+     defined(__ia64__) || \
+     defined(__ppc64__) || \
+     defined(__mips64) || \
+     defined(__sparc64__) || \
+     defined(__riscv_64e) || \
+     defined(__s390x__))
 
 /* Use eventfd only with 64-bit CPU architectures because eventfd has a
  * stringent rule of requiring the 8-byte buffer when calling read(2) and
diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c
index 1f2b7b6..d16a30b 100644
--- a/Utilities/cmcurl/lib/socks.c
+++ b/Utilities/cmcurl/lib/socks.c
@@ -286,7 +286,7 @@
 {
   struct connectdata *conn = cf->conn;
   const bool protocol4a =
-    (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
+    (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A);
   unsigned char *socksreq = sx->buffer;
   CURLcode result;
   CURLproxycode presult;
@@ -512,7 +512,7 @@
   /* Result */
   switch(socksreq[1]) {
   case 90:
-    infof(data, "SOCKS4%s request granted.", protocol4a?"a":"");
+    infof(data, "SOCKS4%s request granted.", protocol4a ? "a" : "");
     break;
   case 91:
     failf(data,
@@ -583,7 +583,7 @@
   CURLcode result;
   CURLproxycode presult;
   bool socks5_resolve_local =
-    (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
+    (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5);
   const size_t hostname_len = strlen(sx->hostname);
   size_t len = 0;
   const unsigned char auth = data->set.socks5auth;
diff --git a/Utilities/cmcurl/lib/socks_gssapi.c b/Utilities/cmcurl/lib/socks_gssapi.c
index f83db97..f6fd55d 100644
--- a/Utilities/cmcurl/lib/socks_gssapi.c
+++ b/Utilities/cmcurl/lib/socks_gssapi.c
@@ -42,6 +42,8 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
+#define MAX_GSS_LEN 1024
+
 static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
 
 /*
@@ -56,10 +58,9 @@
     OM_uint32 maj_stat, min_stat;
     OM_uint32 msg_ctx = 0;
     gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER;
-    char buf[1024];
-    size_t len;
+    struct dynbuf dbuf;
 
-    len = 0;
+    Curl_dyn_init(&dbuf, MAX_GSS_LEN);
     msg_ctx = 0;
     while(!msg_ctx) {
       /* convert major status code (GSS-API error) to text */
@@ -68,19 +69,16 @@
                                     GSS_C_NULL_OID,
                                     &msg_ctx, &status_string);
       if(maj_stat == GSS_S_COMPLETE) {
-        if(sizeof(buf) > len + status_string.length + 1) {
-          strcpy(buf + len, (char *) status_string.value);
-          len += status_string.length;
-        }
+        if(Curl_dyn_addn(&dbuf, status_string.value,
+                         status_string.length))
+          return 1; /* error */
         gss_release_buffer(&min_stat, &status_string);
         break;
       }
       gss_release_buffer(&min_stat, &status_string);
     }
-    if(sizeof(buf) > len + 3) {
-      strcpy(buf + len, ".\n");
-      len += 2;
-    }
+    if(Curl_dyn_addn(&dbuf, ".\n", 2))
+      return 1; /* error */
     msg_ctx = 0;
     while(!msg_ctx) {
       /* convert minor status code (underlying routine error) to text */
@@ -89,14 +87,16 @@
                                     GSS_C_NULL_OID,
                                     &msg_ctx, &status_string);
       if(maj_stat == GSS_S_COMPLETE) {
-        if(sizeof(buf) > len + status_string.length)
-          strcpy(buf + len, (char *) status_string.value);
+        if(Curl_dyn_addn(&dbuf, status_string.value,
+                         status_string.length))
+          return 1; /* error */
         gss_release_buffer(&min_stat, &status_string);
         break;
       }
       gss_release_buffer(&min_stat, &status_string);
     }
-    failf(data, "GSS-API error: %s failed: %s", function, buf);
+    failf(data, "GSS-API error: %s failed: %s", function, Curl_dyn_ptr(&dbuf));
+    Curl_dyn_free(&dbuf);
     return 1;
   }
 
@@ -349,7 +349,8 @@
     gss_enc = 1;
 
   infof(data, "SOCKS5 server supports GSS-API %s data protection.",
-        (gss_enc == 0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
+        (gss_enc == 0) ? "no" :
+        ((gss_enc == 1) ? "integrity" : "confidentiality"));
   /* force for the moment to no data protection */
   gss_enc = 0;
   /*
@@ -525,8 +526,9 @@
   (void)curlx_nonblock(sock, TRUE);
 
   infof(data, "SOCKS5 access with%s protection granted.",
-        (socksreq[0] == 0)?"out GSS-API data":
-        ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
+        (socksreq[0] == 0) ? "out GSS-API data":
+        ((socksreq[0] == 1) ? " GSS-API integrity" :
+         " GSS-API confidentiality"));
 
   conn->socks5_gssapi_enctype = socksreq[0];
   if(socksreq[0] == 0)
diff --git a/Utilities/cmcurl/lib/socks_sspi.c b/Utilities/cmcurl/lib/socks_sspi.c
index a76d261..6d8e6ef 100644
--- a/Utilities/cmcurl/lib/socks_sspi.c
+++ b/Utilities/cmcurl/lib/socks_sspi.c
@@ -355,7 +355,8 @@
     gss_enc = 1;
 
   infof(data, "SOCKS5 server supports GSS-API %s data protection.",
-        (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") );
+        (gss_enc == 0) ? "no" :
+        ((gss_enc == 1) ? "integrity":"confidentiality") );
   /* force to no data protection, avoid encryption/decryption for now */
   gss_enc = 0;
   /*
@@ -606,8 +607,9 @@
   (void)curlx_nonblock(sock, TRUE);
 
   infof(data, "SOCKS5 access with%s protection granted.",
-        (socksreq[0] == 0)?"out GSS-API data":
-        ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
+        (socksreq[0] == 0) ? "out GSS-API data":
+        ((socksreq[0] == 1) ? " GSS-API integrity" :
+         " GSS-API confidentiality"));
 
   /* For later use if encryption is required
      conn->socks5_gssapi_enctype = socksreq[0];
diff --git a/Utilities/cmcurl/lib/speedcheck.h b/Utilities/cmcurl/lib/speedcheck.h
index bff2f32..8b116f1 100644
--- a/Utilities/cmcurl/lib/speedcheck.h
+++ b/Utilities/cmcurl/lib/speedcheck.h
@@ -27,7 +27,7 @@
 #include "curl_setup.h"
 
 #include "timeval.h"
-
+struct Curl_easy;
 void Curl_speedinit(struct Curl_easy *data);
 CURLcode Curl_speedcheck(struct Curl_easy *data,
                          struct curltime now);
diff --git a/Utilities/cmcurl/lib/splay.c b/Utilities/cmcurl/lib/splay.c
index 5e27b08..3f2bae0 100644
--- a/Utilities/cmcurl/lib/splay.c
+++ b/Utilities/cmcurl/lib/splay.c
@@ -113,9 +113,9 @@
     t = Curl_splay(i, t);
     DEBUGASSERT(t);
     if(compare(i, t->key) == 0) {
-      /* There already exists a node in the tree with the very same key. Build
-         a doubly-linked circular list of nodes. We add the new 'node' struct
-         to the end of this list. */
+      /* There already exists a node in the tree with the same key. Build a
+         doubly-linked circular list of nodes. We add the new 'node' struct to
+         the end of this list. */
 
       node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED
                                   to quickly identify this node as a subnode */
@@ -199,7 +199,7 @@
 }
 
 
-/* Deletes the very node we point out from the tree if it is there. Stores a
+/* Deletes the node we point out from the tree if it is there. Stores a
  * pointer to the new resulting tree in 'newroot'.
  *
  * Returns zero on success and non-zero on errors!
diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c
index 76a8ba2..6b67a90 100644
--- a/Utilities/cmcurl/lib/strerror.c
+++ b/Utilities/cmcurl/lib/strerror.c
@@ -151,9 +151,6 @@
   case CURLE_RANGE_ERROR:
     return "Requested range was not delivered by the server";
 
-  case CURLE_HTTP_POST_ERROR:
-    return "Internal problem setting up the POST";
-
   case CURLE_SSL_CONNECT_ERROR:
     return "SSL connect error";
 
@@ -169,9 +166,6 @@
   case CURLE_LDAP_SEARCH_FAILED:
     return "LDAP: search failed";
 
-  case CURLE_FUNCTION_NOT_FOUND:
-    return "A required function in the library was not found";
-
   case CURLE_ABORTED_BY_CALLBACK:
     return "Operation was aborted by an application callback";
 
@@ -330,7 +324,9 @@
   case CURLE_OBSOLETE24:
   case CURLE_OBSOLETE29:
   case CURLE_OBSOLETE32:
+  case CURLE_OBSOLETE34:
   case CURLE_OBSOLETE40:
+  case CURLE_OBSOLETE41:
   case CURLE_OBSOLETE44:
   case CURLE_OBSOLETE46:
   case CURLE_OBSOLETE50:
@@ -348,9 +344,9 @@
    * By using gcc -Wall -Werror, you cannot forget.
    *
    * A table would not have the same benefit. Most compilers will generate
-   * code very similar to a table in any case, so there is little performance
-   * gain from a table. Something is broken for the user's application,
-   * anyways, so does it matter how fast it _does not_ work?
+   * code similar to a table in any case, so there is little performance gain
+   * from a table. Something is broken for the user's application, anyways, so
+   * does it matter how fast it _does not_ work?
    *
    * The line number for the error will be near this comment, which is why it
    * is here, and not at the start of the switch.
diff --git a/Utilities/cmcurl/lib/strtok.h b/Utilities/cmcurl/lib/strtok.h
index 321cba2..9b4d062 100644
--- a/Utilities/cmcurl/lib/strtok.h
+++ b/Utilities/cmcurl/lib/strtok.h
@@ -26,11 +26,11 @@
 #include "curl_setup.h"
 #include <stddef.h>
 
-#ifndef HAVE_STRTOK_R
-char *Curl_strtok_r(char *s, const char *delim, char **last);
-#define strtok_r Curl_strtok_r
-#else
+#ifdef HAVE_STRTOK_R
 #include <string.h>
+#define Curl_strtok_r strtok_r
+#else
+char *Curl_strtok_r(char *s, const char *delim, char **last);
 #endif
 
 #endif /* HEADER_CURL_STRTOK_H */
diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c
index f4dbe03..5ab7118 100644
--- a/Utilities/cmcurl/lib/system_win32.c
+++ b/Utilities/cmcurl/lib/system_win32.c
@@ -175,7 +175,7 @@
  */
 HMODULE Curl_load_library(LPCTSTR filename)
 {
-#ifndef CURL_WINDOWS_APP
+#ifndef CURL_WINDOWS_UWP
   HMODULE hModule = NULL;
   LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
 
diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c
index 8cd19b1..64d552d 100644
--- a/Utilities/cmcurl/lib/telnet.c
+++ b/Utilities/cmcurl/lib/telnet.c
@@ -154,8 +154,8 @@
   int himq[256];
   int him_preferred[256];
   int subnegotiation[256];
-  char subopt_ttype[32];             /* Set with suboption TTYPE */
-  char subopt_xdisploc[128];         /* Set with suboption XDISPLOC */
+  char *subopt_ttype;                /* Set with suboption TTYPE */
+  char *subopt_xdisploc;             /* Set with suboption XDISPLOC */
   unsigned short subopt_wsx;         /* Set with suboption NAWS */
   unsigned short subopt_wsy;         /* Set with suboption NAWS */
   TelnetReceive telrcv_state;
@@ -671,7 +671,7 @@
   if(data->set.verbose) {
     unsigned int i = 0;
     if(direction) {
-      infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
+      infof(data, "%s IAC SB ", (direction == '<') ? "RCVD" : "SENT");
       if(length >= 3) {
         int j;
 
@@ -721,8 +721,8 @@
     switch(pointer[0]) {
     case CURL_TELOPT_NAWS:
       if(length > 4)
-        infof(data, "Width: %d ; Height: %d", (pointer[1]<<8) | pointer[2],
-              (pointer[3]<<8) | pointer[4]);
+        infof(data, "Width: %d ; Height: %d", (pointer[1] << 8) | pointer[2],
+              (pointer[3] << 8) | pointer[4]);
       break;
     default:
       switch(pointer[1]) {
@@ -831,12 +831,9 @@
       case 5:
         /* Terminal type */
         if(strncasecompare(option, "TTYPE", 5)) {
-          size_t l = strlen(arg);
-          if(l < sizeof(tn->subopt_ttype)) {
-            strcpy(tn->subopt_ttype, arg);
-            tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
-            break;
-          }
+          tn->subopt_ttype = arg;
+          tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
+          break;
         }
         result = CURLE_UNKNOWN_OPTION;
         break;
@@ -844,12 +841,9 @@
       case 8:
         /* Display variable */
         if(strncasecompare(option, "XDISPLOC", 8)) {
-          size_t l = strlen(arg);
-          if(l < sizeof(tn->subopt_xdisploc)) {
-            strcpy(tn->subopt_xdisploc, arg);
-            tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
-            break;
-          }
+          tn->subopt_xdisploc = arg;
+          tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
+          break;
         }
         result = CURLE_UNKNOWN_OPTION;
         break;
diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c
index dbae202..e92e512 100644
--- a/Utilities/cmcurl/lib/tftp.c
+++ b/Utilities/cmcurl/lib/tftp.c
@@ -205,7 +205,7 @@
 {
   time_t maxtime, timeout;
   timediff_t timeout_ms;
-  bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
+  bool start = (state->state == TFTP_STATE_START);
 
   /* Compute drop-dead time */
   timeout_ms = Curl_timeleft(state->data, NULL, start);
@@ -228,15 +228,15 @@
   state->retry_max = (int)timeout/5;
 
   /* But bound the total number */
-  if(state->retry_max<3)
+  if(state->retry_max < 3)
     state->retry_max = 3;
 
-  if(state->retry_max>50)
+  if(state->retry_max > 50)
     state->retry_max = 50;
 
   /* Compute the re-ACK interval to suit the timeout */
   state->retry_time = (int)(timeout/state->retry_max);
-  if(state->retry_time<1)
+  if(state->retry_time < 1)
     state->retry_time = 1;
 
   infof(state->data,
@@ -443,7 +443,7 @@
   case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
     /* Increment the retry counter, quit if over the limit */
     state->retries++;
-    if(state->retries>state->retry_max) {
+    if(state->retries > state->retry_max) {
       state->error = TFTP_ERR_NORESPONSE;
       state->state = TFTP_STATE_FIN;
       return result;
@@ -482,11 +482,9 @@
     if(!data->set.tftp_no_options) {
       char buf[64];
       /* add tsize option */
-      if(data->state.upload && (data->state.infilesize != -1))
-        msnprintf(buf, sizeof(buf), "%" FMT_OFF_T,
-                  data->state.infilesize);
-      else
-        strcpy(buf, "0"); /* the destination is large enough */
+      msnprintf(buf, sizeof(buf), "%" FMT_OFF_T,
+                data->state.upload && (data->state.infilesize != -1) ?
+                data->state.infilesize : 0);
 
       result = tftp_option_add(state, &sbytes,
                                (char *)state->spacket.data + sbytes,
@@ -526,7 +524,7 @@
        not have a size_t argument, like older unixes that want an 'int' */
     senddata = sendto(state->sockfd, (void *)state->spacket.data,
                       (SEND_TYPE_ARG3)sbytes, 0,
-                      &data->conn->remote_addr->sa_addr,
+                      &data->conn->remote_addr->curl_sa_addr,
                       (curl_socklen_t)data->conn->remote_addr->addrlen);
     if(senddata != (ssize_t)sbytes) {
       char buffer[STRERROR_LEN];
@@ -664,7 +662,7 @@
                       4, SEND_4TH_ARG,
                       (struct sockaddr *)&state->remote_addr,
                       state->remote_addrlen);
-      if(sbytes<0) {
+      if(sbytes < 0) {
         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
         return CURLE_SEND_ERROR;
       }
@@ -729,7 +727,7 @@
               rblock, state->block);
         state->retries++;
         /* Bail out if over the maximum */
-        if(state->retries>state->retry_max) {
+        if(state->retries > state->retry_max) {
           failf(data, "tftp_tx: giving up waiting for block %d ack",
                 state->block);
           result = CURLE_SEND_ERROR;
@@ -741,7 +739,7 @@
                           (struct sockaddr *)&state->remote_addr,
                           state->remote_addrlen);
           /* Check all sbytes were sent */
-          if(sbytes<0) {
+          if(sbytes < 0) {
             failf(data, "%s", Curl_strerror(SOCKERRNO,
                                             buffer, sizeof(buffer)));
             result = CURLE_SEND_ERROR;
@@ -786,7 +784,7 @@
                     (struct sockaddr *)&state->remote_addr,
                     state->remote_addrlen);
     /* Check all sbytes were sent */
-    if(sbytes<0) {
+    if(sbytes < 0) {
       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
       return CURLE_SEND_ERROR;
     }
@@ -812,7 +810,7 @@
                       (struct sockaddr *)&state->remote_addr,
                       state->remote_addrlen);
       /* Check all sbytes were sent */
-      if(sbytes<0) {
+      if(sbytes < 0) {
         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
         return CURLE_SEND_ERROR;
       }
@@ -1000,7 +998,7 @@
       return CURLE_OUT_OF_MEMORY;
   }
 
-  /* we do not keep TFTP connections up basically because there is none or very
+  /* we do not keep TFTP connections up basically because there is none or
    * little gain for UDP */
   connclose(conn, "TFTP");
 
@@ -1099,24 +1097,20 @@
  **********************************************************/
 static CURLcode tftp_receive_packet(struct Curl_easy *data)
 {
-  struct Curl_sockaddr_storage fromaddr;
   curl_socklen_t        fromlen;
   CURLcode              result = CURLE_OK;
   struct connectdata *conn = data->conn;
   struct tftp_state_data *state = conn->proto.tftpc;
 
   /* Receive the packet */
-  fromlen = sizeof(fromaddr);
+  fromlen = sizeof(state->remote_addr);
   state->rbytes = (int)recvfrom(state->sockfd,
                                 (void *)state->rpacket.data,
                                 (RECV_TYPE_ARG3)state->blksize + 4,
                                 0,
-                                (struct sockaddr *)&fromaddr,
+                                (struct sockaddr *)&state->remote_addr,
                                 &fromlen);
-  if(state->remote_addrlen == 0) {
-    memcpy(&state->remote_addr, &fromaddr, fromlen);
-    state->remote_addrlen = fromlen;
-  }
+  state->remote_addrlen = fromlen;
 
   /* Sanity check packet length */
   if(state->rbytes < 4) {
@@ -1238,7 +1232,7 @@
     result = tftp_state_machine(state, event);
     if(result)
       return result;
-    *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
+    *done = (state->state == TFTP_STATE_FIN);
     if(*done)
       /* Tell curl we are done */
       Curl_xfer_setup_nop(data);
@@ -1261,7 +1255,7 @@
       result = tftp_state_machine(state, state->event);
       if(result)
         return result;
-      *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
+      *done = (state->state == TFTP_STATE_FIN);
       if(*done)
         /* Tell curl we are done */
         Curl_xfer_setup_nop(data);
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
index b660054..d7d3d16 100644
--- a/Utilities/cmcurl/lib/transfer.c
+++ b/Utilities/cmcurl/lib/transfer.c
@@ -79,7 +79,6 @@
 #include "http2.h"
 #include "mime.h"
 #include "strcase.h"
-#include "urlapi-int.h"
 #include "hsts.h"
 #include "setopt.h"
 #include "headers.h"
@@ -205,10 +204,10 @@
  * @param err error    code in case of -1 return
  * @return number of bytes read or -1 for error
  */
-static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data,
-                                   char *buf, size_t blen,
-                                   bool eos_reliable,
-                                   CURLcode *err)
+static ssize_t xfer_recv_resp(struct Curl_easy *data,
+                              char *buf, size_t blen,
+                              bool eos_reliable,
+                              CURLcode *err)
 {
   ssize_t nread;
 
@@ -223,7 +222,7 @@
       blen = (size_t)totalleft;
   }
   else if(xfer_recv_shutdown_started(data)) {
-    /* we already reveived everything. Do not try more. */
+    /* we already received everything. Do not try more. */
     blen = 0;
   }
 
@@ -303,8 +302,7 @@
         bytestoread = (size_t)data->set.max_recv_speed;
     }
 
-    nread = Curl_xfer_recv_resp(data, buf, bytestoread,
-                                is_multiplex, &result);
+    nread = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &result);
     if(nread < 0) {
       if(CURLE_AGAIN != result)
         goto out; /* real error */
@@ -680,6 +678,9 @@
       return CURLE_OUT_OF_MEMORY;
   }
 
+  if(data->set.str[STRING_USERNAME] ||
+     data->set.str[STRING_PASSWORD])
+    data->state.creds_from = CREDS_OPTION;
   if(!result)
     result = Curl_setstropt(&data->state.aptr.user,
                             data->set.str[STRING_USERNAME]);
@@ -700,298 +701,6 @@
   return result;
 }
 
-/*
- * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
- * as given by the remote server and set up the new URL to request.
- *
- * This function DOES NOT FREE the given url.
- */
-CURLcode Curl_follow(struct Curl_easy *data,
-                     char *newurl,    /* the Location: string */
-                     followtype type) /* see transfer.h */
-{
-#ifdef CURL_DISABLE_HTTP
-  (void)data;
-  (void)newurl;
-  (void)type;
-  /* Location: following will not happen when HTTP is disabled */
-  return CURLE_TOO_MANY_REDIRECTS;
-#else
-
-  /* Location: redirect */
-  bool disallowport = FALSE;
-  bool reachedmax = FALSE;
-  CURLUcode uc;
-
-  DEBUGASSERT(type != FOLLOW_NONE);
-
-  if(type != FOLLOW_FAKE)
-    data->state.requests++; /* count all real follows */
-  if(type == FOLLOW_REDIR) {
-    if((data->set.maxredirs != -1) &&
-       (data->state.followlocation >= data->set.maxredirs)) {
-      reachedmax = TRUE;
-      type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected
-                             to URL */
-    }
-    else {
-      data->state.followlocation++; /* count redirect-followings, including
-                                       auth reloads */
-
-      if(data->set.http_auto_referer) {
-        CURLU *u;
-        char *referer = NULL;
-
-        /* We are asked to automatically set the previous URL as the referer
-           when we get the next URL. We pick the ->url field, which may or may
-           not be 100% correct */
-
-        if(data->state.referer_alloc) {
-          Curl_safefree(data->state.referer);
-          data->state.referer_alloc = FALSE;
-        }
-
-        /* Make a copy of the URL without credentials and fragment */
-        u = curl_url();
-        if(!u)
-          return CURLE_OUT_OF_MEMORY;
-
-        uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0);
-        if(!uc)
-          uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0);
-        if(!uc)
-          uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
-        if(!uc)
-          uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
-        if(!uc)
-          uc = curl_url_get(u, CURLUPART_URL, &referer, 0);
-
-        curl_url_cleanup(u);
-
-        if(uc || !referer)
-          return CURLE_OUT_OF_MEMORY;
-
-        data->state.referer = referer;
-        data->state.referer_alloc = TRUE; /* yes, free this later */
-      }
-    }
-  }
-
-  if((type != FOLLOW_RETRY) &&
-     (data->req.httpcode != 401) && (data->req.httpcode != 407) &&
-     Curl_is_absolute_url(newurl, NULL, 0, FALSE)) {
-    /* If this is not redirect due to a 401 or 407 response and an absolute
-       URL: do not allow a custom port number */
-    disallowport = TRUE;
-  }
-
-  DEBUGASSERT(data->state.uh);
-  uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, (unsigned int)
-                    ((type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
-                     ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
-                     CURLU_ALLOW_SPACE |
-                     (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
-  if(uc) {
-    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 */
-    newurl = strdup(newurl);
-    if(!newurl)
-      return CURLE_OUT_OF_MEMORY;
-  }
-  else {
-    uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
-    if(uc)
-      return Curl_uc_to_curlcode(uc);
-
-    /* Clear auth if this redirects to a different port number or protocol,
-       unless permitted */
-    if(!data->set.allow_auth_to_other_hosts && (type != FOLLOW_FAKE)) {
-      char *portnum;
-      int port;
-      bool clear = FALSE;
-
-      if(data->set.use_port && data->state.allow_port)
-        /* a custom port is used */
-        port = (int)data->set.use_port;
-      else {
-        uc = curl_url_get(data->state.uh, CURLUPART_PORT, &portnum,
-                          CURLU_DEFAULT_PORT);
-        if(uc) {
-          free(newurl);
-          return Curl_uc_to_curlcode(uc);
-        }
-        port = atoi(portnum);
-        free(portnum);
-      }
-      if(port != data->info.conn_remote_port) {
-        infof(data, "Clear auth, redirects to port from %u to %u",
-              data->info.conn_remote_port, port);
-        clear = TRUE;
-      }
-      else {
-        char *scheme;
-        const struct Curl_handler *p;
-        uc = curl_url_get(data->state.uh, CURLUPART_SCHEME, &scheme, 0);
-        if(uc) {
-          free(newurl);
-          return Curl_uc_to_curlcode(uc);
-        }
-
-        p = Curl_get_scheme_handler(scheme);
-        if(p && (p->protocol != data->info.conn_protocol)) {
-          infof(data, "Clear auth, redirects scheme from %s to %s",
-                data->info.conn_scheme, scheme);
-          clear = TRUE;
-        }
-        free(scheme);
-      }
-      if(clear) {
-        Curl_safefree(data->state.aptr.user);
-        Curl_safefree(data->state.aptr.passwd);
-      }
-    }
-  }
-
-  if(type == FOLLOW_FAKE) {
-    /* we are only figuring out the new URL if we would have followed locations
-       but now we are done so we can get out! */
-    data->info.wouldredirect = newurl;
-
-    if(reachedmax) {
-      failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
-      return CURLE_TOO_MANY_REDIRECTS;
-    }
-    return CURLE_OK;
-  }
-
-  if(disallowport)
-    data->state.allow_port = FALSE;
-
-  if(data->state.url_alloc)
-    Curl_safefree(data->state.url);
-
-  data->state.url = newurl;
-  data->state.url_alloc = TRUE;
-  Curl_req_soft_reset(&data->req, data);
-  infof(data, "Issue another request to this URL: '%s'", data->state.url);
-
-  /*
-   * We get here when the HTTP code is 300-399 (and 401). We need to perform
-   * differently based on exactly what return code there was.
-   *
-   * News from 7.10.6: we can also get here on a 401 or 407, in case we act on
-   * an HTTP (proxy-) authentication scheme other than Basic.
-   */
-  switch(data->info.httpcode) {
-    /* 401 - Act on a WWW-Authenticate, we keep on moving and do the
-       Authorization: XXXX header in the HTTP request code snippet */
-    /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
-       Proxy-Authorization: XXXX header in the HTTP request code snippet */
-    /* 300 - Multiple Choices */
-    /* 306 - Not used */
-    /* 307 - Temporary Redirect */
-  default:  /* for all above (and the unknown ones) */
-    /* Some codes are explicitly mentioned since I have checked RFC2616 and
-     * they seem to be OK to POST to.
-     */
-    break;
-  case 301: /* Moved Permanently */
-    /* (quote from RFC7231, section 6.4.2)
-     *
-     * Note: For historical reasons, a user agent MAY change the request
-     * method from POST to GET for the subsequent request. If this
-     * behavior is undesired, the 307 (Temporary Redirect) status code
-     * can be used instead.
-     *
-     * ----
-     *
-     * Many webservers expect this, so these servers often answers to a POST
-     * request with an error page. To be sure that libcurl gets the page that
-     * most user agents would get, libcurl has to force GET.
-     *
-     * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
-     * can be overridden with CURLOPT_POSTREDIR.
-     */
-    if((data->state.httpreq == HTTPREQ_POST
-        || data->state.httpreq == HTTPREQ_POST_FORM
-        || data->state.httpreq == HTTPREQ_POST_MIME)
-       && !(data->set.keep_post & CURL_REDIR_POST_301)) {
-      infof(data, "Switch from POST to GET");
-      data->state.httpreq = HTTPREQ_GET;
-      Curl_creader_set_rewind(data, FALSE);
-    }
-    break;
-  case 302: /* Found */
-    /* (quote from RFC7231, section 6.4.3)
-     *
-     * Note: For historical reasons, a user agent MAY change the request
-     * method from POST to GET for the subsequent request. If this
-     * behavior is undesired, the 307 (Temporary Redirect) status code
-     * can be used instead.
-     *
-     * ----
-     *
-     * Many webservers expect this, so these servers often answers to a POST
-     * request with an error page. To be sure that libcurl gets the page that
-     * most user agents would get, libcurl has to force GET.
-     *
-     * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
-     * can be overridden with CURLOPT_POSTREDIR.
-     */
-    if((data->state.httpreq == HTTPREQ_POST
-        || data->state.httpreq == HTTPREQ_POST_FORM
-        || data->state.httpreq == HTTPREQ_POST_MIME)
-       && !(data->set.keep_post & CURL_REDIR_POST_302)) {
-      infof(data, "Switch from POST to GET");
-      data->state.httpreq = HTTPREQ_GET;
-      Curl_creader_set_rewind(data, FALSE);
-    }
-    break;
-
-  case 303: /* See Other */
-    /* 'See Other' location is not the resource but a substitute for the
-     * resource. In this case we switch the method to GET/HEAD, unless the
-     * method is POST and the user specified to keep it as POST.
-     * https://github.com/curl/curl/issues/5237#issuecomment-614641049
-     */
-    if(data->state.httpreq != HTTPREQ_GET &&
-       ((data->state.httpreq != HTTPREQ_POST &&
-         data->state.httpreq != HTTPREQ_POST_FORM &&
-         data->state.httpreq != HTTPREQ_POST_MIME) ||
-        !(data->set.keep_post & CURL_REDIR_POST_303))) {
-      data->state.httpreq = HTTPREQ_GET;
-      infof(data, "Switch to %s",
-            data->req.no_body?"HEAD":"GET");
-    }
-    break;
-  case 304: /* Not Modified */
-    /* 304 means we did a conditional request and it was "Not modified".
-     * We should not get any Location: header in this response!
-     */
-    break;
-  case 305: /* Use Proxy */
-    /* (quote from RFC2616, section 10.3.6):
-     * "The requested resource MUST be accessed through the proxy given
-     * by the Location field. The Location field gives the URI of the
-     * proxy. The recipient is expected to repeat this single request
-     * via the proxy. 305 responses MUST only be generated by origin
-     * servers."
-     */
-    break;
-  }
-  Curl_pgrsTime(data, TIMER_REDIRECT);
-  Curl_pgrsResetTransferSizes(data);
-
-  return CURLE_OK;
-#endif /* CURL_DISABLE_HTTP */
-}
-
 /* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
 
    NOTE: that the *url is malloc()ed. */
@@ -1067,10 +776,12 @@
   int sockindex,            /* socket index to read from or -1 */
   curl_off_t size,          /* -1 if unknown at this point */
   bool getheader,           /* TRUE if header parsing is wanted */
-  int writesockindex,       /* socket index to write to, it may very well be
-                               the same we read from. -1 disables */
-  bool shutdown             /* shutdown connection at transfer end. Only
+  int writesockindex,       /* socket index to write to, it may be the same we
+                               read from. -1 disables */
+  bool shutdown,            /* shutdown connection at transfer end. Only
                              * supported when sending OR receiving. */
+  bool shutdown_err_ignore  /* errors during shutdown do not fail the
+                             * transfer */
   )
 {
   struct SingleRequest *k = &data->req;
@@ -1089,19 +800,20 @@
       conn->sock[sockindex];
     conn->writesockfd = conn->sockfd;
     if(want_send)
-      /* special and very HTTP-specific */
+      /* special and HTTP-specific */
       writesockindex = FIRSTSOCKET;
   }
   else {
     conn->sockfd = sockindex == -1 ?
       CURL_SOCKET_BAD : conn->sock[sockindex];
     conn->writesockfd = writesockindex == -1 ?
-      CURL_SOCKET_BAD:conn->sock[writesockindex];
+      CURL_SOCKET_BAD : conn->sock[writesockindex];
   }
 
   k->getheader = getheader;
   k->size = size;
   k->shutdown = shutdown;
+  k->shutdown_err_ignore = shutdown_err_ignore;
 
   /* The code sequence below is placed in this function just because all
      necessary input is not always known in do_complete() as this function may
@@ -1126,7 +838,7 @@
 
 void Curl_xfer_setup_nop(struct Curl_easy *data)
 {
-  xfer_setup(data, -1, -1, FALSE, -1, FALSE);
+  xfer_setup(data, -1, -1, FALSE, -1, FALSE, FALSE);
 }
 
 void Curl_xfer_setup1(struct Curl_easy *data,
@@ -1134,21 +846,23 @@
                       curl_off_t recv_size,
                       bool getheader)
 {
-  int recv_index = (send_recv & CURL_XFER_RECV)? FIRSTSOCKET : -1;
-  int send_index = (send_recv & CURL_XFER_SEND)? FIRSTSOCKET : -1;
+  int recv_index = (send_recv & CURL_XFER_RECV) ? FIRSTSOCKET : -1;
+  int send_index = (send_recv & CURL_XFER_SEND) ? FIRSTSOCKET : -1;
   DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
-  xfer_setup(data, recv_index, recv_size, getheader, send_index, FALSE);
+  xfer_setup(data, recv_index, recv_size, getheader, send_index, FALSE, FALSE);
 }
 
 void Curl_xfer_setup2(struct Curl_easy *data,
                       int send_recv,
                       curl_off_t recv_size,
-                      bool shutdown)
+                      bool shutdown,
+                      bool shutdown_err_ignore)
 {
-  int recv_index = (send_recv & CURL_XFER_RECV)? SECONDARYSOCKET : -1;
-  int send_index = (send_recv & CURL_XFER_SEND)? SECONDARYSOCKET : -1;
+  int recv_index = (send_recv & CURL_XFER_RECV) ? SECONDARYSOCKET : -1;
+  int send_index = (send_recv & CURL_XFER_SEND) ? SECONDARYSOCKET : -1;
   DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
-  xfer_setup(data, recv_index, recv_size, FALSE, send_index, shutdown);
+  xfer_setup(data, recv_index, recv_size, FALSE, send_index,
+             shutdown, shutdown_err_ignore);
 }
 
 CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/transfer.h b/Utilities/cmcurl/lib/transfer.h
index 8d6f98d..8c9b88c 100644
--- a/Utilities/cmcurl/lib/transfer.h
+++ b/Utilities/cmcurl/lib/transfer.h
@@ -42,8 +42,6 @@
   FOLLOW_REDIR /* a full true redirect */
 } followtype;
 
-CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
-                     followtype type);
 CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp);
 int Curl_single_getsock(struct Curl_easy *data,
                         struct connectdata *conn, curl_socket_t *socks);
@@ -100,12 +98,13 @@
  * the amount to receive or -1 if unknown. With `shutdown` being
  * set, the transfer is only allowed to either send OR receive
  * and the socket 2 connection will be shutdown at the end of
- * the transfer. An unclean shutdown will fail the transfer.
+ * the transfer. An unclean shutdown will fail the transfer
+ * unless `shutdown_err_ignore` is TRUE.
  */
 void Curl_xfer_setup2(struct Curl_easy *data,
                       int send_recv,
                       curl_off_t recv_size,
-                      bool shutdown);
+                      bool shutdown, bool shutdown_err_ignore);
 
 /**
  * Multi has set transfer to DONE. Last chance to trigger
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index 3bf0c05..436edd8 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -338,6 +338,7 @@
   Curl_wildcard_dtor(&data->wildcard);
   Curl_freeset(data);
   Curl_headers_cleanup(data);
+  Curl_netrc_cleanup(&data->state.netrc);
   free(data);
   return CURLE_OK;
 }
@@ -426,9 +427,9 @@
 
   /* Set the default CA cert bundle/path detected/specified at build time.
    *
-   * If Schannel or SecureTransport is the selected SSL backend then these
-   * locations are ignored. We allow setting CA location for schannel and
-   * securetransport when explicitly specified by the user via
+   * If Schannel or Secure Transport is the selected SSL backend then these
+   * locations are ignored. We allow setting CA location for Schannel and
+   * Secure Transport when explicitly specified by the user via
    *  CURLOPT_CAINFO / --cacert.
    */
   if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL &&
@@ -505,10 +506,10 @@
   CURLcode result;
   struct Curl_easy *data;
 
-  /* Very simple start-up: alloc the struct, init it with zeroes and return */
+  /* simple start-up: alloc the struct, init it with zeroes and return */
   data = calloc(1, sizeof(struct Curl_easy));
   if(!data) {
-    /* this is a very serious error */
+    /* this is a serious error */
     DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
     return CURLE_OUT_OF_MEMORY;
   }
@@ -545,6 +546,7 @@
 #ifndef CURL_DISABLE_HTTP
     Curl_llist_init(&data->state.httphdrs, NULL);
 #endif
+    Curl_netrc_init(&data->state.netrc);
   }
 
   if(result) {
@@ -649,13 +651,13 @@
 }
 
 /*
- * Curl_xfer_may_multiplex()
+ * xfer_may_multiplex()
  *
  * Return a TRUE, iff the transfer can be done over an (appropriate)
  * multiplexed connection.
  */
-static bool Curl_xfer_may_multiplex(const struct Curl_easy *data,
-                                    const struct connectdata *conn)
+static bool xfer_may_multiplex(const struct Curl_easy *data,
+                               const struct connectdata *conn)
 {
   /* If an HTTP protocol and multiplexing is enabled */
   if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
@@ -878,16 +880,16 @@
   }
 
   if(needle->localdev || needle->localport) {
-    /* If we are bound to a specific local end (IP+port), we must not
-       reuse a random other one, although if we did not ask for a
-       particular one we can reuse one that was bound.
+    /* If we are bound to a specific local end (IP+port), we must not reuse a
+       random other one, although if we did not ask for a particular one we
+       can reuse one that was bound.
 
        This comparison is a bit rough and too strict. Since the input
-       parameters can be specified in numerous ways and still end up the
-       same it would take a lot of processing to make it really accurate.
-       Instead, this matching will assume that reuses of bound connections
-       will most likely also reuse the exact same binding parameters and
-       missing out a few edge cases should not hurt anyone very much.
+       parameters can be specified in numerous ways and still end up the same
+       it would take a lot of processing to make it really accurate. Instead,
+       this matching will assume that reuses of bound connections will most
+       likely also reuse the exact same binding parameters and missing out a
+       few edge cases should not hurt anyone much.
     */
     if((conn->localport != needle->localport) ||
        (conn->localportrange != needle->localportrange) ||
@@ -1031,13 +1033,25 @@
     return FALSE;
 
   /* If looking for HTTP and the HTTP version we want is less
-   * than the HTTP version of conn, continue looking */
+   * than the HTTP version of conn, continue looking.
+   * CURL_HTTP_VERSION_2TLS is default which indicates no preference,
+   * so we take any existing connection. */
   if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
-     (((conn->httpversion >= 20) &&
-       (data->state.httpwant < CURL_HTTP_VERSION_2_0))
-      || ((conn->httpversion >= 30) &&
-          (data->state.httpwant < CURL_HTTP_VERSION_3))))
-    return FALSE;
+     (data->state.httpwant != CURL_HTTP_VERSION_2TLS)) {
+    if((conn->httpversion >= 20) &&
+       (data->state.httpwant < CURL_HTTP_VERSION_2_0)) {
+      DEBUGF(infof(data, "nor reusing conn #%" CURL_FORMAT_CURL_OFF_T
+             " with httpversion=%d, we want a version less than h2",
+             conn->connection_id, conn->httpversion));
+    }
+    if((conn->httpversion >= 30) &&
+       (data->state.httpwant < CURL_HTTP_VERSION_3)) {
+      DEBUGF(infof(data, "nor reusing conn #%" CURL_FORMAT_CURL_OFF_T
+             " with httpversion=%d, we want a version less than h3",
+             conn->connection_id, conn->httpversion));
+      return FALSE;
+    }
+  }
 #ifdef USE_SSH
   else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
     if(!ssh_config_matches(needle, conn))
@@ -1234,7 +1248,7 @@
   memset(&match, 0, sizeof(match));
   match.data = data;
   match.needle = needle;
-  match.may_multiplex = Curl_xfer_may_multiplex(data, needle);
+  match.may_multiplex = xfer_may_multiplex(data, needle);
 
 #ifdef USE_NTLM
   match.want_ntlm_http = ((data->state.authhost.want & CURLAUTH_NTLM) &&
@@ -1329,22 +1343,19 @@
   /* note that these two proxy bits are now just on what looks to be
      requested, they may be altered down the road */
   conn->bits.proxy = (data->set.str[STRING_PROXY] &&
-                      *data->set.str[STRING_PROXY]) ? TRUE : FALSE;
+                      *data->set.str[STRING_PROXY]);
   conn->bits.httpproxy = (conn->bits.proxy &&
                           (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
                            conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
-                           IS_HTTPS_PROXY(conn->http_proxy.proxytype))) ?
-    TRUE : FALSE;
-  conn->bits.socksproxy = (conn->bits.proxy &&
-                           !conn->bits.httpproxy) ? TRUE : FALSE;
+                           IS_HTTPS_PROXY(conn->http_proxy.proxytype)));
+  conn->bits.socksproxy = (conn->bits.proxy && !conn->bits.httpproxy);
 
   if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
     conn->bits.proxy = TRUE;
     conn->bits.socksproxy = TRUE;
   }
 
-  conn->bits.proxy_user_passwd =
-    (data->state.aptr.proxyuser) ? TRUE : FALSE;
+  conn->bits.proxy_user_passwd = !!data->state.aptr.proxyuser;
   conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
 #endif /* CURL_DISABLE_PROXY */
 
@@ -1497,7 +1508,7 @@
 #else
     NULL,
 #endif
-#if defined(USE_WEBSOCKETS) && \
+#if !defined(CURL_DISABLE_WEBSOCKETS) &&                \
   defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
     &Curl_handler_wss,
 #else
@@ -1566,7 +1577,7 @@
     NULL,
 #endif
     NULL,
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
     &Curl_handler_ws,
 #else
     NULL,
@@ -1846,10 +1857,10 @@
     return result;
 
   /*
-   * username and password set with their own options override the
-   * credentials possibly set in the URL.
+   * username and password set with their own options override the credentials
+   * possibly set in the URL, but netrc does not.
    */
-  if(!data->set.str[STRING_PASSWORD]) {
+  if(!data->state.aptr.passwd || (data->state.creds_from != CREDS_OPTION)) {
     uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
     if(!uc) {
       char *decoded;
@@ -1862,12 +1873,13 @@
       result = Curl_setstropt(&data->state.aptr.passwd, decoded);
       if(result)
         return result;
+      data->state.creds_from = CREDS_URL;
     }
     else if(uc != CURLUE_NO_PASSWORD)
       return Curl_uc_to_curlcode(uc);
   }
 
-  if(!data->set.str[STRING_USERNAME]) {
+  if(!data->state.aptr.user || (data->state.creds_from != CREDS_OPTION)) {
     /* we do not 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 */
@@ -1881,13 +1893,10 @@
         return result;
       conn->user = decoded;
       result = Curl_setstropt(&data->state.aptr.user, decoded);
+      data->state.creds_from = CREDS_URL;
     }
     else if(uc != CURLUE_NO_USER)
       return Curl_uc_to_curlcode(uc);
-    else if(data->state.aptr.passwd) {
-      /* no user was set but a password, set a blank user */
-      result = Curl_setstropt(&data->state.aptr.user, "");
-    }
     if(result)
       return result;
   }
@@ -1949,11 +1958,11 @@
     else
       s->range = strdup(data->set.str[STRING_SET_RANGE]);
 
-    s->rangestringalloc = (s->range) ? TRUE : FALSE;
-
     if(!s->range)
       return CURLE_OUT_OF_MEMORY;
 
+    s->rangestringalloc = TRUE;
+
     /* tell ourselves to fetch this range */
     s->use_range = TRUE;        /* enable range download */
   }
@@ -1994,8 +2003,8 @@
   }
 
   if(conn->primary.remote_port < 0)
-    /* we check for -1 here since if proxy was detected already, this
-       was very likely already set to the proxy port */
+    /* we check for -1 here since if proxy was detected already, this was
+       likely already set to the proxy port */
     conn->primary.remote_port = p->defport;
 
   /* Now create the destination name */
@@ -2090,7 +2099,7 @@
   }
 
   if(!proxy) {
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_WEBSOCKETS
     /* websocket proxy fallbacks */
     if(strcasecompare("ws_proxy", proxy_env)) {
       proxy = curl_getenv("http_proxy");
@@ -2108,7 +2117,7 @@
         envp = (char *)"ALL_PROXY";
         proxy = curl_getenv(envp);
       }
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_WEBSOCKETS
     }
 #endif
   }
@@ -2642,6 +2651,17 @@
   return CURLE_OK;
 }
 
+static bool str_has_ctrl(const char *input)
+{
+  const unsigned char *str = (const unsigned char *)input;
+  while(*str) {
+    if(*str < 0x20)
+      return TRUE;
+    str++;
+  }
+  return FALSE;
+}
+
 /*
  * Override the login details from the URL with that in the CURLOPT_USERPWD
  * option or a .netrc file, if applicable.
@@ -2671,30 +2691,42 @@
     int ret;
     bool url_provided = FALSE;
 
-    if(data->state.aptr.user) {
-      /* there was a username in the URL. Use the URL decoded version */
+    if(data->state.aptr.user &&
+       (data->state.creds_from != CREDS_NETRC)) {
+      /* there was a username with a length in the URL. Use the URL decoded
+         version */
       userp = &data->state.aptr.user;
       url_provided = TRUE;
     }
 
-    ret = Curl_parsenetrc(conn->host.name,
-                          userp, passwdp,
-                          data->set.str[STRING_NETRC_FILE]);
-    if(ret > 0) {
-      infof(data, "Couldn't find host %s in the %s file; using defaults",
-            conn->host.name,
-            (data->set.str[STRING_NETRC_FILE] ?
-             data->set.str[STRING_NETRC_FILE] : ".netrc"));
-    }
-    else if(ret < 0) {
-      failf(data, ".netrc parser error");
-      return CURLE_READ_ERROR;
-    }
-    else {
-      /* set bits.netrc TRUE to remember that we got the name from a .netrc
-         file, so that it is safe to use even if we followed a Location: to a
-         different host or similar. */
-      conn->bits.netrc = TRUE;
+    if(!*passwdp) {
+      ret = Curl_parsenetrc(&data->state.netrc, conn->host.name,
+                            userp, passwdp,
+                            data->set.str[STRING_NETRC_FILE]);
+      if(ret > 0) {
+        infof(data, "Couldn't find host %s in the %s file; using defaults",
+              conn->host.name,
+              (data->set.str[STRING_NETRC_FILE] ?
+               data->set.str[STRING_NETRC_FILE] : ".netrc"));
+      }
+      else if(ret < 0) {
+        failf(data, ".netrc parser error");
+        return CURLE_READ_ERROR;
+      }
+      else {
+        if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) {
+          /* if the protocol can't handle control codes in credentials, make
+             sure there are none */
+          if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
+            failf(data, "control code detected in .netrc credentials");
+            return CURLE_READ_ERROR;
+          }
+        }
+        /* set bits.netrc TRUE to remember that we got the name from a .netrc
+           file, so that it is safe to use even if we followed a Location: to a
+           different host or similar. */
+        conn->bits.netrc = TRUE;
+      }
     }
     if(url_provided) {
       Curl_safefree(conn->user);
@@ -2719,6 +2751,7 @@
       result = Curl_setstropt(&data->state.aptr.user, *userp);
       if(result)
         return result;
+      data->state.creds_from = CREDS_NETRC;
     }
   }
   if(data->state.aptr.user) {
@@ -2736,6 +2769,7 @@
     CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
     if(result)
       return result;
+    data->state.creds_from = CREDS_NETRC;
   }
   if(data->state.aptr.passwd) {
     uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
@@ -2901,8 +2935,8 @@
 {
   CURLcode result = CURLE_OK;
   const char *ptr = conn_to_host;
-  int host_match = FALSE;
-  int port_match = FALSE;
+  bool host_match = FALSE;
+  bool port_match = FALSE;
 
   *host_result = NULL;
   *port_result = -1;
@@ -3015,9 +3049,10 @@
 #endif
        )) {
     /* no connect_to match, try alt-svc! */
-    enum alpnid srcalpnid;
-    bool hit;
-    struct altsvc *as;
+    enum alpnid srcalpnid = ALPN_none;
+    bool use_alt_svc = FALSE;
+    bool hit = FALSE;
+    struct altsvc *as = NULL;
     const int allowed_versions = ( ALPN_h1
 #ifdef USE_HTTP2
                                    | ALPN_h2
@@ -3026,24 +3061,65 @@
                                    | ALPN_h3
 #endif
       ) & data->asi->flags;
+    static enum alpnid alpn_ids[] = {
+#ifdef USE_HTTP3
+      ALPN_h3,
+#endif
+#ifdef USE_HTTP2
+      ALPN_h2,
+#endif
+      ALPN_h1,
+    };
+    size_t i;
+
+    switch(data->state.httpwant) {
+    case CURL_HTTP_VERSION_1_0:
+      break;
+    case CURL_HTTP_VERSION_1_1:
+      use_alt_svc = TRUE;
+      srcalpnid = ALPN_h1; /* only regard alt-svc advice for http/1.1 */
+      break;
+    case CURL_HTTP_VERSION_2_0:
+      use_alt_svc = TRUE;
+      srcalpnid = ALPN_h2; /* only regard alt-svc advice for h2 */
+      break;
+    case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE:
+      break;
+    case CURL_HTTP_VERSION_3:
+      use_alt_svc = TRUE;
+      srcalpnid = ALPN_h3; /* only regard alt-svc advice for h3 */
+      break;
+    case CURL_HTTP_VERSION_3ONLY:
+      break;
+    default: /* no specific HTTP version wanted, look at all of alt-svc */
+      use_alt_svc = TRUE;
+      srcalpnid = ALPN_none;
+      break;
+    }
+    if(!use_alt_svc)
+      return CURLE_OK;
 
     host = conn->host.rawalloc;
-#ifdef USE_HTTP2
-    /* with h2 support, check that first */
-    srcalpnid = ALPN_h2;
-    hit = Curl_altsvc_lookup(data->asi,
-                             srcalpnid, host, conn->remote_port, /* from */
-                             &as /* to */,
-                             allowed_versions);
-    if(!hit)
-#endif
-    {
-      srcalpnid = ALPN_h1;
+    DEBUGF(infof(data, "check Alt-Svc for host %s", host));
+    if(srcalpnid == ALPN_none) {
+      /* scan all alt-svc protocol ids in order or relevance */
+      for(i = 0; !hit && (i < ARRAYSIZE(alpn_ids)); ++i) {
+        srcalpnid = alpn_ids[i];
+        hit = Curl_altsvc_lookup(data->asi,
+                                 srcalpnid, host, conn->remote_port, /* from */
+                                 &as /* to */,
+                                 allowed_versions);
+      }
+    }
+    else {
+      /* look for a specific alt-svc protocol id */
       hit = Curl_altsvc_lookup(data->asi,
                                srcalpnid, host, conn->remote_port, /* from */
                                &as /* to */,
                                allowed_versions);
     }
+
+
     if(hit) {
       char *hostd = strdup((char *)as->dst.host);
       if(!hostd)
@@ -3529,7 +3605,7 @@
 
 #ifndef CURL_DISABLE_PROXY
     infof(data, "Re-using existing connection with %s %s",
-          conn->bits.proxy?"proxy":"host",
+          conn->bits.proxy ? "proxy" : "host",
           conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
           conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
           conn->host.dispname);
diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c
index 3d4a3f9..98c8f6f 100644
--- a/Utilities/cmcurl/lib/urlapi.c
+++ b/Utilities/cmcurl/lib/urlapi.c
@@ -34,7 +34,6 @@
 #include "inet_ntop.h"
 #include "strdup.h"
 #include "idn.h"
-#include "curl_memrchr.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -182,7 +181,7 @@
 
     if(urlchar_needs_escaping(*iptr)) {
       char out[3]={'%'};
-      out[1] = hexdigits[*iptr>>4];
+      out[1] = hexdigits[*iptr >> 4];
       out[2] = hexdigits[*iptr & 0xf];
       result = Curl_dyn_addn(o, out, 3);
     }
@@ -468,7 +467,7 @@
   ccode = Curl_parse_login_details(login, ptr - login - 1,
                                    &userp, &passwdp,
                                    (h && (h->flags & PROTOPT_URLOPTIONS)) ?
-                                   &optionsp:NULL);
+                                   &optionsp : NULL);
   if(ccode) {
     result = CURLUE_BAD_LOGIN;
     goto out;
@@ -611,19 +610,14 @@
     /* hostname is fine */
   }
 
-  /* Check the IPv6 address. */
+  /* Normalize the IPv6 address */
   {
     char dest[16]; /* fits a binary IPv6 address */
-    char norm[MAX_IPADR_LEN];
     hostname[hlen] = 0; /* end the address there */
     if(1 != Curl_inet_pton(AF_INET6, hostname, dest))
       return CURLUE_BAD_IPV6;
-
-    /* check if it can be done shorter */
-    if(Curl_inet_ntop(AF_INET6, dest, norm, sizeof(norm)) &&
-       (strlen(norm) < hlen)) {
-      strcpy(hostname, norm);
-      hlen = strlen(norm);
+    if(Curl_inet_ntop(AF_INET6, dest, hostname, hlen)) {
+      hlen = strlen(hostname); /* might be shorter now */
       hostname[hlen + 1] = 0;
     }
     hostname[hlen] = ']'; /* restore ending bracket */
@@ -1420,8 +1414,8 @@
   const char *ptr;
   CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
   char portbuf[7];
-  bool urldecode = (flags & CURLU_URLDECODE)?1:0;
-  bool urlencode = (flags & CURLU_URLENCODE)?1:0;
+  bool urldecode = (flags & CURLU_URLDECODE) ? 1 : 0;
+  bool urlencode = (flags & CURLU_URLENCODE) ? 1 : 0;
   bool punycode = FALSE;
   bool depunyfy = FALSE;
   bool plusdecode = FALSE;
@@ -1455,8 +1449,8 @@
   case CURLUPART_HOST:
     ptr = u->host;
     ifmissing = CURLUE_NO_HOST;
-    punycode = (flags & CURLU_PUNYCODE)?1:0;
-    depunyfy = (flags & CURLU_PUNY2IDN)?1:0;
+    punycode = (flags & CURLU_PUNYCODE) ? 1 : 0;
+    depunyfy = (flags & CURLU_PUNY2IDN) ? 1 : 0;
     break;
   case CURLUPART_ZONEID:
     ptr = u->zoneid;
@@ -1515,8 +1509,8 @@
     bool show_query =
       (u->query && u->query[0]) ||
       (u->query_present && flags & CURLU_GET_EMPTY);
-    punycode = (flags & CURLU_PUNYCODE)?1:0;
-    depunyfy = (flags & CURLU_PUNY2IDN)?1:0;
+    punycode = (flags & CURLU_PUNYCODE) ? 1 : 0;
+    depunyfy = (flags & CURLU_PUNY2IDN) ? 1 : 0;
     if(u->scheme && strcasecompare("file", u->scheme)) {
       url = aprintf("file://%s%s%s",
                     u->path,
@@ -1618,7 +1612,7 @@
                     show_query ? "?": "",
                     u->query ? u->query : "",
                     show_fragment ? "#": "",
-                    u->fragment? u->fragment : "");
+                    u->fragment ? u->fragment : "");
       free(allochost);
     }
     if(!url)
@@ -1709,7 +1703,7 @@
                        const char *part, unsigned int flags)
 {
   char **storep = NULL;
-  bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
+  bool urlencode = (flags & CURLU_URLENCODE) ? 1 : 0;
   bool plusencode = FALSE;
   bool urlskipslash = FALSE;
   bool leadingslash = FALSE;
@@ -1846,7 +1840,7 @@
     break;
   case CURLUPART_QUERY:
     plusencode = urlencode;
-    appendquery = (flags & CURLU_APPENDQUERY)?1:0;
+    appendquery = (flags & CURLU_APPENDQUERY) ? 1 : 0;
     equalsencode = appendquery;
     storep = &u->query;
     u->query_present = TRUE;
@@ -1928,7 +1922,7 @@
         }
         else {
           char out[3]={'%'};
-          out[1] = hexdigits[*i>>4];
+          out[1] = hexdigits[*i >> 4];
           out[2] = hexdigits[*i & 0xf];
           result = Curl_dyn_addn(&enc, out, 3);
           if(result)
diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h
index 22dceee..704fb7a 100644
--- a/Utilities/cmcurl/lib/urldata.h
+++ b/Utilities/cmcurl/lib/urldata.h
@@ -64,7 +64,7 @@
 # define CURLECH_CLA_CFG    (1<<4)
 #endif
 
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_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
@@ -163,6 +163,7 @@
 #include "dynbuf.h"
 #include "dynhds.h"
 #include "request.h"
+#include "netrc.h"
 
 /* return the count of bytes sent, or -1 on error */
 typedef ssize_t (Curl_send)(struct Curl_easy *data,   /* transfer */
@@ -324,6 +325,7 @@
   char *key_passwd; /* plain text private key password */
   BIT(certinfo);     /* gather lots of certificate info */
   BIT(falsestart);
+  BIT(earlydata);    /* use tls1.3 early data */
   BIT(enable_beast); /* allow this flaw for interoperability's sake */
   BIT(no_revoke);    /* disable SSL certificate revocation checks */
   BIT(no_partialchain); /* do not accept partial certificate chains */
@@ -346,6 +348,7 @@
   char *name;       /* hostname for which this ID was used */
   char *conn_to_host; /* hostname for the connection (may be NULL) */
   const char *scheme; /* protocol scheme used */
+  char *alpn;         /* APLN TLS negotiated protocol string */
   void *sessionid;  /* as returned from the SSL layer */
   size_t idsize;    /* if known, otherwise 0 */
   Curl_ssl_sessionid_dtor *sessionid_free; /* free `sessionid` callback */
@@ -868,9 +871,8 @@
   /**** curl_get() phase fields */
 
   curl_socket_t sockfd;   /* socket to read from or CURL_SOCKET_BAD */
-  curl_socket_t writesockfd; /* socket to write to, it may very
-                                well be the same we read from.
-                                CURL_SOCKET_BAD disables */
+  curl_socket_t writesockfd; /* socket to write to, it may be the same we read
+                                from. CURL_SOCKET_BAD disables */
 
 #ifdef HAVE_GSSAPI
   BIT(sec_complete); /* if Kerberos is enabled for this connection */
@@ -951,7 +953,7 @@
 #ifndef CURL_DISABLE_MQTT
     struct mqtt_conn mqtt;
 #endif
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_WEBSOCKETS
     struct websocket *ws;
 #endif
     unsigned int unused:1; /* avoids empty union */
@@ -1069,6 +1071,7 @@
   struct pgrs_dir dl;
 
   curl_off_t current_speed; /* uses the currently fastest transfer */
+  curl_off_t earlydata_sent;
 
   int width; /* screen width at download start */
   int flags; /* see progress.h */
@@ -1202,6 +1205,11 @@
   char *query;
 };
 
+#define CREDS_NONE   0
+#define CREDS_URL    1 /* from URL */
+#define CREDS_OPTION 2 /* set with a CURLOPT_ */
+#define CREDS_NETRC  3 /* found in netrc */
+
 struct UrlState {
   /* buffers to store authentication data in, as parsed from input options */
   struct curltime keeps_speed; /* for the progress meter really */
@@ -1310,6 +1318,10 @@
   struct curl_trc_feat *feat; /* opt. trace feature transfer is part of */
 #endif
 
+#ifndef CURL_DISABLE_NETRC
+  struct store_netrc netrc;
+#endif
+
   /* Dynamically allocated strings, MUST be freed before this struct is
      killed. */
   struct dynamically_allocated_data {
@@ -1336,7 +1348,6 @@
     char *proxypasswd;
 #endif
   } aptr;
-
   unsigned char httpwant; /* when non-zero, a specific HTTP version requested
                              to be used in the library's request(s) */
   unsigned char httpversion; /* the lowest HTTP version*10 reported by any
@@ -1346,6 +1357,9 @@
   unsigned char select_bits; /* != 0 -> bitmask of socket events for this
                                  transfer overriding anything the socket may
                                  report */
+  unsigned int creds_from:2; /* where is the server credentials originating
+                                from, see the CREDS_* defines above */
+
   /* when curl_easy_perform() is called, the multi handle is "owned" by
      the easy handle so curl_easy_cleanup() on such an easy handle will
      also close the multi handle! */
@@ -1844,7 +1858,7 @@
   BIT(doh_verifystatus);   /* DoH certificate status verification */
 #endif
   BIT(http09_allowed); /* allow HTTP/0.9 responses */
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_WEBSOCKETS
   BIT(ws_raw_mode);
 #endif
 #ifdef USE_ECH
@@ -1881,14 +1895,12 @@
   /* First a simple identifier to easier detect if a user mix up this easy
      handle with a multi handle. Set this to CURLEASY_MAGIC_NUMBER */
   unsigned int magic;
-  /* once an easy handle is tied to a connection pool
-     a non-negative number to distinguish this transfer from
-     other using the same pool. For easier tracking
-     in log output.
-     This may wrap around after LONG_MAX to 0 again, so it
-     has no uniqueness guarantee for very large processings.
-     Note: it has no uniqueness either IFF more than one connection pool
-     is used by the libcurl application. */
+  /* once an easy handle is tied to a connection pool a non-negative number to
+     distinguish this transfer from other using the same pool. For easier
+     tracking in log output. This may wrap around after LONG_MAX to 0 again,
+     so it has no uniqueness guarantee for large processings. Note: it has no
+     uniqueness either IFF more than one connection pool is used by the
+     libcurl application. */
   curl_off_t id;
   /* once an easy handle is added to a multi, either explicitly by the
    * libcurl application or implicitly during `curl_easy_perform()`,
diff --git a/Utilities/cmcurl/lib/vauth/cram.c b/Utilities/cmcurl/lib/vauth/cram.c
index f8bdd54..c51c728 100644
--- a/Utilities/cmcurl/lib/vauth/cram.c
+++ b/Utilities/cmcurl/lib/vauth/cram.c
@@ -67,7 +67,7 @@
   char *response;
 
   /* Compute the digest using the password as the key */
-  ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
+  ctxt = Curl_HMAC_init(&Curl_HMAC_MD5,
                         (const unsigned char *) passwdp,
                         curlx_uztoui(strlen(passwdp)));
   if(!ctxt)
diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c
index 4fc5b1c..0acfcac 100644
--- a/Utilities/cmcurl/lib/vauth/digest.c
+++ b/Utilities/cmcurl/lib/vauth/digest.c
@@ -227,12 +227,12 @@
   *value = 0;
 
   /* Tokenise the list of qop values. Use a temporary clone of the buffer since
-     strtok_r() ruins it. */
+     Curl_strtok_r() ruins it. */
   tmp = strdup(options);
   if(!tmp)
     return CURLE_OUT_OF_MEMORY;
 
-  token = strtok_r(tmp, ",", &tok_buf);
+  token = Curl_strtok_r(tmp, ",", &tok_buf);
   while(token) {
     if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH))
       *value |= DIGEST_QOP_VALUE_AUTH;
@@ -241,7 +241,7 @@
     else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
       *value |= DIGEST_QOP_VALUE_AUTH_CONF;
 
-    token = strtok_r(NULL, ",", &tok_buf);
+    token = Curl_strtok_r(NULL, ",", &tok_buf);
   }
 
   free(tmp);
@@ -388,7 +388,7 @@
     return result;
 
   /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
-  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
   if(!ctxt)
     return CURLE_OUT_OF_MEMORY;
 
@@ -402,7 +402,7 @@
                   curlx_uztoui(strlen(passwdp)));
   Curl_MD5_final(ctxt, digest);
 
-  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
   if(!ctxt)
     return CURLE_OUT_OF_MEMORY;
 
@@ -425,7 +425,7 @@
     return CURLE_OUT_OF_MEMORY;
 
   /* Calculate H(A2) */
-  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
   if(!ctxt) {
     free(spn);
 
@@ -443,7 +443,7 @@
     msnprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
 
   /* Now calculate the response hash */
-  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
   if(!ctxt) {
     free(spn);
 
@@ -553,12 +553,12 @@
       else if(strcasecompare(value, "qop")) {
         char *tok_buf = NULL;
         /* Tokenize the list and choose auth if possible, use a temporary
-           clone of the buffer since strtok_r() ruins it */
+           clone of the buffer since Curl_strtok_r() ruins it */
         tmp = strdup(content);
         if(!tmp)
           return CURLE_OUT_OF_MEMORY;
 
-        token = strtok_r(tmp, ",", &tok_buf);
+        token = Curl_strtok_r(tmp, ",", &tok_buf);
         while(token) {
           /* Pass additional spaces here */
           while(*token && ISBLANK(*token))
@@ -569,7 +569,7 @@
           else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) {
             foundAuthInt = TRUE;
           }
-          token = strtok_r(NULL, ",", &tok_buf);
+          token = Curl_strtok_r(NULL, ",", &tok_buf);
         }
 
         free(tmp);
@@ -709,13 +709,17 @@
     digest->nc = 1;
 
   if(!digest->cnonce) {
-    char cnoncebuf[33];
-    result = Curl_rand_hex(data, (unsigned char *)cnoncebuf,
-                           sizeof(cnoncebuf));
+    char cnoncebuf[12];
+    result = Curl_rand_bytes(data,
+#ifdef DEBUGBUILD
+                             TRUE,
+#endif
+                             (unsigned char *)cnoncebuf,
+                             sizeof(cnoncebuf));
     if(result)
       return result;
 
-    result = Curl_base64_encode(cnoncebuf, strlen(cnoncebuf),
+    result = Curl_base64_encode(cnoncebuf, sizeof(cnoncebuf),
                                 &cnonce, &cnonce_sz);
     if(result)
       return result;
diff --git a/Utilities/cmcurl/lib/vauth/digest_sspi.c b/Utilities/cmcurl/lib/vauth/digest_sspi.c
index 39a0c30..2ae6fb3 100644
--- a/Utilities/cmcurl/lib/vauth/digest_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c
@@ -69,7 +69,7 @@
     Curl_pSecFn->FreeContextBuffer(SecurityPackage);
   }
 
-  return (status == SEC_E_OK ? TRUE : FALSE);
+  return (status == SEC_E_OK);
 }
 
 /*
@@ -329,7 +329,7 @@
   /* We had an input token before so if there is another one now that means we
      provided bad credentials in the previous request or it is stale. */
   if(digest->input_token) {
-    bool stale = false;
+    bool stale = FALSE;
     const char *p = chlg;
 
     /* Check for the 'stale' directive */
@@ -345,7 +345,7 @@
 
       if(strcasecompare(value, "stale") &&
          strcasecompare(content, "true")) {
-        stale = true;
+        stale = TRUE;
         break;
       }
 
diff --git a/Utilities/cmcurl/lib/vauth/gsasl.c b/Utilities/cmcurl/lib/vauth/gsasl.c
index c7d0a8d..ee11b60 100644
--- a/Utilities/cmcurl/lib/vauth/gsasl.c
+++ b/Utilities/cmcurl/lib/vauth/gsasl.c
@@ -59,7 +59,7 @@
     return FALSE;
   }
 
-  return true;
+  return TRUE;
 }
 
 CURLcode Curl_auth_gsasl_start(struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
index 748cdf9..e792782 100644
--- a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
+++ b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
@@ -158,7 +158,7 @@
     gss_release_buffer(&unused_status, &output_token);
   }
   else
-    Curl_bufref_set(out, mutual_auth? "": NULL, 0, NULL);
+    Curl_bufref_set(out, mutual_auth ? "": NULL, 0, NULL);
 
   return result;
 }
diff --git a/Utilities/cmcurl/lib/vauth/krb5_sspi.c b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
index b168a27..4af0bd1 100644
--- a/Utilities/cmcurl/lib/vauth/krb5_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
@@ -64,7 +64,7 @@
     Curl_pSecFn->FreeContextBuffer(SecurityPackage);
   }
 
-  return (status == SEC_E_OK ? TRUE : FALSE);
+  return (status == SEC_E_OK);
 }
 
 /*
diff --git a/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c
index 0050b41..f8f6aea 100644
--- a/Utilities/cmcurl/lib/vauth/ntlm.c
+++ b/Utilities/cmcurl/lib/vauth/ntlm.c
@@ -69,7 +69,7 @@
     fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
   if(flags & NTLMFLAG_REQUEST_TARGET)
     fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
-  if(flags & (1<<3))
+  if(flags & (1 << 3))
     fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
   if(flags & NTLMFLAG_NEGOTIATE_SIGN)
     fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
@@ -81,7 +81,7 @@
     fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
   if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
     fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
-  if(flags & (1<<10))
+  if(flags & (1 << 10))
     fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
   if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
     fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
@@ -109,15 +109,15 @@
     fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
   if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
     fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
-  if(flags & (1<<24))
+  if(flags & (1 << 24))
     fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
-  if(flags & (1<<25))
+  if(flags & (1 << 25))
     fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
-  if(flags & (1<<26))
+  if(flags & (1 << 26))
     fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
-  if(flags & (1<<27))
+  if(flags & (1 << 27))
     fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
-  if(flags & (1<<28))
+  if(flags & (1 << 28))
     fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
   if(flags & NTLMFLAG_NEGOTIATE_128)
     fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
@@ -485,7 +485,7 @@
   unsigned char ntresp[24]; /* fixed-size */
   unsigned char *ptr_ntresp = &ntresp[0];
   unsigned char *ntlmv2resp = NULL;
-  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
+  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE);
   /* The fixed hostname we provide, in order to not leak our real local host
      name. Copy the name used by Firefox. */
   static const char host[] = "WORKSTATION";
diff --git a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
index 55ec820..a2e5bc1 100644
--- a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
@@ -63,7 +63,7 @@
     Curl_pSecFn->FreeContextBuffer(SecurityPackage);
   }
 
-  return (status == SEC_E_OK ? TRUE : FALSE);
+  return (status == SEC_E_OK);
 }
 
 /*
diff --git a/Utilities/cmcurl/lib/vauth/spnego_sspi.c b/Utilities/cmcurl/lib/vauth/spnego_sspi.c
index 38b26ab..7a27c29 100644
--- a/Utilities/cmcurl/lib/vauth/spnego_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/spnego_sspi.c
@@ -67,7 +67,7 @@
   }
 
 
-  return (status == SEC_E_OK ? TRUE : FALSE);
+  return (status == SEC_E_OK);
 }
 
 /*
diff --git a/Utilities/cmcurl/lib/vauth/vauth.c b/Utilities/cmcurl/lib/vauth/vauth.c
index ace43c4..a7e7e17 100644
--- a/Utilities/cmcurl/lib/vauth/vauth.c
+++ b/Utilities/cmcurl/lib/vauth/vauth.c
@@ -134,8 +134,7 @@
     /* Check we have a domain name or UPN present */
     char *p = strpbrk(user, "\\/@");
 
-    valid = (p != NULL && p > user && p < user + strlen(user) - 1 ? TRUE :
-                                                                    FALSE);
+    valid = (p != NULL && p > user && p < user + strlen(user) - 1);
   }
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
   else
diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c
index a3e192d..1b06672 100644
--- a/Utilities/cmcurl/lib/version.c
+++ b/Utilities/cmcurl/lib/version.c
@@ -63,13 +63,13 @@
 #endif
 
 #ifdef HAVE_BROTLI
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
 /* Ignore -Wvla warnings in brotli headers */
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wvla"
 #endif
 #include <brotli/decode.h>
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
 #pragma GCC diagnostic pop
 #endif
 #endif
@@ -93,20 +93,71 @@
   unsigned int major = brotli_version >> 24;
   unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12;
   unsigned int patch = brotli_version & 0x00000FFF;
-  (void)msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+  (void)msnprintf(buf, bufsz, "brotli/%u.%u.%u", major, minor, patch);
 }
 #endif
 
 #ifdef HAVE_ZSTD
 static void zstd_version(char *buf, size_t bufsz)
 {
-  unsigned long zstd_version = (unsigned long)ZSTD_versionNumber();
-  unsigned int major = (unsigned int)(zstd_version / (100 * 100));
-  unsigned int minor = (unsigned int)((zstd_version -
-                                       (major * 100 * 100)) / 100);
-  unsigned int patch = (unsigned int)(zstd_version -
-                                      (major * 100 * 100) - (minor * 100));
-  (void)msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+  unsigned int version = ZSTD_versionNumber();
+  unsigned int major = version / (100 * 100);
+  unsigned int minor = (version - (major * 100 * 100)) / 100;
+  unsigned int patch = version - (major * 100 * 100) - (minor * 100);
+  (void)msnprintf(buf, bufsz, "zstd/%u.%u.%u", major, minor, patch);
+}
+#endif
+
+#ifdef USE_OPENLDAP
+static void oldap_version(char *buf, size_t bufsz)
+{
+  LDAPAPIInfo api;
+  api.ldapai_info_version = LDAP_API_INFO_VERSION;
+
+  if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) {
+    unsigned int patch = (unsigned int)(api.ldapai_vendor_version % 100);
+    unsigned int major = (unsigned int)(api.ldapai_vendor_version / 10000);
+    unsigned int minor =
+      (((unsigned int)api.ldapai_vendor_version - major * 10000)
+       - patch) / 100;
+    msnprintf(buf, bufsz, "%s/%u.%u.%u",
+              api.ldapai_vendor_name, major, minor, patch);
+    ldap_memfree(api.ldapai_vendor_name);
+    ber_memvfree((void **)api.ldapai_extensions);
+  }
+  else
+    msnprintf(buf, bufsz, "OpenLDAP");
+}
+#endif
+
+#ifdef USE_LIBPSL
+static void psl_version(char *buf, size_t bufsz)
+{
+#if defined(PSL_VERSION_MAJOR) && (PSL_VERSION_MAJOR > 0 ||     \
+                                   PSL_VERSION_MINOR >= 11)
+  int num = psl_check_version_number(0);
+  msnprintf(buf, bufsz, "libpsl/%d.%d.%d",
+            num >> 16, (num >> 8) & 0xff, num & 0xff);
+#else
+  msnprintf(buf, bufsz, "libpsl/%s", psl_get_version());
+#endif
+}
+#endif
+
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
+#define USE_IDN
+#endif
+
+#ifdef USE_IDN
+static void idn_version(char *buf, size_t bufsz)
+{
+#ifdef USE_LIBIDN2
+  msnprintf(buf, bufsz, "libidn2/%s", idn2_check_version(NULL));
+#elif defined(USE_WIN32_IDN)
+  msnprintf(buf, bufsz, "WinIDN");
+#elif defined(USE_APPLE_IDN)
+  msnprintf(buf, bufsz, "AppleIDN");
+#endif
 }
 #endif
 
@@ -130,34 +181,34 @@
   char ssl_version[200];
 #endif
 #ifdef HAVE_LIBZ
-  char z_version[40];
+  char z_version[30];
 #endif
 #ifdef HAVE_BROTLI
-  char br_version[40] = "brotli/";
+  char br_version[30];
 #endif
 #ifdef HAVE_ZSTD
-  char zst_version[40] = "zstd/";
+  char zstd_ver[30];
 #endif
 #ifdef USE_ARES
-  char cares_version[40];
+  char cares_version[30];
 #endif
-#if defined(USE_LIBIDN2)
-  char idn_version[40];
+#ifdef USE_IDN
+  char idn_ver[30];
 #endif
 #ifdef USE_LIBPSL
-  char psl_version[40];
+  char psl_ver[30];
 #endif
 #ifdef USE_SSH
-  char ssh_version[40];
+  char ssh_version[30];
 #endif
 #ifdef USE_NGHTTP2
-  char h2_version[40];
+  char h2_version[30];
 #endif
 #ifdef USE_HTTP3
-  char h3_version[40];
+  char h3_version[30];
 #endif
 #ifdef USE_LIBRTMP
-  char rtmp_version[40];
+  char rtmp_version[30];
 #endif
 #ifdef USE_HYPER
   char hyper_buf[30];
@@ -190,43 +241,26 @@
   src[i++] = z_version;
 #endif
 #ifdef HAVE_BROTLI
-  brotli_version(&br_version[7], sizeof(br_version) - 7);
+  brotli_version(br_version, sizeof(br_version));
   src[i++] = br_version;
 #endif
 #ifdef HAVE_ZSTD
-  zstd_version(&zst_version[5], sizeof(zst_version) - 5);
-  src[i++] = zst_version;
+  zstd_version(zstd_ver, sizeof(zstd_ver));
+  src[i++] = zstd_ver;
 #endif
 #ifdef USE_ARES
   msnprintf(cares_version, sizeof(cares_version),
             "c-ares/%s", ares_version(NULL));
   src[i++] = cares_version;
 #endif
-#ifdef USE_LIBIDN2
-  msnprintf(idn_version, sizeof(idn_version),
-            "libidn2/%s", idn2_check_version(NULL));
-  src[i++] = idn_version;
-#elif defined(USE_WIN32_IDN)
-  src[i++] = (char *)"WinIDN";
-#elif defined(USE_APPLE_IDN)
-  src[i++] = (char *)"AppleIDN";
+#ifdef USE_IDN
+  idn_version(idn_ver, sizeof(idn_ver));
+  src[i++] = idn_ver;
 #endif
-
 #ifdef USE_LIBPSL
-  {
-#if defined(PSL_VERSION_MAJOR) && (PSL_VERSION_MAJOR > 0 ||     \
-                                   PSL_VERSION_MINOR >= 11)
-    int num = psl_check_version_number(0);
-    msnprintf(psl_version, sizeof(psl_version), "libpsl/%d.%d.%d",
-              num >> 16, (num >> 8) & 0xff, num & 0xff);
-#else
-    msnprintf(psl_version, sizeof(psl_version), "libpsl/%s",
-              psl_get_version());
+  psl_version(psl_ver, sizeof(psl_ver));
+  src[i++] = psl_ver;
 #endif
-    src[i++] = psl_version;
-  }
-#endif
-
 #ifdef USE_SSH
   Curl_ssh_version(ssh_version, sizeof(ssh_version));
   src[i++] = ssh_version;
@@ -253,23 +287,8 @@
   src[i++] = gsasl_buf;
 #endif
 #ifdef USE_OPENLDAP
-  {
-    LDAPAPIInfo api;
-    api.ldapai_info_version = LDAP_API_INFO_VERSION;
-
-    if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) {
-      unsigned int patch = (unsigned int)(api.ldapai_vendor_version % 100);
-      unsigned int major = (unsigned int)(api.ldapai_vendor_version / 10000);
-      unsigned int minor =
-        (((unsigned int)api.ldapai_vendor_version - major * 10000)
-          - patch) / 100;
-      msnprintf(ldap_buf, sizeof(ldap_buf), "%s/%u.%u.%u",
-                api.ldapai_vendor_name, major, minor, patch);
-      src[i++] = ldap_buf;
-      ldap_memfree(api.ldapai_vendor_name);
-      ber_memvfree((void **)api.ldapai_extensions);
-    }
-  }
+  oldap_version(ldap_buf, sizeof(ldap_buf));
+  src[i++] = ldap_buf;
 #endif
 
   DEBUGASSERT(i <= VERSION_PARTS);
@@ -384,12 +403,15 @@
 #ifndef CURL_DISABLE_TFTP
   "tftp",
 #endif
-#ifdef USE_WEBSOCKETS
+#ifndef CURL_DISABLE_HTTP
+  /* WebSocket support relies on HTTP */
+#ifndef CURL_DISABLE_WEBSOCKETS
   "ws",
 #endif
-#if defined(USE_SSL) && defined(USE_WEBSOCKETS)
+#if defined(USE_SSL) && !defined(CURL_DISABLE_WEBSOCKETS)
   "wss",
 #endif
+#endif
 
   NULL
 };
@@ -529,7 +551,7 @@
 #ifdef HAVE_ZSTD
   FEATURE("zstd",        NULL,                CURL_VERSION_ZSTD),
 #endif
-  {NULL,             NULL,                0}
+  {NULL,                 NULL,                0}
 };
 
 static const char *feature_names[sizeof(features_table) /
@@ -540,7 +562,7 @@
   CURLVERSION_NOW,
   LIBCURL_VERSION,
   LIBCURL_VERSION_NUM,
-  OS,   /* as found by configure or set by hand at build-time */
+  CURL_OS, /* as found by configure or set by hand at build-time */
   0,    /* features bitmask is built at runtime */
   NULL, /* ssl_version */
   0,    /* ssl_version_num, this is kept at zero */
diff --git a/Utilities/cmcurl/lib/version_win32.c b/Utilities/cmcurl/lib/version_win32.c
index 25ec827..21a122f 100644
--- a/Utilities/cmcurl/lib/version_win32.c
+++ b/Utilities/cmcurl/lib/version_win32.c
@@ -79,7 +79,7 @@
 {
   bool matched = FALSE;
 
-#if defined(CURL_WINDOWS_APP)
+#if defined(CURL_WINDOWS_UWP)
   /* We have no way to determine the Windows version from Windows apps,
      so let's assume we are running on the target Windows version. */
   const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
@@ -209,12 +209,12 @@
   typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN)
     (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG);
   static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo;
-  static bool onetime = true; /* safe because first call is during init */
+  static bool onetime = TRUE; /* safe because first call is during init */
 
   if(onetime) {
     pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN,
       (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")));
-    onetime = false;
+    onetime = FALSE;
   }
 
   switch(condition) {
diff --git a/Utilities/cmcurl/lib/vquic/curl_msh3.c b/Utilities/cmcurl/lib/vquic/curl_msh3.c
index ac7865c..fe812f8 100644
--- a/Utilities/cmcurl/lib/vquic/curl_msh3.c
+++ b/Utilities/cmcurl/lib/vquic/curl_msh3.c
@@ -71,7 +71,7 @@
   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
   pthread_mutex_init(lock, &attr); \
   pthread_mutexattr_destroy(&attr); \
-}while(0)
+} while(0)
 #define msh3_lock_uninitialize(lock) pthread_mutex_destroy(lock)
 #define msh3_lock_acquire(lock) pthread_mutex_lock(lock)
 #define msh3_lock_release(lock) pthread_mutex_unlock(lock)
@@ -248,8 +248,8 @@
   }
 }
 
-static void drain_stream(struct Curl_cfilter *cf,
-                         struct Curl_easy *data)
+static void h3_drain_stream(struct Curl_cfilter *cf,
+                            struct Curl_easy *data)
 {
   struct cf_msh3_ctx *ctx = cf->ctx;
   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
@@ -280,9 +280,9 @@
   (void)Connection;
 
   CURL_TRC_CF(data, cf, "[MSH3] connected");
-  ctx->handshake_succeeded = true;
-  ctx->connected = true;
-  ctx->handshake_complete = true;
+  ctx->handshake_succeeded = TRUE;
+  ctx->connected = TRUE;
+  ctx->handshake_complete = TRUE;
 }
 
 static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection,
@@ -294,8 +294,8 @@
 
   (void)Connection;
   CURL_TRC_CF(data, cf, "[MSH3] shutdown complete");
-  ctx->connected = false;
-  ctx->handshake_complete = true;
+  ctx->connected = FALSE;
+  ctx->handshake_complete = TRUE;
 }
 
 static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection,
@@ -450,7 +450,7 @@
       stream->recv_error = result;
       goto out;
     }
-    stream->recv_header_complete = true;
+    stream->recv_header_complete = TRUE;
   }
 
   result = write_resp_raw(data, buf, *buflen);
@@ -476,7 +476,7 @@
     return;
   msh3_lock_acquire(&stream->recv_lock);
   stream->closed = TRUE;
-  stream->recv_header_complete = true;
+  stream->recv_header_complete = TRUE;
   if(error)
     stream->error3 = error;
   if(aborted)
@@ -596,7 +596,7 @@
     if(nread < 0)
       goto out;
     if(stream->closed)
-      drain_stream(cf, data);
+      h3_drain_stream(cf, data);
   }
   else if(stream->closed) {
     nread = recv_closed_stream(cf, data, err);
@@ -722,11 +722,11 @@
   if(stream && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) {
     if(stream->recv_error) {
       Curl_pollset_add_in(data, ps, ctx->sock[SP_LOCAL]);
-      drain_stream(cf, data);
+      h3_drain_stream(cf, data);
     }
     else if(stream->req) {
       Curl_pollset_add_out(data, ps, ctx->sock[SP_LOCAL]);
-      drain_stream(cf, data);
+      h3_drain_stream(cf, data);
     }
   }
 }
@@ -749,7 +749,7 @@
     pending = !Curl_bufq_is_empty(&stream->recvbuf);
     msh3_lock_release(&stream->recv_lock);
     if(pending)
-      drain_stream(cf, (struct Curl_easy *)data);
+      h3_drain_stream(cf, (struct Curl_easy *)data);
   }
 
   CF_DATA_RESTORE(cf, save);
@@ -761,7 +761,7 @@
                               bool pause)
 {
   if(!pause) {
-    drain_stream(cf, data);
+    h3_drain_stream(cf, data);
     Curl_expire(data, 0, EXPIRE_RUN_NOW);
   }
   return CURLE_OK;
@@ -826,7 +826,7 @@
     return CURLE_FAILED_INIT;
   verify = !!conn_config->verifypeer;
 
-  memcpy(&addr, &ctx->addr.sa_addr, ctx->addr.addrlen);
+  memcpy(&addr, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
   MSH3_SET_PORT(&addr, (uint16_t)cf->conn->remote_port);
 
   if(verify && (conn_config->CAfile || conn_config->CApath)) {
@@ -1020,7 +1020,7 @@
   default:
     break;
   }
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
@@ -1092,7 +1092,7 @@
   result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
 
 out:
-  *pcf = (!result)? cf : NULL;
+  *pcf = (!result) ? cf : NULL;
   if(result) {
     Curl_safefree(cf);
     cf_msh3_ctx_free(ctx);
@@ -1105,7 +1105,7 @@
                        const struct connectdata *conn,
                        int sockindex)
 {
-  struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+  struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
 
   (void)data;
   for(; cf; cf = cf->next) {
diff --git a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
index 3b958e2..37009ab 100644
--- a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
+++ b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
@@ -41,6 +41,7 @@
 #include "vtls/gtls.h"
 #elif defined(USE_WOLFSSL)
 #include <ngtcp2/ngtcp2_crypto_wolfssl.h>
+#include "vtls/wolfssl.h"
 #endif
 
 #include "urldata.h"
@@ -342,7 +343,6 @@
   struct Curl_cfilter *cf;
   struct Curl_easy *data;
   ngtcp2_tstamp ts;
-  size_t pkt_count;
   ngtcp2_path_storage ps;
 };
 
@@ -362,7 +362,6 @@
 {
   pktx->cf = cf;
   pktx->data = data;
-  pktx->pkt_count = 0;
   ngtcp2_path_storage_zero(&pktx->ps);
   pktx_update_time(pktx, cf);
 }
@@ -429,7 +428,7 @@
   s->initial_ts = pktx->ts;
   s->handshake_timeout = QUIC_HANDSHAKE_TIMEOUT;
   s->max_window = 100 * ctx->max_stream_window;
-  s->max_stream_window = ctx->max_stream_window;
+  s->max_stream_window = 10 * ctx->max_stream_window;
 
   t->initial_max_data = 10 * ctx->max_stream_window;
   t->initial_max_stream_data_bidi_local = ctx->max_stream_window;
@@ -1199,7 +1198,7 @@
   (void)cf;
   if(stream->reset) {
     failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id);
-    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+    *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
     goto out;
   }
   else if(!stream->resp_hds_complete) {
@@ -1277,7 +1276,7 @@
     }
   }
   CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
-              stream? stream->id : -1, blen, nread, *err);
+              stream ? stream->id : -1, blen, nread, *err);
   CF_DATA_RESTORE(cf, save);
   return nread;
 }
@@ -1375,7 +1374,7 @@
   CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
               "%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
               stream->id, (int)nvecs,
-              *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
+              *pflags == NGHTTP3_DATA_FLAG_EOF ? " EOF" : "",
               nwritten, Curl_bufq_len(&stream->sendbuf),
               stream->upload_left);
   return (nghttp3_ssize)nvecs;
@@ -1612,7 +1611,7 @@
     sent = -1;
   }
   CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
-              stream? stream->id : -1, len, sent, *err);
+              stream ? stream->id : -1, len, sent, *err);
   CF_DATA_RESTORE(cf, save);
   return sent;
 }
@@ -1639,7 +1638,6 @@
   ngtcp2_path path;
   int rv;
 
-  ++pktx->pkt_count;
   ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
                    (socklen_t)ctx->q.local_addrlen);
   ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
@@ -1668,31 +1666,18 @@
 {
   struct cf_ngtcp2_ctx *ctx = cf->ctx;
   struct pkt_io_ctx local_pktx;
-  size_t pkts_chunk = 128, i;
   CURLcode result = CURLE_OK;
 
   if(!pktx) {
     pktx_init(&local_pktx, cf, data);
     pktx = &local_pktx;
   }
-  else {
-    pktx_update_time(pktx, cf);
-  }
 
   result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
   if(result)
     return result;
 
-  for(i = 0; i < 4; ++i) {
-    if(i)
-      pktx_update_time(pktx, cf);
-    pktx->pkt_count = 0;
-    result = vquic_recv_packets(cf, data, &ctx->q, pkts_chunk,
-                                recv_pkt, pktx);
-    if(result || !pktx->pkt_count) /* error or got nothing */
-      break;
-  }
-  return result;
+  return vquic_recv_packets(cf, data, &ctx->q, 1000, recv_pkt, pktx);
 }
 
 /**
@@ -2142,9 +2127,9 @@
   ngtcp2_crypto_conn_ref *cref;
 
   cref = (ngtcp2_crypto_conn_ref *)SSL_get_app_data(ssl);
-  cf = cref? cref->user_data : NULL;
-  ctx = cf? cf->ctx : NULL;
-  data = cf? CF_DATA_CURRENT(cf) : NULL;
+  cf = cref ? cref->user_data : NULL;
+  ctx = cf ? cf->ctx : NULL;
+  data = cf ? CF_DATA_CURRENT(cf) : NULL;
   if(cf && data && ctx) {
     Curl_ossl_add_session(cf, data, &ctx->peer, ssl_sessionid);
     return 1;
@@ -2153,12 +2138,63 @@
 }
 #endif /* USE_OPENSSL */
 
+#ifdef USE_GNUTLS
+static int quic_gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
+                                  unsigned when, unsigned int incoming,
+                                  const gnutls_datum_t *msg)
+{
+  ngtcp2_crypto_conn_ref *conn_ref = gnutls_session_get_ptr(session);
+  struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL;
+  struct cf_ngtcp2_ctx *ctx = cf ? cf->ctx : NULL;
+
+  (void)msg;
+  (void)incoming;
+  if(when && cf && ctx) { /* after message has been processed */
+    struct Curl_easy *data = CF_DATA_CURRENT(cf);
+    DEBUGASSERT(data);
+    if(data) {
+      CURL_TRC_CF(data, cf, "handshake: %s message type %d",
+                  incoming ? "incoming" : "outgoing", htype);
+    }
+    switch(htype) {
+    case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
+      (void)Curl_gtls_update_session_id(cf, data, session, &ctx->peer, "h3");
+      break;
+    }
+    default:
+      break;
+    }
+  }
+  return 0;
+}
+#endif /* USE_GNUTLS */
+
+#ifdef USE_WOLFSSL
+static int wssl_quic_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
+{
+  ngtcp2_crypto_conn_ref *conn_ref = wolfSSL_get_app_data(ssl);
+  struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL;
+
+  DEBUGASSERT(cf != NULL);
+  if(cf && session) {
+    struct cf_ngtcp2_ctx *ctx = cf->ctx;
+    struct Curl_easy *data = CF_DATA_CURRENT(cf);
+    DEBUGASSERT(data);
+    if(data && ctx) {
+      (void)wssl_cache_session(cf, data, &ctx->peer, session);
+    }
+  }
+  return 0;
+}
+#endif /* USE_WOLFSSL */
+
 static CURLcode tls_ctx_setup(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               void *user_data)
 {
   struct curl_tls_ctx *ctx = user_data;
-  (void)cf;
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+
 #ifdef USE_OPENSSL
 #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
   if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ossl.ssl_ctx)
@@ -2172,25 +2208,37 @@
     return CURLE_FAILED_INIT;
   }
 #endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
-  /* Enable the session cache because it is a prerequisite for the
-   * "new session" callback. Use the "external storage" mode to prevent
-   * OpenSSL from creating an internal session cache.
-   */
-  SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
-                                 SSL_SESS_CACHE_CLIENT |
-                                 SSL_SESS_CACHE_NO_INTERNAL);
-  SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb);
+  if(ssl_config->primary.cache_session) {
+    /* Enable the session cache because it is a prerequisite for the
+     * "new session" callback. Use the "external storage" mode to prevent
+     * OpenSSL from creating an internal session cache.
+     */
+    SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
+                                   SSL_SESS_CACHE_CLIENT |
+                                   SSL_SESS_CACHE_NO_INTERNAL);
+    SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb);
+  }
 
 #elif defined(USE_GNUTLS)
   if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) {
     failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
     return CURLE_FAILED_INIT;
   }
+  if(ssl_config->primary.cache_session) {
+    gnutls_handshake_set_hook_function(ctx->gtls.session,
+                                       GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
+                                       quic_gtls_handshake_cb);
+  }
+
 #elif defined(USE_WOLFSSL)
   if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ctx) != 0) {
     failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
     return CURLE_FAILED_INIT;
   }
+  if(ssl_config->primary.cache_session) {
+    /* Register to get notified when a new session is received */
+    wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ctx, wssl_quic_new_session_cb);
+  }
 #endif
   return CURLE_OK;
 }
@@ -2256,7 +2304,7 @@
                    (struct sockaddr *)&ctx->q.local_addr,
                    ctx->q.local_addrlen);
   ngtcp2_addr_init(&ctx->connected_path.remote,
-                   &sockaddr->sa_addr, (socklen_t)sockaddr->addrlen);
+                   &sockaddr->curl_sa_addr, (socklen_t)sockaddr->addrlen);
 
   rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid,
                               &ctx->connected_path,
@@ -2270,8 +2318,10 @@
   ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl);
 #elif defined(USE_GNUTLS)
   ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
-#else
+#elif defined(USE_WOLFSSL)
   ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.handle);
+#else
+  #error "ngtcp2 TLS backend not defined"
 #endif
 
   ngtcp2_ccerr_default(&ctx->last_error);
@@ -2394,7 +2444,7 @@
       if(ctx->max_bidi_streams > ctx->used_bidi_streams)
         avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams;
       max_streams += avail_bidi_streams;
-      *pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
+      *pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams;
     }
     else  /* transport params not arrived yet? take our default. */
       *pres1 = (int)Curl_multi_max_concurrent_streams(data->multi);
@@ -2407,7 +2457,7 @@
   case CF_QUERY_CONNECT_REPLY_MS:
     if(ctx->q.got_first_byte) {
       timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
-      *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
+      *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
     }
     else
       *pres1 = -1;
@@ -2427,7 +2477,7 @@
   default:
     break;
   }
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
@@ -2476,7 +2526,7 @@
     *input_pending = FALSE;
     result = cf_progress_ingress(cf, data, NULL);
     CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
-    alive = result? FALSE : TRUE;
+    alive = result ? FALSE : TRUE;
   }
 
 out:
@@ -2534,7 +2584,7 @@
   cf->next = udp_cf;
 
 out:
-  *pcf = (!result)? cf : NULL;
+  *pcf = (!result) ? cf : NULL;
   if(result) {
     if(udp_cf)
       Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
@@ -2548,7 +2598,7 @@
                          const struct connectdata *conn,
                          int sockindex)
 {
-  struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+  struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
 
   (void)data;
   for(; cf; cf = cf->next) {
diff --git a/Utilities/cmcurl/lib/vquic/curl_osslq.c b/Utilities/cmcurl/lib/vquic/curl_osslq.c
index 6121b2f..e5f737f 100644
--- a/Utilities/cmcurl/lib/vquic/curl_osslq.c
+++ b/Utilities/cmcurl/lib/vquic/curl_osslq.c
@@ -175,7 +175,7 @@
   switch(addr->family) {
   case AF_INET: {
     struct sockaddr_in * const sin =
-      (struct sockaddr_in * const)(void *)&addr->sa_addr;
+      (struct sockaddr_in * const)(void *)&addr->curl_sa_addr;
     if(!BIO_ADDR_rawmake(ba, AF_INET, &sin->sin_addr,
                          sizeof(sin->sin_addr), sin->sin_port)) {
       goto out;
@@ -186,7 +186,7 @@
 #ifdef USE_IPV6
   case AF_INET6: {
     struct sockaddr_in6 * const sin =
-      (struct sockaddr_in6 * const)(void *)&addr->sa_addr;
+      (struct sockaddr_in6 * const)(void *)&addr->curl_sa_addr;
     if(!BIO_ADDR_rawmake(ba, AF_INET6, &sin->sin6_addr,
                          sizeof(sin->sin6_addr), sin->sin6_port)) {
     }
@@ -1037,7 +1037,7 @@
   CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
               "%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
               stream->s.id, (int)nvecs,
-              *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
+              *pflags == NGHTTP3_DATA_FLAG_EOF ? " EOF" : "",
               nwritten, Curl_bufq_len(&stream->sendbuf),
               stream->upload_left);
   return (nghttp3_ssize)nvecs;
@@ -1309,7 +1309,7 @@
   CURLcode result = CURLE_OK;
   ssize_t nread;
   struct h3_quic_recv_ctx x;
-  int rv, eagain = FALSE;
+  bool eagain = FALSE;
   size_t total_recv_len = 0;
 
   DEBUGASSERT(s);
@@ -1359,6 +1359,7 @@
 
     /* When we forwarded everything, handle RESET/EOS */
     if(Curl_bufq_is_empty(&s->recvbuf) && !s->closed) {
+      int rv;
       result = CURLE_OK;
       if(s->reset) {
         uint64_t app_error;
@@ -1531,7 +1532,7 @@
     for(i = 0; (i < n) && !blocked; ++i) {
       /* Without stream->s.ssl, we closed that already, so
        * pretend the write did succeed. */
-      uint64_t flags = (eos && ((i + 1) == n))? SSL_WRITE_FLAG_CONCLUDE : 0;
+      uint64_t flags = (eos && ((i + 1) == n)) ? SSL_WRITE_FLAG_CONCLUDE : 0;
       written = vec[i].len;
       ok = !s->ssl || SSL_write_ex2(s->ssl, vec[i].base, vec[i].len, flags,
                                    &written);
@@ -1632,11 +1633,11 @@
   CURLcode result = CURLE_OK;
   struct timeval tv;
   timediff_t timeoutms;
-  int is_infinite = TRUE;
+  int is_infinite = 1;
 
   if(ctx->tls.ossl.ssl &&
-    SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite) &&
-    !is_infinite) {
+     SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite) &&
+     !is_infinite) {
     timeoutms = curlx_tvtoms(&tv);
     /* QUIC want to be called again latest at the returned timeout */
     if(timeoutms <= 0) {
@@ -1700,6 +1701,14 @@
     }
   }
 
+  /* Since OpenSSL does its own send/recv internally, we may miss the
+   * moment to populate the x509 store right before the server response.
+   * Do it instead before we start the handshake, at the loss of the
+   * time to set this up. */
+  result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
+  if(result)
+    goto out;
+
   ERR_clear_error();
   err = SSL_do_handshake(ctx->tls.ossl.ssl);
 
@@ -1724,7 +1733,6 @@
     case SSL_ERROR_WANT_READ:
       ctx->q.last_io = now;
       CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_RECV");
-      result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
       goto out;
     case SSL_ERROR_WANT_WRITE:
       ctx->q.last_io = now;
@@ -1985,7 +1993,7 @@
 out:
   result = check_and_set_expiry(cf, data);
   CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
-              stream? stream->s.id : -1, len, nwritten, *err);
+              stream ? stream->s.id : -1, len, nwritten, *err);
   CF_DATA_RESTORE(cf, save);
   return nwritten;
 }
@@ -2002,7 +2010,7 @@
     failf(data,
           "HTTP/3 stream %" FMT_PRId64 " reset by server",
           stream->s.id);
-    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+    *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
     goto out;
   }
   else if(!stream->resp_hds_complete) {
@@ -2096,7 +2104,7 @@
     }
   }
   CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(len=%zu) -> %zd, %d",
-              stream? stream->s.id : -1, len, nread, *err);
+              stream ? stream->s.id : -1, len, nread, *err);
   CF_DATA_RESTORE(cf, save);
   return nread;
 }
@@ -2207,7 +2215,7 @@
     *input_pending = FALSE;
     result = cf_progress_ingress(cf, data);
     CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
-    alive = result? FALSE : TRUE;
+    alive = result ? FALSE : TRUE;
   }
 
 out:
@@ -2266,7 +2274,7 @@
     }
     /* we report avail + in_use */
     v += CONN_INUSE(cf->conn);
-    *pres1 = (v > INT_MAX)? INT_MAX : (int)v;
+    *pres1 = (v > INT_MAX) ? INT_MAX : (int)v;
 #else
     *pres1 = 100;
 #endif
@@ -2276,7 +2284,7 @@
   case CF_QUERY_CONNECT_REPLY_MS:
     if(ctx->got_first_byte) {
       timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
-      *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
+      *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
     }
     else
       *pres1 = -1;
@@ -2296,7 +2304,7 @@
   default:
     break;
   }
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
@@ -2351,7 +2359,7 @@
   cf->next = udp_cf;
 
 out:
-  *pcf = (!result)? cf : NULL;
+  *pcf = (!result) ? cf : NULL;
   if(result) {
     if(udp_cf)
       Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
@@ -2365,7 +2373,7 @@
                         const struct connectdata *conn,
                         int sockindex)
 {
-  struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+  struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
 
   (void)data;
   for(; cf; cf = cf->next) {
diff --git a/Utilities/cmcurl/lib/vquic/curl_quiche.c b/Utilities/cmcurl/lib/vquic/curl_quiche.c
index 768a5f2..3048498 100644
--- a/Utilities/cmcurl/lib/vquic/curl_quiche.c
+++ b/Utilities/cmcurl/lib/vquic/curl_quiche.c
@@ -268,8 +268,8 @@
   }
 }
 
-static void drain_stream(struct Curl_cfilter *cf,
-                         struct Curl_easy *data)
+static void h3_drain_stream(struct Curl_cfilter *cf,
+                            struct Curl_easy *data)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
@@ -584,7 +584,7 @@
     }
     else {
       result = h3_process_event(cf, sdata, stream, ev);
-      drain_stream(cf, sdata);
+      h3_drain_stream(cf, sdata);
       if(result) {
         CURL_TRC_CF(data, cf, "error processing event %s "
                     "for [%"FMT_PRIu64"] -> %d", cf_ev_name(ev),
@@ -818,7 +818,7 @@
   if(stream->reset) {
     failf(data,
           "HTTP/3 stream %" FMT_PRIu64 " reset by server", stream->id);
-    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+    *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, was reset -> %d",
                 stream->id, *err);
   }
@@ -882,7 +882,7 @@
 
   if(nread > 0) {
     if(stream->closed)
-      drain_stream(cf, data);
+      h3_drain_stream(cf, data);
   }
   else {
     if(stream->closed) {
@@ -1146,7 +1146,7 @@
     nwritten = -1;
   }
   CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
-              stream? stream->id : (curl_uint64_t)~0, len, nwritten, *err);
+              stream ? stream->id : (curl_uint64_t)~0, len, nwritten, *err);
   return nwritten;
 }
 
@@ -1207,7 +1207,7 @@
   /* TODO: there seems right now no API in quiche to shrink/enlarge
    * the streams windows. As we do in HTTP/2. */
   if(!pause) {
-    drain_stream(cf, data);
+    h3_drain_stream(cf, data);
     Curl_expire(data, 0, EXPIRE_RUN_NOW);
   }
   return CURLE_OK;
@@ -1287,7 +1287,7 @@
     failf(data, "cannot create quiche config");
     return CURLE_FAILED_INIT;
   }
-  quiche_config_enable_pacing(ctx->cfg, false);
+  quiche_config_enable_pacing(ctx->cfg, FALSE);
   quiche_config_set_max_idle_timeout(ctx->cfg, CURL_QUIC_MAX_IDLE_MS);
   quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024)
     /* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */);
@@ -1329,11 +1329,12 @@
     return CURLE_QUIC_CONNECT_ERROR;
 
   ctx->qconn = quiche_conn_new_with_tls((const uint8_t *)ctx->scid,
-                                      sizeof(ctx->scid), NULL, 0,
-                                      (struct sockaddr *)&ctx->q.local_addr,
-                                      ctx->q.local_addrlen,
-                                      &sockaddr->sa_addr, sockaddr->addrlen,
-                                      ctx->cfg, ctx->tls.ossl.ssl, false);
+                                        sizeof(ctx->scid), NULL, 0,
+                                        (struct sockaddr *)&ctx->q.local_addr,
+                                        ctx->q.local_addrlen,
+                                        &sockaddr->curl_sa_addr,
+                                        sockaddr->addrlen,
+                                        ctx->cfg, ctx->tls.ossl.ssl, FALSE);
   if(!ctx->qconn) {
     failf(data, "cannot create quiche connection");
     return CURLE_OUT_OF_MEMORY;
@@ -1546,7 +1547,7 @@
     if(!ctx->goaway) {
       max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn);
     }
-    *pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
+    *pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams;
     CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
                 "MAX_CONCURRENT -> %d (%zu in use)",
                 cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
@@ -1555,7 +1556,7 @@
   case CF_QUERY_CONNECT_REPLY_MS:
     if(ctx->q.got_first_byte) {
       timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
-      *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
+      *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
     }
     else
       *pres1 = -1;
@@ -1575,7 +1576,7 @@
   default:
     break;
   }
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
@@ -1667,7 +1668,7 @@
   cf->next = udp_cf;
 
 out:
-  *pcf = (!result)? cf : NULL;
+  *pcf = (!result) ? cf : NULL;
   if(result) {
     if(udp_cf)
       Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
@@ -1682,7 +1683,7 @@
                          const struct connectdata *conn,
                          int sockindex)
 {
-  struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
+  struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
 
   (void)data;
   for(; cf; cf = cf->next) {
diff --git a/Utilities/cmcurl/lib/vquic/vquic-tls.c b/Utilities/cmcurl/lib/vquic/vquic-tls.c
index cc8c22d..580e570 100644
--- a/Utilities/cmcurl/lib/vquic/vquic-tls.c
+++ b/Utilities/cmcurl/lib/vquic/vquic-tls.c
@@ -76,11 +76,11 @@
 }
 #endif
 
-static CURLcode Curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
-                                   struct Curl_cfilter *cf,
-                                   struct Curl_easy *data,
-                                   Curl_vquic_tls_ctx_setup *cb_setup,
-                                   void *cb_user_data)
+static CURLcode wssl_init_ctx(struct curl_tls_ctx *ctx,
+                              struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              Curl_vquic_tls_ctx_setup *cb_setup,
+                              void *cb_user_data)
 {
   struct ssl_primary_config *conn_config;
   CURLcode result = CURLE_FAILED_INIT;
@@ -173,10 +173,10 @@
 
   /* give application a chance to interfere with SSL set up. */
   if(data->set.ssl.fsslctx) {
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     result = (*data->set.ssl.fsslctx)(data, ctx->wssl.ctx,
                                       data->set.ssl.fsslctxp);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
     if(result) {
       failf(data, "error signaled by ssl ctx callback");
       goto out;
@@ -194,13 +194,15 @@
 
 /** SSL callbacks ***/
 
-static CURLcode Curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
-                                   struct Curl_easy *data,
-                                   struct ssl_peer *peer,
-                                   const char *alpn, size_t alpn_len,
-                                   void *user_data)
+static CURLcode wssl_init_ssl(struct curl_tls_ctx *ctx,
+                              struct Curl_cfilter *cf,
+                              struct Curl_easy *data,
+                              struct ssl_peer *peer,
+                              const char *alpn, size_t alpn_len,
+                              void *user_data)
 {
-  (void)data;
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+
   DEBUGASSERT(!ctx->wssl.handle);
   DEBUGASSERT(ctx->wssl.ctx);
   ctx->wssl.handle = wolfSSL_new(ctx->wssl.ctx);
@@ -218,6 +220,10 @@
                    peer->sni, (unsigned short)strlen(peer->sni));
   }
 
+  if(ssl_config->primary.cache_session) {
+    (void)wssl_setup_session(cf, data, &ctx->wssl, peer);
+  }
+
   return CURLE_OK;
 }
 #endif /* defined(USE_WOLFSSL) */
@@ -240,14 +246,14 @@
 #elif defined(USE_GNUTLS)
   (void)result;
   return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer,
-                            (const unsigned char *)alpn, alpn_len,
+                            (const unsigned char *)alpn, alpn_len, NULL,
                             cb_setup, cb_user_data, ssl_user_data);
 #elif defined(USE_WOLFSSL)
-  result = Curl_wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
+  result = wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
   if(result)
     return result;
 
-  return Curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, ssl_user_data);
+  return wssl_init_ssl(ctx, cf, data, peer, alpn, alpn_len, ssl_user_data);
 #else
 #error "no TLS lib in used, should not happen"
   return CURLE_FAILED_INIT;
diff --git a/Utilities/cmcurl/lib/vquic/vquic-tls.h b/Utilities/cmcurl/lib/vquic/vquic-tls.h
index 0ec74bf..969acad 100644
--- a/Utilities/cmcurl/lib/vquic/vquic-tls.h
+++ b/Utilities/cmcurl/lib/vquic/vquic-tls.h
@@ -64,7 +64,7 @@
  * @param alpn        the ALPN string in protocol format ((len+bytes+)+),
  *                    may be NULL
  * @param alpn_len    the overall number of bytes in `alpn`
- * @param cb_setup    optional callback for very early TLS config
+ * @param cb_setup    optional callback for early TLS config
  ± @param cb_user_data user_data param for callback
  * @param ssl_user_data  optional pointer to set in TLS application context
  */
diff --git a/Utilities/cmcurl/lib/vquic/vquic.c b/Utilities/cmcurl/lib/vquic/vquic.c
index 4648b5a..20ff6a6 100644
--- a/Utilities/cmcurl/lib/vquic/vquic.c
+++ b/Utilities/cmcurl/lib/vquic/vquic.c
@@ -22,18 +22,6 @@
  *
  ***************************************************************************/
 
-/* WIP, experimental: use recvmmsg() on Linux
- * we have no configure check, yet
- * and also it is only available for _GNU_SOURCE, which
- * we do not use otherwise.
-#define HAVE_SENDMMSG
- */
-#if defined(HAVE_SENDMMSG)
-#define _GNU_SOURCE
-#include <sys/socket.h>
-#undef _GNU_SOURCE
-#endif
-
 #include "curl_setup.h"
 
 #ifdef HAVE_NETINET_UDP_H
@@ -51,6 +39,7 @@
 #include "curl_ngtcp2.h"
 #include "curl_osslq.h"
 #include "curl_quiche.h"
+#include "multiif.h"
 #include "rand.h"
 #include "vquic.h"
 #include "vquic_int.h"
@@ -153,8 +142,8 @@
     /* Only set this, when we need it. macOS, for example,
      * does not seem to like a msg_control of length 0. */
     msg.msg_control = msg_ctrl;
-    assert(sizeof(msg_ctrl) >= CMSG_SPACE(sizeof(uint16_t)));
-    msg.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
+    assert(sizeof(msg_ctrl) >= CMSG_SPACE(sizeof(int)));
+    msg.msg_controllen = CMSG_SPACE(sizeof(int));
     cm = CMSG_FIRSTHDR(&msg);
     cm->cmsg_level = SOL_UDP;
     cm->cmsg_type = UDP_SEGMENT;
@@ -333,20 +322,20 @@
 }
 
 #if defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)
-static size_t msghdr_get_udp_gro(struct msghdr *msg)
+static size_t vquic_msghdr_get_udp_gro(struct msghdr *msg)
 {
   int gso_size = 0;
 #if defined(__linux__) && defined(UDP_GRO)
   struct cmsghdr *cmsg;
 
   /* Workaround musl CMSG_NXTHDR issue */
-#ifndef __GLIBC__
+#if defined(__clang__) && !defined(__GLIBC__)
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wsign-compare"
 #pragma clang diagnostic ignored "-Wcast-align"
 #endif
   for(cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
-#ifndef __GLIBC__
+#if defined(__clang__) && !defined(__GLIBC__)
 #pragma clang diagnostic pop
 #endif
     if(cmsg->cmsg_level == SOL_UDP && cmsg->cmsg_type == UDP_GRO) {
@@ -369,21 +358,28 @@
                                  size_t max_pkts,
                                  vquic_recv_pkt_cb *recv_cb, void *userp)
 {
-#define MMSG_NUM  64
+#define MMSG_NUM  16
   struct iovec msg_iov[MMSG_NUM];
   struct mmsghdr mmsg[MMSG_NUM];
-  uint8_t msg_ctrl[MMSG_NUM * CMSG_SPACE(sizeof(uint16_t))];
-  uint8_t bufs[MMSG_NUM][2*1024];
+  uint8_t msg_ctrl[MMSG_NUM * CMSG_SPACE(sizeof(int))];
   struct sockaddr_storage remote_addr[MMSG_NUM];
-  size_t total_nread, pkts;
+  size_t total_nread = 0, pkts;
   int mcount, i, n;
   char errstr[STRERROR_LEN];
   CURLcode result = CURLE_OK;
   size_t gso_size;
   size_t pktlen;
   size_t offset, to;
+  char *sockbuf = NULL;
+  uint8_t (*bufs)[64*1024] = NULL;
 
   DEBUGASSERT(max_pkts > 0);
+  result = Curl_multi_xfer_sockbuf_borrow(data, MMSG_NUM * sizeof(bufs[0]),
+                                          &sockbuf);
+  if(result)
+    goto out;
+  bufs = (uint8_t (*)[64*1024])sockbuf;
+
   pkts = 0;
   total_nread = 0;
   while(pkts < max_pkts) {
@@ -396,8 +392,8 @@
       mmsg[i].msg_hdr.msg_iovlen = 1;
       mmsg[i].msg_hdr.msg_name = &remote_addr[i];
       mmsg[i].msg_hdr.msg_namelen = sizeof(remote_addr[i]);
-      mmsg[i].msg_hdr.msg_control = &msg_ctrl[i];
-      mmsg[i].msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
+      mmsg[i].msg_hdr.msg_control = &msg_ctrl[i * CMSG_SPACE(sizeof(int))];
+      mmsg[i].msg_hdr.msg_controllen = CMSG_SPACE(sizeof(int));
     }
 
     while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 &&
@@ -427,7 +423,7 @@
     for(i = 0; i < mcount; ++i) {
       total_nread += mmsg[i].msg_len;
 
-      gso_size = msghdr_get_udp_gro(&mmsg[i].msg_hdr);
+      gso_size = vquic_msghdr_get_udp_gro(&mmsg[i].msg_hdr);
       if(gso_size == 0) {
         gso_size = mmsg[i].msg_len;
       }
@@ -455,6 +451,7 @@
   if(total_nread || result)
     CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
                 pkts, total_nread, result);
+  Curl_multi_xfer_sockbuf_release(data, sockbuf);
   return result;
 }
 
@@ -473,7 +470,7 @@
   ssize_t nread;
   char errstr[STRERROR_LEN];
   CURLcode result = CURLE_OK;
-  uint8_t msg_ctrl[CMSG_SPACE(sizeof(uint16_t))];
+  uint8_t msg_ctrl[CMSG_SPACE(sizeof(int))];
   size_t gso_size;
   size_t pktlen;
   size_t offset, to;
@@ -515,7 +512,7 @@
 
     total_nread += (size_t)nread;
 
-    gso_size = msghdr_get_udp_gro(&msg);
+    gso_size = vquic_msghdr_get_udp_gro(&msg);
     if(gso_size == 0) {
       gso_size = (size_t)nread;
     }
diff --git a/Utilities/cmcurl/lib/curl_path.c b/Utilities/cmcurl/lib/vssh/curl_path.c
similarity index 99%
rename from Utilities/cmcurl/lib/curl_path.c
rename to Utilities/cmcurl/lib/vssh/curl_path.c
index 144f880..61452a4 100644
--- a/Utilities/cmcurl/lib/curl_path.c
+++ b/Utilities/cmcurl/lib/vssh/curl_path.c
@@ -26,9 +26,9 @@
 
 #if defined(USE_SSH)
 
+#include "curl_path.h"
 #include <curl/curl.h>
 #include "curl_memory.h"
-#include "curl_path.h"
 #include "escape.h"
 #include "memdebug.h"
 
diff --git a/Utilities/cmcurl/lib/curl_path.h b/Utilities/cmcurl/lib/vssh/curl_path.h
similarity index 83%
rename from Utilities/cmcurl/lib/curl_path.h
rename to Utilities/cmcurl/lib/vssh/curl_path.h
index 6fdb2fd..8e98417 100644
--- a/Utilities/cmcurl/lib/curl_path.h
+++ b/Utilities/cmcurl/lib/vssh/curl_path.h
@@ -28,19 +28,6 @@
 #include <curl/curl.h>
 #include "urldata.h"
 
-#ifdef _WIN32
-#  undef  PATH_MAX
-#  define PATH_MAX MAX_PATH
-#  ifndef R_OK
-#    define R_OK 4
-#  endif
-#endif
-
-#ifndef PATH_MAX
-#define PATH_MAX 1024 /* just an extra precaution since there are systems that
-                         have their definition hidden well */
-#endif
-
 CURLcode Curl_getworkingpath(struct Curl_easy *data,
                              char *homedir,
                              char **path);
diff --git a/Utilities/cmcurl/lib/vssh/libssh.c b/Utilities/cmcurl/lib/vssh/libssh.c
index 230fddc..6bae061 100644
--- a/Utilities/cmcurl/lib/vssh/libssh.c
+++ b/Utilities/cmcurl/lib/vssh/libssh.c
@@ -134,6 +134,7 @@
 static void sftp_quote_stat(struct Curl_easy *data);
 static int myssh_getsock(struct Curl_easy *data,
                          struct connectdata *conn, curl_socket_t *sock);
+static void myssh_block2waitfor(struct connectdata *conn, bool block);
 
 static CURLcode myssh_setup_connection(struct Curl_easy *data,
                                        struct connectdata *conn);
@@ -495,11 +496,11 @@
         goto cleanup;
       }
 
-      Curl_set_in_callback(data, true);
+      Curl_set_in_callback(data, TRUE);
       rc = func(data, knownkeyp, /* from the knownhosts file */
                 &foundkey, /* from the remote host */
                 keymatch, data->set.ssh_keyfunc_userp);
-      Curl_set_in_callback(data, false);
+      Curl_set_in_callback(data, FALSE);
 
       switch(rc) {
       case CURLKHSTAT_FINE_ADD_TO_FILE:
@@ -693,8 +694,12 @@
 
     case SSH_S_STARTUP:
       rc = ssh_connect(sshc->ssh_session);
-      if(rc == SSH_AGAIN)
+
+      myssh_block2waitfor(conn, (rc == SSH_AGAIN));
+      if(rc == SSH_AGAIN) {
+        DEBUGF(infof(data, "ssh_connect -> EAGAIN"));
         break;
+      }
 
       if(rc != SSH_OK) {
         failf(data, "Failure establishing ssh session");
@@ -1289,10 +1294,10 @@
       if(data->state.resume_from > 0) {
         /* Let's read off the proper amount of bytes from the input. */
         if(data->set.seek_func) {
-          Curl_set_in_callback(data, true);
+          Curl_set_in_callback(data, TRUE);
           seekerr = data->set.seek_func(data->set.seek_client,
                                         data->state.resume_from, SEEK_SET);
-          Curl_set_in_callback(data, false);
+          Curl_set_in_callback(data, FALSE);
         }
 
         if(seekerr != CURL_SEEKFUNC_OK) {
@@ -1363,7 +1368,9 @@
          state machine to move on as soon as possible so we set a very short
          timeout here */
       Curl_expire(data, 0, EXPIRE_RUN_NOW);
-
+#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
+      sshc->sftp_send_state = 0;
+#endif
       state(data, SSH_STOP);
       break;
     }
@@ -1767,6 +1774,13 @@
       /* during times we get here due to a broken transfer and then the
          sftp_handle might not have been taken down so make sure that is done
          before we proceed */
+      ssh_set_blocking(sshc->ssh_session, 0);
+#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
+      if(sshc->sftp_aio) {
+        sftp_aio_free(sshc->sftp_aio);
+        sshc->sftp_aio = NULL;
+      }
+#endif
 
       if(sshc->sftp_file) {
         sftp_close(sshc->sftp_file);
@@ -2047,6 +2061,7 @@
   if(!conn->waitfor)
     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
 
+  DEBUGF(infof(data, "ssh_getsock -> %x", bitmap));
   return bitmap;
 }
 
@@ -2060,13 +2075,12 @@
 
   if(block) {
     int dir = ssh_get_poll_flags(sshc->ssh_session);
-    if(dir & SSH_READ_PENDING) {
-      /* translate the libssh define bits into our own bit defines */
-      conn->waitfor = KEEP_RECV;
-    }
-    else if(dir & SSH_WRITE_PENDING) {
-      conn->waitfor = KEEP_SEND;
-    }
+    conn->waitfor = 0;
+    /* translate the libssh define bits into our own bit defines */
+    if(dir & SSH_READ_PENDING)
+      conn->waitfor |= KEEP_RECV;
+    if(dir & SSH_WRITE_PENDING)
+      conn->waitfor |= KEEP_SEND;
   }
 }
 
@@ -2080,7 +2094,7 @@
                     implementation */
   CURLcode result = myssh_statemach_act(data, &block);
 
-  *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
+  *done = (sshc->state == SSH_STOP);
   myssh_block2waitfor(conn, block);
 
   return result;
@@ -2141,7 +2155,7 @@
   data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
   if(!ssh)
     return CURLE_OUT_OF_MEMORY;
-  Curl_dyn_init(&sshc->readdir_buf, PATH_MAX * 2);
+  Curl_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2);
 
   return CURLE_OK;
 }
@@ -2186,7 +2200,14 @@
     return CURLE_FAILED_INIT;
   }
 
-  rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
+  if(conn->bits.ipv6_ip) {
+    char ipv6[MAX_IPADR_LEN];
+    msnprintf(ipv6, sizeof(ipv6), "[%s]", conn->host.name);
+    rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, ipv6);
+  }
+  else
+    rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
+
   if(rc != SSH_OK) {
     failf(data, "Could not set remote host");
     return CURLE_FAILED_INIT;
@@ -2312,7 +2333,7 @@
 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
 {
   CURLcode result;
-  bool connected = 0;
+  bool connected = FALSE;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 
@@ -2410,7 +2431,7 @@
   /* The following code is misleading, mostly added as wishful thinking
    * that libssh at some point will implement non-blocking ssh_scp_write/read.
    * Currently rc can only be number of bytes read or SSH_ERROR. */
-  myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE);
+  myssh_block2waitfor(conn, (rc == SSH_AGAIN));
 
   if(rc == SSH_AGAIN) {
     *err = CURLE_AGAIN;
@@ -2442,7 +2463,7 @@
    * that libssh at some point will implement non-blocking ssh_scp_write/read.
    * Currently rc can only be SSH_OK or SSH_ERROR. */
 
-  myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE);
+  myssh_block2waitfor(conn, (nread == SSH_AGAIN));
   if(nread == SSH_AGAIN) {
     *err = CURLE_AGAIN;
     nread = -1;
@@ -2558,7 +2579,39 @@
    */
   if(len > 32768)
     len = 32768;
-
+#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
+  switch(conn->proto.sshc.sftp_send_state) {
+    case 0:
+      sftp_file_set_nonblocking(conn->proto.sshc.sftp_file);
+      if(sftp_aio_begin_write(conn->proto.sshc.sftp_file, mem, len,
+                              &conn->proto.sshc.sftp_aio) == SSH_ERROR) {
+        *err = CURLE_SEND_ERROR;
+        return -1;
+      }
+      conn->proto.sshc.sftp_send_state = 1;
+      FALLTHROUGH();
+    case 1:
+      nwrite = sftp_aio_wait_write(&conn->proto.sshc.sftp_aio);
+      myssh_block2waitfor(conn, (nwrite == SSH_AGAIN) ? TRUE : FALSE);
+      if(nwrite == SSH_AGAIN) {
+        *err = CURLE_AGAIN;
+        return 0;
+      }
+      else if(nwrite < 0) {
+        *err = CURLE_SEND_ERROR;
+        return -1;
+      }
+      if(conn->proto.sshc.sftp_aio) {
+        sftp_aio_free(conn->proto.sshc.sftp_aio);
+        conn->proto.sshc.sftp_aio = NULL;
+      }
+      conn->proto.sshc.sftp_send_state = 0;
+      return nwrite;
+    default:
+      /* we never reach here */
+      return -1;
+  }
+#else
   nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
 
   myssh_block2waitfor(conn, FALSE);
@@ -2576,6 +2629,7 @@
   }
 
   return nwrite;
+#endif
 }
 
 /*
@@ -2609,7 +2663,7 @@
                               mem, (uint32_t)len,
                               (uint32_t)conn->proto.sshc.sftp_file_index);
 
-      myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
+      myssh_block2waitfor(conn, (nread == SSH_AGAIN));
 
       if(nread == SSH_AGAIN) {
         *err = CURLE_AGAIN;
diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c
index 83e356c..e19ffef 100644
--- a/Utilities/cmcurl/lib/vssh/libssh2.c
+++ b/Utilities/cmcurl/lib/vssh/libssh2.c
@@ -279,23 +279,27 @@
   return CURLE_SSH;
 }
 
+/* These functions are made to use the libcurl memory functions - NOT the
+   debugmem functions, as that leads us to trigger on libssh2 memory leaks
+   that are not ours to care for */
+
 static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc)
 {
   (void)abstract; /* arg not used */
-  return malloc(count);
+  return Curl_cmalloc(count);
 }
 
 static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc)
 {
   (void)abstract; /* arg not used */
-  return realloc(ptr, count);
+  return Curl_crealloc(ptr, count);
 }
 
 static LIBSSH2_FREE_FUNC(my_libssh2_free)
 {
   (void)abstract; /* arg not used */
   if(ptr) /* ssh2 agent sometimes call free with null ptr */
-    free(ptr);
+    Curl_cfree(ptr);
 }
 
 /*
@@ -385,7 +389,7 @@
 
 
 #ifdef HAVE_LIBSSH2_KNOWNHOST_API
-static int sshkeycallback(struct Curl_easy *easy,
+static int sshkeycallback(CURL *easy,
                           const struct curl_khkey *knownkey, /* known */
                           const struct curl_khkey *foundkey, /* found */
                           enum curl_khmatch match,
@@ -397,7 +401,7 @@
   (void)clientp;
 
   /* we only allow perfect matches, and we reject everything else */
-  return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE;
+  return (match != CURLKHMATCH_OK) ? CURLKHSTAT_REJECT : CURLKHSTAT_FINE;
 }
 #endif
 
@@ -534,8 +538,8 @@
 #ifdef HAVE_LIBSSH2_KNOWNHOST_CHECKP
         keycheck = libssh2_knownhost_checkp(sshc->kh,
                                             conn->host.name,
-                                            (conn->remote_port != PORT_SSH)?
-                                            conn->remote_port:-1,
+                                            (conn->remote_port != PORT_SSH) ?
+                                            conn->remote_port : -1,
                                             remotekey, keylen,
                                             LIBSSH2_KNOWNHOST_TYPE_PLAIN|
                                             LIBSSH2_KNOWNHOST_KEYENC_RAW|
@@ -552,8 +556,8 @@
 #endif
 
         infof(data, "SSH host check: %d, key: %s", keycheck,
-              (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
-              host->key:"<none>");
+              (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) ?
+              host->key : "<none>");
 
         /* setup 'knownkey' */
         if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
@@ -576,11 +580,11 @@
         keymatch = (enum curl_khmatch)keycheck;
 
         /* Ask the callback how to behave */
-        Curl_set_in_callback(data, true);
+        Curl_set_in_callback(data, TRUE);
         rc = func(data, knownkeyp, /* from the knownhosts file */
                   &foundkey, /* from the remote host */
                   keymatch, data->set.ssh_keyfunc_userp);
-        Curl_set_in_callback(data, false);
+        Curl_set_in_callback(data, FALSE);
       }
     }
     else
@@ -778,10 +782,10 @@
                                                       &keylen, &sshkeytype);
       if(remotekey) {
         enum curl_khtype keytype = convert_ssh2_keytype(sshkeytype);
-        Curl_set_in_callback(data, true);
+        Curl_set_in_callback(data, TRUE);
         rc = data->set.ssh_hostkeyfunc(data->set.ssh_hostkeyfunc_userp,
                                        (int)keytype, remotekey, keylen);
-        Curl_set_in_callback(data, false);
+        Curl_set_in_callback(data, FALSE);
         if(rc!= CURLKHMATCH_OK) {
           state(data, SSH_SESSION_FREE);
           sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
@@ -845,7 +849,7 @@
   const char *kh_name_end = NULL;
   size_t kh_name_size = 0;
   int port = 0;
-  bool found = false;
+  bool found = FALSE;
 
   if(sshc->kh && !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
     /* lets try to find our host in the known hosts file */
@@ -866,18 +870,18 @@
               kh_name_size = strlen(store->name) - 1 - strlen(kh_name_end);
               if(strncmp(store->name + 1,
                  conn->host.name, kh_name_size) == 0) {
-                found = true;
+                found = TRUE;
                 break;
               }
             }
           }
           else if(strcmp(store->name, conn->host.name) == 0) {
-            found = true;
+            found = TRUE;
             break;
           }
         }
         else {
-          found = true;
+          found = TRUE;
           break;
         }
       }
@@ -955,25 +959,744 @@
   return result;
 }
 
+static CURLcode sftp_quote(struct Curl_easy *data,
+                           struct ssh_conn *sshc,
+                           struct SSHPROTO *sshp)
+{
+  const char *cp;
+  CURLcode result = CURLE_OK;
+
+  /*
+   * Support some of the "FTP" commands
+   *
+   * 'sshc->quote_item' is already verified to be non-NULL before it
+   * switched to this state.
+   */
+  char *cmd = sshc->quote_item->data;
+  sshc->acceptfail = FALSE;
+
+  /* if a command starts with an asterisk, which a legal SFTP command never
+     can, the command will be allowed to fail without it causing any
+     aborts or cancels etc. It will cause libcurl to act as if the command
+     is successful, whatever the server responds. */
+
+  if(cmd[0] == '*') {
+    cmd++;
+    sshc->acceptfail = TRUE;
+  }
+
+  if(strcasecompare("pwd", cmd)) {
+    /* output debug output if that is requested */
+    char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+    Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4);
+    Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
+
+    /* this sends an FTP-like "header" to the header callback so that the
+       current directory can be read very similar to how it is read when
+       using ordinary FTP. */
+    result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+    free(tmp);
+    if(!result)
+      state(data, SSH_SFTP_NEXT_QUOTE);
+    return result;
+  }
+
+  /*
+   * the arguments following the command must be separated from the
+   * command with a space so we can check for it unconditionally
+   */
+  cp = strchr(cmd, ' ');
+  if(!cp) {
+    failf(data, "Syntax error command '%s', missing parameter", cmd);
+    return result;
+  }
+
+  /*
+   * also, every command takes at least one argument so we get that
+   * first argument right now
+   */
+  result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
+  if(result) {
+    if(result != CURLE_OUT_OF_MEMORY)
+      failf(data, "Syntax error: Bad first parameter to '%s'", cmd);
+    return result;
+  }
+
+  /*
+   * SFTP is a binary protocol, so we do not send text commands to the server.
+   * Instead, we scan for commands used by OpenSSH's sftp program and call the
+   * appropriate libssh2 functions.
+   */
+  if(strncasecompare(cmd, "chgrp ", 6) ||
+     strncasecompare(cmd, "chmod ", 6) ||
+     strncasecompare(cmd, "chown ", 6) ||
+     strncasecompare(cmd, "atime ", 6) ||
+     strncasecompare(cmd, "mtime ", 6)) {
+    /* attribute change */
+
+    /* sshc->quote_path1 contains the mode to set */
+    /* get the destination */
+    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+    if(result) {
+      if(result != CURLE_OUT_OF_MEMORY)
+        failf(data, "Syntax error in %s: Bad second parameter", cmd);
+      Curl_safefree(sshc->quote_path1);
+      return result;
+    }
+    memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+    state(data, SSH_SFTP_QUOTE_STAT);
+    return result;
+  }
+  if(strncasecompare(cmd, "ln ", 3) ||
+     strncasecompare(cmd, "symlink ", 8)) {
+    /* symbolic linking */
+    /* sshc->quote_path1 is the source */
+    /* get the destination */
+    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+    if(result) {
+      if(result != CURLE_OUT_OF_MEMORY)
+        failf(data, "Syntax error in ln/symlink: Bad second parameter");
+      Curl_safefree(sshc->quote_path1);
+      return result;
+    }
+    state(data, SSH_SFTP_QUOTE_SYMLINK);
+    return result;
+  }
+  else if(strncasecompare(cmd, "mkdir ", 6)) {
+    /* create dir */
+    state(data, SSH_SFTP_QUOTE_MKDIR);
+    return result;
+  }
+  else if(strncasecompare(cmd, "rename ", 7)) {
+    /* rename file */
+    /* first param is the source path */
+    /* second param is the dest. path */
+    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+    if(result) {
+      if(result != CURLE_OUT_OF_MEMORY)
+        failf(data, "Syntax error in rename: Bad second parameter");
+      Curl_safefree(sshc->quote_path1);
+      return result;
+    }
+    state(data, SSH_SFTP_QUOTE_RENAME);
+    return result;
+  }
+  else if(strncasecompare(cmd, "rmdir ", 6)) {
+    /* delete dir */
+    state(data, SSH_SFTP_QUOTE_RMDIR);
+    return result;
+  }
+  else if(strncasecompare(cmd, "rm ", 3)) {
+    state(data, SSH_SFTP_QUOTE_UNLINK);
+    return result;
+  }
+#ifdef HAS_STATVFS_SUPPORT
+  else if(strncasecompare(cmd, "statvfs ", 8)) {
+    state(data, SSH_SFTP_QUOTE_STATVFS);
+    return result;
+  }
+#endif
+
+  failf(data, "Unknown SFTP command");
+  Curl_safefree(sshc->quote_path1);
+  Curl_safefree(sshc->quote_path2);
+  return CURLE_QUOTE_ERROR;
+}
+
+static CURLcode
+sftp_upload_init(struct Curl_easy *data,
+                 struct ssh_conn *sshc,
+                 struct SSHPROTO *sshp,
+                 bool *blockp)
+{
+  unsigned long flags;
+
+  /*
+   * NOTE!!!  libssh2 requires that the destination path is a full path
+   *          that includes the destination file and name OR ends in a "/"
+   *          If this is not done the destination file will be named the
+   *          same name as the last directory in the path.
+   */
+
+  if(data->state.resume_from) {
+    LIBSSH2_SFTP_ATTRIBUTES attrs;
+    if(data->state.resume_from < 0) {
+      int rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
+                                    curlx_uztoui(strlen(sshp->path)),
+                                    LIBSSH2_SFTP_STAT, &attrs);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        *blockp = TRUE;
+        return CURLE_OK;
+      }
+      if(rc) {
+        data->state.resume_from = 0;
+      }
+      else {
+        curl_off_t size = attrs.filesize;
+        if(size < 0) {
+          failf(data, "Bad file size (%" FMT_OFF_T ")", size);
+          return CURLE_BAD_DOWNLOAD_RESUME;
+        }
+        data->state.resume_from = attrs.filesize;
+      }
+    }
+  }
+
+  if(data->set.remote_append)
+    /* Try to open for append, but create if nonexisting */
+    flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
+  else if(data->state.resume_from > 0)
+    /* If we have restart position then open for append */
+    flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
+  else
+    /* Clear file before writing (normal behavior) */
+    flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
+
+  sshc->sftp_handle =
+    libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
+                         curlx_uztoui(strlen(sshp->path)),
+                         flags, (long)data->set.new_file_perms,
+                         LIBSSH2_SFTP_OPENFILE);
+
+  if(!sshc->sftp_handle) {
+    unsigned long sftperr;
+    int rc = libssh2_session_last_errno(sshc->ssh_session);
+
+    if(LIBSSH2_ERROR_EAGAIN == rc) {
+      *blockp = TRUE;
+      return CURLE_OK;
+    }
+
+    if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
+      /* only when there was an SFTP protocol error can we extract
+         the sftp error! */
+      sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+    else
+      sftperr = LIBSSH2_FX_OK; /* not an sftp error at all */
+
+    if(sshc->secondCreateDirs) {
+      state(data, SSH_SFTP_CLOSE);
+      sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
+        sftp_libssh2_error_to_CURLE(sftperr) : CURLE_SSH;
+      failf(data, "Creating the dir/file failed: %s",
+            sftp_libssh2_strerror(sftperr));
+      return CURLE_OK;
+    }
+    if(((sftperr == LIBSSH2_FX_NO_SUCH_FILE) ||
+        (sftperr == LIBSSH2_FX_FAILURE) ||
+        (sftperr == LIBSSH2_FX_NO_SUCH_PATH)) &&
+       (data->set.ftp_create_missing_dirs &&
+        (strlen(sshp->path) > 1))) {
+      /* try to create the path remotely */
+      sshc->secondCreateDirs = 1;
+      state(data, SSH_SFTP_CREATE_DIRS_INIT);
+      return CURLE_OK;
+    }
+    state(data, SSH_SFTP_CLOSE);
+    sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
+      sftp_libssh2_error_to_CURLE(sftperr) : CURLE_SSH;
+    if(!sshc->actualcode) {
+      /* Sometimes, for some reason libssh2_sftp_last_error() returns zero
+         even though libssh2_sftp_open() failed previously! We need to
+         work around that! */
+      sshc->actualcode = CURLE_SSH;
+      sftperr = LIBSSH2_FX_OK;
+    }
+    failf(data, "Upload failed: %s (%lu/%d)",
+          sftperr != LIBSSH2_FX_OK ?
+          sftp_libssh2_strerror(sftperr) : "ssh error",
+          sftperr, rc);
+    return sshc->actualcode;
+  }
+
+  /* If we have a restart point then we need to seek to the correct
+     position. */
+  if(data->state.resume_from > 0) {
+    int seekerr = CURL_SEEKFUNC_OK;
+    /* Let's read off the proper amount of bytes from the input. */
+    if(data->set.seek_func) {
+      Curl_set_in_callback(data, TRUE);
+      seekerr = data->set.seek_func(data->set.seek_client,
+                                    data->state.resume_from, SEEK_SET);
+      Curl_set_in_callback(data, FALSE);
+    }
+
+    if(seekerr != CURL_SEEKFUNC_OK) {
+      curl_off_t passed = 0;
+
+      if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+        failf(data, "Could not seek stream");
+        return CURLE_FTP_COULDNT_USE_REST;
+      }
+      /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
+      do {
+        char scratch[4*1024];
+        size_t readthisamountnow =
+          (data->state.resume_from - passed >
+           (curl_off_t)sizeof(scratch)) ?
+          sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
+
+        size_t actuallyread;
+        Curl_set_in_callback(data, TRUE);
+        actuallyread = data->state.fread_func(scratch, 1,
+                                              readthisamountnow,
+                                              data->state.in);
+        Curl_set_in_callback(data, FALSE);
+
+        passed += actuallyread;
+        if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+          /* this checks for greater-than only to make sure that the
+             CURL_READFUNC_ABORT return code still aborts */
+          failf(data, "Failed to read data");
+          return CURLE_FTP_COULDNT_USE_REST;
+        }
+      } while(passed < data->state.resume_from);
+    }
+
+    /* now, decrease the size of the read */
+    if(data->state.infilesize > 0) {
+      data->state.infilesize -= data->state.resume_from;
+      data->req.size = data->state.infilesize;
+      Curl_pgrsSetUploadSize(data, data->state.infilesize);
+    }
+
+    SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+  }
+  if(data->state.infilesize > 0) {
+    data->req.size = data->state.infilesize;
+    Curl_pgrsSetUploadSize(data, data->state.infilesize);
+  }
+  /* upload data */
+  Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+
+  /* not set by Curl_xfer_setup to preserve keepon bits */
+  data->conn->sockfd = data->conn->writesockfd;
+
+  /* store this original bitmask setup to use later on if we cannot
+     figure out a "real" bitmask */
+  sshc->orig_waitfor = data->req.keepon;
+
+  /* we want to use the _sending_ function even when the socket turns
+     out readable as the underlying libssh2 sftp send function will deal
+     with both accordingly */
+  data->state.select_bits = CURL_CSELECT_OUT;
+
+  /* since we do not really wait for anything at this point, we want the
+     state machine to move on as soon as possible so we set a very short
+     timeout here */
+  Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+  state(data, SSH_STOP);
+  return CURLE_OK;
+}
+
+static CURLcode
+sftp_pkey_init(struct Curl_easy *data,
+               struct ssh_conn *sshc)
+{
+  /*
+   * Check the supported auth types in the order I feel is most secure
+   * with the requested type of authentication
+   */
+  sshc->authed = FALSE;
+
+  if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
+     (strstr(sshc->authlist, "publickey") != NULL)) {
+    bool out_of_memory = FALSE;
+
+    sshc->rsa_pub = sshc->rsa = NULL;
+
+    if(data->set.str[STRING_SSH_PRIVATE_KEY])
+      sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]);
+    else {
+      /* To ponder about: should really the lib be messing about with the
+         HOME environment variable etc? */
+      char *home = curl_getenv("HOME");
+      struct_stat sbuf;
+
+      /* If no private key file is specified, try some common paths. */
+      if(home) {
+        /* Try ~/.ssh first. */
+        sshc->rsa = aprintf("%s/.ssh/id_rsa", home);
+        if(!sshc->rsa)
+          out_of_memory = TRUE;
+        else if(stat(sshc->rsa, &sbuf)) {
+          Curl_safefree(sshc->rsa);
+          sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
+          if(!sshc->rsa)
+            out_of_memory = TRUE;
+          else if(stat(sshc->rsa, &sbuf)) {
+            Curl_safefree(sshc->rsa);
+          }
+        }
+        free(home);
+      }
+      if(!out_of_memory && !sshc->rsa) {
+        /* Nothing found; try the current dir. */
+        sshc->rsa = strdup("id_rsa");
+        if(sshc->rsa && stat(sshc->rsa, &sbuf)) {
+          Curl_safefree(sshc->rsa);
+          sshc->rsa = strdup("id_dsa");
+          if(sshc->rsa && stat(sshc->rsa, &sbuf)) {
+            Curl_safefree(sshc->rsa);
+            /* Out of guesses. Set to the empty string to avoid
+             * surprising info messages. */
+            sshc->rsa = strdup("");
+          }
+        }
+      }
+    }
+
+    /*
+     * Unless the user explicitly specifies a public key file, let
+     * libssh2 extract the public key from the private key file.
+     * This is done by simply passing sshc->rsa_pub = NULL.
+     */
+    if(data->set.str[STRING_SSH_PUBLIC_KEY]
+       /* treat empty string the same way as NULL */
+       && data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
+      sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
+      if(!sshc->rsa_pub)
+        out_of_memory = TRUE;
+    }
+
+    if(out_of_memory || !sshc->rsa) {
+      Curl_safefree(sshc->rsa);
+      Curl_safefree(sshc->rsa_pub);
+      state(data, SSH_SESSION_FREE);
+      sshc->actualcode = CURLE_OUT_OF_MEMORY;
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    sshc->passphrase = data->set.ssl.key_passwd;
+    if(!sshc->passphrase)
+      sshc->passphrase = "";
+
+    if(sshc->rsa_pub)
+      infof(data, "Using SSH public key file '%s'", sshc->rsa_pub);
+    infof(data, "Using SSH private key file '%s'", sshc->rsa);
+
+    state(data, SSH_AUTH_PKEY);
+  }
+  else {
+    state(data, SSH_AUTH_PASS_INIT);
+  }
+  return CURLE_OK;
+}
+
+static CURLcode
+sftp_quote_stat(struct Curl_easy *data,
+                struct ssh_conn *sshc,
+                struct SSHPROTO *sshp,
+                bool *blockp)
+{
+  char *cmd = sshc->quote_item->data;
+  sshc->acceptfail = FALSE;
+
+  /* if a command starts with an asterisk, which a legal SFTP command never
+     can, the command will be allowed to fail without it causing any aborts or
+     cancels etc. It will cause libcurl to act as if the command is
+     successful, whatever the server responds. */
+
+  if(cmd[0] == '*') {
+    cmd++;
+    sshc->acceptfail = TRUE;
+  }
+
+  if(!strncasecompare(cmd, "chmod", 5)) {
+    /* Since chown and chgrp only set owner OR group but libssh2 wants to set
+     * them both at once, we need to obtain the current ownership first. This
+     * takes an extra protocol round trip.
+     */
+    int rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
+                                  curlx_uztoui(strlen(sshc->quote_path2)),
+                                  LIBSSH2_SFTP_STAT,
+                                  &sshp->quote_attrs);
+    if(rc == LIBSSH2_ERROR_EAGAIN) {
+      *blockp = TRUE;
+      return CURLE_OK;
+    }
+    if(rc && !sshc->acceptfail) { /* get those attributes */
+      unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+      failf(data, "Attempt to get SFTP stats failed: %s",
+            sftp_libssh2_strerror(sftperr));
+      goto fail;
+    }
+  }
+
+  /* Now set the new attributes... */
+  if(strncasecompare(cmd, "chgrp", 5)) {
+    sshp->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
+    sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+    if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+       !sshc->acceptfail) {
+      failf(data, "Syntax error: chgrp gid not a number");
+      goto fail;
+    }
+  }
+  else if(strncasecompare(cmd, "chmod", 5)) {
+    sshp->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
+    sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
+    /* permissions are octal */
+    if(sshp->quote_attrs.permissions == 0 &&
+       !ISDIGIT(sshc->quote_path1[0])) {
+      failf(data, "Syntax error: chmod permissions not a number");
+      goto fail;
+    }
+  }
+  else if(strncasecompare(cmd, "chown", 5)) {
+    sshp->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
+    sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+    if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+       !sshc->acceptfail) {
+      failf(data, "Syntax error: chown uid not a number");
+      goto fail;
+    }
+  }
+  else if(strncasecompare(cmd, "atime", 5) ||
+          strncasecompare(cmd, "mtime", 5)) {
+    time_t date = Curl_getdate_capped(sshc->quote_path1);
+    bool fail = FALSE;
+
+    if(date == -1) {
+      failf(data, "incorrect date format for %.*s", 5, cmd);
+      fail = TRUE;
+    }
+#if SIZEOF_TIME_T > SIZEOF_LONG
+    if(date > 0xffffffff) {
+      /* if 'long' cannot old >32-bit, this date cannot be sent */
+      failf(data, "date overflow");
+      fail = TRUE;
+    }
+#endif
+    if(fail)
+      goto fail;
+    if(strncasecompare(cmd, "atime", 5))
+      sshp->quote_attrs.atime = (unsigned long)date;
+    else /* mtime */
+      sshp->quote_attrs.mtime = (unsigned long)date;
+
+    sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME;
+  }
+
+  /* Now send the completed structure... */
+  state(data, SSH_SFTP_QUOTE_SETSTAT);
+  return CURLE_OK;
+fail:
+  Curl_safefree(sshc->quote_path1);
+  Curl_safefree(sshc->quote_path2);
+  return CURLE_QUOTE_ERROR;
+}
+
+static CURLcode
+sftp_download_stat(struct Curl_easy *data,
+                   struct ssh_conn *sshc,
+                   struct SSHPROTO *sshp,
+                   bool *blockp)
+{
+  LIBSSH2_SFTP_ATTRIBUTES attrs;
+  int rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
+                                curlx_uztoui(strlen(sshp->path)),
+                                LIBSSH2_SFTP_STAT, &attrs);
+  if(rc == LIBSSH2_ERROR_EAGAIN) {
+    *blockp = TRUE;
+    return CURLE_OK;
+  }
+  if(rc ||
+     !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
+     (attrs.filesize == 0)) {
+    /*
+     * libssh2_sftp_open() did not return an error, so maybe the server
+     * just does not support stat()
+     * OR the server does not return a file size with a stat()
+     * OR file size is 0
+     */
+    data->req.size = -1;
+    data->req.maxdownload = -1;
+    Curl_pgrsSetDownloadSize(data, -1);
+  }
+  else {
+    curl_off_t size = attrs.filesize;
+
+    if(size < 0) {
+      failf(data, "Bad file size (%" FMT_OFF_T ")", size);
+      return CURLE_BAD_DOWNLOAD_RESUME;
+    }
+    if(data->state.use_range) {
+      curl_off_t from, to;
+      char *ptr;
+      char *ptr2;
+      CURLofft to_t;
+      CURLofft from_t;
+
+      from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
+      if(from_t == CURL_OFFT_FLOW)
+        return CURLE_RANGE_ERROR;
+      while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
+        ptr++;
+      to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
+      if(to_t == CURL_OFFT_FLOW)
+        return CURLE_RANGE_ERROR;
+      if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
+         || (to >= size)) {
+        to = size - 1;
+      }
+      if(from_t) {
+        /* from is relative to end of file */
+        from = size - to;
+        to = size - 1;
+      }
+      if(from > size) {
+        failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
+              FMT_OFF_T ")", from, (curl_off_t)attrs.filesize);
+        return CURLE_BAD_DOWNLOAD_RESUME;
+      }
+      if(from > to) {
+        from = to;
+        size = 0;
+      }
+      else {
+        if((to - from) == CURL_OFF_T_MAX)
+          return CURLE_RANGE_ERROR;
+        size = to - from + 1;
+      }
+
+      SFTP_SEEK(sshc->sftp_handle, from);
+    }
+    data->req.size = size;
+    data->req.maxdownload = size;
+    Curl_pgrsSetDownloadSize(data, size);
+  }
+
+  /* We can resume if we can seek to the resume position */
+  if(data->state.resume_from) {
+    if(data->state.resume_from < 0) {
+      /* We are supposed to download the last abs(from) bytes */
+      if((curl_off_t)attrs.filesize < -data->state.resume_from) {
+        failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
+              FMT_OFF_T ")",
+              data->state.resume_from, (curl_off_t)attrs.filesize);
+        return CURLE_BAD_DOWNLOAD_RESUME;
+      }
+      /* download from where? */
+      data->state.resume_from += attrs.filesize;
+    }
+    else {
+      if((curl_off_t)attrs.filesize < data->state.resume_from) {
+        failf(data, "Offset (%" FMT_OFF_T
+              ") was beyond file size (%" FMT_OFF_T ")",
+              data->state.resume_from, (curl_off_t)attrs.filesize);
+        return CURLE_BAD_DOWNLOAD_RESUME;
+      }
+    }
+    /* Now store the number of bytes we are expected to download */
+    data->req.size = attrs.filesize - data->state.resume_from;
+    data->req.maxdownload = attrs.filesize - data->state.resume_from;
+    Curl_pgrsSetDownloadSize(data,
+                             attrs.filesize - data->state.resume_from);
+    SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+  }
+
+  /* Setup the actual download */
+  if(data->req.size == 0) {
+    /* no data to transfer */
+    Curl_xfer_setup_nop(data);
+    infof(data, "File already completely downloaded");
+    state(data, SSH_STOP);
+    return CURLE_OK;
+  }
+  Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
+
+  /* not set by Curl_xfer_setup to preserve keepon bits */
+  data->conn->writesockfd = data->conn->sockfd;
+
+  /* we want to use the _receiving_ function even when the socket turns
+     out writableable as the underlying libssh2 recv function will deal
+     with both accordingly */
+  data->state.select_bits = CURL_CSELECT_IN;
+  state(data, SSH_STOP);
+
+  return CURLE_OK;
+}
+
+static CURLcode sftp_readdir(struct Curl_easy *data,
+                             struct ssh_conn *sshc,
+                             struct SSHPROTO *sshp,
+                             bool *blockp)
+{
+  CURLcode result = CURLE_OK;
+  int rc = libssh2_sftp_readdir_ex(sshc->sftp_handle,
+                                   sshp->readdir_filename, CURL_PATH_MAX,
+                                   sshp->readdir_longentry, CURL_PATH_MAX,
+                                   &sshp->readdir_attrs);
+  if(rc == LIBSSH2_ERROR_EAGAIN) {
+    *blockp = TRUE;
+    return result;
+  }
+  if(rc > 0) {
+    size_t readdir_len = (size_t) rc;
+    sshp->readdir_filename[readdir_len] = '\0';
+
+    if(data->set.list_only) {
+      result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                 sshp->readdir_filename,
+                                 readdir_len);
+      if(!result)
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                   (char *)"\n", 1);
+      if(result)
+        return result;
+    }
+    else {
+      result = Curl_dyn_add(&sshp->readdir, sshp->readdir_longentry);
+
+      if(!result) {
+        if((sshp->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+           ((sshp->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+            LIBSSH2_SFTP_S_IFLNK)) {
+          Curl_dyn_init(&sshp->readdir_link, CURL_PATH_MAX);
+          result = Curl_dyn_addf(&sshp->readdir_link, "%s%s", sshp->path,
+                                 sshp->readdir_filename);
+          state(data, SSH_SFTP_READDIR_LINK);
+        }
+        else {
+          state(data, SSH_SFTP_READDIR_BOTTOM);
+        }
+      }
+      return result;
+    }
+  }
+  else if(rc == 0) {
+    state(data, SSH_SFTP_READDIR_DONE);
+  }
+  else if(rc < 0) {
+    unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+    result = sftp_libssh2_error_to_CURLE(sftperr);
+    sshc->actualcode = result ? result : CURLE_SSH;
+    failf(data, "Could not open remote file for reading: %s :: %d",
+          sftp_libssh2_strerror(sftperr),
+          libssh2_session_last_errno(sshc->ssh_session));
+    state(data, SSH_SFTP_CLOSE);
+  }
+  return result;
+}
 /*
- * ssh_statemach_act() runs the SSH state machine as far as it can without
+ * ssh_statemachine() runs the SSH state machine as far as it can without
  * blocking and without reaching the end. The data the pointer 'block' points
  * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
  * meaning it wants to be called again when the socket is ready
  */
 
-static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
+static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block)
 {
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
   struct SSHPROTO *sshp = data->req.p.ssh;
   struct ssh_conn *sshc = &conn->proto.sshc;
-  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+
   int rc = LIBSSH2_ERROR_NONE;
-  int ssherr;
-  unsigned long sftperr;
-  int seekerr = CURL_SEEKFUNC_OK;
-  size_t readdir_len;
   *block = 0; /* we are not blocking by default */
 
   do {
@@ -998,7 +1721,7 @@
       FALLTHROUGH();
 
     case SSH_S_STARTUP:
-      rc = session_startup(sshc->ssh_session, sock);
+      rc = session_startup(sshc->ssh_session, conn->sock[FIRSTSOCKET]);
       if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
       }
@@ -1049,12 +1772,12 @@
           state(data, SSH_AUTH_DONE);
           break;
         }
-        ssherr = libssh2_session_last_errno(sshc->ssh_session);
-        if(ssherr == LIBSSH2_ERROR_EAGAIN)
+        rc = libssh2_session_last_errno(sshc->ssh_session);
+        if(rc == LIBSSH2_ERROR_EAGAIN)
           rc = LIBSSH2_ERROR_EAGAIN;
         else {
           state(data, SSH_SESSION_FREE);
-          sshc->actualcode = libssh2_session_error_to_CURLE(ssherr);
+          sshc->actualcode = libssh2_session_error_to_CURLE(rc);
         }
         break;
       }
@@ -1065,93 +1788,7 @@
       break;
 
     case SSH_AUTH_PKEY_INIT:
-      /*
-       * Check the supported auth types in the order I feel is most secure
-       * with the requested type of authentication
-       */
-      sshc->authed = FALSE;
-
-      if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
-         (strstr(sshc->authlist, "publickey") != NULL)) {
-        bool out_of_memory = FALSE;
-
-        sshc->rsa_pub = sshc->rsa = NULL;
-
-        if(data->set.str[STRING_SSH_PRIVATE_KEY])
-          sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]);
-        else {
-          /* To ponder about: should really the lib be messing about with the
-             HOME environment variable etc? */
-          char *home = curl_getenv("HOME");
-          struct_stat sbuf;
-
-          /* If no private key file is specified, try some common paths. */
-          if(home) {
-            /* Try ~/.ssh first. */
-            sshc->rsa = aprintf("%s/.ssh/id_rsa", home);
-            if(!sshc->rsa)
-              out_of_memory = TRUE;
-            else if(stat(sshc->rsa, &sbuf)) {
-              Curl_safefree(sshc->rsa);
-              sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
-              if(!sshc->rsa)
-                out_of_memory = TRUE;
-              else if(stat(sshc->rsa, &sbuf)) {
-                Curl_safefree(sshc->rsa);
-              }
-            }
-            free(home);
-          }
-          if(!out_of_memory && !sshc->rsa) {
-            /* Nothing found; try the current dir. */
-            sshc->rsa = strdup("id_rsa");
-            if(sshc->rsa && stat(sshc->rsa, &sbuf)) {
-              Curl_safefree(sshc->rsa);
-              sshc->rsa = strdup("id_dsa");
-              if(sshc->rsa && stat(sshc->rsa, &sbuf)) {
-                Curl_safefree(sshc->rsa);
-                /* Out of guesses. Set to the empty string to avoid
-                 * surprising info messages. */
-                sshc->rsa = strdup("");
-              }
-            }
-          }
-        }
-
-        /*
-         * Unless the user explicitly specifies a public key file, let
-         * libssh2 extract the public key from the private key file.
-         * This is done by simply passing sshc->rsa_pub = NULL.
-         */
-        if(data->set.str[STRING_SSH_PUBLIC_KEY]
-           /* treat empty string the same way as NULL */
-           && data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
-          sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
-          if(!sshc->rsa_pub)
-            out_of_memory = TRUE;
-        }
-
-        if(out_of_memory || !sshc->rsa) {
-          Curl_safefree(sshc->rsa);
-          Curl_safefree(sshc->rsa_pub);
-          state(data, SSH_SESSION_FREE);
-          sshc->actualcode = CURLE_OUT_OF_MEMORY;
-          break;
-        }
-
-        sshc->passphrase = data->set.ssl.key_passwd;
-        if(!sshc->passphrase)
-          sshc->passphrase = "";
-
-        if(sshc->rsa_pub)
-          infof(data, "Using SSH public key file '%s'", sshc->rsa_pub);
-        infof(data, "Using SSH private key file '%s'", sshc->rsa);
-
-        state(data, SSH_AUTH_PKEY);
-      }
-      else {
-        state(data, SSH_AUTH_PASS_INIT);
-      }
+      result = sftp_pkey_init(data, sshc);
       break;
 
     case SSH_AUTH_PKEY:
@@ -1374,7 +2011,7 @@
 
       Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
 
-      conn->sockfd = sock;
+      conn->sockfd = conn->sock[FIRSTSOCKET];
       conn->writesockfd = CURL_SOCKET_BAD;
 
       if(conn->handler->protocol == CURLPROTO_SFTP) {
@@ -1409,21 +2046,18 @@
       break;
 
     case SSH_SFTP_REALPATH:
-    {
-      char tempHome[PATH_MAX];
-
       /*
        * Get the "home" directory
        */
       rc = sftp_libssh2_realpath(sshc->sftp_session, ".",
-                                 tempHome, PATH_MAX-1);
+                                 sshp->readdir_filename, CURL_PATH_MAX);
       if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
       }
       if(rc > 0) {
         /* It seems that this string is not always NULL terminated */
-        tempHome[rc] = '\0';
-        sshc->homedir = strdup(tempHome);
+        sshp->readdir_filename[rc] = '\0';
+        sshc->homedir = strdup(sshp->readdir_filename);
         if(!sshc->homedir) {
           state(data, SSH_SFTP_CLOSE);
           sshc->actualcode = CURLE_OUT_OF_MEMORY;
@@ -1433,7 +2067,7 @@
       }
       else {
         /* Return the error type */
-        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         if(sftperr)
           result = sftp_libssh2_error_to_CURLE(sftperr);
         else
@@ -1446,7 +2080,7 @@
         state(data, SSH_STOP);
         break;
       }
-    }
+
     /* This is the last step in the SFTP connect phase. Do note that while
        we get the homedir here, we get the "workingpath" in the DO action
        since the homedir will remain the same between request but the
@@ -1486,187 +2120,14 @@
       break;
 
     case SSH_SFTP_QUOTE:
-      /* Send any quote commands */
-    {
-      const char *cp;
-
-      /*
-       * Support some of the "FTP" commands
-       *
-       * 'sshc->quote_item' is already verified to be non-NULL before it
-       * switched to this state.
-       */
-      char *cmd = sshc->quote_item->data;
-      sshc->acceptfail = FALSE;
-
-      /* if a command starts with an asterisk, which a legal SFTP command never
-         can, the command will be allowed to fail without it causing any
-         aborts or cancels etc. It will cause libcurl to act as if the command
-         is successful, whatever the server responds. */
-
-      if(cmd[0] == '*') {
-        cmd++;
-        sshc->acceptfail = TRUE;
-      }
-
-      if(strcasecompare("pwd", cmd)) {
-        /* output debug output if that is requested */
-        char *tmp = aprintf("257 \"%s\" is current directory.\n",
-                            sshp->path);
-        if(!tmp) {
-          result = CURLE_OUT_OF_MEMORY;
-          state(data, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          break;
-        }
-        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4);
-        Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
-
-        /* this sends an FTP-like "header" to the header callback so that the
-           current directory can be read very similar to how it is read when
-           using ordinary FTP. */
-        result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
-        free(tmp);
-        if(result) {
-          state(data, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          sshc->actualcode = result;
-        }
-        else
-          state(data, SSH_SFTP_NEXT_QUOTE);
-        break;
-      }
-
-      /*
-       * the arguments following the command must be separated from the
-       * command with a space so we can check for it unconditionally
-       */
-      cp = strchr(cmd, ' ');
-      if(!cp) {
-        failf(data, "Syntax error command '%s', missing parameter",
-              cmd);
-        state(data, SSH_SFTP_CLOSE);
-        sshc->nextstate = SSH_NO_STATE;
-        sshc->actualcode = CURLE_QUOTE_ERROR;
-        break;
-      }
-
-      /*
-       * also, every command takes at least one argument so we get that
-       * first argument right now
-       */
-      result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
+      /* Send quote commands */
+      result = sftp_quote(data, sshc, sshp);
       if(result) {
-        if(result == CURLE_OUT_OF_MEMORY)
-          failf(data, "Out of memory");
-        else
-          failf(data, "Syntax error: Bad first parameter to '%s'", cmd);
         state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = result;
-        break;
       }
-
-      /*
-       * SFTP is a binary protocol, so we do not send text commands
-       * to the server. Instead, we scan for commands used by
-       * OpenSSH's sftp program and call the appropriate libssh2
-       * functions.
-       */
-      if(strncasecompare(cmd, "chgrp ", 6) ||
-         strncasecompare(cmd, "chmod ", 6) ||
-         strncasecompare(cmd, "chown ", 6) ||
-         strncasecompare(cmd, "atime ", 6) ||
-         strncasecompare(cmd, "mtime ", 6)) {
-        /* attribute change */
-
-        /* sshc->quote_path1 contains the mode to set */
-        /* get the destination */
-        result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
-        if(result) {
-          if(result == CURLE_OUT_OF_MEMORY)
-            failf(data, "Out of memory");
-          else
-            failf(data, "Syntax error in %s: Bad second parameter", cmd);
-          Curl_safefree(sshc->quote_path1);
-          state(data, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          sshc->actualcode = result;
-          break;
-        }
-        memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
-        state(data, SSH_SFTP_QUOTE_STAT);
-        break;
-      }
-      if(strncasecompare(cmd, "ln ", 3) ||
-         strncasecompare(cmd, "symlink ", 8)) {
-        /* symbolic linking */
-        /* sshc->quote_path1 is the source */
-        /* get the destination */
-        result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
-        if(result) {
-          if(result == CURLE_OUT_OF_MEMORY)
-            failf(data, "Out of memory");
-          else
-            failf(data,
-                  "Syntax error in ln/symlink: Bad second parameter");
-          Curl_safefree(sshc->quote_path1);
-          state(data, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          sshc->actualcode = result;
-          break;
-        }
-        state(data, SSH_SFTP_QUOTE_SYMLINK);
-        break;
-      }
-      else if(strncasecompare(cmd, "mkdir ", 6)) {
-        /* create dir */
-        state(data, SSH_SFTP_QUOTE_MKDIR);
-        break;
-      }
-      else if(strncasecompare(cmd, "rename ", 7)) {
-        /* rename file */
-        /* first param is the source path */
-        /* second param is the dest. path */
-        result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
-        if(result) {
-          if(result == CURLE_OUT_OF_MEMORY)
-            failf(data, "Out of memory");
-          else
-            failf(data, "Syntax error in rename: Bad second parameter");
-          Curl_safefree(sshc->quote_path1);
-          state(data, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          sshc->actualcode = result;
-          break;
-        }
-        state(data, SSH_SFTP_QUOTE_RENAME);
-        break;
-      }
-      else if(strncasecompare(cmd, "rmdir ", 6)) {
-        /* delete dir */
-        state(data, SSH_SFTP_QUOTE_RMDIR);
-        break;
-      }
-      else if(strncasecompare(cmd, "rm ", 3)) {
-        state(data, SSH_SFTP_QUOTE_UNLINK);
-        break;
-      }
-#ifdef HAS_STATVFS_SUPPORT
-      else if(strncasecompare(cmd, "statvfs ", 8)) {
-        state(data, SSH_SFTP_QUOTE_STATVFS);
-        break;
-      }
-#endif
-
-      failf(data, "Unknown SFTP command");
-      Curl_safefree(sshc->quote_path1);
-      Curl_safefree(sshc->quote_path2);
-      state(data, SSH_SFTP_CLOSE);
-      sshc->nextstate = SSH_NO_STATE;
-      sshc->actualcode = CURLE_QUOTE_ERROR;
       break;
-    }
 
     case SSH_SFTP_NEXT_QUOTE:
       Curl_safefree(sshc->quote_path1);
@@ -1689,125 +2150,13 @@
       break;
 
     case SSH_SFTP_QUOTE_STAT:
-    {
-      char *cmd = sshc->quote_item->data;
-      sshc->acceptfail = FALSE;
-
-      /* if a command starts with an asterisk, which a legal SFTP command never
-         can, the command will be allowed to fail without it causing any
-         aborts or cancels etc. It will cause libcurl to act as if the command
-         is successful, whatever the server responds. */
-
-      if(cmd[0] == '*') {
-        cmd++;
-        sshc->acceptfail = TRUE;
+      result = sftp_quote_stat(data, sshc, sshp, block);
+      if(result) {
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = result;
       }
-
-      if(!strncasecompare(cmd, "chmod", 5)) {
-        /* Since chown and chgrp only set owner OR group but libssh2 wants to
-         * set them both at once, we need to obtain the current ownership
-         * first. This takes an extra protocol round trip.
-         */
-        rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
-                                  curlx_uztoui(strlen(sshc->quote_path2)),
-                                  LIBSSH2_SFTP_STAT,
-                                  &sshp->quote_attrs);
-        if(rc == LIBSSH2_ERROR_EAGAIN) {
-          break;
-        }
-        if(rc && !sshc->acceptfail) { /* get those attributes */
-          sftperr = libssh2_sftp_last_error(sshc->sftp_session);
-          Curl_safefree(sshc->quote_path1);
-          Curl_safefree(sshc->quote_path2);
-          failf(data, "Attempt to get SFTP stats failed: %s",
-                sftp_libssh2_strerror(sftperr));
-          state(data, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          sshc->actualcode = CURLE_QUOTE_ERROR;
-          break;
-        }
-      }
-
-      /* Now set the new attributes... */
-      if(strncasecompare(cmd, "chgrp", 5)) {
-        sshp->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
-        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
-        if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
-           !sshc->acceptfail) {
-          Curl_safefree(sshc->quote_path1);
-          Curl_safefree(sshc->quote_path2);
-          failf(data, "Syntax error: chgrp gid not a number");
-          state(data, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          sshc->actualcode = CURLE_QUOTE_ERROR;
-          break;
-        }
-      }
-      else if(strncasecompare(cmd, "chmod", 5)) {
-        sshp->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
-        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
-        /* permissions are octal */
-        if(sshp->quote_attrs.permissions == 0 &&
-           !ISDIGIT(sshc->quote_path1[0])) {
-          Curl_safefree(sshc->quote_path1);
-          Curl_safefree(sshc->quote_path2);
-          failf(data, "Syntax error: chmod permissions not a number");
-          state(data, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          sshc->actualcode = CURLE_QUOTE_ERROR;
-          break;
-        }
-      }
-      else if(strncasecompare(cmd, "chown", 5)) {
-        sshp->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
-        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
-        if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
-           !sshc->acceptfail) {
-          Curl_safefree(sshc->quote_path1);
-          Curl_safefree(sshc->quote_path2);
-          failf(data, "Syntax error: chown uid not a number");
-          state(data, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          sshc->actualcode = CURLE_QUOTE_ERROR;
-          break;
-        }
-      }
-      else if(strncasecompare(cmd, "atime", 5) ||
-              strncasecompare(cmd, "mtime", 5)) {
-        time_t date = Curl_getdate_capped(sshc->quote_path1);
-        bool fail = FALSE;
-
-        if(date == -1) {
-          failf(data, "incorrect date format for %.*s", 5, cmd);
-          fail = TRUE;
-        }
-#if SIZEOF_TIME_T > SIZEOF_LONG
-        if(date > 0xffffffff) {
-          /* if 'long' cannot old >32-bit, this date cannot be sent */
-          failf(data, "date overflow");
-          fail = TRUE;
-        }
-#endif
-        if(fail) {
-          Curl_safefree(sshc->quote_path1);
-          Curl_safefree(sshc->quote_path2);
-          state(data, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          sshc->actualcode = CURLE_QUOTE_ERROR;
-          break;
-        }
-        if(strncasecompare(cmd, "atime", 5))
-          sshp->quote_attrs.atime = (unsigned long)date;
-        else /* mtime */
-          sshp->quote_attrs.mtime = (unsigned long)date;
-
-        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME;
-      }
-
-      /* Now send the completed structure... */
-      state(data, SSH_SFTP_QUOTE_SETSTAT);
       break;
-    }
 
     case SSH_SFTP_QUOTE_SETSTAT:
       rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
@@ -1818,7 +2167,7 @@
         break;
       }
       if(rc && !sshc->acceptfail) {
-        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         Curl_safefree(sshc->quote_path2);
         failf(data, "Attempt to set SFTP stats failed: %s",
@@ -1841,7 +2190,7 @@
         break;
       }
       if(rc && !sshc->acceptfail) {
-        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         Curl_safefree(sshc->quote_path2);
         failf(data, "symlink command failed: %s",
@@ -1862,7 +2211,7 @@
         break;
       }
       if(rc && !sshc->acceptfail) {
-        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         failf(data, "mkdir command failed: %s",
               sftp_libssh2_strerror(sftperr));
@@ -1887,7 +2236,7 @@
         break;
       }
       if(rc && !sshc->acceptfail) {
-        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         Curl_safefree(sshc->quote_path2);
         failf(data, "rename command failed: %s",
@@ -1907,7 +2256,7 @@
         break;
       }
       if(rc && !sshc->acceptfail) {
-        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         failf(data, "rmdir command failed: %s",
               sftp_libssh2_strerror(sftperr));
@@ -1926,7 +2275,7 @@
         break;
       }
       if(rc && !sshc->acceptfail) {
-        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         failf(data, "rm command failed: %s", sftp_libssh2_strerror(sftperr));
         state(data, SSH_SFTP_CLOSE);
@@ -1949,7 +2298,7 @@
         break;
       }
       if(rc && !sshc->acceptfail) {
-        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         failf(data, "statvfs command failed: %s",
               sftp_libssh2_strerror(sftperr));
@@ -1959,11 +2308,11 @@
         break;
       }
       else if(rc == 0) {
-        #ifdef _MSC_VER
-        #define CURL_LIBSSH2_VFS_SIZE_MASK "I64u"
-        #else
-        #define CURL_LIBSSH2_VFS_SIZE_MASK "llu"
-        #endif
+#ifdef _MSC_VER
+#define CURL_LIBSSH2_VFS_SIZE_MASK "I64u"
+#else
+#define CURL_LIBSSH2_VFS_SIZE_MASK "llu"
+#endif
         char *tmp = aprintf("statvfs:\n"
                             "f_bsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
                             "f_frsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
@@ -2042,188 +2391,13 @@
       break;
 
     case SSH_SFTP_UPLOAD_INIT:
-    {
-      unsigned long flags;
-      /*
-       * NOTE!!!  libssh2 requires that the destination path is a full path
-       *          that includes the destination file and name OR ends in a "/"
-       *          If this is not done the destination file will be named the
-       *          same name as the last directory in the path.
-       */
-
-      if(data->state.resume_from) {
-        LIBSSH2_SFTP_ATTRIBUTES attrs;
-        if(data->state.resume_from < 0) {
-          rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
-                                    curlx_uztoui(strlen(sshp->path)),
-                                    LIBSSH2_SFTP_STAT, &attrs);
-          if(rc == LIBSSH2_ERROR_EAGAIN) {
-            break;
-          }
-          if(rc) {
-            data->state.resume_from = 0;
-          }
-          else {
-            curl_off_t size = attrs.filesize;
-            if(size < 0) {
-              failf(data, "Bad file size (%" FMT_OFF_T ")", size);
-              return CURLE_BAD_DOWNLOAD_RESUME;
-            }
-            data->state.resume_from = attrs.filesize;
-          }
-        }
-      }
-
-      if(data->set.remote_append)
-        /* Try to open for append, but create if nonexisting */
-        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
-      else if(data->state.resume_from > 0)
-        /* If we have restart position then open for append */
-        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
-      else
-        /* Clear file before writing (normal behavior) */
-        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
-
-      sshc->sftp_handle =
-        libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
-                             curlx_uztoui(strlen(sshp->path)),
-                             flags, (long)data->set.new_file_perms,
-                             LIBSSH2_SFTP_OPENFILE);
-
-      if(!sshc->sftp_handle) {
-        rc = libssh2_session_last_errno(sshc->ssh_session);
-
-        if(LIBSSH2_ERROR_EAGAIN == rc)
-          break;
-
-        if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
-          /* only when there was an SFTP protocol error can we extract
-             the sftp error! */
-          sftperr = libssh2_sftp_last_error(sshc->sftp_session);
-        else
-          sftperr = LIBSSH2_FX_OK; /* not an sftp error at all */
-
-        if(sshc->secondCreateDirs) {
-          state(data, SSH_SFTP_CLOSE);
-          sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
-            sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH;
-          failf(data, "Creating the dir/file failed: %s",
-                sftp_libssh2_strerror(sftperr));
-          break;
-        }
-        if(((sftperr == LIBSSH2_FX_NO_SUCH_FILE) ||
-            (sftperr == LIBSSH2_FX_FAILURE) ||
-            (sftperr == LIBSSH2_FX_NO_SUCH_PATH)) &&
-           (data->set.ftp_create_missing_dirs &&
-            (strlen(sshp->path) > 1))) {
-          /* try to create the path remotely */
-          rc = 0; /* clear rc and continue */
-          sshc->secondCreateDirs = 1;
-          state(data, SSH_SFTP_CREATE_DIRS_INIT);
-          break;
-        }
-        state(data, SSH_SFTP_CLOSE);
-        sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
-          sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH;
-        if(!sshc->actualcode) {
-          /* Sometimes, for some reason libssh2_sftp_last_error() returns zero
-             even though libssh2_sftp_open() failed previously! We need to
-             work around that! */
-          sshc->actualcode = CURLE_SSH;
-          sftperr = LIBSSH2_FX_OK;
-        }
-        failf(data, "Upload failed: %s (%lu/%d)",
-              sftperr != LIBSSH2_FX_OK ?
-              sftp_libssh2_strerror(sftperr):"ssh error",
-              sftperr, rc);
-        break;
-      }
-
-      /* If we have a restart point then we need to seek to the correct
-         position. */
-      if(data->state.resume_from > 0) {
-        /* Let's read off the proper amount of bytes from the input. */
-        if(data->set.seek_func) {
-          Curl_set_in_callback(data, true);
-          seekerr = data->set.seek_func(data->set.seek_client,
-                                        data->state.resume_from, SEEK_SET);
-          Curl_set_in_callback(data, false);
-        }
-
-        if(seekerr != CURL_SEEKFUNC_OK) {
-          curl_off_t passed = 0;
-
-          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
-            failf(data, "Could not seek stream");
-            return CURLE_FTP_COULDNT_USE_REST;
-          }
-          /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
-          do {
-            char scratch[4*1024];
-            size_t readthisamountnow =
-              (data->state.resume_from - passed >
-                (curl_off_t)sizeof(scratch)) ?
-              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
-
-            size_t actuallyread;
-            Curl_set_in_callback(data, true);
-            actuallyread = data->state.fread_func(scratch, 1,
-                                                  readthisamountnow,
-                                                  data->state.in);
-            Curl_set_in_callback(data, false);
-
-            passed += actuallyread;
-            if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
-              /* this checks for greater-than only to make sure that the
-                 CURL_READFUNC_ABORT return code still aborts */
-              failf(data, "Failed to read data");
-              return CURLE_FTP_COULDNT_USE_REST;
-            }
-          } while(passed < data->state.resume_from);
-        }
-
-        /* now, decrease the size of the read */
-        if(data->state.infilesize > 0) {
-          data->state.infilesize -= data->state.resume_from;
-          data->req.size = data->state.infilesize;
-          Curl_pgrsSetUploadSize(data, data->state.infilesize);
-        }
-
-        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
-      }
-      if(data->state.infilesize > 0) {
-        data->req.size = data->state.infilesize;
-        Curl_pgrsSetUploadSize(data, data->state.infilesize);
-      }
-      /* upload data */
-      Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
-
-      /* not set by Curl_xfer_setup to preserve keepon bits */
-      conn->sockfd = conn->writesockfd;
-
+      result = sftp_upload_init(data, sshc, sshp, block);
       if(result) {
         state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = result;
       }
-      else {
-        /* store this original bitmask setup to use later on if we cannot
-           figure out a "real" bitmask */
-        sshc->orig_waitfor = data->req.keepon;
-
-        /* we want to use the _sending_ function even when the socket turns
-           out readable as the underlying libssh2 sftp send function will deal
-           with both accordingly */
-        data->state.select_bits = CURL_CSELECT_OUT;
-
-        /* since we do not really wait for anything at this point, we want the
-           state machine to move on as soon as possible so we set a very short
-           timeout here */
-        Curl_expire(data, 0, EXPIRE_RUN_NOW);
-
-        state(data, SSH_STOP);
-      }
       break;
-    }
 
     case SSH_SFTP_CREATE_DIRS_INIT:
       if(strlen(sshp->path) > 1) {
@@ -2263,13 +2437,13 @@
          * permission was denied (creation might succeed further down the
          * path) - retry on unspecific FAILURE also
          */
-        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+        unsigned long sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         if((sftperr != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
            (sftperr != LIBSSH2_FX_FAILURE) &&
            (sftperr != LIBSSH2_FX_PERMISSION_DENIED)) {
           result = sftp_libssh2_error_to_CURLE(sftperr);
           state(data, SSH_SFTP_CLOSE);
-          sshc->actualcode = result?result:CURLE_SSH;
+          sshc->actualcode = result ? result : CURLE_SSH;
           break;
         }
         rc = 0; /* clear rc and continue */
@@ -2288,12 +2462,12 @@
        * This is a directory that we are trying to get, so produce a directory
        * listing
        */
-      sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session,
-                                               sshp->path,
-                                               curlx_uztoui(
-                                                 strlen(sshp->path)),
-                                               0, 0, LIBSSH2_SFTP_OPENDIR);
+      sshc->sftp_handle =
+        libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
+                             curlx_uztoui(strlen(sshp->path)),
+                             0, 0, LIBSSH2_SFTP_OPENDIR);
       if(!sshc->sftp_handle) {
+        unsigned long sftperr;
         if(libssh2_session_last_errno(sshc->ssh_session) ==
            LIBSSH2_ERROR_EAGAIN) {
           rc = LIBSSH2_ERROR_EAGAIN;
@@ -2304,94 +2478,18 @@
               sftp_libssh2_strerror(sftperr));
         state(data, SSH_SFTP_CLOSE);
         result = sftp_libssh2_error_to_CURLE(sftperr);
-        sshc->actualcode = result?result:CURLE_SSH;
+        sshc->actualcode = result ? result : CURLE_SSH;
         break;
       }
-      sshp->readdir_filename = malloc(PATH_MAX + 1);
-      if(!sshp->readdir_filename) {
-        state(data, SSH_SFTP_CLOSE);
-        sshc->actualcode = CURLE_OUT_OF_MEMORY;
-        break;
-      }
-      sshp->readdir_longentry = malloc(PATH_MAX + 1);
-      if(!sshp->readdir_longentry) {
-        Curl_safefree(sshp->readdir_filename);
-        state(data, SSH_SFTP_CLOSE);
-        sshc->actualcode = CURLE_OUT_OF_MEMORY;
-        break;
-      }
-      Curl_dyn_init(&sshp->readdir, PATH_MAX * 2);
+      Curl_dyn_init(&sshp->readdir, CURL_PATH_MAX * 2);
       state(data, SSH_SFTP_READDIR);
       break;
 
     case SSH_SFTP_READDIR:
-      rc = libssh2_sftp_readdir_ex(sshc->sftp_handle,
-                                   sshp->readdir_filename,
-                                   PATH_MAX,
-                                   sshp->readdir_longentry,
-                                   PATH_MAX,
-                                   &sshp->readdir_attrs);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
-      }
-      if(rc > 0) {
-        readdir_len = (size_t) rc;
-        sshp->readdir_filename[readdir_len] = '\0';
-
-        if(data->set.list_only) {
-          result = Curl_client_write(data, CLIENTWRITE_BODY,
-                                     sshp->readdir_filename,
-                                     readdir_len);
-          if(!result)
-            result = Curl_client_write(data, CLIENTWRITE_BODY,
-                                       (char *)"\n", 1);
-          if(result) {
-            state(data, SSH_STOP);
-            break;
-          }
-
-        }
-        else {
-          result = Curl_dyn_add(&sshp->readdir, sshp->readdir_longentry);
-
-          if(!result) {
-            if((sshp->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
-               ((sshp->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
-                LIBSSH2_SFTP_S_IFLNK)) {
-              Curl_dyn_init(&sshp->readdir_link, PATH_MAX);
-              result = Curl_dyn_addf(&sshp->readdir_link, "%s%s", sshp->path,
-                                     sshp->readdir_filename);
-              state(data, SSH_SFTP_READDIR_LINK);
-              if(!result)
-                break;
-            }
-            else {
-              state(data, SSH_SFTP_READDIR_BOTTOM);
-              break;
-            }
-          }
-          sshc->actualcode = result;
-          state(data, SSH_SFTP_CLOSE);
-          break;
-        }
-      }
-      else if(rc == 0) {
-        Curl_safefree(sshp->readdir_filename);
-        Curl_safefree(sshp->readdir_longentry);
-        state(data, SSH_SFTP_READDIR_DONE);
-        break;
-      }
-      else if(rc < 0) {
-        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
-        result = sftp_libssh2_error_to_CURLE(sftperr);
-        sshc->actualcode = result?result:CURLE_SSH;
-        failf(data, "Could not open remote file for reading: %s :: %d",
-              sftp_libssh2_strerror(sftperr),
-              libssh2_session_last_errno(sshc->ssh_session));
-        Curl_safefree(sshp->readdir_filename);
-        Curl_safefree(sshp->readdir_longentry);
+      result = sftp_readdir(data, sshc, sshp, block);
+      if(result) {
+        sshc->actualcode = result;
         state(data, SSH_SFTP_CLOSE);
-        break;
       }
       break;
 
@@ -2402,7 +2500,7 @@
                                 (unsigned int)
                                   Curl_dyn_len(&sshp->readdir_link),
                                 sshp->readdir_filename,
-                                PATH_MAX, LIBSSH2_SFTP_READLINK);
+                                CURL_PATH_MAX, LIBSSH2_SFTP_READLINK);
       if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
       }
@@ -2412,8 +2510,6 @@
       result = Curl_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename);
 
       if(result) {
-        Curl_safefree(sshp->readdir_filename);
-        Curl_safefree(sshp->readdir_longentry);
         state(data, SSH_SFTP_CLOSE);
         sshc->actualcode = result;
         break;
@@ -2446,8 +2542,6 @@
         break;
       }
       sshc->sftp_handle = NULL;
-      Curl_safefree(sshp->readdir_filename);
-      Curl_safefree(sshp->readdir_longentry);
 
       /* no data to transfer */
       Curl_xfer_setup_nop(data);
@@ -2464,6 +2558,7 @@
                              LIBSSH2_FXF_READ, (long)data->set.new_file_perms,
                              LIBSSH2_SFTP_OPENFILE);
       if(!sshc->sftp_handle) {
+        unsigned long sftperr;
         if(libssh2_session_last_errno(sshc->ssh_session) ==
            LIBSSH2_ERROR_EAGAIN) {
           rc = LIBSSH2_ERROR_EAGAIN;
@@ -2474,146 +2569,20 @@
               sftp_libssh2_strerror(sftperr));
         state(data, SSH_SFTP_CLOSE);
         result = sftp_libssh2_error_to_CURLE(sftperr);
-        sshc->actualcode = result?result:CURLE_SSH;
+        sshc->actualcode = result ? result : CURLE_SSH;
         break;
       }
       state(data, SSH_SFTP_DOWNLOAD_STAT);
       break;
 
     case SSH_SFTP_DOWNLOAD_STAT:
-    {
-      LIBSSH2_SFTP_ATTRIBUTES attrs;
-
-      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
-                                curlx_uztoui(strlen(sshp->path)),
-                                LIBSSH2_SFTP_STAT, &attrs);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
+      result = sftp_download_stat(data, sshc, sshp, block);
+      if(result) {
+        state(data, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = result;
       }
-      if(rc ||
-         !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
-         (attrs.filesize == 0)) {
-        /*
-         * libssh2_sftp_open() did not return an error, so maybe the server
-         * just does not support stat()
-         * OR the server does not return a file size with a stat()
-         * OR file size is 0
-         */
-        data->req.size = -1;
-        data->req.maxdownload = -1;
-        Curl_pgrsSetDownloadSize(data, -1);
-      }
-      else {
-        curl_off_t size = attrs.filesize;
-
-        if(size < 0) {
-          failf(data, "Bad file size (%" FMT_OFF_T ")", size);
-          return CURLE_BAD_DOWNLOAD_RESUME;
-        }
-        if(data->state.use_range) {
-          curl_off_t from, to;
-          char *ptr;
-          char *ptr2;
-          CURLofft to_t;
-          CURLofft from_t;
-
-          from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
-          if(from_t == CURL_OFFT_FLOW)
-            return CURLE_RANGE_ERROR;
-          while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
-            ptr++;
-          to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
-          if(to_t == CURL_OFFT_FLOW)
-            return CURLE_RANGE_ERROR;
-          if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
-             || (to >= size)) {
-            to = size - 1;
-          }
-          if(from_t) {
-            /* from is relative to end of file */
-            from = size - to;
-            to = size - 1;
-          }
-          if(from > size) {
-            failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
-                  FMT_OFF_T ")", from, (curl_off_t)attrs.filesize);
-            return CURLE_BAD_DOWNLOAD_RESUME;
-          }
-          if(from > to) {
-            from = to;
-            size = 0;
-          }
-          else {
-            if((to - from) == CURL_OFF_T_MAX)
-              return CURLE_RANGE_ERROR;
-            size = to - from + 1;
-          }
-
-          SFTP_SEEK(sshc->sftp_handle, from);
-        }
-        data->req.size = size;
-        data->req.maxdownload = size;
-        Curl_pgrsSetDownloadSize(data, size);
-      }
-
-      /* We can resume if we can seek to the resume position */
-      if(data->state.resume_from) {
-        if(data->state.resume_from < 0) {
-          /* We are supposed to download the last abs(from) bytes */
-          if((curl_off_t)attrs.filesize < -data->state.resume_from) {
-            failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
-                  FMT_OFF_T ")",
-                  data->state.resume_from, (curl_off_t)attrs.filesize);
-            return CURLE_BAD_DOWNLOAD_RESUME;
-          }
-          /* download from where? */
-          data->state.resume_from += attrs.filesize;
-        }
-        else {
-          if((curl_off_t)attrs.filesize < data->state.resume_from) {
-            failf(data, "Offset (%" FMT_OFF_T
-                  ") was beyond file size (%" FMT_OFF_T ")",
-                  data->state.resume_from, (curl_off_t)attrs.filesize);
-            return CURLE_BAD_DOWNLOAD_RESUME;
-          }
-        }
-        /* Now store the number of bytes we are expected to download */
-        data->req.size = attrs.filesize - data->state.resume_from;
-        data->req.maxdownload = attrs.filesize - data->state.resume_from;
-        Curl_pgrsSetDownloadSize(data,
-                                 attrs.filesize - data->state.resume_from);
-        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
-      }
-    }
-
-    /* Setup the actual download */
-    if(data->req.size == 0) {
-      /* no data to transfer */
-      Curl_xfer_setup_nop(data);
-      infof(data, "File already completely downloaded");
-      state(data, SSH_STOP);
       break;
-    }
-    Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
-
-    /* not set by Curl_xfer_setup to preserve keepon bits */
-    conn->writesockfd = conn->sockfd;
-
-    /* we want to use the _receiving_ function even when the socket turns
-       out writableable as the underlying libssh2 recv function will deal
-       with both accordingly */
-    data->state.select_bits = CURL_CSELECT_IN;
-
-    if(result) {
-      /* this should never occur; the close state should be entered
-         at the time the error occurs */
-      state(data, SSH_SFTP_CLOSE);
-      sshc->actualcode = result;
-    }
-    else {
-      state(data, SSH_STOP);
-    }
-    break;
 
     case SSH_SFTP_CLOSE:
       if(sshc->sftp_handle) {
@@ -3078,8 +3047,8 @@
     dir = libssh2_session_block_directions(sshc->ssh_session);
     if(dir) {
       /* translate the libssh2 define bits into our own bit defines */
-      conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
-        ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0);
+      conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND) ? KEEP_RECV : 0) |
+        ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND) ? KEEP_SEND : 0);
     }
   }
   if(!dir)
@@ -3097,8 +3066,8 @@
   bool block; /* we store the status and use that to provide a ssh_getsock()
                  implementation */
   do {
-    result = ssh_statemach_act(data, &block);
-    *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
+    result = ssh_statemachine(data, &block);
+    *done = (sshc->state == SSH_STOP);
     /* if there is no error, it is not done and it did not EWOULDBLOCK, then
        try again */
   } while(!result && !*done && !block);
@@ -3120,7 +3089,7 @@
     timediff_t left = 1000;
     struct curltime now = Curl_now();
 
-    result = ssh_statemach_act(data, &block);
+    result = ssh_statemachine(data, &block);
     if(result)
       break;
 
@@ -3156,7 +3125,7 @@
         fd_write = sock;
       /* wait for the socket to become ready */
       (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
-                              left>1000?1000:left);
+                              left > 1000 ? 1000 : left);
     }
   }
 
@@ -3449,7 +3418,7 @@
 static CURLcode ssh_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result;
-  bool connected = 0;
+  bool connected = FALSE;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 
@@ -3509,8 +3478,6 @@
     result = status;
 
   Curl_safefree(sshp->path);
-  Curl_safefree(sshp->readdir_filename);
-  Curl_safefree(sshp->readdir_longentry);
   Curl_dyn_free(&sshp->readdir);
 
   if(Curl_pgrsDone(data))
@@ -3545,7 +3512,7 @@
   /* libssh2_channel_write() returns int! */
   nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len);
 
-  ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+  ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN));
 
   if(nwrite == LIBSSH2_ERROR_EAGAIN) {
     *err = CURLE_AGAIN;
@@ -3570,7 +3537,7 @@
   /* libssh2_channel_read() returns int */
   nread = (ssize_t) libssh2_channel_read(sshc->ssh_channel, mem, len);
 
-  ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+  ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN));
   if(nread == LIBSSH2_ERROR_EAGAIN) {
     *err = CURLE_AGAIN;
     nread = -1;
@@ -3683,7 +3650,7 @@
 
   nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len);
 
-  ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+  ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN));
 
   if(nwrite == LIBSSH2_ERROR_EAGAIN) {
     *err = CURLE_AGAIN;
@@ -3711,7 +3678,7 @@
 
   nread = libssh2_sftp_read(sshc->sftp_handle, mem, len);
 
-  ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+  ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN));
 
   if(nread == LIBSSH2_ERROR_EAGAIN) {
     *err = CURLE_AGAIN;
diff --git a/Utilities/cmcurl/lib/vssh/ssh.h b/Utilities/cmcurl/lib/vssh/ssh.h
index 2ed7864..8d8a9b3 100644
--- a/Utilities/cmcurl/lib/vssh/ssh.h
+++ b/Utilities/cmcurl/lib/vssh/ssh.h
@@ -39,6 +39,8 @@
 #include <wolfssh/wolfsftp.h>
 #endif
 
+#include "curl_path.h"
+
 /****************************************************************************
  * SSH unique setup
  ***************************************************************************/
@@ -109,6 +111,8 @@
   SSH_LAST  /* never used */
 } sshstate;
 
+#define CURL_PATH_MAX 1024
+
 /* this struct is used in the HandleData struct which is part of the
    Curl_easy, which means this is used on a per-easy handle basis.
    Everything that is strictly related to a connection is banned from this
@@ -118,8 +122,8 @@
 #ifdef USE_LIBSSH2
   struct dynbuf readdir_link;
   struct dynbuf readdir;
-  char *readdir_filename;
-  char *readdir_longentry;
+  char readdir_filename[CURL_PATH_MAX + 1];
+  char readdir_longentry[CURL_PATH_MAX + 1];
 
   LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */
 
@@ -173,6 +177,10 @@
   sftp_dir sftp_dir;
 
   unsigned sftp_recv_state; /* 0 or 1 */
+#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
+  sftp_aio sftp_aio;
+  unsigned sftp_send_state; /* 0 or 1 */
+#endif
   int sftp_file_index; /* for async read */
   sftp_attributes readdir_attrs; /* used by the SFTP readdir actions */
   sftp_attributes readdir_link_attrs; /* used by the SFTP readdir actions */
diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.c b/Utilities/cmcurl/lib/vssh/wolfssh.c
index 1d01bcd..5400821 100644
--- a/Utilities/cmcurl/lib/vssh/wolfssh.c
+++ b/Utilities/cmcurl/lib/vssh/wolfssh.c
@@ -256,8 +256,8 @@
   (void)sockindex;
   (void)eos;
 
-  offset[0] = (word32)sshc->offset&0xFFFFFFFF;
-  offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
+  offset[0] = (word32)sshc->offset & 0xFFFFFFFF;
+  offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF;
 
   rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle,
                                     sshc->handleSz,
@@ -300,8 +300,8 @@
   word32 offset[2];
   (void)sockindex;
 
-  offset[0] = (word32)sshc->offset&0xFFFFFFFF;
-  offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
+  offset[0] = (word32)sshc->offset & 0xFFFFFFFF;
+  offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF;
 
   rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle,
                                    sshc->handleSz,
@@ -629,10 +629,10 @@
         /* Let's read off the proper amount of bytes from the input. */
         int seekerr = CURL_SEEKFUNC_OK;
         if(data->set.seek_func) {
-          Curl_set_in_callback(data, true);
+          Curl_set_in_callback(data, TRUE);
           seekerr = data->set.seek_func(data->set.seek_client,
                                         data->state.resume_from, SEEK_SET);
-          Curl_set_in_callback(data, false);
+          Curl_set_in_callback(data, FALSE);
         }
 
         if(seekerr != CURL_SEEKFUNC_OK) {
@@ -651,11 +651,11 @@
               sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
 
             size_t actuallyread;
-            Curl_set_in_callback(data, true);
+            Curl_set_in_callback(data, TRUE);
             actuallyread = data->state.fread_func(scratch, 1,
                                                   readthisamountnow,
                                                   data->state.in);
-            Curl_set_in_callback(data, false);
+            Curl_set_in_callback(data, FALSE);
 
             passed += actuallyread;
             if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
@@ -763,7 +763,7 @@
         return CURLE_SSH;
       }
 
-      size = ((curl_off_t)attrs.sz[1] <<32) | attrs.sz[0];
+      size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0];
 
       data->req.size = size;
       data->req.maxdownload = size;
@@ -908,7 +908,7 @@
                  implementation */
   do {
     result = wssh_statemach_act(data, &block);
-    *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
+    *done = (sshc->state == SSH_STOP);
     /* if there is no error, it is not done and it did not EWOULDBLOCK, then
        try again */
     if(*done) {
@@ -962,7 +962,7 @@
 static CURLcode wssh_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result;
-  bool connected = 0;
+  bool connected = FALSE;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 
@@ -1028,7 +1028,7 @@
 
       /* wait for the socket to become ready */
       (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
-                              left>1000?1000:left); /* ignore result */
+                              left > 1000 ? 1000 : left); /* ignore result */
     }
   }
 
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c
index 0199d6b..53fd4a6 100644
--- a/Utilities/cmcurl/lib/vtls/bearssl.c
+++ b/Utilities/cmcurl/lib/vtls/bearssl.c
@@ -609,11 +609,15 @@
   br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);
 
   if(ssl_config->primary.cache_session) {
-    void *session;
+    void *sdata;
+    size_t slen;
+    const br_ssl_session_parameters *session;
 
     CURL_TRC_CF(data, cf, "connect_step1, check session cache");
     Curl_ssl_sessionid_lock(data);
-    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &session, NULL)) {
+    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &sdata, &slen, NULL) &&
+       slen == sizeof(*session)) {
+      session = sdata;
       br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
       session_set = 1;
       infof(data, "BearSSL: reusing session ID");
@@ -653,10 +657,10 @@
 
   /* give application a chance to interfere with SSL set up. */
   if(data->set.ssl.fsslctx) {
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     ret = (*data->set.ssl.fsslctx)(data, &backend->ctx,
                                    data->set.ssl.fsslctxp);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
     if(ret) {
       failf(data, "BearSSL: error signaled by ssl ctx callback");
       return ret;
@@ -761,7 +765,6 @@
     (struct bearssl_ssl_backend_data *)connssl->backend;
   br_ssl_session_parameters session;
   char cipher_str[64];
-  char ver_str[16];
   CURLcode ret;
 
   DEBUGASSERT(backend);
@@ -772,6 +775,7 @@
     return CURLE_OK;
   if(ret == CURLE_OK) {
     unsigned int tver;
+    int subver = 0;
 
     if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
       failf(data, "SSL: connection closed during handshake");
@@ -780,19 +784,22 @@
     connssl->connecting_state = ssl_connect_3;
     /* Informational message */
     tver = br_ssl_engine_get_version(&backend->ctx.eng);
-    if(tver == BR_TLS12)
-      strcpy(ver_str, "TLSv1.2");
-    else if(tver == BR_TLS11)
-      strcpy(ver_str, "TLSv1.1");
-    else if(tver == BR_TLS10)
-      strcpy(ver_str, "TLSv1.0");
-    else {
-      msnprintf(ver_str, sizeof(ver_str), "TLS 0x%04x", tver);
+    switch(tver) {
+    case BR_TLS12:
+      subver = 2; /* 1.2 */
+      break;
+    case BR_TLS11:
+      subver = 1; /* 1.1 */
+      break;
+    case BR_TLS10: /* 1.0 */
+    default: /* unknown, leave it at zero */
+      break;
     }
     br_ssl_engine_get_session_parameters(&backend->ctx.eng, &session);
     Curl_cipher_suite_get_str(session.cipher_suite, cipher_str,
-                              sizeof(cipher_str), true);
-    infof(data, "BearSSL: %s connection using %s", ver_str, cipher_str);
+                              sizeof(cipher_str), TRUE);
+    infof(data, "BearSSL: TLS v1.%d connection using %s", subver,
+          cipher_str);
   }
   return ret;
 }
@@ -820,8 +827,8 @@
     const char *proto;
 
     proto = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
-    Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto,
-                             proto? strlen(proto) : 0);
+    Curl_alpn_set_negotiated(cf, data, connssl, (const unsigned char *)proto,
+                             proto ? strlen(proto) : 0);
   }
 
   if(ssl_config->primary.cache_session) {
@@ -832,7 +839,8 @@
       return CURLE_OUT_OF_MEMORY;
     br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
     Curl_ssl_sessionid_lock(data);
-    ret = Curl_ssl_set_sessionid(cf, data, &connssl->peer, session, 0,
+    ret = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
+                                 session, sizeof(*session),
                                  bearssl_session_free);
     Curl_ssl_sessionid_unlock(data);
     if(ret)
@@ -941,15 +949,14 @@
 
     /* if ssl is expecting something, check if it is available. */
     if(connssl->io_need) {
-
-      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
-                              sockfd:CURL_SOCKET_BAD;
-      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
-                             sockfd:CURL_SOCKET_BAD;
+      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+        sockfd : CURL_SOCKET_BAD;
+      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+        sockfd : CURL_SOCKET_BAD;
 
       CURL_TRC_CF(data, cf, "connect_common, check socket");
       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
-                               nonblocking?0:timeout_ms);
+                               nonblocking ? 0 : timeout_ms);
       CURL_TRC_CF(data, cf, "connect_common, check socket -> %d", what);
       if(what < 0) {
         /* fatal error */
diff --git a/Utilities/cmcurl/lib/vtls/cipher_suite.c b/Utilities/cmcurl/lib/vtls/cipher_suite.c
index c025b53..a694b146 100644
--- a/Utilities/cmcurl/lib/vtls/cipher_suite.c
+++ b/Utilities/cmcurl/lib/vtls/cipher_suite.c
@@ -844,10 +844,10 @@
     case ':':
     case ',':
     case ';':
-      return true;
+      return TRUE;
     default:;
   }
-  return false;
+  return FALSE;
 }
 
 uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end)
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index ad9a6b9..af4f0c3 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -50,6 +50,7 @@
 #include "vauth/vauth.h"
 #include "parsedate.h"
 #include "connect.h" /* for the connect timeout */
+#include "progress.h"
 #include "select.h"
 #include "strcase.h"
 #include "warnless.h"
@@ -108,7 +109,7 @@
   backend->gtls.io_result = result;
   if(nwritten < 0) {
     gnutls_transport_set_errno(backend->gtls.session,
-                               (CURLE_AGAIN == result)? EAGAIN : EINVAL);
+                               (CURLE_AGAIN == result) ? EAGAIN : EINVAL);
     nwritten = -1;
   }
   return nwritten;
@@ -140,7 +141,7 @@
   backend->gtls.io_result = result;
   if(nread < 0) {
     gnutls_transport_set_errno(backend->gtls.session,
-                               (CURLE_AGAIN == result)? EAGAIN : EINVAL);
+                               (CURLE_AGAIN == result) ? EAGAIN : EINVAL);
     nread = -1;
   }
   else if(nread == 0)
@@ -159,7 +160,7 @@
 {
   int ret = 1;
   if(!gtls_inited) {
-    ret = gnutls_global_init()?0:1;
+    ret = gnutls_global_init() ? 0 : 1;
 #ifdef GTLSDEBUG
     gnutls_global_set_log_function(tls_log_func);
     gnutls_global_set_log_level(2);
@@ -193,7 +194,7 @@
             sizeof(str),
             "  %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
             text,
-            Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+            Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6],
             tm->tm_mday,
             Curl_month[tm->tm_mon],
             tm->tm_year + 1900,
@@ -269,14 +270,14 @@
     /* if ssl is expecting something, check if it is available. */
     if(connssl->io_need) {
       int what;
-      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
-                              sockfd:CURL_SOCKET_BAD;
-      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
-                             sockfd:CURL_SOCKET_BAD;
+      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+        sockfd : CURL_SOCKET_BAD;
+      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+        sockfd : CURL_SOCKET_BAD;
 
       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
-                               nonblocking?0:
-                               timeout_ms?timeout_ms:1000);
+                               nonblocking ? 0 :
+                               timeout_ms ? timeout_ms : 1000);
       if(what < 0) {
         /* fatal error */
         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -284,7 +285,7 @@
       }
       else if(0 == what) {
         if(nonblocking)
-          return CURLE_OK;
+          return CURLE_AGAIN;
         else if(timeout_ms) {
           /* timeout */
           failf(data, "SSL connection timeout at %ld", (long)timeout_ms);
@@ -308,8 +309,8 @@
 
     if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
       connssl->io_need =
-        gnutls_record_get_direction(session)?
-        CURL_SSL_IO_NEED_SEND:CURL_SSL_IO_NEED_RECV;
+        gnutls_record_get_direction(session) ?
+        CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
       continue;
     }
     else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
@@ -509,7 +510,7 @@
   int rc;
 
   if(config->verifypeer) {
-    bool imported_native_ca = false;
+    bool imported_native_ca = FALSE;
 
     if(ssl_config->native_ca_store) {
       rc = gnutls_certificate_set_x509_system_trust(creds);
@@ -519,7 +520,7 @@
       else {
         infof(data, "found %d certificates in native ca store", rc);
         if(rc > 0)
-          imported_native_ca = true;
+          imported_native_ca = TRUE;
       }
     }
 
@@ -590,7 +591,7 @@
   timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
 
   if(timeout_ms < 0)
-    return false;
+    return FALSE;
 
   return elapsed_ms >= timeout_ms;
 }
@@ -719,45 +720,57 @@
   free(sessionid);
 }
 
-static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
-                                       struct Curl_easy *data,
-                                       gnutls_session_t session)
+CURLcode Curl_gtls_update_session_id(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data,
+                                     gnutls_session_t session,
+                                     struct ssl_peer *peer,
+                                     const char *alpn)
 {
   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-  struct ssl_connect_data *connssl = cf->ctx;
+  void *connect_sessionid;
+  size_t connect_idsize = 0;
   CURLcode result = CURLE_OK;
 
-  if(ssl_config->primary.cache_session) {
-    /* we always unconditionally get the session id here, as even if we
-       already got it from the cache and asked to use it in the connection, it
-       might've been rejected and then a new one is in use now and we need to
-       detect that. */
-    void *connect_sessionid;
-    size_t connect_idsize = 0;
+  if(!ssl_config->primary.cache_session)
+    return CURLE_OK;
 
-    /* get the session ID data size */
-    gnutls_session_get_data(session, NULL, &connect_idsize);
-    connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
-    if(!connect_sessionid) {
-      return CURLE_OUT_OF_MEMORY;
-    }
-    else {
-      /* extract session ID to the allocated buffer */
-      gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+  /* we always unconditionally get the session id here, as even if we
+     already got it from the cache and asked to use it in the connection, it
+     might've been rejected and then a new one is in use now and we need to
+     detect that. */
 
-      CURL_TRC_CF(data, cf, "get session id (len=%zu) and store in cache",
-                  connect_idsize);
-      Curl_ssl_sessionid_lock(data);
-      /* store this session id, takes ownership */
-      result = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
-                                      connect_sessionid, connect_idsize,
-                                      gtls_sessionid_free);
-      Curl_ssl_sessionid_unlock(data);
-    }
-  }
+  /* get the session ID data size */
+  gnutls_session_get_data(session, NULL, &connect_idsize);
+  if(!connect_idsize) /* gnutls does this for some version combinations */
+    return CURLE_OK;
+
+  connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
+  if(!connect_sessionid)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* extract session ID to the allocated buffer */
+  gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+  CURL_TRC_CF(data, cf, "get session id (len=%zu, alpn=%s) and store in cache",
+              connect_idsize, alpn ? alpn : "-");
+  Curl_ssl_sessionid_lock(data);
+  /* store this session id, takes ownership */
+  result = Curl_ssl_set_sessionid(cf, data, peer, alpn,
+                                  connect_sessionid, connect_idsize,
+                                  gtls_sessionid_free);
+  Curl_ssl_sessionid_unlock(data);
   return result;
 }
 
+static CURLcode cf_gtls_update_session_id(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data,
+                                          gnutls_session_t session)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  return Curl_gtls_update_session_id(cf, data, session, &connssl->peer,
+                                     connssl->alpn_negotiated);
+}
+
 static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
                              unsigned when, unsigned int incoming,
                              const gnutls_datum_t *msg)
@@ -770,10 +783,10 @@
     struct Curl_easy *data = CF_DATA_CURRENT(cf);
     if(data) {
       CURL_TRC_CF(data, cf, "handshake: %s message type %d",
-                  incoming? "incoming" : "outgoing", htype);
+                  incoming ? "incoming" : "outgoing", htype);
       switch(htype) {
       case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
-        gtls_update_session_id(cf, data, session);
+        cf_gtls_update_session_id(cf, data, session);
         break;
       }
       default:
@@ -845,9 +858,13 @@
   init_flags |= GNUTLS_FORCE_CLIENT_CERT;
 #endif
 
-#if defined(GNUTLS_NO_TICKETS)
-  /* Disable TLS session tickets */
-  init_flags |= GNUTLS_NO_TICKETS;
+#if defined(GNUTLS_NO_TICKETS_TLS12)
+    init_flags |= GNUTLS_NO_TICKETS_TLS12;
+#elif defined(GNUTLS_NO_TICKETS)
+  /* Disable TLS session tickets for non 1.3 connections */
+  if((config->version != CURL_SSLVERSION_TLSv1_3) &&
+     (config->version != CURL_SSLVERSION_DEFAULT))
+    init_flags |= GNUTLS_NO_TICKETS;
 #endif
 
 #if defined(GNUTLS_NO_STATUS_REQUEST)
@@ -936,7 +953,19 @@
       if(result)
         return result;
     }
-    if(ssl_config->key_passwd) {
+    if(ssl_config->cert_type && strcasecompare(ssl_config->cert_type, "P12")) {
+      rc = gnutls_certificate_set_x509_simple_pkcs12_file(
+        gtls->shared_creds->creds, config->clientcert, GNUTLS_X509_FMT_DER,
+        ssl_config->key_passwd ? ssl_config->key_passwd : "");
+      if(rc != GNUTLS_E_SUCCESS) {
+        failf(data,
+              "error reading X.509 potentially-encrypted key or certificate "
+              "file: %s",
+              gnutls_strerror(rc));
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+    else if(ssl_config->key_passwd) {
       const unsigned int supported_key_encryption_algorithms =
         GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
         GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
@@ -1022,11 +1051,15 @@
                             struct Curl_easy *data,
                             struct ssl_peer *peer,
                             const unsigned char *alpn, size_t alpn_len,
+                            struct ssl_connect_data *connssl,
                             Curl_gtls_ctx_setup_cb *cb_setup,
                             void *cb_user_data,
                             void *ssl_user_data)
 {
   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  gnutls_datum_t gtls_alpns[5];
+  size_t gtls_alpns_count = 0;
   CURLcode result;
 
   DEBUGASSERT(gctx);
@@ -1049,52 +1082,91 @@
     gnutls_session_set_keylog_function(gctx->session, keylog_callback);
   }
 
-  /* convert the ALPN string from our arguments to a list of strings
-   * that gnutls wants and will convert internally back to this very
-   * string for sending to the server. nice. */
-  if(alpn && alpn_len) {
-    gnutls_datum_t alpns[5];
-    size_t i, alen = alpn_len;
-    unsigned char *s = (unsigned char *)alpn;
-    unsigned char slen;
-    for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) {
-      slen = s[0];
-      if(slen >= alen)
-        return CURLE_FAILED_INIT;
-      alpns[i].data = s + 1;
-      alpns[i].size = slen;
-      s += slen + 1;
-      alen -= (size_t)slen + 1;
-    }
-    if(alen) /* not all alpn chars used, wrong format or too many */
-        return CURLE_FAILED_INIT;
-    if(i && gnutls_alpn_set_protocols(gctx->session,
-                                      alpns, (unsigned int)i,
-                                      GNUTLS_ALPN_MANDATORY)) {
-      failf(data, "failed setting ALPN");
-      return CURLE_SSL_CONNECT_ERROR;
-    }
-  }
-
   /* This might be a reconnect, so we check for a session ID in the cache
      to speed up things */
   if(conn_config->cache_session) {
     void *ssl_sessionid;
     size_t ssl_idsize;
-
+    char *session_alpn;
     Curl_ssl_sessionid_lock(data);
-    if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, &ssl_idsize)) {
+    if(!Curl_ssl_getsessionid(cf, data, peer,
+                              &ssl_sessionid, &ssl_idsize, &session_alpn)) {
       /* we got a session id, use it! */
       int rc;
 
       rc = gnutls_session_set_data(gctx->session, ssl_sessionid, ssl_idsize);
       if(rc < 0)
         infof(data, "SSL failed to set session ID");
-      else
-        infof(data, "SSL reusing session ID (size=%zu)", ssl_idsize);
+      else {
+        infof(data, "SSL reusing session ID (size=%zu, alpn=%s)",
+              ssl_idsize, session_alpn ? session_alpn : "-");
+#ifdef DEBUGBUILD
+        if((ssl_config->earlydata || !!getenv("CURL_USE_EARLYDATA")) &&
+#else
+        if(ssl_config->earlydata &&
+#endif
+           !cf->conn->connect_only && connssl &&
+           (gnutls_protocol_get_version(gctx->session) == GNUTLS_TLS1_3) &&
+           Curl_alpn_contains_proto(connssl->alpn, session_alpn)) {
+          connssl->earlydata_max =
+            gnutls_record_get_max_early_data_size(gctx->session);
+          if((!connssl->earlydata_max ||
+              connssl->earlydata_max == 0xFFFFFFFFUL)) {
+            /* Seems to be GnuTLS way to signal no EarlyData in session */
+            CURL_TRC_CF(data, cf, "TLS session does not allow earlydata");
+          }
+          else {
+            CURL_TRC_CF(data, cf, "TLS session allows %zu earlydata bytes, "
+                        "reusing ALPN '%s'",
+                        connssl->earlydata_max, session_alpn);
+            connssl->earlydata_state = ssl_earlydata_use;
+            connssl->state = ssl_connection_deferred;
+            result = Curl_alpn_set_negotiated(cf, data, connssl,
+                            (const unsigned char *)session_alpn,
+                            session_alpn ? strlen(session_alpn) : 0);
+            if(result)
+              return result;
+            /* We only try the ALPN protocol the session used before,
+             * otherwise we might send early data for the wrong protocol */
+            gtls_alpns[0].data = (unsigned char *)session_alpn;
+            gtls_alpns[0].size = (unsigned)strlen(session_alpn);
+            gtls_alpns_count = 1;
+          }
+        }
+      }
     }
     Curl_ssl_sessionid_unlock(data);
   }
+
+  /* convert the ALPN string from our arguments to a list of strings that
+   * gnutls wants and will convert internally back to this string for sending
+   * to the server. nice. */
+  if(!gtls_alpns_count && alpn && alpn_len) {
+    size_t i, alen = alpn_len;
+    unsigned char *s = (unsigned char *)alpn;
+    unsigned char slen;
+    for(i = 0; (i < ARRAYSIZE(gtls_alpns)) && alen; ++i) {
+      slen = s[0];
+      if(slen >= alen)
+        return CURLE_FAILED_INIT;
+      gtls_alpns[i].data = s + 1;
+      gtls_alpns[i].size = slen;
+      s += slen + 1;
+      alen -= (size_t)slen + 1;
+    }
+    if(alen) /* not all alpn chars used, wrong format or too many */
+        return CURLE_FAILED_INIT;
+    gtls_alpns_count = i;
+  }
+
+  if(gtls_alpns_count &&
+     gnutls_alpn_set_protocols(gctx->session,
+                               gtls_alpns, (unsigned int)gtls_alpns_count,
+                               GNUTLS_ALPN_MANDATORY)) {
+    failf(data, "failed setting ALPN");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
   return CURLE_OK;
 }
 
@@ -1125,10 +1197,15 @@
   }
 
   result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer,
-                              proto.data, proto.len, NULL, NULL, cf);
+                              proto.data, proto.len, connssl, NULL, NULL, cf);
   if(result)
     return result;
 
+  if(connssl->alpn && (connssl->state != ssl_connection_deferred)) {
+    Curl_alpn_to_proto_str(&proto, connssl->alpn);
+    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+  }
+
   gnutls_handshake_set_hook_function(backend->gtls.session,
                                      GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
                                      gtls_handshake_cb);
@@ -1313,7 +1390,7 @@
           cause = "attached OCSP status response is invalid";
         failf(data, "server verification failed: %s. (CAfile: %s "
               "CRLfile: %s)", cause,
-              config->CAfile ? config->CAfile: "none",
+              config->CAfile ? config->CAfile : "none",
               ssl_config->primary.CRLfile ?
               ssl_config->primary.CRLfile : "none");
         return CURLE_PEER_FAILED_VERIFICATION;
@@ -1440,12 +1517,12 @@
     unload_file(issuerp);
     if(rc <= 0) {
       failf(data, "server certificate issuer check failed (IssuerCert: %s)",
-            config->issuercert?config->issuercert:"none");
+            config->issuercert ? config->issuercert : "none");
       gnutls_x509_crt_deinit(x509_cert);
       return CURLE_SSL_ISSUER_ERROR;
     }
     infof(data, "  server certificate issuer check OK (Issuer Cert: %s)",
-          config->issuercert?config->issuercert:"none");
+          config->issuercert ? config->issuercert : "none");
   }
 
   size = sizeof(certname);
@@ -1650,8 +1727,8 @@
   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
 #ifndef CURL_DISABLE_PROXY
-  const char *pinned_key = Curl_ssl_cf_is_proxy(cf)?
-    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+  const char *pinned_key = Curl_ssl_cf_is_proxy(cf) ?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
     data->set.str[STRING_SSL_PINNEDPUBLICKEY];
 #else
   const char *pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
@@ -1663,26 +1740,79 @@
   if(result)
     goto out;
 
-  if(connssl->alpn) {
-    gnutls_datum_t proto;
-    int rc;
-
-    rc = gnutls_alpn_get_selected_protocol(session, &proto);
-    if(rc == 0)
-      Curl_alpn_set_negotiated(cf, data, proto.data, proto.size);
-    else
-      Curl_alpn_set_negotiated(cf, data, NULL, 0);
-  }
-
   /* Only on TLSv1.2 or lower do we have the session id now. For
    * TLSv1.3 we get it via a SESSION_TICKET message that arrives later. */
   if(gnutls_protocol_get_version(session) < GNUTLS_TLS1_3)
-    result = gtls_update_session_id(cf, data, session);
+    result = cf_gtls_update_session_id(cf, data, session);
 
 out:
   return result;
 }
 
+static CURLcode gtls_set_earlydata(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   const void *buf, size_t blen)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  ssize_t nwritten = 0;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_use);
+  DEBUGASSERT(Curl_bufq_is_empty(&connssl->earlydata));
+  if(blen) {
+    if(blen > connssl->earlydata_max)
+      blen = connssl->earlydata_max;
+    nwritten = Curl_bufq_write(&connssl->earlydata, buf, blen, &result);
+    CURL_TRC_CF(data, cf, "gtls_set_earlydata(len=%zu) -> %zd",
+                blen, nwritten);
+    if(nwritten < 0)
+      return result;
+  }
+  connssl->earlydata_state = ssl_earlydata_sending;
+  connssl->earlydata_skip = Curl_bufq_len(&connssl->earlydata);
+  return CURLE_OK;
+}
+
+static CURLcode gtls_send_earlydata(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct gtls_ssl_backend_data *backend =
+      (struct gtls_ssl_backend_data *)connssl->backend;
+  CURLcode result = CURLE_OK;
+  const unsigned char *buf;
+  size_t blen;
+  ssize_t n;
+
+  DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sending);
+  backend->gtls.io_result = CURLE_OK;
+  while(Curl_bufq_peek(&connssl->earlydata, &buf, &blen)) {
+    n = gnutls_record_send_early_data(backend->gtls.session, buf, blen);
+    CURL_TRC_CF(data, cf, "gtls_send_earlydata(len=%zu) -> %zd",
+                blen, n);
+    if(n < 0) {
+      if(n == GNUTLS_E_AGAIN)
+        result = CURLE_AGAIN;
+      else
+        result = backend->gtls.io_result ?
+                 backend->gtls.io_result : CURLE_SEND_ERROR;
+      goto out;
+    }
+    else if(!n) {
+      /* gnutls is buggy, it *SHOULD* return the amount of bytes it took in.
+       * Instead it returns 0 if everything was written. */
+      n = (ssize_t)blen;
+    }
+
+    Curl_bufq_skip(&connssl->earlydata, (size_t)n);
+  }
+  /* sent everything there was */
+  infof(data, "SSL sending %" FMT_OFF_T " bytes of early data",
+        connssl->earlydata_skip);
+out:
+  return result;
+}
+
 /*
  * This function is called after the TCP connect has completed. Setup the TLS
  * layer and do all necessary magic.
@@ -1696,46 +1826,89 @@
 gtls_connect_common(struct Curl_cfilter *cf,
                     struct Curl_easy *data,
                     bool nonblocking,
-                    bool *done)
-{
+                    bool *done) {
   struct ssl_connect_data *connssl = cf->ctx;
-  CURLcode rc;
+  struct gtls_ssl_backend_data *backend =
+      (struct gtls_ssl_backend_data *)connssl->backend;
   CURLcode result = CURLE_OK;
 
+  DEBUGASSERT(backend);
+
   /* Initiate the connection, if not already done */
-  if(ssl_connect_1 == connssl->connecting_state) {
-    rc = gtls_connect_step1(cf, data);
-    if(rc) {
-      result = rc;
+  if(connssl->connecting_state == ssl_connect_1) {
+    result = gtls_connect_step1(cf, data);
+    if(result)
       goto out;
-    }
+    connssl->connecting_state = ssl_connect_2;
   }
 
-  rc = handshake(cf, data, TRUE, nonblocking);
-  if(rc) {
-    /* handshake() sets its own error message with failf() */
-    result = rc;
-    goto out;
+  if(connssl->connecting_state == ssl_connect_2) {
+    if(connssl->earlydata_state == ssl_earlydata_use) {
+      goto out;
+    }
+    else if(connssl->earlydata_state == ssl_earlydata_sending) {
+      result = gtls_send_earlydata(cf, data);
+      if(result)
+        goto out;
+      connssl->earlydata_state = ssl_earlydata_sent;
+      if(!Curl_ssl_cf_is_proxy(cf))
+        Curl_pgrsEarlyData(data, (curl_off_t)connssl->earlydata_skip);
+    }
+    DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
+                (connssl->earlydata_state == ssl_earlydata_sent));
+
+    result = handshake(cf, data, TRUE, nonblocking);
+    if(result)
+      goto out;
+    connssl->connecting_state = ssl_connect_3;
   }
 
   /* Finish connecting once the handshake is done */
-  if(ssl_connect_1 == connssl->connecting_state) {
-    struct gtls_ssl_backend_data *backend =
-      (struct gtls_ssl_backend_data *)connssl->backend;
-    gnutls_session_t session;
-    DEBUGASSERT(backend);
-    session = backend->gtls.session;
-    rc = gtls_verifyserver(cf, data, session);
-    if(rc) {
-      result = rc;
+  if(connssl->connecting_state == ssl_connect_3) {
+    gnutls_datum_t proto;
+    int rc;
+    result = gtls_verifyserver(cf, data, backend->gtls.session);
+    if(result)
       goto out;
-    }
+
     connssl->state = ssl_connection_complete;
+    connssl->connecting_state = ssl_connect_1;
+
+    rc = gnutls_alpn_get_selected_protocol(backend->gtls.session, &proto);
+    if(rc) {  /* No ALPN from server */
+      proto.data = NULL;
+      proto.size = 0;
+    }
+
+    result = Curl_alpn_set_negotiated(cf, data, connssl,
+                                      proto.data, proto.size);
+    if(result)
+      goto out;
+
+    if(connssl->earlydata_state == ssl_earlydata_sent) {
+      if(gnutls_session_get_flags(backend->gtls.session) &
+         GNUTLS_SFLAGS_EARLY_DATA) {
+        connssl->earlydata_state = ssl_earlydata_accepted;
+        infof(data, "Server accepted %zu bytes of TLS early data.",
+              connssl->earlydata_skip);
+      }
+      else {
+        connssl->earlydata_state = ssl_earlydata_rejected;
+        if(!Curl_ssl_cf_is_proxy(cf))
+          Curl_pgrsEarlyData(data, -(curl_off_t)connssl->earlydata_skip);
+        infof(data, "Server rejected TLS early data.");
+        connssl->earlydata_skip = 0;
+      }
+    }
   }
 
 out:
-  *done = ssl_connect_1 == connssl->connecting_state;
-
+  if(result == CURLE_AGAIN) {
+    *done = FALSE;
+    return CURLE_OK;
+  }
+  *done = ((connssl->connecting_state == ssl_connect_1) ||
+           (connssl->state == ssl_connection_deferred));
   return result;
 }
 
@@ -1743,6 +1916,12 @@
                                          struct Curl_easy *data,
                                          bool *done)
 {
+  struct ssl_connect_data *connssl = cf->ctx;
+  if(connssl->state == ssl_connection_deferred) {
+    /* We refuse to be pushed, we are waiting for someone to send/recv. */
+    *done = TRUE;
+    return CURLE_OK;
+  }
   return gtls_connect_common(cf, data, TRUE, done);
 }
 
@@ -1761,6 +1940,26 @@
   return CURLE_OK;
 }
 
+static CURLcode gtls_connect_deferred(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data,
+                                      const void *buf,
+                                      size_t blen,
+                                      bool *done)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(connssl->state == ssl_connection_deferred);
+  *done = FALSE;
+  if(connssl->earlydata_state == ssl_earlydata_use) {
+    result = gtls_set_earlydata(cf, data, buf, blen);
+    if(result)
+      return result;
+  }
+
+  return gtls_connect_common(cf, data, TRUE, done);
+}
+
 static bool gtls_data_pending(struct Curl_cfilter *cf,
                               const struct Curl_easy *data)
 {
@@ -1788,8 +1987,38 @@
   ssize_t rc;
   size_t nwritten, total_written = 0;
 
-  (void)data;
   DEBUGASSERT(backend);
+
+  if(connssl->state == ssl_connection_deferred) {
+    bool done = FALSE;
+    *curlcode = gtls_connect_deferred(cf, data, buf, blen, &done);
+    if(*curlcode) {
+      rc = -1;
+      goto out;
+    }
+    else if(!done) {
+      *curlcode = CURLE_AGAIN;
+      rc = -1;
+      goto out;
+    }
+    DEBUGASSERT(connssl->state == ssl_connection_complete);
+  }
+
+  if(connssl->earlydata_skip) {
+    if(connssl->earlydata_skip >= blen) {
+      connssl->earlydata_skip -= blen;
+      *curlcode = CURLE_OK;
+      rc = (ssize_t)blen;
+      goto out;
+    }
+    else {
+      total_written += connssl->earlydata_skip;
+      buf = ((const char *)buf) + connssl->earlydata_skip;
+      blen -= connssl->earlydata_skip;
+      connssl->earlydata_skip = 0;
+    }
+  }
+
   while(blen) {
     backend->gtls.io_result = CURLE_OK;
     rc = gnutls_record_send(backend->gtls.session, buf, blen);
@@ -1800,9 +2029,9 @@
         rc = (ssize_t)total_written;
         goto out;
       }
-      *curlcode = (rc == GNUTLS_E_AGAIN)?
+      *curlcode = (rc == GNUTLS_E_AGAIN) ?
         CURLE_AGAIN :
-        (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);
+        (backend->gtls.io_result ? backend->gtls.io_result : CURLE_SEND_ERROR);
 
       rc = -1;
       goto out;
@@ -1836,7 +2065,9 @@
   size_t i;
 
   DEBUGASSERT(backend);
-  if(!backend->gtls.session || cf->shutdown) {
+   /* If we have no handshaked connection or already shut down */
+  if(!backend->gtls.session || cf->shutdown ||
+     connssl->state != ssl_connection_complete) {
     *done = TRUE;
     goto out;
   }
@@ -1851,7 +2082,7 @@
       int ret = gnutls_bye(backend->gtls.session, GNUTLS_SHUT_RDWR);
       if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
         CURL_TRC_CF(data, cf, "SSL shutdown, gnutls_bye EAGAIN");
-        connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
+        connssl->io_need = gnutls_record_get_direction(backend->gtls.session) ?
           CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
         backend->gtls.sent_shutdown = FALSE;
         result = CURLE_OK;
@@ -1881,7 +2112,7 @@
     *done = TRUE;
   }
   else if((nread == GNUTLS_E_AGAIN) || (nread == GNUTLS_E_INTERRUPTED)) {
-    connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
+    connssl->io_need = gnutls_record_get_direction(backend->gtls.session) ?
       CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
   }
   else {
@@ -1934,7 +2165,21 @@
   (void)data;
   DEBUGASSERT(backend);
 
-  backend->gtls.io_result = CURLE_OK;
+  if(connssl->state == ssl_connection_deferred) {
+    bool done = FALSE;
+    *curlcode = gtls_connect_deferred(cf, data, NULL, 0, &done);
+    if(*curlcode) {
+      ret = -1;
+      goto out;
+    }
+    else if(!done) {
+      *curlcode = CURLE_AGAIN;
+      ret = -1;
+      goto out;
+    }
+    DEBUGASSERT(connssl->state == ssl_connection_complete);
+  }
+
   ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
   if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
     *curlcode = CURLE_AGAIN;
@@ -1957,10 +2202,9 @@
 
   if(ret < 0) {
     failf(data, "GnuTLS recv error (%d): %s",
-
           (int)ret, gnutls_strerror((int)ret));
-    *curlcode = backend->gtls.io_result?
-                backend->gtls.io_result : CURLE_RECV_ERROR;
+    *curlcode = backend->gtls.io_result ?
+      backend->gtls.io_result : CURLE_RECV_ERROR;
     ret = -1;
     goto out;
   }
@@ -1981,7 +2225,7 @@
   int rc;
   (void)data;
   rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
-  return rc?CURLE_FAILED_INIT:CURLE_OK;
+  return rc ? CURLE_FAILED_INIT : CURLE_OK;
 }
 
 static CURLcode gtls_sha256sum(const unsigned char *tmp, /* input */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h
index b0ca55b..4f9c540 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.h
+++ b/Utilities/cmcurl/lib/vtls/gtls.h
@@ -45,6 +45,7 @@
 struct ssl_primary_config;
 struct ssl_config_data;
 struct ssl_peer;
+struct ssl_connect_data;
 
 struct gtls_shared_creds {
   gnutls_certificate_credentials_t creds;
@@ -78,6 +79,7 @@
                             struct Curl_easy *data,
                             struct ssl_peer *peer,
                             const unsigned char *alpn, size_t alpn_len,
+                            struct ssl_connect_data *connssl,
                             Curl_gtls_ctx_setup_cb *cb_setup,
                             void *cb_user_data,
                             void *ssl_user_data);
@@ -93,6 +95,13 @@
                                 struct ssl_peer *peer,
                                 const char *pinned_key);
 
+/* Extract TLS session and place in cache, if configured. */
+CURLcode Curl_gtls_update_session_id(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data,
+                                     gnutls_session_t session,
+                                     struct ssl_peer *peer,
+                                     const char *alpn);
+
 extern const struct Curl_ssl Curl_ssl_gnutls;
 
 #endif /* USE_GNUTLS */
diff --git a/Utilities/cmcurl/lib/vtls/keylog.c b/Utilities/cmcurl/lib/vtls/keylog.c
index ab7baaa..ca86c15 100644
--- a/Utilities/cmcurl/lib/vtls/keylog.c
+++ b/Utilities/cmcurl/lib/vtls/keylog.c
@@ -99,13 +99,13 @@
   char buf[256];
 
   if(!keylog_file_fp || !line) {
-    return false;
+    return FALSE;
   }
 
   linelen = strlen(line);
   if(linelen == 0 || linelen > sizeof(buf) - 2) {
     /* Empty line or too big to fit in a LF and NUL. */
-    return false;
+    return FALSE;
   }
 
   memcpy(buf, line, linelen);
@@ -117,7 +117,7 @@
   /* Using fputs here instead of fprintf since libcurl's fprintf replacement
      may not be thread-safe. */
   fputs(buf, keylog_file_fp);
-  return true;
+  return TRUE;
 }
 
 bool
@@ -131,13 +131,13 @@
             2 * SECRET_MAXLEN + 1 + 1];
 
   if(!keylog_file_fp) {
-    return false;
+    return FALSE;
   }
 
   pos = strlen(label);
   if(pos > KEYLOG_LABEL_MAXLEN || !secretlen || secretlen > SECRET_MAXLEN) {
     /* Should never happen - sanity check anyway. */
-    return false;
+    return FALSE;
   }
 
   memcpy(line, label, pos);
@@ -161,7 +161,7 @@
   /* Using fputs here instead of fprintf since libcurl's fprintf replacement
      may not be thread-safe. */
   fputs(line, keylog_file_fp);
-  return true;
+  return TRUE;
 }
 
 #endif  /* TLS or QUIC backend */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index 1c00cbe..e071ded 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
@@ -36,13 +36,6 @@
 /* Define this to enable lots of debugging for mbedTLS */
 /* #define MBEDTLS_DEBUG */
 
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-/* mbedTLS (as of v3.5.1) has a duplicate function declaration
-   in its public headers. Disable the warning that detects it. */
-#pragma GCC diagnostic ignored "-Wredundant-decls"
-#endif
-
 #include <mbedtls/version.h>
 #if MBEDTLS_VERSION_NUMBER >= 0x02040000
 #include <mbedtls/net_sockets.h>
@@ -61,11 +54,7 @@
 #  ifdef MBEDTLS_DEBUG
 #    include <mbedtls/debug.h>
 #  endif
-#endif
-
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
+#endif /* MBEDTLS_VERSION_MAJOR >= 2 */
 
 #include "cipher_suite.h"
 #include "strcase.h"
@@ -129,7 +118,11 @@
 #define TLS13_SUPPORT
 #endif
 
-#if defined(THREADING_SUPPORT)
+#if defined(TLS13_SUPPORT) && defined(MBEDTLS_SSL_SESSION_TICKETS)
+#define HAS_SESSION_TICKETS
+#endif
+
+#ifdef THREADING_SUPPORT
 static mbedtls_entropy_context ts_entropy;
 
 static int entropy_init_initialized = 0;
@@ -302,7 +295,8 @@
     break;
 #endif
   default:
-    failf(data, "mbedTLS: unsupported minimum TLS version value");
+    failf(data, "mbedTLS: unsupported minimum TLS version value: %x",
+          conn_config->version);
     return CURLE_SSL_CONNECT_ERROR;
   }
 
@@ -351,6 +345,7 @@
    cipher suite present in other SSL implementations. Provide
    provisional support for specifying the cipher suite here. */
 #ifdef MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
 static int
 mbed_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
                           bool prefer_rfc)
@@ -361,6 +356,7 @@
     return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
   return 0;
 }
+#endif
 
 static uint16_t
 mbed_cipher_suite_walk_str(const char **str, const char **end)
@@ -552,7 +548,7 @@
     mbedtls_x509_crt_verify_info(buf, sizeof(buf), "", *flags);
     failf(data, "mbedTLS: %s", buf);
 #else
-    failf(data, "mbedTLS: cerificate verification error 0x%08x", *flags);
+    failf(data, "mbedTLS: certificate verification error 0x%08x", *flags);
 #endif
   }
 
@@ -589,16 +585,6 @@
     return CURLE_NOT_BUILT_IN;
   }
 
-#ifdef TLS13_SUPPORT
-  ret = psa_crypto_init();
-  if(ret != PSA_SUCCESS) {
-    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-    failf(data, "mbedTLS psa_crypto_init returned (-0x%04X) %s",
-          -ret, errorbuf);
-    return CURLE_SSL_CONNECT_ERROR;
-  }
-#endif /* TLS13_SUPPORT */
-
 #ifdef THREADING_SUPPORT
   mbedtls_ctr_drbg_init(&backend->ctr_drbg);
 
@@ -638,7 +624,7 @@
     ret = mbedtls_x509_crt_parse(&backend->cacert, newblob,
                                  ca_info_blob->len + 1);
     free(newblob);
-    if(ret<0) {
+    if(ret < 0) {
       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
       failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s",
             -ret, errorbuf);
@@ -650,7 +636,7 @@
 #ifdef MBEDTLS_FS_IO
     ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile);
 
-    if(ret<0) {
+    if(ret < 0) {
       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
       failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
             ssl_cafile, -ret, errorbuf);
@@ -666,7 +652,7 @@
 #ifdef MBEDTLS_FS_IO
     ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath);
 
-    if(ret<0) {
+    if(ret < 0) {
       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
       failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
             ssl_capath, -ret, errorbuf);
@@ -816,6 +802,12 @@
     return CURLE_SSL_CONNECT_ERROR;
   }
 
+#ifdef MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED
+  /* New in mbedTLS 3.6.1, need to enable, default is now disabled */
+  mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(&backend->config,
+    MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED);
+#endif
+
   /* Always let mbedTLS verify certificates, if verifypeer or verifyhost are
    * disabled we clear the corresponding error flags in the verify callback
    * function. That is also where we log verification errors. */
@@ -883,17 +875,27 @@
 
   /* Check if there is a cached ID we can/should use here! */
   if(ssl_config->primary.cache_session) {
-    void *old_session = NULL;
+    void *sdata = NULL;
+    size_t slen = 0;
 
     Curl_ssl_sessionid_lock(data);
-    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &old_session, NULL)) {
-      ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
+    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
+                              &sdata, &slen, NULL) && slen) {
+      mbedtls_ssl_session session;
+
+      mbedtls_ssl_session_init(&session);
+      ret = mbedtls_ssl_session_load(&session, sdata, slen);
       if(ret) {
-        Curl_ssl_sessionid_unlock(data);
-        failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
-        return CURLE_SSL_CONNECT_ERROR;
+        failf(data, "error loading cached session: -0x%x", -ret);
       }
-      infof(data, "mbedTLS reusing session");
+      else {
+        ret = mbedtls_ssl_set_session(&backend->ssl, &session);
+        if(ret)
+          failf(data, "error setting session: -0x%x", -ret);
+        else
+          infof(data, "SSL reusing session ID");
+      }
+      mbedtls_ssl_session_free(&session);
     }
     Curl_ssl_sessionid_unlock(data);
   }
@@ -911,7 +913,7 @@
                               &backend->clicert, &backend->pk);
   }
 
-  if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni?
+  if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni ?
                               connssl->peer.sni : connssl->peer.hostname)) {
     /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
        the name to set in the SNI extension. So even if curl connects to a
@@ -975,8 +977,8 @@
   struct mbed_ssl_backend_data *backend =
     (struct mbed_ssl_backend_data *)connssl->backend;
 #ifndef CURL_DISABLE_PROXY
-  const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
-    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+  const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf) ?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
     data->set.str[STRING_SSL_PINNEDPUBLICKEY];
 #else
   const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
@@ -1016,7 +1018,7 @@
     uint16_t cipher_id;
     cipher_id = (uint16_t)
                 mbedtls_ssl_get_ciphersuite_id_from_ssl(&backend->ssl);
-    mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), true);
+    mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), TRUE);
     infof(data, "mbedTLS: %s Handshake complete, cipher is %s",
           mbedtls_ssl_get_version(&backend->ssl), cipher_str);
   }
@@ -1059,7 +1061,7 @@
 
     /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
        needs a non-const key, for now.
-       https://github.com/ARMmbed/mbedtls/issues/396 */
+       https://github.com/Mbed-TLS/mbedtls/issues/396 */
 #if MBEDTLS_VERSION_NUMBER == 0x03000000
     if(mbedtls_x509_crt_parse_der(p,
                         peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
@@ -1102,8 +1104,8 @@
   if(connssl->alpn) {
     const char *proto = mbedtls_ssl_get_alpn_protocol(&backend->ssl);
 
-    Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto,
-                             proto? strlen(proto) : 0);
+    Curl_alpn_set_negotiated(cf, data, connssl, (const unsigned char *)proto,
+                             proto ? strlen(proto) : 0);
   }
 #endif
 
@@ -1113,57 +1115,62 @@
   return CURLE_OK;
 }
 
-static void mbedtls_session_free(void *sessionid, size_t idsize)
+static void mbedtls_session_free(void *session, size_t slen)
 {
-  (void)idsize;
-  mbedtls_ssl_session_free(sessionid);
-  free(sessionid);
+  (void)slen;
+  free(session);
 }
 
 static CURLcode
-mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
+mbed_new_session(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
-  CURLcode retcode = CURLE_OK;
   struct ssl_connect_data *connssl = cf->ctx;
   struct mbed_ssl_backend_data *backend =
     (struct mbed_ssl_backend_data *)connssl->backend;
   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+  CURLcode result = CURLE_OK;
 
-  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
   DEBUGASSERT(backend);
-
   if(ssl_config->primary.cache_session) {
     int ret;
-    mbedtls_ssl_session *our_ssl_sessionid;
+    mbedtls_ssl_session session;
+    unsigned char *sdata = NULL;
+    size_t slen = 0;
 
-    our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
-    if(!our_ssl_sessionid)
-      return CURLE_OUT_OF_MEMORY;
-
-    mbedtls_ssl_session_init(our_ssl_sessionid);
-
-    ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid);
+    mbedtls_ssl_session_init(&session);
+    ret = mbedtls_ssl_get_session(&backend->ssl, &session);
     if(ret) {
       if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED)
-        mbedtls_ssl_session_free(our_ssl_sessionid);
-      free(our_ssl_sessionid);
+        mbedtls_ssl_session_free(&session);
       failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
       return CURLE_SSL_CONNECT_ERROR;
     }
 
-    /* If there is already a matching session in the cache, delete it */
-    Curl_ssl_sessionid_lock(data);
-    retcode = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
-                                     our_ssl_sessionid, 0,
-                                     mbedtls_session_free);
-    Curl_ssl_sessionid_unlock(data);
-    if(retcode)
-      return retcode;
+    mbedtls_ssl_session_save(&session, NULL, 0, &slen);
+    if(!slen) {
+      failf(data, "failed to serialize session: length is 0");
+    }
+    else {
+      sdata = malloc(slen);
+      if(sdata) {
+        ret = mbedtls_ssl_session_save(&session, sdata, slen, &slen);
+        if(ret) {
+          failf(data, "failed to serialize session: -0x%x", -ret);
+        }
+        else {
+          Curl_ssl_sessionid_lock(data);
+          result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
+                                          sdata, slen, mbedtls_session_free);
+          Curl_ssl_sessionid_unlock(data);
+          if(!result)
+            sdata = NULL;
+        }
+      }
+    }
+    mbedtls_ssl_session_free(&session);
+    free(sdata);
   }
-
-  connssl->connecting_state = ssl_connect_done;
-
-  return CURLE_OK;
+  return result;
 }
 
 static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -1186,7 +1193,7 @@
 #ifdef TLS13_SUPPORT
       || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
 #endif
-      )? CURLE_AGAIN : CURLE_SEND_ERROR;
+      ) ? CURLE_AGAIN : CURLE_SEND_ERROR;
     ret = -1;
   }
 
@@ -1322,7 +1329,6 @@
   struct mbed_ssl_backend_data *backend =
     (struct mbed_ssl_backend_data *)connssl->backend;
   int ret = -1;
-  ssize_t len = -1;
 
   (void)data;
   DEBUGASSERT(backend);
@@ -1332,24 +1338,31 @@
   if(ret <= 0) {
     CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X",
                 buffersize, -ret);
-    if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
-      return 0;
-    *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
-#ifdef TLS13_SUPPORT
-              || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
+    switch(ret) {
+#ifdef HAS_SESSION_TICKETS
+    case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
+      mbed_new_session(cf, data);
+      FALLTHROUGH();
 #endif
-    ) ? CURLE_AGAIN : CURLE_RECV_ERROR;
-    if(*curlcode != CURLE_AGAIN) {
+    case MBEDTLS_ERR_SSL_WANT_READ:
+      *curlcode = CURLE_AGAIN;
+      ret = -1;
+      break;
+    case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+      *curlcode = CURLE_OK;
+      ret = 0;
+      break;
+    default: {
       char errorbuf[128];
       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
       failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf);
+      *curlcode = CURLE_RECV_ERROR;
+      ret = -1;
+      break;
     }
-    return -1;
+    }
   }
-
-  len = ret;
-
-  return len;
+  return (ssize_t)ret;
 }
 
 static size_t mbedtls_version(char *buffer, size_t size)
@@ -1357,42 +1370,31 @@
 #ifdef MBEDTLS_VERSION_C
   /* if mbedtls_version_get_number() is available it is better */
   unsigned int version = mbedtls_version_get_number();
-  return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version>>24,
-                   (version>>16)&0xff, (version>>8)&0xff);
+  return msnprintf(buffer, size, "mbedTLS/%u.%u.%u", version >> 24,
+                   (version >> 16) & 0xff, (version >> 8) & 0xff);
 #else
   return msnprintf(buffer, size, "mbedTLS/%s", MBEDTLS_VERSION_STRING);
 #endif
 }
 
+/* 'data' might be NULL */
 static CURLcode mbedtls_random(struct Curl_easy *data,
                                unsigned char *entropy, size_t length)
 {
 #if defined(MBEDTLS_CTR_DRBG_C)
-  int ret = -1;
-  char errorbuf[128];
+  int ret;
   mbedtls_entropy_context ctr_entropy;
   mbedtls_ctr_drbg_context ctr_drbg;
   mbedtls_entropy_init(&ctr_entropy);
   mbedtls_ctr_drbg_init(&ctr_drbg);
+  (void)data;
 
   ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
                               &ctr_entropy, NULL, 0);
 
-  if(ret) {
-    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-    failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s",
-          -ret, errorbuf);
-  }
-  else {
+  if(!ret)
     ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length);
 
-    if(ret) {
-      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-      failf(data, "mbedtls_ctr_drbg_random returned (-0x%04X) %s",
-            -ret, errorbuf);
-    }
-  }
-
   mbedtls_ctr_drbg_free(&ctr_drbg);
   mbedtls_entropy_free(&ctr_entropy);
 
@@ -1452,11 +1454,10 @@
 
     /* if ssl is expecting something, check if it is available. */
     if(connssl->io_need) {
-
-      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
-                              sockfd:CURL_SOCKET_BAD;
-      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
-                             sockfd:CURL_SOCKET_BAD;
+      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+        sockfd : CURL_SOCKET_BAD;
+      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+        sockfd : CURL_SOCKET_BAD;
 
       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                                nonblocking ? 0 : timeout_ms);
@@ -1495,9 +1496,22 @@
   } /* repeat step2 until all transactions are done. */
 
   if(ssl_connect_3 == connssl->connecting_state) {
-    retcode = mbed_connect_step3(cf, data);
-    if(retcode)
-      return retcode;
+    /* For tls1.3 we get notified about new sessions */
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
+    struct ssl_connect_data *ctx = cf->ctx;
+    struct mbed_ssl_backend_data *backend =
+      (struct mbed_ssl_backend_data *)ctx->backend;
+
+    if(mbedtls_ssl_get_version_number(&backend->ssl) <=
+       MBEDTLS_SSL_VERSION_TLS1_2) {
+#else
+    {  /* no TLSv1.3 supported here */
+#endif
+      retcode = mbed_new_session(cf, data);
+      if(retcode)
+        return retcode;
+    }
+    connssl->connecting_state = ssl_connect_done;
   }
 
   if(ssl_connect_done == connssl->connecting_state) {
@@ -1547,6 +1561,20 @@
 #ifdef THREADING_SUPPORT
   entropy_init_mutex(&ts_entropy);
 #endif
+#ifdef TLS13_SUPPORT
+  {
+    int ret;
+#ifdef THREADING_SUPPORT
+    Curl_mbedtlsthreadlock_lock_function(0);
+#endif
+    ret = psa_crypto_init();
+#ifdef THREADING_SUPPORT
+    Curl_mbedtlsthreadlock_unlock_function(0);
+#endif
+    if(ret != PSA_SUCCESS)
+      return 0;
+  }
+#endif /* TLS13_SUPPORT */
   return 1;
 }
 
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index 303dc1d..d2b146f 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -83,7 +83,7 @@
 #include <openssl/evp.h>
 
 #ifdef USE_ECH
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
 #  include <openssl/ech.h>
 # endif
 # include "curl_base64.h"
@@ -249,7 +249,7 @@
 #elif defined(OPENSSL_IS_AWSLC)
 #define OSSL_PACKAGE "AWS-LC"
 #else
-# if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
+# if (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_MSH3)
 #   define OSSL_PACKAGE "quictls"
 # else
 #   define OSSL_PACKAGE "OpenSSL"
@@ -929,7 +929,7 @@
   if(master_key_length <= 0)
     return;
 
-  *keylog_done = true;
+  *keylog_done = TRUE;
   Curl_tls_keylog_write("CLIENT_RANDOM", client_random,
                         master_key, master_key_length);
 }
@@ -1028,7 +1028,7 @@
  */
 static bool rand_enough(void)
 {
-  return (0 != RAND_status()) ? TRUE : FALSE;
+  return (0 != RAND_status());
 }
 
 static CURLcode ossl_seed(struct Curl_easy *data)
@@ -1165,9 +1165,8 @@
 
 static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine);
 
-static int
-SSL_CTX_use_certificate_blob(SSL_CTX *ctx, const struct curl_blob *blob,
-                             int type, const char *key_passwd)
+static int use_certificate_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+                                int type, const char *key_passwd)
 {
   int ret = 0;
   X509 *x = NULL;
@@ -1203,9 +1202,8 @@
   return ret;
 }
 
-static int
-SSL_CTX_use_PrivateKey_blob(SSL_CTX *ctx, const struct curl_blob *blob,
-                            int type, const char *key_passwd)
+static int use_privatekey_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+                               int type, const char *key_passwd)
 {
   int ret = 0;
   EVP_PKEY *pkey = NULL;
@@ -1218,14 +1216,12 @@
                                    (void *)key_passwd);
   else if(type == SSL_FILETYPE_ASN1)
     pkey = d2i_PrivateKey_bio(in, NULL);
-  else {
-    ret = 0;
+  else
     goto end;
-  }
-  if(!pkey) {
-    ret = 0;
+
+  if(!pkey)
     goto end;
-  }
+
   ret = SSL_CTX_use_PrivateKey(ctx, pkey);
   EVP_PKEY_free(pkey);
 end:
@@ -1234,8 +1230,8 @@
 }
 
 static int
-SSL_CTX_use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob,
-                                   const char *key_passwd)
+use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+                           const char *key_passwd)
 {
 /* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */
 #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* OpenSSL 1.0.2 or later */ \
@@ -1252,11 +1248,8 @@
 
   x = PEM_read_bio_X509_AUX(in, NULL,
                             passwd_callback, (void *)key_passwd);
-
-  if(!x) {
-    ret = 0;
+  if(!x)
     goto end;
-  }
 
   ret = SSL_CTX_use_certificate(ctx, x);
 
@@ -1337,7 +1330,7 @@
     case SSL_FILETYPE_PEM:
       /* SSL_CTX_use_certificate_chain_file() only works on PEM files */
       cert_use_result = cert_blob ?
-        SSL_CTX_use_certificate_chain_blob(ctx, cert_blob, key_passwd) :
+        use_certificate_chain_blob(ctx, cert_blob, key_passwd) :
         SSL_CTX_use_certificate_chain_file(ctx, cert_file);
       if(cert_use_result != 1) {
         failf(data,
@@ -1357,8 +1350,7 @@
          ASN1 files. */
 
       cert_use_result = cert_blob ?
-        SSL_CTX_use_certificate_blob(ctx, cert_blob,
-                                     file_type, key_passwd) :
+        use_certificate_blob(ctx, cert_blob, file_type, key_passwd) :
       SSL_CTX_use_certificate_file(ctx, cert_file, file_type);
       if(cert_use_result != 1) {
         failf(data,
@@ -1567,11 +1559,12 @@
       FALLTHROUGH();
     case SSL_FILETYPE_ASN1:
       cert_use_result = key_blob ?
-        SSL_CTX_use_PrivateKey_blob(ctx, key_blob, file_type, key_passwd) :
+        use_privatekey_blob(ctx, key_blob, file_type, key_passwd) :
       SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type);
       if(cert_use_result != 1) {
         failf(data, "unable to set private key file: '%s' type %s",
-              key_file?key_file:"(memory blob)", key_type?key_type:"PEM");
+              key_file ? key_file : "(memory blob)",
+              key_type ? key_type : "PEM");
         return 0;
       }
       break;
@@ -1693,29 +1686,23 @@
 }
 
 /* returns non-zero on failure */
-static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
+static CURLcode x509_name_oneline(X509_NAME *a, struct dynbuf *d)
 {
   BIO *bio_out = BIO_new(BIO_s_mem());
   BUF_MEM *biomem;
   int rc;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
 
-  if(!bio_out)
-    return 1; /* alloc failed! */
-
-  rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
-  BIO_get_mem_ptr(bio_out, &biomem);
-
-  if((size_t)biomem->length < size)
-    size = biomem->length;
-  else
-    size--; /* do not overwrite the buffer end */
-
-  memcpy(buf, biomem->data, size);
-  buf[size] = 0;
-
-  BIO_free(bio_out);
-
-  return !rc;
+  if(bio_out) {
+    Curl_dyn_reset(d);
+    rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
+    if(rc != -1) {
+      BIO_get_mem_ptr(bio_out, &biomem);
+      result = Curl_dyn_addn(d, biomem->data, biomem->length);
+      BIO_free(bio_out);
+    }
+  }
+  return result;
 }
 
 /**
@@ -1953,8 +1940,9 @@
 
   /* SSL should now have started the shutdown from our side. Since it
    * was not complete, we are lacking the close notify from the server. */
-  if(send_shutdown) {
+  if(send_shutdown && !(SSL_get_shutdown(octx->ssl) & SSL_SENT_SHUTDOWN)) {
     ERR_clear_error();
+    CURL_TRC_CF(data, cf, "send SSL close notify");
     if(SSL_shutdown(octx->ssl) == 1) {
       CURL_TRC_CF(data, cf, "SSL shutdown finished");
       *done = TRUE;
@@ -1979,7 +1967,10 @@
   err = SSL_get_error(octx->ssl, nread);
   switch(err) {
   case SSL_ERROR_ZERO_RETURN: /* no more data */
-    CURL_TRC_CF(data, cf, "SSL shutdown not received, but closed");
+    if(SSL_shutdown(octx->ssl) == 1)
+      CURL_TRC_CF(data, cf, "SSL shutdown finished");
+    else
+      CURL_TRC_CF(data, cf, "SSL shutdown not received, but closed");
     *done = TRUE;
     break;
   case SSL_ERROR_NONE: /* just did not get anything */
@@ -2247,8 +2238,9 @@
     /* we have to look to the last occurrence of a commonName in the
        distinguished one to get the most significant one. */
     int i = -1;
-    unsigned char *peer_CN = NULL;
-    int peerlen = 0;
+    unsigned char *cn = NULL;
+    int cnlen = 0;
+    bool free_cn = FALSE;
 
     /* The following is done because of a bug in 0.9.6b */
     X509_NAME *name = X509_get_subject_name(server_cert);
@@ -2272,21 +2264,17 @@
          conditional in the future when OpenSSL has been fixed. */
       if(tmp) {
         if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
-          peerlen = ASN1_STRING_length(tmp);
-          if(peerlen >= 0) {
-            peer_CN = OPENSSL_malloc(peerlen + 1);
-            if(peer_CN) {
-              memcpy(peer_CN, ASN1_STRING_get0_data(tmp), peerlen);
-              peer_CN[peerlen] = '\0';
-            }
-            else
-              result = CURLE_OUT_OF_MEMORY;
-          }
+          cnlen = ASN1_STRING_length(tmp);
+          cn = (unsigned char *) ASN1_STRING_get0_data(tmp);
         }
-        else /* not a UTF8 name */
-          peerlen = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+        else { /* not a UTF8 name */
+          cnlen = ASN1_STRING_to_UTF8(&cn, tmp);
+          free_cn = TRUE;
+        }
 
-        if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != peerlen)) {
+        if((cnlen <= 0) || !cn)
+          result = CURLE_OUT_OF_MEMORY;
+        else if((size_t)cnlen != strlen((char *)cn)) {
           /* there was a terminating zero before the end of string, this
              cannot match and we return failure! */
           failf(data, "SSL: illegal cert name field");
@@ -2298,22 +2286,22 @@
     if(result)
       /* error already detected, pass through */
       ;
-    else if(!peer_CN) {
+    else if(!cn) {
       failf(data,
             "SSL: unable to obtain common name from peer certificate");
       result = CURLE_PEER_FAILED_VERIFICATION;
     }
-    else if(!Curl_cert_hostcheck((const char *)peer_CN,
-                                 peerlen, peer->hostname, hostlen)) {
+    else if(!Curl_cert_hostcheck((const char *)cn, cnlen,
+                                 peer->hostname, hostlen)) {
       failf(data, "SSL: certificate subject name '%s' does not match "
-            "target hostname '%s'", peer_CN, peer->dispname);
+            "target hostname '%s'", cn, peer->dispname);
       result = CURLE_PEER_FAILED_VERIFICATION;
     }
     else {
-      infof(data, " common name: %s (matched)", peer_CN);
+      infof(data, " common name: %s (matched)", cn);
     }
-    if(peer_CN)
-      OPENSSL_free(peer_CN);
+    if(free_cn)
+      OPENSSL_free(cn);
   }
 
   return result;
@@ -2698,11 +2686,9 @@
 
     txt_len = msnprintf(ssl_buf, sizeof(ssl_buf),
                         "%s (%s), %s, %s (%d):\n",
-                        verstr, direction?"OUT":"IN",
+                        verstr, direction ? "OUT" : "IN",
                         tls_rt_name, msg_name, msg_type);
-    if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) {
-      Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len);
-    }
+    Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len);
   }
 
   Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
@@ -2943,8 +2929,8 @@
     }
 
     Curl_ssl_sessionid_lock(data);
-    result = Curl_ssl_set_sessionid(cf, data, peer, der_session_buf,
-     der_session_size, ossl_session_free);
+    result = Curl_ssl_set_sessionid(cf, data, peer, NULL, der_session_buf,
+                                    der_session_size, ossl_session_free);
     Curl_ssl_sessionid_unlock(data);
   }
 
@@ -2962,8 +2948,8 @@
   struct ssl_connect_data *connssl;
 
   cf = (struct Curl_cfilter*) SSL_get_app_data(ssl);
-  connssl = cf? cf->ctx : NULL;
-  data = connssl? CF_DATA_CURRENT(cf) : NULL;
+  connssl = cf ? cf->ctx : NULL;
+  data = connssl ? CF_DATA_CURRENT(cf) : NULL;
   Curl_ossl_add_session(cf, data, &connssl->peer, ssl_sessionid);
   return 0;
 }
@@ -3033,7 +3019,7 @@
   CURLcode result = CURLE_OK;
   HCERTSTORE hStore;
 
-  *imported = false;
+  *imported = FALSE;
 
   hStore = CertOpenSystemStoreA(0, name);
   if(hStore) {
@@ -3055,20 +3041,19 @@
       BYTE key_usage[2];
       DWORD req_size;
       const unsigned char *encoded_cert;
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-      char cert_name[256];
-#endif
-
       pContext = CertEnumCertificatesInStore(hStore, pContext);
       if(!pContext)
         break;
 
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-      if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
-                             NULL, cert_name, sizeof(cert_name))) {
-        strcpy(cert_name, "Unknown");
+      else {
+        char cert_name[256];
+        if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
+                               NULL, cert_name, sizeof(cert_name)))
+          infof(data, "SSL: unknown cert name");
+        else
+          infof(data, "SSL: Checking cert \"%s\"", cert_name);
       }
-      infof(data, "SSL: Checking cert \"%s\"", cert_name);
 #endif
       encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
       if(!encoded_cert)
@@ -3121,12 +3106,12 @@
           }
           else {
             DWORD i;
-            bool found = false;
+            bool found = FALSE;
 
             for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) {
               if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */,
                          enhkey_usage->rgpszUsageIdentifier[i])) {
-                found = true;
+                found = TRUE;
                 break;
               }
             }
@@ -3150,9 +3135,9 @@
          not OpenSSL. */
       if(X509_STORE_add_cert(store, x509) == 1) {
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-        infof(data, "SSL: Imported cert \"%s\"", cert_name);
+        infof(data, "SSL: Imported cert");
 #endif
-        *imported = true;
+        *imported = TRUE;
       }
       X509_free(x509);
     }
@@ -3184,11 +3169,11 @@
   const char * const ssl_capath = conn_config->CApath;
   const char * const ssl_crlfile = ssl_config->primary.CRLfile;
   const bool verifypeer = conn_config->verifypeer;
-  bool imported_native_ca = false;
-  bool imported_ca_info_blob = false;
+  bool imported_native_ca = FALSE;
+  bool imported_ca_info_blob = FALSE;
 
   CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
-              ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
+              ssl_cafile ? ssl_cafile : "none", !!ca_info_blob);
   if(!store)
     return CURLE_OUT_OF_MEMORY;
 
@@ -3206,14 +3191,14 @@
       };
       size_t i;
       for(i = 0; i < ARRAYSIZE(storeNames); ++i) {
-        bool imported = false;
+        bool imported = FALSE;
         result = import_windows_cert_store(data, storeNames[i], store,
                                            &imported);
         if(result)
           return result;
         if(imported) {
           infof(data, "successfully imported Windows %s store", storeNames[i]);
-          imported_native_ca = true;
+          imported_native_ca = TRUE;
         }
         else
           infof(data, "error importing Windows %s store, continuing anyway",
@@ -3228,7 +3213,7 @@
         return result;
       }
       else {
-        imported_ca_info_blob = true;
+        imported_ca_info_blob = TRUE;
         infof(data, "successfully imported CA certificate blob");
       }
     }
@@ -3392,9 +3377,9 @@
   X509_STORE *store = NULL;
 
   DEBUGASSERT(multi);
-  share = multi? Curl_hash_pick(&multi->proto_hash,
-                                (void *)MPROTO_OSSL_X509_KEY,
-                                sizeof(MPROTO_OSSL_X509_KEY)-1) : NULL;
+  share = multi ? Curl_hash_pick(&multi->proto_hash,
+                                 (void *)MPROTO_OSSL_X509_KEY,
+                                 sizeof(MPROTO_OSSL_X509_KEY)-1) : NULL;
   if(share && share->store &&
      !cached_x509_store_expired(data, share) &&
      !cached_x509_store_different(cf, share)) {
@@ -3702,14 +3687,14 @@
   SSL_CTX_set_mode(octx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
 #endif
 
-#ifdef HAS_ALPN
   if(alpn && alpn_len) {
+#ifdef HAS_ALPN
     if(SSL_CTX_set_alpn_protos(octx->ssl_ctx, alpn, (int)alpn_len)) {
       failf(data, "Error setting ALPN");
       return CURLE_SSL_CONNECT_ERROR;
     }
-  }
 #endif
+  }
 
   if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
     if(!result &&
@@ -3825,10 +3810,10 @@
         return result;
       octx->x509_store_setup = TRUE;
     }
-    Curl_set_in_callback(data, true);
+    Curl_set_in_callback(data, TRUE);
     result = (*data->set.ssl.fsslctx)(data, octx->ssl_ctx,
                                       data->set.ssl.fsslctxp);
-    Curl_set_in_callback(data, false);
+    Curl_set_in_callback(data, FALSE);
     if(result) {
       failf(data, "error signaled by ssl ctx callback");
       return result;
@@ -3877,15 +3862,15 @@
 
     if(data->set.tls_ech & CURLECH_GREASE) {
       infof(data, "ECH: will GREASE ClientHello");
-# ifdef OPENSSL_IS_BORINGSSL
+# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
       SSL_set_enable_ech_grease(octx->ssl, 1);
 # else
       SSL_set_options(octx->ssl, SSL_OP_ECH_GREASE);
 # endif
     }
     else if(data->set.tls_ech & CURLECH_CLA_CFG) {
-# ifdef OPENSSL_IS_BORINGSSL
-      /* have to do base64 decode here for boring */
+# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+      /* have to do base64 decode here for BoringSSL */
       const char *b64 = data->set.str[STRING_ECH_CONFIG];
 
       if(!b64) {
@@ -3945,7 +3930,7 @@
           size_t elen = rinfo->echconfiglist_len;
 
           infof(data, "ECH: ECHConfig from DoH HTTPS RR");
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
           if(SSL_ech_set1_echconfig(octx->ssl, ecl, elen) != 1) {
             infof(data, "ECH: SSL_ECH_set1_echconfig failed");
             if(data->set.tls_ech & CURLECH_HARD)
@@ -3953,7 +3938,7 @@
           }
 # else
           if(SSL_set1_ech_config_list(octx->ssl, ecl, elen) != 1) {
-            infof(data, "ECH: SSL_set1_ech_config_list failed (boring)");
+            infof(data, "ECH: SSL_set1_ech_config_list failed (BoringSSL)");
             if(data->set.tls_ech & CURLECH_HARD)
               return CURLE_SSL_CONNECT_ERROR;
           }
@@ -3971,7 +3956,7 @@
         Curl_resolv_unlink(data, &dns);
       }
     }
-# ifdef OPENSSL_IS_BORINGSSL
+# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
     if(trying_ech_now && outername) {
       infof(data, "ECH: setting public_name not supported with BoringSSL");
       return CURLE_SSL_CONNECT_ERROR;
@@ -3988,7 +3973,7 @@
         return CURLE_SSL_CONNECT_ERROR;
       }
     }
-# endif  /* not BORING */
+# endif  /* OPENSSL_IS_BORINGSSL || OPENSSL_IS_AWSLC */
     if(trying_ech_now
        && SSL_set_min_proto_version(octx->ssl, TLS1_3_VERSION) != 1) {
       infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
@@ -4000,10 +3985,10 @@
 #endif
 
   octx->reused_session = FALSE;
-  if(ssl_config->primary.cache_session && transport == TRNSPRT_TCP) {
+  if(ssl_config->primary.cache_session) {
     Curl_ssl_sessionid_lock(data);
     if(!Curl_ssl_getsessionid(cf, data, peer, (void **)&der_sessionid,
-      &der_sessionid_size)) {
+      &der_sessionid_size, NULL)) {
       /* we got a session id, use it! */
       ssl_session = d2i_SSL_SESSION(NULL, &der_sessionid,
         (long)der_sessionid_size);
@@ -4022,8 +4007,8 @@
         octx->reused_session = TRUE;
       }
       else {
-          Curl_ssl_sessionid_unlock(data);
-          return CURLE_SSL_CONNECT_ERROR;
+        Curl_ssl_sessionid_unlock(data);
+        return CURLE_SSL_CONNECT_ERROR;
       }
     }
     Curl_ssl_sessionid_unlock(data);
@@ -4099,7 +4084,7 @@
   CURLcode result = CURLE_OK;
   size_t rcl = 0;
   int rv = 1;
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
   char *inner = NULL;
   unsigned char *rcs = NULL;
   char *outer = NULL;
@@ -4114,7 +4099,7 @@
   /* nothing to trace if not doing ECH */
   if(!ECH_ENABLED(data))
     return;
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
   rv = SSL_ech_get_retry_config(ssl, &rcs, &rcl);
 # else
   SSL_get0_ech_retry_configs(ssl, &rcs, &rcl);
@@ -4131,23 +4116,23 @@
     if(!result && b64str)
       infof(data, "ECH: retry_configs %s", b64str);
     free(b64str);
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
     rv = SSL_ech_get_status(ssl, &inner, &outer);
     infof(data, "ECH: retry_configs for %s from %s, %d %d",
           inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
-#else
+# else
     rv = SSL_ech_accepted(ssl);
     servername_type = SSL_get_servername_type(ssl);
     inner = SSL_get_servername(ssl, servername_type);
     SSL_get0_ech_name_override(ssl, &outer, &out_name_len);
-    /* TODO: get the inner from boring */
+    /* TODO: get the inner from BoringSSL */
     infof(data, "ECH: retry_configs for %s from %s, %d %d",
           inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
-#endif
+# endif
   }
   else
     infof(data, "ECH: no retry_configs (rv = %d)", rv);
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
   OPENSSL_free((void *)rcs);
 # endif
   return;
@@ -4248,14 +4233,11 @@
         lerr = SSL_get_verify_result(octx->ssl);
         if(lerr != X509_V_OK) {
           ssl_config->certverifyresult = lerr;
-          msnprintf(error_buffer, sizeof(error_buffer),
-                    "SSL certificate problem: %s",
-                    X509_verify_cert_error_string(lerr));
+          failf(data, "SSL certificate problem: %s",
+                X509_verify_cert_error_string(lerr));
         }
         else
-          /* strcpy() is fine here as long as the string fits within
-             error_buffer */
-          strcpy(error_buffer, "SSL certificate verification failed");
+          failf(data, "%s", "SSL certificate verification failed");
       }
 #if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)
       /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
@@ -4265,12 +4247,13 @@
         /* If client certificate is required, communicate the
            error to client */
         result = CURLE_SSL_CLIENTCERT;
-        ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+        failf(data, "TLS cert problem: %s",
+              ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)));
       }
 #endif
 #ifdef USE_ECH
       else if((lib == ERR_LIB_SSL) &&
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
               (reason == SSL_R_ECH_REQUIRED)) {
 # else
               (reason == SSL_R_ECH_REJECTED)) {
@@ -4280,12 +4263,14 @@
         ossl_trace_ech_retry_configs(data, octx->ssl, reason);
 
         result = CURLE_ECH_REQUIRED;
-        ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+        failf(data, "ECH required: %s",
+              ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)));
       }
 #endif
       else {
         result = CURLE_SSL_CONNECT_ERROR;
-        ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+        failf(data, "TLS connect error: %s",
+              ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)));
       }
 
       /* detail is already set to the SSL error above */
@@ -4303,12 +4288,8 @@
         failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
               extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
               connssl->peer.hostname, connssl->peer.port);
-        return result;
       }
 
-      /* Could be a CERT problem */
-      failf(data, "%s", error_buffer);
-
       return result;
     }
   }
@@ -4333,11 +4314,11 @@
     infof(data, "SSL connection using %s / %s / %s / %s",
           SSL_get_version(octx->ssl),
           SSL_get_cipher(octx->ssl),
-          negotiated_group_name? negotiated_group_name : "[blank]",
+          negotiated_group_name ? negotiated_group_name : "[blank]",
           OBJ_nid2sn(psigtype_nid));
 
 #ifdef USE_ECH
-# ifndef OPENSSL_IS_BORINGSSL
+# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
     if(ECH_ENABLED(data)) {
       char *inner = NULL, *outer = NULL;
       const char *status = NULL;
@@ -4377,9 +4358,9 @@
         infof(data, "ECH: unexpected status %d",rv);
       }
       infof(data, "ECH: result: status is %s, inner is %s, outer is %s",
-             (status?status:"NULL"),
-             (inner?inner:"NULL"),
-             (outer?outer:"NULL"));
+            (status ? status : "NULL"),
+            (inner ? inner : "NULL"),
+            (outer ? outer : "NULL"));
       OPENSSL_free(inner);
       OPENSSL_free(outer);
       if(rv == SSL_ECH_STATUS_GREASE_ECH) {
@@ -4395,7 +4376,7 @@
    else {
       infof(data, "ECH: result: status is not attempted");
    }
-# endif  /* BORING */
+# endif  /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
 #endif  /* USE_ECH */
 
 #ifdef HAS_ALPN
@@ -4407,7 +4388,7 @@
       unsigned int len;
       SSL_get0_alpn_selected(octx->ssl, &neg_protocol, &len);
 
-      return Curl_alpn_set_negotiated(cf, data, neg_protocol, len);
+      return Curl_alpn_set_negotiated(cf, data, connssl, neg_protocol, len);
     }
 #endif
 
@@ -4542,6 +4523,8 @@
 #define infof_certstack(data, ssl)
 #endif
 
+#define MAX_CERT_NAME_LENGTH 2048
+
 CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   struct ossl_ctx *octx,
@@ -4551,18 +4534,19 @@
   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
   CURLcode result = CURLE_OK;
-  int rc;
   long lerr;
   X509 *issuer;
   BIO *fp = NULL;
   char error_buffer[256]="";
-  char buffer[2048];
   const char *ptr;
   BIO *mem = BIO_new(BIO_s_mem());
   bool strict = (conn_config->verifypeer || conn_config->verifyhost);
+  struct dynbuf dname;
 
   DEBUGASSERT(octx);
 
+  Curl_dyn_init(&dname, MAX_CERT_NAME_LENGTH);
+
   if(!mem) {
     failf(data,
           "BIO_new return NULL, " OSSL_PACKAGE
@@ -4587,11 +4571,11 @@
   }
 
   infof(data, "%s certificate:",
-        Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server");
+        Curl_ssl_cf_is_proxy(cf) ? "Proxy" : "Server");
 
-  rc = x509_name_oneline(X509_get_subject_name(octx->server_cert),
-                         buffer, sizeof(buffer));
-  infof(data, " subject: %s", rc?"[NONE]":buffer);
+  result = x509_name_oneline(X509_get_subject_name(octx->server_cert),
+                             &dname);
+  infof(data, " subject: %s", result ? "[NONE]" : Curl_dyn_ptr(&dname));
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   {
@@ -4615,19 +4599,21 @@
     if(result) {
       X509_free(octx->server_cert);
       octx->server_cert = NULL;
+      Curl_dyn_free(&dname);
       return result;
     }
   }
 
-  rc = x509_name_oneline(X509_get_issuer_name(octx->server_cert),
-                         buffer, sizeof(buffer));
-  if(rc) {
+  result = x509_name_oneline(X509_get_issuer_name(octx->server_cert),
+                             &dname);
+  if(result) {
     if(strict)
       failf(data, "SSL: could not get X509-issuer name");
     result = CURLE_PEER_FAILED_VERIFICATION;
   }
   else {
-    infof(data, " issuer: %s", buffer);
+    infof(data, " issuer: %s", Curl_dyn_ptr(&dname));
+    Curl_dyn_free(&dname);
 
     /* We could do all sorts of certificate verification stuff here before
        deallocating the certificate. */
@@ -4720,7 +4706,6 @@
     else
       infof(data, " SSL certificate verify ok.");
   }
-
   infof_certstack(data, octx->ssl);
 
 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
@@ -4736,7 +4721,7 @@
         bool incache;
         Curl_ssl_sessionid_lock(data);
         incache = !(Curl_ssl_getsessionid(cf, data, peer,
-                                          &old_ssl_sessionid, NULL));
+                                          &old_ssl_sessionid, NULL, NULL));
         if(incache) {
           infof(data, "Remove session ID again from cache");
           Curl_ssl_delsessionid(data, old_ssl_sessionid);
@@ -4756,8 +4741,8 @@
     result = CURLE_OK;
 
 #ifndef CURL_DISABLE_PROXY
-  ptr = Curl_ssl_cf_is_proxy(cf)?
-    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+  ptr = Curl_ssl_cf_is_proxy(cf) ?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
     data->set.str[STRING_SSL_PINNEDPUBLICKEY];
 #else
   ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
@@ -4843,11 +4828,10 @@
 
     /* if ssl is expecting something, check if it is available. */
     if(!nonblocking && connssl->io_need) {
-
-      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
-                              sockfd:CURL_SOCKET_BAD;
-      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
-                             sockfd:CURL_SOCKET_BAD;
+      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+        sockfd : CURL_SOCKET_BAD;
+      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+        sockfd : CURL_SOCKET_BAD;
 
       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                                timeout_ms);
@@ -5157,9 +5141,8 @@
   } while(cf->next);
 
   if(!octx) {
-    failf(data,
-          "Failed to find SSL backend for endpoint");
-    return CURLE_SSL_ENGINE_INITFAILED;
+    failf(data, "Failed to find the SSL filter");
+    return CURLE_BAD_FUNCTION_ARGUMENT;
   }
 
   cert = SSL_get1_peer_certificate(octx->ssl);
@@ -5230,9 +5213,9 @@
 #else
   return msnprintf(buffer, size, "%s/%lx.%lx.%lx",
                    OSSL_PACKAGE,
-                   (LIBRESSL_VERSION_NUMBER>>28)&0xf,
-                   (LIBRESSL_VERSION_NUMBER>>20)&0xff,
-                   (LIBRESSL_VERSION_NUMBER>>12)&0xff);
+                   (LIBRESSL_VERSION_NUMBER >> 28) & 0xf,
+                   (LIBRESSL_VERSION_NUMBER >> 20) & 0xff,
+                   (LIBRESSL_VERSION_NUMBER >> 12) & 0xff);
 #endif
 #elif defined(OPENSSL_IS_BORINGSSL)
 #ifdef CURL_BORINGSSL_VERSION
@@ -5283,9 +5266,9 @@
 #endif
                    ,
                    OSSL_PACKAGE,
-                   (ssleay_value>>28)&0xf,
-                   (ssleay_value>>20)&0xff,
-                   (ssleay_value>>12)&0xff,
+                   (ssleay_value >> 28) & 0xf,
+                   (ssleay_value >> 20) & 0xff,
+                   (ssleay_value >> 12) & 0xff,
                    sub);
 #endif /* OPENSSL_IS_BORINGSSL */
 }
diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c
index 02ed4ec..5d14348 100644
--- a/Utilities/cmcurl/lib/vtls/rustls.c
+++ b/Utilities/cmcurl/lib/vtls/rustls.c
@@ -37,6 +37,7 @@
 #include "sendf.h"
 #include "vtls.h"
 #include "vtls_int.h"
+#include "rustls.h"
 #include "select.h"
 #include "strerror.h"
 #include "multiif.h"
@@ -570,7 +571,7 @@
       break;
     default:
       failf(data, "rustls: unsupported minimum TLS version value");
-      return CURLE_SSL_ENGINE_INITFAILED;
+      return CURLE_BAD_FUNCTION_ARGUMENT;
     }
 
     switch(conn_config->version_max) {
@@ -588,7 +589,7 @@
     case CURL_SSLVERSION_MAX_TLSv1_0:
     default:
       failf(data, "rustls: unsupported maximum TLS version value");
-      return CURLE_SSL_ENGINE_INITFAILED;
+      return CURLE_BAD_FUNCTION_ARGUMENT;
     }
 
     cipher_suites = malloc(sizeof(cipher_suites) * (cipher_suites_len));
@@ -610,7 +611,7 @@
     if(result != RUSTLS_RESULT_OK) {
       failf(data,
             "rustls: failed to create crypto provider builder from default");
-      return CURLE_SSL_ENGINE_INITFAILED;
+      return CURLE_SSL_CIPHER;
     }
 
     result =
@@ -622,7 +623,7 @@
       failf(data,
             "rustls: failed to set ciphersuites for crypto provider builder");
       rustls_crypto_provider_builder_free(custom_provider_builder);
-      return CURLE_SSL_ENGINE_INITFAILED;
+      return CURLE_SSL_CIPHER;
     }
 
     result = rustls_crypto_provider_builder_build(
@@ -630,7 +631,7 @@
     if(result != RUSTLS_RESULT_OK) {
       failf(data, "rustls: failed to build custom crypto provider");
       rustls_crypto_provider_builder_free(custom_provider_builder);
-      return CURLE_SSL_ENGINE_INITFAILED;
+      return CURLE_SSL_CIPHER;
     }
 
     result = rustls_client_config_builder_new_custom(custom_provider,
@@ -640,7 +641,7 @@
     free(cipher_suites);
     if(result != RUSTLS_RESULT_OK) {
       failf(data, "rustls: failed to create client config");
-      return CURLE_SSL_ENGINE_INITFAILED;
+      return CURLE_SSL_CIPHER;
     }
   }
 
@@ -747,7 +748,7 @@
   if(result != RUSTLS_RESULT_OK) {
     failf(data, "rustls: failed to build client config");
     rustls_client_config_free(backend->config);
-    return CURLE_SSL_ENGINE_INITFAILED;
+    return CURLE_SSL_CONNECT_ERROR;
   }
 
   DEBUGASSERT(rconn == NULL);
@@ -768,11 +769,12 @@
 cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data,
   const struct rustls_connection *rconn)
 {
+  struct ssl_connect_data *const connssl = cf->ctx;
   const uint8_t *protocol = NULL;
   size_t len = 0;
 
   rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
-  Curl_alpn_set_negotiated(cf, data, protocol, len);
+  Curl_alpn_set_negotiated(cf, data, connssl, protocol, len);
 }
 
 /* Given an established network connection, do a TLS handshake.
@@ -852,7 +854,7 @@
           ver = "TLSv1.3";
         if(proto == RUSTLS_TLS_VERSION_TLSV1_2)
           ver = "TLSv1.2";
-        Curl_cipher_suite_get_str(cipher, buf, sizeof(buf), true);
+        Curl_cipher_suite_get_str(cipher, buf, sizeof(buf), TRUE);
         infof(data, "rustls: handshake complete, %s, cipher: %s",
               ver, buf);
       }
@@ -866,8 +868,8 @@
     wants_write = rustls_connection_wants_write(rconn) ||
                   backend->plain_out_buffered;
     DEBUGASSERT(wants_read || wants_write);
-    writefd = wants_write?sockfd:CURL_SOCKET_BAD;
-    readfd = wants_read?sockfd:CURL_SOCKET_BAD;
+    writefd = wants_write ? sockfd : CURL_SOCKET_BAD;
+    readfd = wants_read ? sockfd : CURL_SOCKET_BAD;
 
     /* check allowed time left */
     timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -878,7 +880,7 @@
       return CURLE_OPERATION_TIMEDOUT;
     }
 
-    socket_check_timeout = blocking?timeout_ms:0;
+    socket_check_timeout = blocking ? timeout_ms : 0;
 
     what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                              socket_check_timeout);
@@ -894,7 +896,7 @@
     }
     if(0 == what) {
       CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block",
-            wants_read&&wants_write ? "writing and reading" :
+            wants_read && wants_write ? "writing and reading" :
             wants_write ? "writing" : "reading");
       if(wants_write)
         connssl->io_need |= CURL_SSL_IO_NEED_SEND;
@@ -935,7 +937,7 @@
 
   /* We should never fall through the loop. We should return either because
      the handshake is done or because we cannot read/write without blocking. */
-  DEBUGASSERT(false);
+  DEBUGASSERT(FALSE);
 }
 
 static CURLcode
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index a9dcbe4..f4bbe4e 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -59,6 +59,17 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
+/* Some verbose debug messages are wrapped by SCH_DEV() instead of DEBUGF()
+ * and only shown if CURL_SCHANNEL_DEV_DEBUG was defined at build time. These
+ * messages are extra verbose and intended for curl developers debugging
+ * Schannel recv decryption.
+ */
+#ifdef CURL_SCHANNEL_DEV_DEBUG
+#define SCH_DEV(x) x
+#else
+#define SCH_DEV(x) do { } while(0)
+#endif
+
 /* ALPN requires version 8.1 of the Windows SDK, which was
    shipped with Visual Studio 2013, aka _MSC_VER 1800:
 
@@ -440,11 +451,6 @@
 }
 #endif
 
-static bool algo(const char *check, char *namep, size_t nlen)
-{
-  return (strlen(check) == nlen) && !strncmp(check, namep, nlen);
-}
-
 static CURLcode
 schannel_acquire_credential_handle(struct Curl_cfilter *cf,
                                    struct Curl_easy *data)
@@ -770,187 +776,14 @@
      curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT,
                                   VERSION_GREATER_THAN_EQUAL)) {
 
-    char *ciphers13 = 0;
-
-    bool disable_aes_gcm_sha384 = FALSE;
-    bool disable_aes_gcm_sha256 = FALSE;
-    bool disable_chacha_poly = FALSE;
-    bool disable_aes_ccm_8_sha256 = FALSE;
-    bool disable_aes_ccm_sha256 = FALSE;
-
     SCH_CREDENTIALS credentials = { 0 };
     TLS_PARAMETERS tls_parameters = { 0 };
-    CRYPTO_SETTINGS crypto_settings[4] = { { 0 } };
-    UNICODE_STRING blocked_ccm_modes[1] = { { 0 } };
-    UNICODE_STRING blocked_gcm_modes[1] = { { 0 } };
-
-    int crypto_settings_idx = 0;
-
-
-    /* If TLS 1.3 ciphers are explicitly listed, then
-     * disable all the ciphers and re-enable which
-     * ciphers the user has provided.
-     */
-    ciphers13 = conn_config->cipher_list13;
-    if(ciphers13) {
-      const int remaining_ciphers = 5;
-
-      /* detect which remaining ciphers to enable
-         and then disable everything else.
-      */
-
-      char *startCur = ciphers13;
-      int algCount = 0;
-      char *nameEnd;
-
-      disable_aes_gcm_sha384 = TRUE;
-      disable_aes_gcm_sha256 = TRUE;
-      disable_chacha_poly = TRUE;
-      disable_aes_ccm_8_sha256 = TRUE;
-      disable_aes_ccm_sha256 = TRUE;
-
-      while(startCur && (0 != *startCur) && (algCount < remaining_ciphers)) {
-        size_t n;
-        char *namep;
-        nameEnd = strchr(startCur, ':');
-        n = nameEnd ? (size_t)(nameEnd - startCur) : strlen(startCur);
-        namep = startCur;
-
-        if(disable_aes_gcm_sha384 &&
-           algo("TLS_AES_256_GCM_SHA384", namep, n)) {
-          disable_aes_gcm_sha384 = FALSE;
-        }
-        else if(disable_aes_gcm_sha256
-                && algo("TLS_AES_128_GCM_SHA256", namep, n)) {
-          disable_aes_gcm_sha256 = FALSE;
-        }
-        else if(disable_chacha_poly
-                && algo("TLS_CHACHA20_POLY1305_SHA256", namep, n)) {
-          disable_chacha_poly = FALSE;
-        }
-        else if(disable_aes_ccm_8_sha256
-                && algo("TLS_AES_128_CCM_8_SHA256", namep, n)) {
-          disable_aes_ccm_8_sha256 = FALSE;
-        }
-        else if(disable_aes_ccm_sha256
-                && algo("TLS_AES_128_CCM_SHA256", namep, n)) {
-          disable_aes_ccm_sha256 = FALSE;
-        }
-        else {
-          failf(data, "schannel: Unknown TLS 1.3 cipher: %.*s", (int)n, namep);
-          return CURLE_SSL_CIPHER;
-        }
-
-        startCur = nameEnd;
-        if(startCur)
-          startCur++;
-
-        algCount++;
-      }
-    }
-
-    if(disable_aes_gcm_sha384 && disable_aes_gcm_sha256
-       && disable_chacha_poly && disable_aes_ccm_8_sha256
-       && disable_aes_ccm_sha256) {
-      failf(data, "schannel: All available TLS 1.3 ciphers were disabled");
-      return CURLE_SSL_CIPHER;
-    }
-
-    /* Disable TLS_AES_128_CCM_8_SHA256 and/or TLS_AES_128_CCM_SHA256 */
-    if(disable_aes_ccm_8_sha256 || disable_aes_ccm_sha256) {
-      /*
-        Disallow AES_CCM algorithm.
-      */
-      blocked_ccm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_CCM);
-      blocked_ccm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_CCM);
-      blocked_ccm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_CCM;
-
-      crypto_settings[crypto_settings_idx].eAlgorithmUsage =
-        TlsParametersCngAlgUsageCipher;
-      crypto_settings[crypto_settings_idx].rgstrChainingModes =
-        blocked_ccm_modes;
-      crypto_settings[crypto_settings_idx].cChainingModes =
-        ARRAYSIZE(blocked_ccm_modes);
-      crypto_settings[crypto_settings_idx].strCngAlgId.Length =
-        sizeof(BCRYPT_AES_ALGORITHM);
-      crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
-        sizeof(BCRYPT_AES_ALGORITHM);
-      crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
-        (PWSTR)BCRYPT_AES_ALGORITHM;
-
-      /* only disabling one of the CCM modes */
-      if(disable_aes_ccm_8_sha256 != disable_aes_ccm_sha256) {
-        if(disable_aes_ccm_8_sha256)
-          crypto_settings[crypto_settings_idx].dwMinBitLength = 128;
-        else /* disable_aes_ccm_sha256 */
-          crypto_settings[crypto_settings_idx].dwMaxBitLength = 64;
-      }
-
-      crypto_settings_idx++;
-    }
-
-    /* Disable TLS_AES_256_GCM_SHA384 and/or TLS_AES_128_GCM_SHA256 */
-    if(disable_aes_gcm_sha384 || disable_aes_gcm_sha256) {
-
-      /*
-        Disallow AES_GCM algorithm
-      */
-      blocked_gcm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_GCM);
-      blocked_gcm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_GCM);
-      blocked_gcm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_GCM;
-
-      /* if only one is disabled, then explicitly disable the
-         digest cipher suite (sha384 or sha256) */
-      if(disable_aes_gcm_sha384 != disable_aes_gcm_sha256) {
-        crypto_settings[crypto_settings_idx].eAlgorithmUsage =
-          TlsParametersCngAlgUsageDigest;
-        crypto_settings[crypto_settings_idx].strCngAlgId.Length =
-          sizeof(disable_aes_gcm_sha384 ?
-                 BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
-        crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
-          sizeof(disable_aes_gcm_sha384 ?
-                 BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
-        crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
-          (PWSTR)(disable_aes_gcm_sha384 ?
-                  BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM);
-      }
-      else { /* Disable both AES_GCM ciphers */
-        crypto_settings[crypto_settings_idx].eAlgorithmUsage =
-          TlsParametersCngAlgUsageCipher;
-        crypto_settings[crypto_settings_idx].strCngAlgId.Length =
-          sizeof(BCRYPT_AES_ALGORITHM);
-        crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
-          sizeof(BCRYPT_AES_ALGORITHM);
-        crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
-          (PWSTR)BCRYPT_AES_ALGORITHM;
-      }
-
-      crypto_settings[crypto_settings_idx].rgstrChainingModes =
-        blocked_gcm_modes;
-      crypto_settings[crypto_settings_idx].cChainingModes = 1;
-
-      crypto_settings_idx++;
-    }
-
-    /*
-      Disable ChaCha20-Poly1305.
-    */
-    if(disable_chacha_poly) {
-      crypto_settings[crypto_settings_idx].eAlgorithmUsage =
-        TlsParametersCngAlgUsageCipher;
-      crypto_settings[crypto_settings_idx].strCngAlgId.Length =
-        sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM);
-      crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength =
-        sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM);
-      crypto_settings[crypto_settings_idx].strCngAlgId.Buffer =
-        (PWSTR)BCRYPT_CHACHA20_POLY1305_ALGORITHM;
-      crypto_settings_idx++;
-    }
+    CRYPTO_SETTINGS crypto_settings[1] = { { 0 } };
 
     tls_parameters.pDisabledCrypto = crypto_settings;
 
     /* The number of blocked suites */
-    tls_parameters.cDisabledCrypto = (DWORD)crypto_settings_idx;
+    tls_parameters.cDisabledCrypto = (DWORD)0;
     credentials.pTlsParameters = &tls_parameters;
     credentials.cTlsParameters = 1;
 
@@ -975,9 +808,8 @@
                                          &backend->cred->time_stamp);
   }
   else {
-    /* Pre-Windows 10 1809 or the user set a legacy algorithm list. Although MS
-       does not document it, currently Schannel will not negotiate TLS 1.3 when
-       SCHANNEL_CRED is used. */
+    /* Pre-Windows 10 1809 or the user set a legacy algorithm list.
+       Schannel will not negotiate TLS 1.3 when SCHANNEL_CRED is used. */
     ALG_ID algIds[NUM_CIPHERS];
     char *ciphers = conn_config->cipher_list;
     SCHANNEL_CRED schannel_cred = { 0 };
@@ -987,16 +819,10 @@
 
     if(ciphers) {
       if((enabled_protocols & SP_PROT_TLS1_3_CLIENT)) {
-        infof(data, "schannel: WARNING: This version of Schannel may "
-              "negotiate a less-secure TLS version than TLS 1.3 because the "
+        infof(data, "schannel: WARNING: This version of Schannel "
+              "negotiates a less-secure TLS version than TLS 1.3 because the "
               "user set an algorithm cipher list.");
       }
-      if(conn_config->cipher_list13) {
-        failf(data, "schannel: This version of Schannel does not support "
-              "setting an algorithm cipher list and TLS 1.3 cipher list at "
-              "the same time");
-        return CURLE_SSL_CIPHER;
-      }
       result = set_ssl_ciphers(&schannel_cred, ciphers, algIds);
       if(CURLE_OK != result) {
         failf(data, "schannel: Failed setting algorithm cipher list");
@@ -1090,14 +916,14 @@
     curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
                                  VERSION_GREATER_THAN_EQUAL);
 #else
-  backend->use_alpn = false;
+  backend->use_alpn = FALSE;
 #endif
 
 #ifdef _WIN32_WCE
 #ifdef HAS_MANUAL_VERIFY_API
   /* certificate validation on CE does not seem to work right; we will
    * do it following a more manual process. */
-  backend->use_manual_cred_validation = true;
+  backend->use_manual_cred_validation = TRUE;
 #else
 #error "compiler too old to support Windows CE requisite manual cert verify"
 #endif
@@ -1106,7 +932,7 @@
   if(conn_config->CAfile || conn_config->ca_info_blob) {
     if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
                                     VERSION_GREATER_THAN_EQUAL)) {
-      backend->use_manual_cred_validation = true;
+      backend->use_manual_cred_validation = TRUE;
     }
     else {
       failf(data, "schannel: this version of Windows is too old to support "
@@ -1115,7 +941,7 @@
     }
   }
   else
-    backend->use_manual_cred_validation = false;
+    backend->use_manual_cred_validation = FALSE;
 #else
   if(conn_config->CAfile || conn_config->ca_info_blob) {
     failf(data, "schannel: CA cert support not built in");
@@ -1130,7 +956,7 @@
   if(ssl_config->primary.cache_session) {
     Curl_ssl_sessionid_lock(data);
     if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
-                              (void **)&old_cred, NULL)) {
+                              (void **)&old_cred, NULL, NULL)) {
       backend->cred = old_cred;
       DEBUGF(infof(data, "schannel: reusing existing credential handle"));
 
@@ -1153,7 +979,7 @@
 
     /* A hostname associated with the credential is needed by
        InitializeSecurityContext for SNI and other reasons. */
-    snihost = connssl->peer.sni? connssl->peer.sni : connssl->peer.hostname;
+    snihost = connssl->peer.sni ? connssl->peer.sni : connssl->peer.hostname;
     backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
     if(!backend->cred->sni_hostname)
       return CURLE_OUT_OF_MEMORY;
@@ -1300,10 +1126,10 @@
                "sent %zd bytes", written));
 
   backend->recv_unrecoverable_err = CURLE_OK;
-  backend->recv_sspi_close_notify = false;
-  backend->recv_connection_closed = false;
-  backend->recv_renegotiating = false;
-  backend->encdata_is_incomplete = false;
+  backend->recv_sspi_close_notify = FALSE;
+  backend->recv_connection_closed = FALSE;
+  backend->recv_renegotiating = FALSE;
+  backend->encdata_is_incomplete = FALSE;
 
   /* continue to second handshake step */
   connssl->connecting_state = ssl_connect_2;
@@ -1332,7 +1158,7 @@
 
   DEBUGASSERT(backend);
 
-  doread = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? FALSE : TRUE;
+  doread = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ? FALSE : TRUE;
   connssl->io_need = CURL_SSL_IO_NEED_NONE;
 
   DEBUGF(infof(data,
@@ -1355,7 +1181,7 @@
 
   /* buffer to store previously received and encrypted data */
   if(!backend->encdata_buffer) {
-    backend->encdata_is_incomplete = false;
+    backend->encdata_is_incomplete = FALSE;
     backend->encdata_offset = 0;
     backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
     backend->encdata_buffer = malloc(backend->encdata_length);
@@ -1407,13 +1233,13 @@
 
       /* increase encrypted data buffer offset */
       backend->encdata_offset += nread;
-      backend->encdata_is_incomplete = false;
-      DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
+      backend->encdata_is_incomplete = FALSE;
+      SCH_DEV(infof(data, "schannel: encrypted data got %zd", nread));
     }
 
-    DEBUGF(infof(data,
-                 "schannel: encrypted data buffer: offset %zu length %zu",
-                 backend->encdata_offset, backend->encdata_length));
+    SCH_DEV(infof(data,
+                  "schannel: encrypted data buffer: offset %zu length %zu",
+                  backend->encdata_offset, backend->encdata_length));
 
     /* setup input buffers */
     InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset),
@@ -1447,7 +1273,7 @@
 
     /* check if the handshake was incomplete */
     if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
-      backend->encdata_is_incomplete = true;
+      backend->encdata_is_incomplete = TRUE;
       connssl->io_need = CURL_SSL_IO_NEED_RECV;
       DEBUGF(infof(data,
                    "schannel: received incomplete message, need more data"));
@@ -1527,8 +1353,8 @@
 
     /* check if there was additional remaining encrypted data */
     if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
-      DEBUGF(infof(data, "schannel: encrypted data length: %lu",
-                   inbuf[1].cbBuffer));
+      SCH_DEV(infof(data, "schannel: encrypted data length: %lu",
+                    inbuf[1].cbBuffer));
       /*
         There are two cases where we could be getting extra data here:
         1) If we are renegotiating a connection and the handshake is already
@@ -1571,8 +1397,8 @@
   }
 
 #ifndef CURL_DISABLE_PROXY
-  pubkey_ptr = Curl_ssl_cf_is_proxy(cf)?
-    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+  pubkey_ptr = Curl_ssl_cf_is_proxy(cf) ?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
     data->set.str[STRING_SSL_PINNEDPUBLICKEY];
 #else
   pubkey_ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
@@ -1617,9 +1443,9 @@
                     void *arg)
 {
   const CERT_CONTEXT *current_context = NULL;
-  bool should_continue = true;
-  bool first = true;
-  bool reverse_order = false;
+  bool should_continue = TRUE;
+  bool first = TRUE;
+  bool reverse_order = FALSE;
   while(should_continue &&
         (current_context = CertEnumCertificatesInStore(
           context->hCertStore,
@@ -1630,9 +1456,9 @@
        by comparing SECPKG_ATTR_REMOTE_CERT_CONTEXT's pbCertContext with the
        first certificate's pbCertContext. */
     if(first && context->pbCertEncoded != current_context->pbCertEncoded)
-      reverse_order = true;
+      reverse_order = TRUE;
     should_continue = func(current_context, reverse_order, arg);
-    first = false;
+    first = FALSE;
   }
 
   if(current_context)
@@ -1646,7 +1472,7 @@
   (void)reverse_order; /* unused */
   if(valid_cert_encoding(ccert_context))
     (*(int *)certs_count)++;
-  return true;
+  return TRUE;
 }
 
 struct Adder_args
@@ -1752,7 +1578,7 @@
        SecApplicationProtocolNegotiationStatus_Success) {
       unsigned char prev_alpn = cf->conn->alpn;
 
-      Curl_alpn_set_negotiated(cf, data, alpn_result.ProtocolId,
+      Curl_alpn_set_negotiated(cf, data, connssl, alpn_result.ProtocolId,
                                alpn_result.ProtocolIdSize);
       if(backend->recv_renegotiating) {
         if(prev_alpn != cf->conn->alpn &&
@@ -1766,7 +1592,7 @@
     }
     else {
       if(!backend->recv_renegotiating)
-        Curl_alpn_set_negotiated(cf, data, NULL, 0);
+        Curl_alpn_set_negotiated(cf, data, connssl, NULL, 0);
     }
   }
 #endif
@@ -1776,7 +1602,8 @@
     Curl_ssl_sessionid_lock(data);
     /* Up ref count since call takes ownership */
     backend->cred->refcount++;
-    result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, backend->cred,
+    result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
+                                    backend->cred,
                                     sizeof(struct Curl_schannel_cred),
                                     schannel_session_free);
     Curl_ssl_sessionid_unlock(data);
@@ -1863,10 +1690,10 @@
     /* if ssl is expecting something, check if it is available. */
     if(connssl->io_need) {
 
-      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
-                              sockfd : CURL_SOCKET_BAD;
-      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
-                             sockfd : CURL_SOCKET_BAD;
+      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+        sockfd : CURL_SOCKET_BAD;
+      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+        sockfd : CURL_SOCKET_BAD;
 
       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                                nonblocking ? 0 : timeout_ms);
@@ -2109,17 +1936,23 @@
    * cleanup. The pattern for return error is set *err, optional infof, goto
    * cleanup.
    *
+   * Some verbose debug messages are wrapped by SCH_DEV() instead of DEBUGF()
+   * and only shown if CURL_SCHANNEL_DEV_DEBUG was defined at build time. These
+   * messages are extra verbose and intended for curl developers debugging
+   * Schannel recv decryption.
+   *
    * Our priority is to always return as much decrypted data to the caller as
    * possible, even if an error occurs. The state of the decrypted buffer must
    * always be valid. Transfer of decrypted data to the caller's buffer is
    * handled in the cleanup.
    */
 
-  DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
+  SCH_DEV(infof(data, "schannel: client wants to read %zu bytes", len));
   *err = CURLE_OK;
 
   if(len && len <= backend->decdata_offset) {
-    infof(data, "schannel: enough decrypted data is already available");
+    SCH_DEV(infof(data,
+                  "schannel: enough decrypted data is already available"));
     goto cleanup;
   }
   else if(backend->recv_unrecoverable_err) {
@@ -2157,13 +1990,13 @@
       backend->encdata_buffer = reallocated_buffer;
       backend->encdata_length = reallocated_length;
       size = backend->encdata_length - backend->encdata_offset;
-      DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
-                   backend->encdata_length));
+      SCH_DEV(infof(data, "schannel: encdata_buffer resized %zu",
+                    backend->encdata_length));
     }
 
-    DEBUGF(infof(data,
-                 "schannel: encrypted data buffer: offset %zu length %zu",
-                 backend->encdata_offset, backend->encdata_length));
+    SCH_DEV(infof(data,
+                  "schannel: encrypted data buffer: offset %zu length %zu",
+                  backend->encdata_offset, backend->encdata_length));
 
     /* read encrypted data from socket */
     nread = Curl_conn_cf_recv(cf->next, data,
@@ -2173,27 +2006,25 @@
     if(*err) {
       nread = -1;
       if(*err == CURLE_AGAIN)
-        DEBUGF(infof(data,
-                     "schannel: recv returned CURLE_AGAIN"));
+        SCH_DEV(infof(data, "schannel: recv returned CURLE_AGAIN"));
       else if(*err == CURLE_RECV_ERROR)
         infof(data, "schannel: recv returned CURLE_RECV_ERROR");
       else
         infof(data, "schannel: recv returned error %d", *err);
     }
     else if(nread == 0) {
-      backend->recv_connection_closed = true;
+      backend->recv_connection_closed = TRUE;
       DEBUGF(infof(data, "schannel: server closed the connection"));
     }
     else if(nread > 0) {
       backend->encdata_offset += (size_t)nread;
-      backend->encdata_is_incomplete = false;
-      DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
+      backend->encdata_is_incomplete = FALSE;
+      SCH_DEV(infof(data, "schannel: encrypted data got %zd", nread));
     }
   }
 
-  DEBUGF(infof(data,
-               "schannel: encrypted data buffer: offset %zu length %zu",
-               backend->encdata_offset, backend->encdata_length));
+  SCH_DEV(infof(data, "schannel: encrypted data buffer: offset %zu length %zu",
+                backend->encdata_offset, backend->encdata_length));
 
   /* decrypt loop */
   while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
@@ -2221,8 +2052,8 @@
       /* check for successfully decrypted data, even before actual
          renegotiation or shutdown of the connection context */
       if(inbuf[1].BufferType == SECBUFFER_DATA) {
-        DEBUGF(infof(data, "schannel: decrypted data length: %lu",
-                     inbuf[1].cbBuffer));
+        SCH_DEV(infof(data, "schannel: decrypted data length: %lu",
+                      inbuf[1].cbBuffer));
 
         /* increase buffer in order to fit the received amount of data */
         size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
@@ -2254,16 +2085,16 @@
           backend->decdata_offset += size;
         }
 
-        DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
-        DEBUGF(infof(data,
-                     "schannel: decrypted cached: offset %zu length %zu",
-                     backend->decdata_offset, backend->decdata_length));
+        SCH_DEV(infof(data, "schannel: decrypted data added: %zu", size));
+        SCH_DEV(infof(data,
+                      "schannel: decrypted cached: offset %zu length %zu",
+                      backend->decdata_offset, backend->decdata_length));
       }
 
       /* check for remaining encrypted data */
       if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
-        DEBUGF(infof(data, "schannel: encrypted data length: %lu",
-                     inbuf[3].cbBuffer));
+        SCH_DEV(infof(data, "schannel: encrypted data length: %lu",
+                      inbuf[3].cbBuffer));
 
         /* check if the remaining data is less than the total amount
          * and therefore begins after the already processed data
@@ -2277,9 +2108,9 @@
           backend->encdata_offset = inbuf[3].cbBuffer;
         }
 
-        DEBUGF(infof(data,
-                     "schannel: encrypted cached: offset %zu length %zu",
-                     backend->encdata_offset, backend->encdata_length));
+        SCH_DEV(infof(data,
+                      "schannel: encrypted cached: offset %zu length %zu",
+                      backend->encdata_offset, backend->encdata_length));
       }
       else {
         /* reset encrypted buffer offset, because there is no data remaining */
@@ -2299,9 +2130,9 @@
         connssl->state = ssl_connection_negotiating;
         connssl->connecting_state = ssl_connect_2;
         connssl->io_need = CURL_SSL_IO_NEED_SEND;
-        backend->recv_renegotiating = true;
+        backend->recv_renegotiating = TRUE;
         *err = schannel_connect_common(cf, data, FALSE, &done);
-        backend->recv_renegotiating = false;
+        backend->recv_renegotiating = FALSE;
         if(*err) {
           infof(data, "schannel: renegotiation failed");
           goto cleanup;
@@ -2315,25 +2146,30 @@
       else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
         /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
            returned so we have to work around that in cleanup. */
-        backend->recv_sspi_close_notify = true;
+        backend->recv_sspi_close_notify = TRUE;
         if(!backend->recv_connection_closed)
-          backend->recv_connection_closed = true;
+          backend->recv_connection_closed = TRUE;
+        /* We received the close notify just fine, any error we got
+         * from the lower filters afterwards (e.g. the socket), is not
+         * an error on the TLS data stream. That one ended here. */
+        if(*err == CURLE_RECV_ERROR)
+          *err = CURLE_OK;
         infof(data,
               "schannel: server close notification received (close_notify)");
         goto cleanup;
       }
     }
     else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
-      backend->encdata_is_incomplete = true;
+      backend->encdata_is_incomplete = TRUE;
       if(!*err)
         *err = CURLE_AGAIN;
-      infof(data, "schannel: failed to decrypt data, need more data");
+      SCH_DEV(infof(data, "schannel: failed to decrypt data, need more data"));
       goto cleanup;
     }
     else {
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
       char buffer[STRERROR_LEN];
-      infof(data, "schannel: failed to read data from server: %s",
+      failf(data, "schannel: failed to read data from server: %s",
             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
 #endif
       *err = CURLE_RECV_ERROR;
@@ -2341,17 +2177,15 @@
     }
   }
 
-  DEBUGF(infof(data,
-               "schannel: encrypted data buffer: offset %zu length %zu",
-               backend->encdata_offset, backend->encdata_length));
+  SCH_DEV(infof(data, "schannel: encrypted data buffer: offset %zu length %zu",
+                backend->encdata_offset, backend->encdata_length));
 
-  DEBUGF(infof(data,
-               "schannel: decrypted data buffer: offset %zu length %zu",
-               backend->decdata_offset, backend->decdata_length));
+  SCH_DEV(infof(data, "schannel: decrypted data buffer: offset %zu length %zu",
+                backend->decdata_offset, backend->decdata_length));
 
 cleanup:
   /* Warning- there is no guarantee the encdata state is valid at this point */
-  DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
+  SCH_DEV(infof(data, "schannel: schannel_recv cleanup"));
 
   /* Error if the connection has closed without a close_notify.
 
@@ -2370,10 +2204,10 @@
                                                 VERSION_EQUAL);
 
     if(isWin2k && sspi_status == SEC_E_OK)
-      backend->recv_sspi_close_notify = true;
+      backend->recv_sspi_close_notify = TRUE;
     else {
       *err = CURLE_RECV_ERROR;
-      infof(data, "schannel: server closed abruptly (missing close_notify)");
+      failf(data, "schannel: server closed abruptly (missing close_notify)");
     }
   }
 
@@ -2387,10 +2221,10 @@
     memmove(backend->decdata_buffer, backend->decdata_buffer + size,
             backend->decdata_offset - size);
     backend->decdata_offset -= size;
-    DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
-    DEBUGF(infof(data,
-                 "schannel: decrypted data buffer: offset %zu length %zu",
-                 backend->decdata_offset, backend->decdata_length));
+    SCH_DEV(infof(data, "schannel: decrypted data returned %zu", size));
+    SCH_DEV(infof(data,
+                  "schannel: decrypted data buffer: offset %zu length %zu",
+                  backend->decdata_offset, backend->decdata_length));
     *err = CURLE_OK;
     return (ssize_t)size;
   }
@@ -2536,7 +2370,7 @@
       if(!result) {
         if(written < (ssize_t)outbuf.cbBuffer) {
           /* TODO: handle partial sends */
-          infof(data, "schannel: failed to send close msg: %s"
+          failf(data, "schannel: failed to send close msg: %s"
                 " (bytes written: %zd)", curl_easy_strerror(result), written);
           result = CURLE_SEND_ERROR;
           goto out;
@@ -2551,7 +2385,7 @@
       }
       else {
         if(!backend->recv_connection_closed) {
-          infof(data, "schannel: error sending close msg: %d", result);
+          failf(data, "schannel: error sending close msg: %d", result);
           result = CURLE_SEND_ERROR;
           goto out;
         }
@@ -2622,7 +2456,7 @@
     Curl_safefree(backend->encdata_buffer);
     backend->encdata_length = 0;
     backend->encdata_offset = 0;
-    backend->encdata_is_incomplete = false;
+    backend->encdata_is_incomplete = FALSE;
   }
 
   /* free internal buffer for received decrypted data */
@@ -2732,7 +2566,7 @@
                               DWORD provType,
                               const unsigned int algId)
 {
-#ifdef CURL_WINDOWS_APP
+#ifdef CURL_WINDOWS_UWP
   (void)input;
   (void)inputlen;
   (void)provType;
@@ -2896,7 +2730,7 @@
   DEBUGASSERT(multi);
 
   if(!multi) {
-    return false;
+    return FALSE;
   }
 
   share = Curl_hash_pick(&multi->proto_hash,
@@ -2905,14 +2739,14 @@
   if(!share) {
     share = calloc(1, sizeof(*share));
     if(!share) {
-      return false;
+      return FALSE;
     }
     if(!Curl_hash_add2(&multi->proto_hash,
                        (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
                        sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1,
                        share, schannel_cert_share_free)) {
       free(share);
-      return false;
+      return FALSE;
     }
   }
 
@@ -2927,7 +2761,7 @@
     if(conn_config->CAfile) {
       CAfile = strdup(conn_config->CAfile);
       if(!CAfile) {
-        return false;
+        return FALSE;
       }
     }
   }
@@ -2942,7 +2776,7 @@
   share->cert_store = cert_store;
   share->CAinfo_blob_size = CAinfo_blob_size;
   share->CAfile = CAfile;
-  return true;
+  return TRUE;
 }
 
 const struct Curl_ssl Curl_ssl_schannel = {
@@ -2952,10 +2786,9 @@
 #ifdef HAS_MANUAL_VERIFY_API
   SSLSUPP_CAINFO_BLOB |
 #endif
-#ifndef CURL_WINDOWS_APP
+#ifndef CURL_WINDOWS_UWP
   SSLSUPP_PINNEDPUBKEY |
 #endif
-  SSLSUPP_TLS13_CIPHERSUITES |
   SSLSUPP_CA_CACHE |
   SSLSUPP_HTTPS_PROXY |
   SSLSUPP_CIPHER_LIST,
diff --git a/Utilities/cmcurl/lib/vtls/schannel_int.h b/Utilities/cmcurl/lib/vtls/schannel_int.h
index 800fdf8..81476bc 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_int.h
+++ b/Utilities/cmcurl/lib/vtls/schannel_int.h
@@ -31,7 +31,7 @@
 #include "vtls.h"
 
 #if (defined(__MINGW32__) || defined(CERT_CHAIN_REVOCATION_CHECK_CHAIN)) \
-  && !defined(CURL_WINDOWS_APP)
+  && !defined(CURL_WINDOWS_UWP)
 #define HAS_MANUAL_VERIFY_API
 #endif
 
@@ -176,6 +176,17 @@
   struct curltime time;              /* when the cached store was created */
 };
 
+/*
+* size of the structure: 20 bytes.
+*/
+struct num_ip_data {
+  DWORD size; /* 04 bytes */
+  union {
+    struct in_addr  ia;  /* 04 bytes */
+    struct in6_addr ia6; /* 16 bytes */
+  } bData;
+};
+
 HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
                                                const struct Curl_easy *data);
 
diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c
index 11e61b6..fede390 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_verify.c
+++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c
@@ -39,6 +39,7 @@
 #include "schannel.h"
 #include "schannel_int.h"
 
+#include "inet_pton.h"
 #include "vtls.h"
 #include "vtls_int.h"
 #include "sendf.h"
@@ -54,7 +55,6 @@
 
 #define BACKEND ((struct schannel_ssl_backend_data *)connssl->backend)
 
-
 #ifdef HAS_MANUAL_VERIFY_API
 
 #define MAX_CAFILE_SIZE 1048576 /* 1 MiB */
@@ -116,7 +116,7 @@
   const char *current_ca_file_ptr = ca_buffer;
   const char *ca_buffer_limit = ca_buffer + ca_buffer_size;
 
-  while(more_certs && (current_ca_file_ptr<ca_buffer_limit)) {
+  while(more_certs && (current_ca_file_ptr < ca_buffer_limit)) {
     const char *begin_cert_ptr = c_memmem(current_ca_file_ptr,
                                           ca_buffer_limit-current_ca_file_ptr,
                                           BEGIN_CERT,
@@ -343,29 +343,26 @@
 static DWORD cert_get_name_string(struct Curl_easy *data,
                                   CERT_CONTEXT *cert_context,
                                   LPTSTR host_names,
-                                  DWORD length)
+                                  DWORD length,
+                                  PCERT_ALT_NAME_INFO alt_name_info,
+                                  BOOL Win8_compat)
 {
   DWORD actual_length = 0;
-#if defined(CURL_WINDOWS_APP)
+#if defined(CURL_WINDOWS_UWP)
   (void)data;
   (void)cert_context;
   (void)host_names;
   (void)length;
+  (void)alt_name_info;
+  (void)Win8_compat;
 #else
   BOOL compute_content = FALSE;
-  CERT_INFO *cert_info = NULL;
-  CERT_EXTENSION *extension = NULL;
-  CRYPT_DECODE_PARA decode_para = {0, 0, 0};
-  CERT_ALT_NAME_INFO *alt_name_info = NULL;
-  DWORD alt_name_info_size = 0;
-  BOOL ret_val = FALSE;
   LPTSTR current_pos = NULL;
   DWORD i;
 
 #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
   /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */
-  if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
-                                  VERSION_GREATER_THAN_EQUAL)) {
+  if(Win8_compat) {
     /* CertGetNameString will provide the 8-bit character string without
      * any decoding */
     DWORD name_flags =
@@ -378,6 +375,9 @@
                                       length);
     return actual_length;
   }
+#else
+  (void)cert_context;
+  (void)Win8_compat;
 #endif
 
   compute_content = host_names != NULL && length != 0;
@@ -388,43 +388,6 @@
     *host_names = '\0';
   }
 
-  if(!cert_context) {
-    failf(data, "schannel: Null certificate context.");
-    return actual_length;
-  }
-
-  cert_info = cert_context->pCertInfo;
-  if(!cert_info) {
-    failf(data, "schannel: Null certificate info.");
-    return actual_length;
-  }
-
-  extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
-                                cert_info->cExtension,
-                                cert_info->rgExtension);
-  if(!extension) {
-    failf(data, "schannel: CertFindExtension() returned no extension.");
-    return actual_length;
-  }
-
-  decode_para.cbSize = sizeof(CRYPT_DECODE_PARA);
-
-  ret_val =
-    CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
-                        szOID_SUBJECT_ALT_NAME2,
-                        extension->Value.pbData,
-                        extension->Value.cbData,
-                        CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
-                        &decode_para,
-                        &alt_name_info,
-                        &alt_name_info_size);
-  if(!ret_val) {
-    failf(data,
-          "schannel: CryptDecodeObjectEx() returned no alternate name "
-          "information.");
-    return actual_length;
-  }
-
   current_pos = host_names;
 
   /* Iterate over the alternate names and populate host_names. */
@@ -467,6 +430,88 @@
   return actual_length;
 }
 
+/*
+* Returns TRUE if the hostname is a numeric IPv4/IPv6 Address,
+* and populates the buffer with IPv4/IPv6 info.
+*/
+
+static bool get_num_host_info(struct num_ip_data *ip_blob,
+                              LPCSTR hostname)
+{
+  struct in_addr ia;
+  struct in6_addr ia6;
+  bool result = FALSE;
+
+  int res = Curl_inet_pton(AF_INET, hostname, &ia);
+  if(res) {
+    ip_blob->size = sizeof(struct in_addr);
+    memcpy(&ip_blob->bData.ia, &ia, sizeof(struct in_addr));
+    result = TRUE;
+  }
+  else {
+    res = Curl_inet_pton(AF_INET6, hostname, &ia6);
+    if(res) {
+      ip_blob->size = sizeof(struct in6_addr);
+      memcpy(&ip_blob->bData.ia6, &ia6, sizeof(struct in6_addr));
+      result = TRUE;
+    }
+  }
+  return result;
+}
+
+static bool get_alt_name_info(struct Curl_easy *data,
+                              PCCERT_CONTEXT ctx,
+                              PCERT_ALT_NAME_INFO *alt_name_info,
+                              LPDWORD alt_name_info_size)
+{
+  bool result = FALSE;
+#if defined(CURL_WINDOWS_UWP)
+  (void)data;
+  (void)ctx;
+  (void)alt_name_info;
+  (void)alt_name_info_size;
+#else
+  PCERT_INFO cert_info = NULL;
+  PCERT_EXTENSION extension = NULL;
+  CRYPT_DECODE_PARA decode_para = { sizeof(CRYPT_DECODE_PARA), NULL, NULL };
+
+  if(!ctx) {
+    failf(data, "schannel: Null certificate context.");
+    return result;
+  }
+
+  cert_info = ctx->pCertInfo;
+  if(!cert_info) {
+    failf(data, "schannel: Null certificate info.");
+    return result;
+  }
+
+  extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
+                                cert_info->cExtension,
+                                cert_info->rgExtension);
+  if(!extension) {
+    failf(data, "schannel: CertFindExtension() returned no extension.");
+    return result;
+  }
+
+  if(!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+                          szOID_SUBJECT_ALT_NAME2,
+                          extension->Value.pbData,
+                          extension->Value.cbData,
+                          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
+                          &decode_para,
+                          alt_name_info,
+                          alt_name_info_size)) {
+    failf(data,
+          "schannel: CryptDecodeObjectEx() returned no alternate name "
+          "information.");
+    return result;
+  }
+  result = TRUE;
+#endif
+  return result;
+}
+
 /* Verify the server's hostname */
 CURLcode Curl_verify_host(struct Curl_cfilter *cf,
                           struct Curl_easy *data)
@@ -481,6 +526,12 @@
   size_t hostlen = strlen(conn_hostname);
   DWORD len = 0;
   DWORD actual_len = 0;
+  PCERT_ALT_NAME_INFO alt_name_info = NULL;
+  DWORD alt_name_info_size = 0;
+  struct num_ip_data ip_blob = { 0 };
+  bool Win8_compat;
+  struct num_ip_data *p = &ip_blob;
+  DWORD i;
 
   sspi_status =
     Curl_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
@@ -491,97 +542,122 @@
     char buffer[STRERROR_LEN];
     failf(data, "schannel: Failed to read remote certificate context: %s",
           Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
-    result = CURLE_PEER_FAILED_VERIFICATION;
     goto cleanup;
   }
 
-  /* Determine the size of the string needed for the cert hostname */
-  len = cert_get_name_string(data, pCertContextServer, NULL, 0);
-  if(len == 0) {
-    failf(data,
-          "schannel: CertGetNameString() returned no "
-          "certificate name information");
-    result = CURLE_PEER_FAILED_VERIFICATION;
-    goto cleanup;
-  }
-
-  /* CertGetNameString guarantees that the returned name will not contain
-   * embedded null bytes. This appears to be undocumented behavior.
-   */
-  cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR));
-  if(!cert_hostname_buff) {
-    result = CURLE_OUT_OF_MEMORY;
-    goto cleanup;
-  }
-  actual_len = cert_get_name_string(
-    data, pCertContextServer, (LPTSTR)cert_hostname_buff, len);
-
-  /* Sanity check */
-  if(actual_len != len) {
-    failf(data,
-          "schannel: CertGetNameString() returned certificate "
-          "name information of unexpected size");
-    result = CURLE_PEER_FAILED_VERIFICATION;
-    goto cleanup;
-  }
-
-  /* cert_hostname_buff contains all DNS names, where each name is
-   * null-terminated and the last DNS name is double null-terminated. Due to
-   * this encoding, use the length of the buffer to iterate over all names.
-   */
-  result = CURLE_PEER_FAILED_VERIFICATION;
-  while(cert_hostname_buff_index < len &&
-        cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') &&
-        result == CURLE_PEER_FAILED_VERIFICATION) {
-
-    char *cert_hostname;
-
-    /* Comparing the cert name and the connection hostname encoded as UTF-8
-     * is acceptable since both values are assumed to use ASCII
-     * (or some equivalent) encoding
-     */
-    cert_hostname = curlx_convert_tchar_to_UTF8(
-      &cert_hostname_buff[cert_hostname_buff_index]);
-    if(!cert_hostname) {
-      result = CURLE_OUT_OF_MEMORY;
+  Win8_compat = curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
+                                             VERSION_GREATER_THAN_EQUAL);
+  if(get_num_host_info(p, conn_hostname) || !Win8_compat) {
+    if(!get_alt_name_info(data, pCertContextServer,
+                          &alt_name_info, &alt_name_info_size)) {
+      goto cleanup;
     }
-    else {
-      if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname),
-                             conn_hostname, hostlen)) {
-        infof(data,
-              "schannel: connection hostname (%s) validated "
-              "against certificate name (%s)",
-              conn_hostname, cert_hostname);
-        result = CURLE_OK;
+  }
+
+  if(p->size && alt_name_info) {
+    for(i = 0; i < alt_name_info->cAltEntry; ++i) {
+      PCERT_ALT_NAME_ENTRY entry = &alt_name_info->rgAltEntry[i];
+      if(entry->dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS) {
+        if(entry->IPAddress.cbData == p->size) {
+          if(!memcmp(entry->IPAddress.pbData, &p->bData,
+                     entry->IPAddress.cbData)) {
+            result = CURLE_OK;
+            infof(data,
+             "schannel: connection hostname (%s) matched cert's IP address!",
+             conn_hostname);
+            break;
+          }
+        }
+      }
+    }
+  }
+  else {
+    /* Determine the size of the string needed for the cert hostname */
+    len = cert_get_name_string(data, pCertContextServer,
+                               NULL, 0, alt_name_info, Win8_compat);
+    if(len == 0) {
+      failf(data,
+            "schannel: CertGetNameString() returned no "
+            "certificate name information");
+      goto cleanup;
+    }
+
+    /* CertGetNameString guarantees that the returned name will not contain
+     * embedded null bytes. This appears to be undocumented behavior.
+     */
+    cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR));
+    if(!cert_hostname_buff) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto cleanup;
+    }
+    actual_len = cert_get_name_string(data, pCertContextServer,
+                 (LPTSTR)cert_hostname_buff, len, alt_name_info, Win8_compat);
+
+    /* Sanity check */
+    if(actual_len != len) {
+      failf(data,
+      "schannel: CertGetNameString() returned certificate "
+      "name information of unexpected size");
+      goto cleanup;
+    }
+
+    /* cert_hostname_buff contains all DNS names, where each name is
+     * null-terminated and the last DNS name is double null-terminated. Due to
+     * this encoding, use the length of the buffer to iterate over all names.
+     */
+    while(cert_hostname_buff_index < len &&
+          cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') &&
+          result == CURLE_PEER_FAILED_VERIFICATION) {
+
+      char *cert_hostname;
+
+      /* Comparing the cert name and the connection hostname encoded as UTF-8
+       * is acceptable since both values are assumed to use ASCII
+       * (or some equivalent) encoding
+       */
+      cert_hostname = curlx_convert_tchar_to_UTF8(
+      &cert_hostname_buff[cert_hostname_buff_index]);
+      if(!cert_hostname) {
+        result = CURLE_OUT_OF_MEMORY;
       }
       else {
-        size_t cert_hostname_len;
+        if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname),
+                               conn_hostname, hostlen)) {
+          infof(data,
+                "schannel: connection hostname (%s) validated "
+                "against certificate name (%s)",
+                conn_hostname, cert_hostname);
+          result = CURLE_OK;
+        }
+        else {
+          size_t cert_hostname_len;
 
-        infof(data,
-              "schannel: connection hostname (%s) did not match "
-              "against certificate name (%s)",
-              conn_hostname, cert_hostname);
+          infof(data,
+                "schannel: connection hostname (%s) did not match "
+                "against certificate name (%s)",
+                conn_hostname, cert_hostname);
 
-        cert_hostname_len =
-          _tcslen(&cert_hostname_buff[cert_hostname_buff_index]);
+          cert_hostname_len =
+            _tcslen(&cert_hostname_buff[cert_hostname_buff_index]);
 
-        /* Move on to next cert name */
-        cert_hostname_buff_index += cert_hostname_len + 1;
+          /* Move on to next cert name */
+          cert_hostname_buff_index += cert_hostname_len + 1;
 
-        result = CURLE_PEER_FAILED_VERIFICATION;
+          result = CURLE_PEER_FAILED_VERIFICATION;
+        }
+        curlx_unicodefree(cert_hostname);
       }
-      curlx_unicodefree(cert_hostname);
     }
-  }
 
-  if(result == CURLE_PEER_FAILED_VERIFICATION) {
-    failf(data,
-          "schannel: CertGetNameString() failed to match "
-          "connection hostname (%s) against server certificate names",
-          conn_hostname);
+    if(result == CURLE_PEER_FAILED_VERIFICATION) {
+      failf(data,
+            "schannel: CertGetNameString() failed to match "
+            "connection hostname (%s) against server certificate names",
+            conn_hostname);
+    }
+    else if(result != CURLE_OK)
+      failf(data, "schannel: server certificate name verification failed");
   }
-  else if(result != CURLE_OK)
-    failf(data, "schannel: server certificate name verification failed");
 
 cleanup:
   Curl_safefree(cert_hostname_buff);
@@ -592,7 +668,6 @@
   return result;
 }
 
-
 #ifdef HAS_MANUAL_VERIFY_API
 /* Verify the server's certificate and hostname */
 CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c
index 0eb079b..c6a1c73 100644
--- a/Utilities/cmcurl/lib/vtls/sectransp.c
+++ b/Utilities/cmcurl/lib/vtls/sectransp.c
@@ -24,7 +24,7 @@
  ***************************************************************************/
 
 /*
- * Source file for all iOS and macOS SecureTransport-specific code for the
+ * Source file for all iOS and macOS Secure Transport-specific code for the
  * TLS/SSL layer. No code but vtls.c should ever call or use these functions.
  */
 
@@ -197,7 +197,7 @@
   TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,      /* 0xCCA8 */
   TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,    /* 0xCCA9 */
 
-  /* TLSv1.3 is not supported by sectransp, but there is also other
+  /* TLSv1.3 is not supported by Secure Transport, but there is also other
    * code referencing TLSv1.3, like: kTLSProtocol13 ? */
   TLS_AES_128_GCM_SHA256,                           /* 0x1301 */
   TLS_AES_256_GCM_SHA384,                           /* 0x1302 */
@@ -278,7 +278,7 @@
       case CURLE_OK:
       case CURLE_AGAIN:
         rtn = errSSLWouldBlock;
-        backend->ssl_direction = false;
+        backend->ssl_direction = FALSE;
         break;
       default:
         rtn = ioErr;
@@ -317,7 +317,7 @@
   if(nwritten <= 0) {
     if(result == CURLE_AGAIN) {
       rtn = errSSLWouldBlock;
-      backend->ssl_direction = true;
+      backend->ssl_direction = TRUE;
     }
     else {
       rtn = ioErr;
@@ -354,8 +354,8 @@
   }
 
   /* Parse the version: */
-  os_version_major = strtok_r(os_version, ".", &tok_buf);
-  os_version_minor = strtok_r(NULL, ".", &tok_buf);
+  os_version_major = Curl_strtok_r(os_version, ".", &tok_buf);
+  os_version_minor = Curl_strtok_r(NULL, ".", &tok_buf);
   *major = atoi(os_version_major);
   *minor = atoi(os_version_minor);
   free(os_version);
@@ -512,7 +512,7 @@
                                     * label matching below worked correctly */
     keys[2] = kSecMatchLimit;
     /* identity searches need a SecPolicyRef in order to work */
-    values[3] = SecPolicyCreateSSL(false, NULL);
+    values[3] = SecPolicyCreateSSL(FALSE, NULL);
     keys[3] = kSecMatchPolicy;
     /* match the name of the certificate (does not work in macOS 10.12.1) */
     values[4] = label_cf;
@@ -532,7 +532,7 @@
       keys_list_count = CFArrayGetCount(keys_list);
       *out_cert_and_key = NULL;
       status = 1;
-      for(i = 0; i<keys_list_count; i++) {
+      for(i = 0; i < keys_list_count; i++) {
         OSStatus err = noErr;
         SecCertificateRef cert = NULL;
         SecIdentityRef identity =
@@ -609,7 +609,7 @@
     pkcs_url =
       CFURLCreateFromFileSystemRepresentation(NULL,
                                               (const UInt8 *)cPath,
-                                              (CFIndex)strlen(cPath), false);
+                                              (CFIndex)strlen(cPath), FALSE);
     resource_imported =
       CFURLCreateDataAndPropertiesFromResource(NULL,
                                                pkcs_url, &pkcs_data,
@@ -711,11 +711,11 @@
   struct_stat st;
 
   if(!filename)
-    return false;
+    return FALSE;
 
   if(stat(filename, &st) == 0)
     return S_ISREG(st.st_mode);
-  return false;
+  return FALSE;
 }
 
 static CURLcode
@@ -796,8 +796,8 @@
   }
 
   /* only TLS 1.0 is supported, disable SSL 3.0 and SSL 2.0 */
-  SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false);
-  SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, true);
+  SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, FALSE);
+  SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, TRUE);
 
   return CURLE_OK;
 #endif
@@ -1069,7 +1069,7 @@
 #if CURL_SUPPORT_MAC_10_8
     if(backend->ssl_ctx)
       (void)SSLDisposeContext(backend->ssl_ctx);
-    err = SSLNewContext(false, &(backend->ssl_ctx));
+    err = SSLNewContext(FALSE, &(backend->ssl_ctx));
     if(err != noErr) {
       failf(data, "SSL: could not create a context: OSStatus %d", err);
       return CURLE_OUT_OF_MEMORY;
@@ -1079,7 +1079,7 @@
 #else
   if(backend->ssl_ctx)
     (void)SSLDisposeContext(backend->ssl_ctx);
-  err = SSLNewContext(false, &(backend->ssl_ctx));
+  err = SSLNewContext(FALSE, &(backend->ssl_ctx));
   if(err != noErr) {
     failf(data, "SSL: could not create a context: OSStatus %d", err);
     return CURLE_OUT_OF_MEMORY;
@@ -1227,8 +1227,7 @@
      Mountain Lion.
      So we need to call SSLSetEnableCertVerify() on those older cats in order
      to disable certificate validation if the user turned that off.
-     (SecureTransport will always validate the certificate chain by
-     default.)
+     (Secure Transport always validates the certificate chain by default.)
   Note:
   Darwin 11.x.x is Lion (10.7)
   Darwin 12.x.x is Mountain Lion (10.8)
@@ -1254,7 +1253,7 @@
   else {
 #if CURL_SUPPORT_MAC_10_8
     err = SSLSetEnableCertVerify(backend->ssl_ctx,
-                                 conn_config->verifypeer?true:false);
+                                 conn_config->verifypeer ? true : FALSE);
     if(err != noErr) {
       failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
       return CURLE_SSL_CONNECT_ERROR;
@@ -1263,7 +1262,7 @@
   }
 #else
   err = SSLSetEnableCertVerify(backend->ssl_ctx,
-                               conn_config->verifypeer?true:false);
+                               conn_config->verifypeer ? true : FALSE);
   if(err != noErr) {
     failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
     return CURLE_SSL_CONNECT_ERROR;
@@ -1285,8 +1284,8 @@
    * Both hostname check and SNI require SSLSetPeerDomainName().
    * Also: the verifyhost setting influences SNI usage */
   if(conn_config->verifyhost) {
-    char *server = connssl->peer.sni?
-                   connssl->peer.sni : connssl->peer.hostname;
+    char *server = connssl->peer.sni ?
+      connssl->peer.sni : connssl->peer.hostname;
     err = SSLSetPeerDomainName(backend->ssl_ctx, server, strlen(server));
 
     if(err != noErr) {
@@ -1335,7 +1334,8 @@
 
     Curl_ssl_sessionid_lock(data);
     if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
-                              (void **)&ssl_sessionid, &ssl_sessionid_len)) {
+                              (void **)&ssl_sessionid, &ssl_sessionid_len,
+                              NULL)) {
       /* we got a session id, use it! */
       err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
       Curl_ssl_sessionid_unlock(data);
@@ -1363,8 +1363,8 @@
         return CURLE_SSL_CONNECT_ERROR;
       }
 
-      result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, ssl_sessionid,
-                                      ssl_sessionid_len,
+      result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
+                                      ssl_sessionid, ssl_sessionid_len,
                                       sectransp_session_free);
       Curl_ssl_sessionid_unlock(data);
       if(result)
@@ -1605,7 +1605,7 @@
     failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret);
     goto out;
   }
-  ret = SecTrustSetAnchorCertificatesOnly(trust, true);
+  ret = SecTrustSetAnchorCertificatesOnly(trust, TRUE);
   if(ret != noErr) {
     failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret);
     goto out;
@@ -2054,7 +2054,7 @@
     (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);
 
     sectransp_cipher_suite_get_str((uint16_t) cipher, cipher_str,
-                                   sizeof(cipher_str), true);
+                                   sizeof(cipher_str), TRUE);
     switch(protocol) {
       case kSSLProtocol2:
         infof(data, "SSL 2.0 connection using %s", cipher_str);
@@ -2169,7 +2169,7 @@
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   const bool show_verbose_server_cert = data->set.verbose;
 #else
-  const bool show_verbose_server_cert = false;
+  const bool show_verbose_server_cert = FALSE;
 #endif
   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
   CURLcode result = ssl_config->certinfo ?
@@ -2328,10 +2328,10 @@
     /* if ssl is expecting something, check if it is available. */
     if(connssl->io_need) {
 
-      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
-                              sockfd:CURL_SOCKET_BAD;
-      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
-                             sockfd:CURL_SOCKET_BAD;
+      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+        sockfd : CURL_SOCKET_BAD;
+      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+        sockfd : CURL_SOCKET_BAD;
 
       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                                nonblocking ? 0 : timeout_ms);
@@ -2463,7 +2463,7 @@
     }
     else {
       /* We would like to read the close notify from the server using
-       * secure transport, however SSLRead() no longer works after we
+       * Secure Transport, however SSLRead() no longer works after we
        * sent the notify from our side. So, we just read from the
        * underlying filter and hope it will end. */
       nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
@@ -2544,10 +2544,10 @@
     err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer);
     if(err == noErr)
       return buffer > 0UL;
-    return false;
+    return FALSE;
   }
   else
-    return false;
+    return FALSE;
 }
 
 static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM,
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index 36a4226..61b407a 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -55,6 +55,16 @@
 
 #include "vtls.h" /* generic SSL protos etc */
 #include "vtls_int.h"
+
+#include "openssl.h"        /* OpenSSL versions */
+#include "gtls.h"           /* GnuTLS versions */
+#include "wolfssl.h"        /* wolfSSL versions */
+#include "schannel.h"       /* Schannel SSPI version */
+#include "sectransp.h"      /* Secure Transport (Darwin) version */
+#include "mbedtls.h"        /* mbedTLS versions */
+#include "bearssl.h"        /* BearSSL versions */
+#include "rustls.h"         /* Rustls versions */
+
 #include "slist.h"
 #include "sendf.h"
 #include "strcase.h"
@@ -259,7 +269,7 @@
   return TRUE;
 }
 
-static void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
+static void free_primary_ssl_config(struct ssl_primary_config *sslc)
 {
   Curl_safefree(sslc->CApath);
   Curl_safefree(sslc->CAfile);
@@ -359,9 +369,9 @@
 
 void Curl_ssl_conn_config_cleanup(struct connectdata *conn)
 {
-  Curl_free_primary_ssl_config(&conn->ssl_config);
+  free_primary_ssl_config(&conn->ssl_config);
 #ifndef CURL_DISABLE_PROXY
-  Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
+  free_primary_ssl_config(&conn->proxy_ssl_config);
 #endif
 }
 
@@ -371,8 +381,8 @@
   if(data->conn) {
     struct ssl_primary_config *src, *dest;
 #ifndef CURL_DISABLE_PROXY
-    src = for_proxy? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
-    dest = for_proxy? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
+    src = for_proxy ? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
+    dest = for_proxy ? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
 #else
     (void)for_proxy;
     src = &data->set.ssl.primary;
@@ -454,6 +464,7 @@
     return NULL;
 
   ctx->alpn = alpn;
+  Curl_bufq_init2(&ctx->earlydata, CURL_SSL_EARLY_MAX, 1, BUFQ_OPT_NO_SPARES);
   ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data);
   if(!ctx->backend) {
     free(ctx);
@@ -465,6 +476,8 @@
 static void cf_ctx_free(struct ssl_connect_data *ctx)
 {
   if(ctx) {
+    Curl_safefree(ctx->alpn_negotiated);
+    Curl_bufq_free(&ctx->earlydata);
     free(ctx->backend);
     free(ctx);
   }
@@ -527,7 +540,8 @@
                            struct Curl_easy *data,
                            const struct ssl_peer *peer,
                            void **ssl_sessionid,
-                           size_t *idsize) /* set 0 if unknown */
+                           size_t *idsize, /* set 0 if unknown */
+                           char **palpn)
 {
   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
@@ -537,6 +551,8 @@
   bool no_match = TRUE;
 
   *ssl_sessionid = NULL;
+  if(palpn)
+    *palpn = NULL;
   if(!ssl_config)
     return TRUE;
 
@@ -575,13 +591,15 @@
       *ssl_sessionid = check->sessionid;
       if(idsize)
         *idsize = check->idsize;
+      if(palpn)
+        *palpn = check->alpn;
       no_match = FALSE;
       break;
     }
   }
 
   CURL_TRC_CF(data, cf, "%s cached session ID for %s://%s:%d",
-              no_match? "No": "Found",
+              no_match ? "No" : "Found",
               cf->conn->handler->scheme, peer->hostname, peer->port);
   return no_match;
 }
@@ -601,10 +619,11 @@
     session->sessionid_free = NULL;
     session->age = 0; /* fresh */
 
-    Curl_free_primary_ssl_config(&session->ssl_config);
+    free_primary_ssl_config(&session->ssl_config);
 
     Curl_safefree(session->name);
     Curl_safefree(session->conn_to_host);
+    Curl_safefree(session->alpn);
   }
 }
 
@@ -628,6 +647,7 @@
 CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 const struct ssl_peer *peer,
+                                const char *alpn,
                                 void *ssl_sessionid,
                                 size_t idsize,
                                 Curl_ssl_sessionid_dtor *sessionid_free_cb)
@@ -639,6 +659,7 @@
   long oldest_age;
   char *clone_host = NULL;
   char *clone_conn_to_host = NULL;
+  char *clone_alpn = NULL;
   int conn_to_port;
   long *general_age;
   void *old_sessionid;
@@ -653,7 +674,7 @@
     return CURLE_OK;
   }
 
-  if(!Curl_ssl_getsessionid(cf, data, peer, &old_sessionid, &old_size)) {
+  if(!Curl_ssl_getsessionid(cf, data, peer, &old_sessionid, &old_size, NULL)) {
     if((old_size == idsize) &&
        ((old_sessionid == ssl_sessionid) ||
         (idsize && !memcmp(old_sessionid, ssl_sessionid, idsize)))) {
@@ -679,6 +700,10 @@
       goto out;
   }
 
+  clone_alpn = alpn ? strdup(alpn) : NULL;
+  if(alpn && !clone_alpn)
+    goto out;
+
   if(cf->conn->bits.conn_to_port)
     conn_to_port = cf->conn->conn_to_port;
   else
@@ -711,7 +736,7 @@
 
   /* now init the session struct wisely */
   if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
-    Curl_free_primary_ssl_config(&store->ssl_config);
+    free_primary_ssl_config(&store->ssl_config);
     store->sessionid = NULL; /* let caller free sessionid */
     goto out;
   }
@@ -727,6 +752,8 @@
   store->conn_to_host = clone_conn_to_host; /* clone connect to hostname */
   clone_conn_to_host = NULL;
   store->conn_to_port = conn_to_port; /* connect to port number */
+  store->alpn = clone_alpn;
+  clone_alpn = NULL;
   /* port number */
   store->remote_port = peer->port;
   store->scheme = cf->conn->handler->scheme;
@@ -737,6 +764,7 @@
 out:
   free(clone_host);
   free(clone_conn_to_host);
+  free(clone_alpn);
   if(result) {
     failf(data, "Failed to add Session ID to cache for %s://%s:%d [%s]",
           store->scheme, store->name, store->remote_port,
@@ -857,7 +885,7 @@
   if(ci->num_of_certs) {
     /* free all individual lists used */
     int i;
-    for(i = 0; i<ci->num_of_certs; i++) {
+    for(i = 0; i < ci->num_of_certs; i++) {
       curl_slist_free_all(ci->certinfo[i]);
       ci->certinfo[i] = NULL;
     }
@@ -941,14 +969,17 @@
 static CURLcode pubkey_pem_to_der(const char *pem,
                                   unsigned char **der, size_t *der_len)
 {
-  char *stripped_pem, *begin_pos, *end_pos;
-  size_t pem_count, stripped_pem_count = 0, pem_len;
+  char *begin_pos, *end_pos;
+  size_t pem_count, pem_len;
   CURLcode result;
+  struct dynbuf pbuf;
 
   /* if no pem, exit. */
   if(!pem)
     return CURLE_BAD_CONTENT_ENCODING;
 
+  Curl_dyn_init(&pbuf, MAX_PINNED_PUBKEY_SIZE);
+
   begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
   if(!begin_pos)
     return CURLE_BAD_CONTENT_ENCODING;
@@ -968,26 +999,23 @@
 
   pem_len = end_pos - pem;
 
-  stripped_pem = malloc(pem_len - pem_count + 1);
-  if(!stripped_pem)
-    return CURLE_OUT_OF_MEMORY;
-
   /*
    * Here we loop through the pem array one character at a time between the
    * correct indices, and place each character that is not '\n' or '\r'
    * into the stripped_pem array, which should represent the raw base64 string
    */
   while(pem_count < pem_len) {
-    if('\n' != pem[pem_count] && '\r' != pem[pem_count])
-      stripped_pem[stripped_pem_count++] = pem[pem_count];
+    if('\n' != pem[pem_count] && '\r' != pem[pem_count]) {
+      result = Curl_dyn_addn(&pbuf, &pem[pem_count], 1);
+      if(result)
+        return result;
+    }
     ++pem_count;
   }
-  /* Place the null terminator in the correct place */
-  stripped_pem[stripped_pem_count] = '\0';
 
-  result = Curl_base64_decode(stripped_pem, der, der_len);
+  result = Curl_base64_decode(Curl_dyn_ptr(&pbuf), der, der_len);
 
-  Curl_safefree(stripped_pem);
+  Curl_dyn_free(&pbuf);
 
   return result;
 }
@@ -1000,8 +1028,6 @@
                               const char *pinnedpubkey,
                               const unsigned char *pubkey, size_t pubkeylen)
 {
-  FILE *fp;
-  unsigned char *buf = NULL, *pem_ptr = NULL;
   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
   (void)data;
@@ -1014,7 +1040,7 @@
     return result;
 
   /* only do this if pinnedpubkey starts with "sha256//", length 8 */
-  if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
+  if(!strncmp(pinnedpubkey, "sha256//", 8)) {
     CURLcode encode;
     size_t encodedlen = 0;
     char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos;
@@ -1078,26 +1104,28 @@
     } while(end_pos && begin_pos);
     Curl_safefree(encoded);
     Curl_safefree(pinkeycopy);
-    return result;
   }
-
-  fp = fopen(pinnedpubkey, "rb");
-  if(!fp)
-    return result;
-
-  do {
+  else {
     long filesize;
     size_t size, pem_len;
     CURLcode pem_read;
+    struct dynbuf buf;
+    char unsigned *pem_ptr = NULL;
+    size_t left;
+    FILE *fp = fopen(pinnedpubkey, "rb");
+    if(!fp)
+      return result;
+
+    Curl_dyn_init(&buf, MAX_PINNED_PUBKEY_SIZE);
 
     /* Determine the file's size */
     if(fseek(fp, 0, SEEK_END))
-      break;
+      goto end;
     filesize = ftell(fp);
     if(fseek(fp, 0, SEEK_SET))
-      break;
+      goto end;
     if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
-      break;
+      goto end;
 
     /*
      * if the size of our certificate is bigger than the file
@@ -1105,36 +1133,37 @@
      */
     size = curlx_sotouz((curl_off_t) filesize);
     if(pubkeylen > size)
-      break;
+      goto end;
 
     /*
-     * Allocate buffer for the pinned key
-     * With 1 additional byte for null terminator in case of PEM key
+     * Read the file into the dynbuf
      */
-    buf = malloc(size + 1);
-    if(!buf)
-      break;
-
-    /* Returns number of elements read, which should be 1 */
-    if((int) fread(buf, size, 1, fp) != 1)
-      break;
+    left = size;
+    do {
+      char buffer[1024];
+      size_t want = left > sizeof(buffer) ? sizeof(buffer) : left;
+      if(want != fread(buffer, 1, want, fp))
+        goto end;
+      if(Curl_dyn_addn(&buf, buffer, want))
+        goto end;
+      left -= want;
+    } while(left);
 
     /* If the sizes are the same, it cannot be base64 encoded, must be der */
     if(pubkeylen == size) {
-      if(!memcmp(pubkey, buf, pubkeylen))
+      if(!memcmp(pubkey, Curl_dyn_ptr(&buf), pubkeylen))
         result = CURLE_OK;
-      break;
+      goto end;
     }
 
     /*
      * Otherwise we will assume it is PEM and try to decode it
      * after placing null terminator
      */
-    buf[size] = '\0';
-    pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
+    pem_read = pubkey_pem_to_der(Curl_dyn_ptr(&buf), &pem_ptr, &pem_len);
     /* if it was not read successfully, exit */
     if(pem_read)
-      break;
+      goto end;
 
     /*
      * if the size of our certificate does not match the size of
@@ -1142,11 +1171,11 @@
      */
     if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
       result = CURLE_OK;
-  } while(0);
-
-  Curl_safefree(buf);
-  Curl_safefree(pem_ptr);
-  fclose(fp);
+end:
+    Curl_dyn_free(&buf);
+    Curl_safefree(pem_ptr);
+    fclose(fp);
+  }
 
   return result;
 }
@@ -1715,7 +1744,9 @@
   if(!result && *done) {
     cf->connected = TRUE;
     connssl->handshake_done = Curl_now();
-    DEBUGASSERT(connssl->state == ssl_connection_complete);
+    /* Connection can be deferred when sending early data */
+    DEBUGASSERT(connssl->state == ssl_connection_complete ||
+                connssl->state == ssl_connection_deferred);
   }
 out:
   CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
@@ -1743,13 +1774,16 @@
                            bool eos, CURLcode *err)
 {
   struct cf_call_data save;
-  ssize_t nwritten;
+  ssize_t nwritten = 0;
 
-  (void)eos; /* unused */
-  CF_DATA_SAVE(save, cf, data);
+  (void)eos;
+  /* OpenSSL and maybe other TLS libs do not like 0-length writes. Skip. */
   *err = CURLE_OK;
-  nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
-  CF_DATA_RESTORE(cf, save);
+  if(len > 0) {
+    CF_DATA_SAVE(save, cf, data);
+    nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
+    CF_DATA_RESTORE(cf, save);
+  }
   return nwritten;
 }
 
@@ -1851,7 +1885,7 @@
   default:
     break;
   }
-  return cf->next?
+  return cf->next ?
     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
     CURLE_UNKNOWN_OPTION;
 }
@@ -1881,7 +1915,7 @@
     return FALSE;
   }
   /* ssl backend does not know */
-  return cf->next?
+  return cf->next ?
     cf->next->cft->is_alive(cf->next, data, input_pending) :
     FALSE; /* pessimistic in absence of data */
 }
@@ -1950,7 +1984,7 @@
 out:
   if(result)
     cf_ctx_free(ctx);
-  *pcf = result? NULL : cf;
+  *pcf = result ? NULL : cf;
   return result;
 }
 
@@ -2008,7 +2042,7 @@
 out:
   if(result)
     cf_ctx_free(ctx);
-  *pcf = result? NULL : cf;
+  *pcf = result ? NULL : cf;
   return result;
 }
 
@@ -2029,7 +2063,7 @@
 bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option)
 {
   (void)data;
-  return (Curl_ssl->supports & ssl_option)? TRUE : FALSE;
+  return (Curl_ssl->supports & ssl_option);
 }
 
 static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
@@ -2124,7 +2158,7 @@
   struct Curl_cfilter *cf, *head;
   CURLcode result = CURLE_OK;
 
-  head = data->conn? data->conn->cfilter[sockindex] : NULL;
+  head = data->conn ? data->conn->cfilter[sockindex] : NULL;
   for(cf = head; cf; cf = cf->next) {
     if(cf->cft == &Curl_cft_ssl) {
       bool done;
@@ -2154,7 +2188,7 @@
   (void)cf;
   return &data->set.ssl;
 #else
-  return Curl_ssl_cf_is_proxy(cf)? &data->set.proxy_ssl : &data->set.ssl;
+  return Curl_ssl_cf_is_proxy(cf) ? &data->set.proxy_ssl : &data->set.ssl;
 #endif
 }
 
@@ -2164,7 +2198,7 @@
 #ifdef CURL_DISABLE_PROXY
   return &cf->conn->ssl_config;
 #else
-  return Curl_ssl_cf_is_proxy(cf)?
+  return Curl_ssl_cf_is_proxy(cf) ?
     &cf->conn->proxy_ssl_config : &cf->conn->ssl_config;
 #endif
 }
@@ -2215,20 +2249,73 @@
   return CURLE_OK;
 }
 
+bool Curl_alpn_contains_proto(const struct alpn_spec *spec,
+                              const char *proto)
+{
+  size_t i, plen = proto ? strlen(proto) : 0;
+  for(i = 0; spec && plen && i < spec->count; ++i) {
+    size_t slen = strlen(spec->entries[i]);
+    if((slen == plen) && !memcmp(proto, spec->entries[i], plen))
+      return TRUE;
+  }
+  return FALSE;
+}
+
 CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
+                                  struct ssl_connect_data *connssl,
                                   const unsigned char *proto,
                                   size_t proto_len)
 {
+  CURLcode result = CURLE_OK;
   unsigned char *palpn =
 #ifndef CURL_DISABLE_PROXY
-    (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf))?
+    (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf)) ?
     &cf->conn->proxy_alpn : &cf->conn->alpn
 #else
     &cf->conn->alpn
 #endif
     ;
 
+  if(connssl->alpn_negotiated) {
+    /* When we ask for a specific ALPN protocol, we need the confirmation
+     * of it by the server, as we have installed protocol handler and
+     * connection filter chain for exactly this protocol. */
+    if(!proto_len) {
+      failf(data, "ALPN: asked for '%s' from previous session, "
+            "but server did not confirm it. Refusing to continue.",
+            connssl->alpn_negotiated);
+      result = CURLE_SSL_CONNECT_ERROR;
+      goto out;
+    }
+    else if((strlen(connssl->alpn_negotiated) != proto_len) ||
+            memcmp(connssl->alpn_negotiated, proto, proto_len)) {
+      failf(data, "ALPN: asked for '%s' from previous session, but server "
+            "selected '%.*s'. Refusing to continue.",
+            connssl->alpn_negotiated, (int)proto_len, proto);
+      result = CURLE_SSL_CONNECT_ERROR;
+      goto out;
+    }
+    /* ALPN is exactly what we asked for, done. */
+    infof(data, "ALPN: server confirmed to use '%s'",
+          connssl->alpn_negotiated);
+    goto out;
+  }
+
+  if(proto && proto_len) {
+    if(memchr(proto, '\0', proto_len)) {
+      failf(data, "ALPN: server selected protocol contains NUL. "
+            "Refusing to continue.");
+      result = CURLE_SSL_CONNECT_ERROR;
+      goto out;
+    }
+    connssl->alpn_negotiated = malloc(proto_len + 1);
+    if(!connssl->alpn_negotiated)
+      return CURLE_OUT_OF_MEMORY;
+    memcpy(connssl->alpn_negotiated, proto, proto_len);
+    connssl->alpn_negotiated[proto_len] = 0;
+  }
+
   if(proto && proto_len) {
     if(proto_len == ALPN_HTTP_1_1_LENGTH &&
        !memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) {
@@ -2254,15 +2341,22 @@
       /* return CURLE_NOT_BUILT_IN; */
       goto out;
     }
-    infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, (int)proto_len, proto);
+
+    if(connssl->state == ssl_connection_deferred)
+      infof(data, VTLS_INFOF_ALPN_DEFERRED, (int)proto_len, proto);
+    else
+      infof(data, VTLS_INFOF_ALPN_ACCEPTED, (int)proto_len, proto);
   }
   else {
     *palpn = CURL_HTTP_VERSION_NONE;
-    infof(data, VTLS_INFOF_NO_ALPN);
+    if(connssl->state == ssl_connection_deferred)
+      infof(data, VTLS_INFOF_NO_ALPN_DEFERRED);
+    else
+      infof(data, VTLS_INFOF_NO_ALPN);
   }
 
 out:
-  return CURLE_OK;
+  return result;
 }
 
 #endif /* USE_SSL */
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index fce1e00..7a223f6 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -43,15 +43,18 @@
 
 #define ALPN_ACCEPTED "ALPN: server accepted "
 
-#define VTLS_INFOF_NO_ALPN                                      \
+#define VTLS_INFOF_NO_ALPN            \
   "ALPN: server did not agree on a protocol. Uses default."
-#define VTLS_INFOF_ALPN_OFFER_1STR              \
+#define VTLS_INFOF_ALPN_OFFER_1STR    \
   "ALPN: curl offers %s"
-#define VTLS_INFOF_ALPN_ACCEPTED_1STR           \
-  ALPN_ACCEPTED "%s"
-#define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR       \
+#define VTLS_INFOF_ALPN_ACCEPTED      \
   ALPN_ACCEPTED "%.*s"
 
+#define VTLS_INFOF_NO_ALPN_DEFERRED   \
+  "ALPN: deferred handshake for early data without specific protocol."
+#define VTLS_INFOF_ALPN_DEFERRED      \
+  "ALPN: deferred handshake for early data using '%.*s'."
+
 /* Curl_multi SSL backend-specific data; declared differently by each SSL
    backend */
 struct Curl_cfilter;
diff --git a/Utilities/cmcurl/lib/vtls/vtls_int.h b/Utilities/cmcurl/lib/vtls/vtls_int.h
index 836bfad..13bd3fb 100644
--- a/Utilities/cmcurl/lib/vtls/vtls_int.h
+++ b/Utilities/cmcurl/lib/vtls/vtls_int.h
@@ -29,6 +29,8 @@
 
 #ifdef USE_SSL
 
+struct ssl_connect_data;
+
 /* see https://www.iana.org/assignments/tls-extensiontype-values/ */
 #define ALPN_HTTP_1_1_LENGTH 8
 #define ALPN_HTTP_1_1 "http/1.1"
@@ -61,9 +63,13 @@
 
 CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
+                                  struct ssl_connect_data *connssl,
                                   const unsigned char *proto,
                                   size_t proto_len);
 
+bool Curl_alpn_contains_proto(const struct alpn_spec *spec,
+                              const char *proto);
+
 /* enum for the nonblocking SSL connection state machine */
 typedef enum {
   ssl_connect_1,
@@ -74,14 +80,27 @@
 
 typedef enum {
   ssl_connection_none,
+  ssl_connection_deferred,
   ssl_connection_negotiating,
   ssl_connection_complete
 } ssl_connection_state;
 
+typedef enum {
+  ssl_earlydata_none,
+  ssl_earlydata_use,
+  ssl_earlydata_sending,
+  ssl_earlydata_sent,
+  ssl_earlydata_accepted,
+  ssl_earlydata_rejected
+} ssl_earlydata_state;
+
 #define CURL_SSL_IO_NEED_NONE   (0)
 #define CURL_SSL_IO_NEED_RECV   (1<<0)
 #define CURL_SSL_IO_NEED_SEND   (1<<1)
 
+/* Max earlydata payload we want to send */
+#define CURL_SSL_EARLY_MAX       (64*1024)
+
 /* Information in each SSL cfilter context: cf->ctx */
 struct ssl_connect_data {
   struct ssl_peer peer;
@@ -89,8 +108,14 @@
   void *backend;                    /* vtls backend specific props */
   struct cf_call_data call_data;    /* data handle used in current call */
   struct curltime handshake_done;   /* time when handshake finished */
+  char *alpn_negotiated;            /* negotiated ALPN value or NULL */
+  struct bufq earlydata;            /* earlydata to be send to peer */
+  size_t earlydata_max;             /* max earlydata allowed by peer */
+  size_t earlydata_skip;            /* sending bytes to skip when earlydata
+                                     * is accepted by peer */
   ssl_connection_state state;
   ssl_connect_state connecting_state;
+  ssl_earlydata_state earlydata_state;
   int io_need;                      /* TLS signals special SEND/RECV needs */
   BIT(use_alpn);                    /* if ALPN shall be used in handshake */
   BIT(peer_closed);                 /* peer has closed connection */
@@ -193,15 +218,23 @@
  * Caller must make sure that the ownership of returned sessionid object
  * is properly taken (e.g. its refcount is incremented
  * under sessionid mutex).
+ * @param cf      the connection filter wanting to use it
+ * @param data    the transfer involved
+ * @param peer    the peer the filter wants to talk to
+ * @param sessionid on return the TLS session
+ * @param idsize  on return the size of the TLS session data
+ * @param palpn   on return the ALPN string used by the session,
+ *                set to NULL when not interested
  */
 bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
                            struct Curl_easy *data,
                            const struct ssl_peer *peer,
                            void **ssl_sessionid,
-                           size_t *idsize); /* set 0 if unknown */
+                           size_t *idsize, /* set 0 if unknown */
+                           char **palpn);
 
 /* Set a TLS session ID for `peer`. Replaces an existing session ID if
- * not already the very same.
+ * not already the same.
  * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
  * Call takes ownership of `ssl_sessionid`, using `sessionid_free_cb`
  * to deallocate it. Is called in all outcomes, either right away or
@@ -212,19 +245,11 @@
 CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 const struct ssl_peer *peer,
+                                const char *alpn,
                                 void *sessionid,
                                 size_t sessionid_size,
                                 Curl_ssl_sessionid_dtor *sessionid_free_cb);
 
-#include "openssl.h"        /* OpenSSL versions */
-#include "gtls.h"           /* GnuTLS versions */
-#include "wolfssl.h"        /* wolfSSL versions */
-#include "schannel.h"       /* Schannel SSPI version */
-#include "sectransp.h"      /* SecureTransport (Darwin) version */
-#include "mbedtls.h"        /* mbedTLS versions */
-#include "bearssl.h"        /* BearSSL versions */
-#include "rustls.h"         /* Rustls versions */
-
 #endif /* USE_SSL */
 
 #endif /* HEADER_CURL_VTLS_INT_H */
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c
index bd7963e..3394cb2 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.c
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.c
@@ -33,8 +33,8 @@
 #ifdef USE_WOLFSSL
 
 #define WOLFSSL_OPTIONS_IGNORE_SYS
-#include <wolfssl/version.h>
 #include <wolfssl/options.h>
+#include <wolfssl/version.h>
 
 #if LIBWOLFSSL_VERSION_HEX < 0x03004006 /* wolfSSL 3.4.6 (2015) */
 #error "wolfSSL version should be at least 3.4.6"
@@ -97,9 +97,25 @@
 #endif
 #endif
 
-#if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO
+#ifdef HAVE_WOLFSSL_BIO
 #define USE_BIO_CHAIN
-#else
+#ifdef HAVE_WOLFSSL_FULL_BIO
+#define USE_FULL_BIO
+#else /* HAVE_WOLFSSL_FULL_BIO */
+#undef USE_FULL_BIO
+#endif
+/* wolfSSL 5.7.4 and older do not have these symbols, but only the
+ * OpenSSL ones. */
+#ifndef WOLFSSL_BIO_CTRL_GET_CLOSE
+#define WOLFSSL_BIO_CTRL_GET_CLOSE    BIO_CTRL_GET_CLOSE
+#define WOLFSSL_BIO_CTRL_SET_CLOSE    BIO_CTRL_SET_CLOSE
+#define WOLFSSL_BIO_CTRL_FLUSH        BIO_CTRL_FLUSH
+#define WOLFSSL_BIO_CTRL_DUP          BIO_CTRL_DUP
+#define wolfSSL_BIO_set_retry_write   BIO_set_retry_write
+#define wolfSSL_BIO_set_retry_read    BIO_set_retry_read
+#endif /* !WOLFSSL_BIO_CTRL_GET_CLOSE */
+
+#else /* HAVE_WOLFSSL_BIO */
 #undef USE_BIO_CHAIN
 #endif
 
@@ -163,7 +179,7 @@
 #endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */
 
 static void
-wolfssl_log_tls12_secret(SSL *ssl)
+wolfssl_log_tls12_secret(WOLFSSL *ssl)
 {
   unsigned char *ms, *sr, *cr;
   unsigned int msLen, srLen, crLen, i, x = 0;
@@ -187,7 +203,7 @@
 #endif
 
   if(wolfSSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) !=
-     SSL_SUCCESS) {
+     WOLFSSL_SUCCESS) {
     return;
   }
 
@@ -208,11 +224,11 @@
 static int wolfssl_do_file_type(const char *type)
 {
   if(!type || !type[0])
-    return SSL_FILETYPE_PEM;
+    return WOLFSSL_FILETYPE_PEM;
   if(strcasecompare(type, "PEM"))
-    return SSL_FILETYPE_PEM;
+    return WOLFSSL_FILETYPE_PEM;
   if(strcasecompare(type, "DER"))
-    return SSL_FILETYPE_ASN1;
+    return WOLFSSL_FILETYPE_ASN1;
   return -1;
 }
 
@@ -237,7 +253,9 @@
 
 static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio)
 {
+#ifdef USE_FULL_BIO
   wolfSSL_BIO_set_shutdown(bio, 1);
+#endif
   wolfSSL_BIO_set_data(bio, NULL);
   return 1;
 }
@@ -251,28 +269,35 @@
 
 static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
 {
-  struct Curl_cfilter *cf = BIO_get_data(bio);
+  struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
   long ret = 1;
 
   (void)cf;
   (void)ptr;
+  (void)num;
   switch(cmd) {
-  case BIO_CTRL_GET_CLOSE:
+  case WOLFSSL_BIO_CTRL_GET_CLOSE:
+#ifdef USE_FULL_BIO
     ret = (long)wolfSSL_BIO_get_shutdown(bio);
+#else
+    ret = 0;
+#endif
     break;
-  case BIO_CTRL_SET_CLOSE:
+  case WOLFSSL_BIO_CTRL_SET_CLOSE:
+#ifdef USE_FULL_BIO
     wolfSSL_BIO_set_shutdown(bio, (int)num);
+#endif
     break;
-  case BIO_CTRL_FLUSH:
+  case WOLFSSL_BIO_CTRL_FLUSH:
     /* we do no delayed writes, but if we ever would, this
      * needs to trigger it. */
     ret = 1;
     break;
-  case BIO_CTRL_DUP:
+  case WOLFSSL_BIO_CTRL_DUP:
     ret = 1;
     break;
-#ifdef BIO_CTRL_EOF
-  case BIO_CTRL_EOF:
+#ifdef WOLFSSL_BIO_CTRL_EOF
+  case WOLFSSL_BIO_CTRL_EOF:
     /* EOF has been reached on input? */
     return (!cf->next || !cf->next->connected);
 #endif
@@ -309,9 +334,11 @@
   backend->io_result = result;
   CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
               blen, nwritten, result);
+#ifdef USE_FULL_BIO
   wolfSSL_BIO_clear_retry_flags(bio);
+#endif
   if(nwritten < 0 && CURLE_AGAIN == result) {
-    BIO_set_retry_write(bio);
+    wolfSSL_BIO_set_retry_write(bio);
     if(backend->shutting_down && !backend->io_send_blocked_len)
       backend->io_send_blocked_len = blen;
   }
@@ -338,9 +365,11 @@
   nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
   backend->io_result = result;
   CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result);
+#ifdef USE_FULL_BIO
   wolfSSL_BIO_clear_retry_flags(bio);
+#endif
   if(nread < 0 && CURLE_AGAIN == result)
-    BIO_set_retry_read(bio);
+    wolfSSL_BIO_set_retry_read(bio);
   else if(nread == 0)
     connssl->peer_closed = TRUE;
   return (int)nread;
@@ -350,7 +379,8 @@
 
 static void wolfssl_bio_cf_init_methods(void)
 {
-  wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO");
+  wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(WOLFSSL_BIO_MEMORY,
+                                               "wolfSSL CF BIO");
   wolfSSL_BIO_meth_set_write(wolfssl_bio_cf_method, &wolfssl_bio_cf_out_write);
   wolfSSL_BIO_meth_set_read(wolfssl_bio_cf_method, &wolfssl_bio_cf_in_read);
   wolfSSL_BIO_meth_set_ctrl(wolfssl_bio_cf_method, &wolfssl_bio_cf_ctrl);
@@ -370,9 +400,114 @@
 
 #endif /* !USE_BIO_CHAIN */
 
+static void wolfssl_session_free(void *sdata, size_t slen)
+{
+  (void)slen;
+  free(sdata);
+}
+
+CURLcode wssl_cache_session(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            struct ssl_peer *peer,
+                            WOLFSSL_SESSION *session)
+{
+  CURLcode result = CURLE_OK;
+  unsigned char *sdata = NULL;
+  unsigned int slen;
+
+  if(!session)
+    goto out;
+
+  slen = wolfSSL_i2d_SSL_SESSION(session, NULL);
+  if(slen <= 0) {
+    CURL_TRC_CF(data, cf, "fail to assess session length: %u", slen);
+    result = CURLE_FAILED_INIT;
+    goto out;
+  }
+  sdata = calloc(1, slen);
+  if(!sdata) {
+    failf(data, "unable to allocate session buffer of %u bytes", slen);
+    result = CURLE_OUT_OF_MEMORY;
+    goto out;
+  }
+  slen = wolfSSL_i2d_SSL_SESSION(session, &sdata);
+  if(slen <= 0) {
+    CURL_TRC_CF(data, cf, "fail to serialize session: %u", slen);
+    result = CURLE_FAILED_INIT;
+    goto out;
+  }
+
+  Curl_ssl_sessionid_lock(data);
+  result = Curl_ssl_set_sessionid(cf, data, peer, NULL,
+                                  sdata, slen, wolfssl_session_free);
+  Curl_ssl_sessionid_unlock(data);
+  if(result)
+    failf(data, "failed to add new ssl session to cache (%d)", result);
+  else {
+    CURL_TRC_CF(data, cf, "added new session to cache");
+    sdata = NULL;
+  }
+
+out:
+  free(sdata);
+  return 0;
+}
+
+static int wssl_vtls_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
+{
+  struct Curl_cfilter *cf;
+
+  cf = (struct Curl_cfilter*)wolfSSL_get_app_data(ssl);
+  DEBUGASSERT(cf != NULL);
+  if(cf && session) {
+    struct ssl_connect_data *connssl = cf->ctx;
+    struct Curl_easy *data = CF_DATA_CURRENT(cf);
+    DEBUGASSERT(connssl);
+    DEBUGASSERT(data);
+    if(connssl && data) {
+      (void)wssl_cache_session(cf, data, &connssl->peer, session);
+    }
+  }
+  return 0;
+}
+
+CURLcode wssl_setup_session(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            struct wolfssl_ctx *wss,
+                            struct ssl_peer *peer)
+{
+  void *psdata;
+  const unsigned char *sdata = NULL;
+  size_t slen = 0;
+  CURLcode result = CURLE_OK;
+
+  Curl_ssl_sessionid_lock(data);
+  if(!Curl_ssl_getsessionid(cf, data, peer, &psdata, &slen, NULL)) {
+    WOLFSSL_SESSION *session;
+    sdata = psdata;
+    session = wolfSSL_d2i_SSL_SESSION(NULL, &sdata, (long)slen);
+    if(session) {
+      int ret = wolfSSL_set_session(wss->handle, session);
+      if(ret != WOLFSSL_SUCCESS) {
+        Curl_ssl_delsessionid(data, psdata);
+        infof(data, "previous session not accepted (%d), "
+              "removing from cache", ret);
+      }
+      else
+        infof(data, "SSL reusing session ID");
+      wolfSSL_SESSION_free(session);
+    }
+    else {
+      failf(data, "could not decode previous session");
+    }
+  }
+  Curl_ssl_sessionid_unlock(data);
+  return result;
+}
+
 static CURLcode populate_x509_store(struct Curl_cfilter *cf,
                                     struct Curl_easy *data,
-                                    X509_STORE *store,
+                                    WOLFSSL_X509_STORE *store,
                                     struct wolfssl_ctx *wssl)
 {
   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
@@ -382,7 +517,7 @@
     (ca_info_blob ? NULL : conn_config->CAfile);
   const char * const ssl_capath = conn_config->CApath;
   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-  bool imported_native_ca = false;
+  bool imported_native_ca = FALSE;
 
 #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
   /* load native CA certificates */
@@ -391,7 +526,7 @@
       infof(data, "error importing native CA store, continuing anyway");
     }
     else {
-      imported_native_ca = true;
+      imported_native_ca = TRUE;
       infof(data, "successfully imported native CA store");
       wssl->x509_store_setup = TRUE;
     }
@@ -402,7 +537,8 @@
   if(ca_info_blob) {
     if(wolfSSL_CTX_load_verify_buffer(wssl->ctx, ca_info_blob->data,
                                       (long)ca_info_blob->len,
-                                      SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+                                      WOLFSSL_FILETYPE_PEM) !=
+       WOLFSSL_SUCCESS) {
       if(imported_native_ca) {
         infof(data, "error importing CA certificate blob, continuing anyway");
       }
@@ -421,7 +557,7 @@
   /* load trusted cacert from file if not blob */
 
   CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
-              ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
+              ssl_cafile ? ssl_cafile : "none", !!ca_info_blob);
   if(!store)
     return CURLE_OUT_OF_MEMORY;
 
@@ -431,7 +567,7 @@
                                            ssl_cafile,
                                            ssl_capath,
                                            WOLFSSL_LOAD_FLAG_IGNORE_ERR);
-    if(SSL_SUCCESS != rc) {
+    if(WOLFSSL_SUCCESS != rc) {
       if(conn_config->verifypeer) {
         /* Fail if we insist on successfully verifying the server. */
         failf(data, "error setting certificate verify locations:"
@@ -493,7 +629,7 @@
   timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
 
   if(timeout_ms < 0)
-    return false;
+    return FALSE;
 
   return elapsed_ms >= timeout_ms;
 }
@@ -509,17 +645,17 @@
   return strcmp(mb->CAfile, conn_config->CAfile);
 }
 
-static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
-                                         const struct Curl_easy *data)
+static WOLFSSL_X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
+                                                 const struct Curl_easy *data)
 {
   struct Curl_multi *multi = data->multi;
   struct wssl_x509_share *share;
   WOLFSSL_X509_STORE *store = NULL;
 
   DEBUGASSERT(multi);
-  share = multi? Curl_hash_pick(&multi->proto_hash,
-                                (void *)MPROTO_WSSL_X509_KEY,
-                                sizeof(MPROTO_WSSL_X509_KEY)-1) : NULL;
+  share = multi ? Curl_hash_pick(&multi->proto_hash,
+                                 (void *)MPROTO_WSSL_X509_KEY,
+                                 sizeof(MPROTO_WSSL_X509_KEY)-1) : NULL;
   if(share && share->store &&
      !cached_x509_store_expired(data, share) &&
      !cached_x509_store_different(cf, share)) {
@@ -531,7 +667,7 @@
 
 static void set_cached_x509_store(struct Curl_cfilter *cf,
                                   const struct Curl_easy *data,
-                                  X509_STORE *store)
+                                  WOLFSSL_X509_STORE *store)
 {
   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
   struct Curl_multi *multi = data->multi;
@@ -563,13 +699,13 @@
     if(conn_config->CAfile) {
       CAfile = strdup(conn_config->CAfile);
       if(!CAfile) {
-        X509_STORE_free(store);
+        wolfSSL_X509_STORE_free(store);
         return;
       }
     }
 
     if(share->store) {
-      X509_STORE_free(share->store);
+      wolfSSL_X509_STORE_free(share->store);
       free(share->CAfile);
     }
 
@@ -609,7 +745,7 @@
   else if(cache_criteria_met) {
     /* wolfSSL's initial store in CTX is not shareable by default.
      * Make a new one, suitable for adding to the cache. See #14278 */
-    X509_STORE *store = wolfSSL_X509_STORE_new();
+    WOLFSSL_X509_STORE *store = wolfSSL_X509_STORE_new();
     if(!store) {
       failf(data, "SSL: could not create a X509 store");
       return CURLE_OUT_OF_MEMORY;
@@ -623,7 +759,7 @@
   }
   else {
    /* We never share the CTX's store, use it. */
-   X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);
+   WOLFSSL_X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);
    result = populate_x509_store(cf, data, store, wssl);
   }
 
@@ -631,36 +767,35 @@
 }
 
 #ifdef WOLFSSL_TLS13
-static size_t
-wssl_get_default_ciphers(bool tls13, char *buf, size_t size)
+static CURLcode
+wssl_add_default_ciphers(bool tls13, struct dynbuf *buf)
 {
-  size_t len = 0;
-  char *term = buf;
   int i;
   char *str;
-  size_t n;
 
   for(i = 0; (str = wolfSSL_get_cipher_list(i)); i++) {
+    size_t n;
     if((strncmp(str, "TLS13", 5) == 0) != tls13)
       continue;
 
-    n = strlen(str);
-    if(buf && len + n + 1 <= size) {
-      memcpy(buf + len, str, n);
-      term = buf + len + n;
-      *term = ':';
+    /* if there already is data in the string, add colon separator */
+    if(Curl_dyn_len(buf)) {
+      CURLcode result = Curl_dyn_addn(buf, ":", 1);
+      if(result)
+        return result;
     }
-    len += n + 1;
+
+    n = strlen(str);
+    if(Curl_dyn_addn(buf, str, n))
+      return CURLE_OUT_OF_MEMORY;
   }
 
-  if(buf)
-    *term = '\0';
-
-  return len > 0 ? len - 1 : 0;
+  return CURLE_OK;
 }
 #endif
 
-#if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */
+/* 4.2.0 (2019) */
+#if LIBWOLFSSL_VERSION_HEX < 0x04002000 || !defined(OPENSSL_EXTRA)
 static int
 wssl_legacy_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version)
 {
@@ -707,7 +842,7 @@
 wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
   int res;
-  char *ciphers, *curves;
+  char *curves;
   struct ssl_connect_data *connssl = cf->ctx;
   struct wolfssl_ctx *backend =
     (struct wolfssl_ctx *)connssl->backend;
@@ -798,50 +933,50 @@
   }
 
 #ifndef WOLFSSL_TLS13
-  ciphers = conn_config->cipher_list;
-  if(ciphers) {
-    if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
-      failf(data, "failed setting cipher list: %s", ciphers);
-      return CURLE_SSL_CIPHER;
+  {
+    char *ciphers = conn_config->cipher_list;
+    if(ciphers) {
+      if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
+        failf(data, "failed setting cipher list: %s", ciphers);
+        return CURLE_SSL_CIPHER;
+      }
+      infof(data, "Cipher selection: %s", ciphers);
     }
-    infof(data, "Cipher selection: %s", ciphers);
   }
 #else
+#define MAX_CIPHER_LEN 4096
   if(conn_config->cipher_list || conn_config->cipher_list13) {
     const char *ciphers12 = conn_config->cipher_list;
     const char *ciphers13 = conn_config->cipher_list13;
-
-    /* Set ciphers to a combination of ciphers_list and ciphers_list13.
-     * If cipher_list is not set use the default TLSv1.2 (1.1, 1.0) ciphers.
-     * If cipher_list13 is not set use the default TLSv1.3 ciphers. */
-    size_t len13 = ciphers13 ? strlen(ciphers13)
-        : wssl_get_default_ciphers(true, NULL, 0);
-    size_t len12 = ciphers12 ? strlen(ciphers12)
-        : wssl_get_default_ciphers(false, NULL, 0);
-
-    ciphers = malloc(len13 + 1 + len12 + 1);
-    if(!ciphers)
-      return CURLE_OUT_OF_MEMORY;
+    struct dynbuf c;
+    CURLcode result;
+    Curl_dyn_init(&c, MAX_CIPHER_LEN);
 
     if(ciphers13)
-      memcpy(ciphers, ciphers13, len13);
+      result = Curl_dyn_add(&c, ciphers13);
     else
-      wssl_get_default_ciphers(true, ciphers, len13 + 1);
-    ciphers[len13] = ':';
+      result = wssl_add_default_ciphers(TRUE, &c);
 
-    if(ciphers12)
-      memcpy(ciphers + len13 + 1, ciphers12, len12);
-    else
-      wssl_get_default_ciphers(false, ciphers + len13 + 1, len12 + 1);
-    ciphers[len13 + 1 + len12] = '\0';
+    if(!result) {
+      if(ciphers12) {
+        if(Curl_dyn_len(&c))
+          result = Curl_dyn_addn(&c, ":", 1);
+        if(!result)
+          result = Curl_dyn_add(&c, ciphers12);
+      }
+      else
+        result = wssl_add_default_ciphers(FALSE, &c);
+    }
+    if(result)
+      return result;
 
-    if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
-      failf(data, "failed setting cipher list: %s", ciphers);
-      free(ciphers);
+    if(!wolfSSL_CTX_set_cipher_list(backend->ctx, Curl_dyn_ptr(&c))) {
+      failf(data, "failed setting cipher list: %s", Curl_dyn_ptr(&c));
+      Curl_dyn_free(&c);
       return CURLE_SSL_CIPHER;
     }
-    infof(data, "Cipher selection: %s", ciphers);
-    free(ciphers);
+    infof(data, "Cipher selection: %s", Curl_dyn_ptr(&c));
+    Curl_dyn_free(&c);
   }
 #endif
 
@@ -859,7 +994,7 @@
     if(pqkem == 0)
 #endif
     {
-      if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
+      if(!wolfSSL_CTX_set1_curves_list(backend->ctx, curves)) {
         failf(data, "failed setting curves list: '%s'", curves);
         return CURLE_SSL_CIPHER;
       }
@@ -960,8 +1095,8 @@
    * anyway. In the latter case the result of the verification is checked with
    * SSL_get_verify_result() below. */
   wolfSSL_CTX_set_verify(backend->ctx,
-                         conn_config->verifypeer?SSL_VERIFY_PEER:
-                         SSL_VERIFY_NONE, NULL);
+                         conn_config->verifypeer ? WOLFSSL_VERIFY_PEER :
+                         WOLFSSL_VERIFY_NONE, NULL);
 
 #ifdef HAVE_SNI
   if(connssl->peer.sni) {
@@ -1028,7 +1163,7 @@
     if(result ||
        wolfSSL_UseALPN(backend->handle,
                        (char *)proto.data, (unsigned int)proto.len,
-                       WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
+                       WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != WOLFSSL_SUCCESS) {
       failf(data, "SSL: failed setting ALPN protocols");
       return CURLE_SSL_CONNECT_ERROR;
     }
@@ -1056,20 +1191,11 @@
 
   /* Check if there is a cached ID we can/should use here! */
   if(ssl_config->primary.cache_session) {
-    void *ssl_sessionid = NULL;
-
-    Curl_ssl_sessionid_lock(data);
-    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
-                              &ssl_sessionid, NULL)) {
-      /* we got a session id, use it! */
-      if(!SSL_set_session(backend->handle, ssl_sessionid)) {
-        Curl_ssl_delsessionid(data, ssl_sessionid);
-        infof(data, "cannot use session ID, going on without");
-      }
-      else
-        infof(data, "SSL reusing session ID");
-    }
-    Curl_ssl_sessionid_unlock(data);
+    /* Set session from cache if there is one */
+    (void)wssl_setup_session(cf, data, backend, &connssl->peer);
+    /* Register to get notified when a new session is received */
+    wolfSSL_set_app_data(backend->handle, cf);
+    wolfSSL_CTX_sess_set_new_cb(backend->ctx, wssl_vtls_new_session_cb);
   }
 
 #ifdef USE_ECH
@@ -1152,7 +1278,7 @@
   {
     WOLFSSL_BIO *bio;
 
-    bio = BIO_new(wolfssl_bio_cf_method);
+    bio = wolfSSL_BIO_new(wolfssl_bio_cf_method);
     if(!bio)
       return CURLE_OUT_OF_MEMORY;
 
@@ -1200,8 +1326,8 @@
     (struct wolfssl_ctx *)connssl->backend;
   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
 #ifndef CURL_DISABLE_PROXY
-  const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
-    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+  const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf) ?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
     data->set.str[STRING_SSL_PINNEDPUBLICKEY];
 #else
   const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
@@ -1213,9 +1339,9 @@
 
   /* Enable RFC2818 checks */
   if(conn_config->verifyhost) {
-    char *snihost = connssl->peer.sni?
-                    connssl->peer.sni : connssl->peer.hostname;
-    if(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE)
+    char *snihost = connssl->peer.sni ?
+      connssl->peer.sni : connssl->peer.hostname;
+    if(wolfSSL_check_domain_name(backend->handle, snihost) == WOLFSSL_FAILURE)
       return CURLE_SSL_CONNECT_ERROR;
   }
 
@@ -1244,7 +1370,7 @@
      * Note that OpenSSL SSL_want_read() is always true here. If wolfSSL ever
      * changes, the worst case is that no key is logged on error.
      */
-    if(ret == SSL_SUCCESS ||
+    if(ret == WOLFSSL_SUCCESS ||
        (!wolfSSL_want_read(backend->handle) &&
         !wolfSSL_want_write(backend->handle))) {
       wolfssl_log_tls12_secret(backend->handle);
@@ -1258,11 +1384,11 @@
   if(ret != 1) {
     int detail = wolfSSL_get_error(backend->handle, ret);
 
-    if(SSL_ERROR_WANT_READ == detail) {
+    if(WOLFSSL_ERROR_WANT_READ == detail) {
       connssl->io_need = CURL_SSL_IO_NEED_RECV;
       return CURLE_OK;
     }
-    else if(SSL_ERROR_WANT_WRITE == detail) {
+    else if(WOLFSSL_ERROR_WANT_WRITE == detail) {
       connssl->io_need = CURL_SSL_IO_NEED_SEND;
       return CURLE_OK;
     }
@@ -1354,7 +1480,7 @@
 
   if(pinnedpubkey) {
 #ifdef KEEP_PEER_CERT
-    X509 *x509;
+    WOLFSSL_X509 *x509;
     const char *x509_der;
     int x509_der_len;
     struct Curl_X509certificate x509_parsed;
@@ -1406,12 +1532,12 @@
 
     rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
 
-    if(rc == SSL_SUCCESS) {
-      Curl_alpn_set_negotiated(cf, data, (const unsigned char *)protocol,
-                               protocol_len);
+    if(rc == WOLFSSL_SUCCESS) {
+      Curl_alpn_set_negotiated(cf, data, connssl,
+                               (const unsigned char *)protocol, protocol_len);
     }
-    else if(rc == SSL_ALPN_NOT_FOUND)
-      Curl_alpn_set_negotiated(cf, data, NULL, 0);
+    else if(rc == WOLFSSL_ALPN_NOT_FOUND)
+      Curl_alpn_set_negotiated(cf, data, connssl, NULL, 0);
     else {
       failf(data, "ALPN, failure getting protocol, error %d", rc);
       return CURLE_SSL_CONNECT_ERROR;
@@ -1431,50 +1557,6 @@
   return CURLE_OK;
 }
 
-
-static void wolfssl_session_free(void *sessionid, size_t idsize)
-{
-  (void)idsize;
-  wolfSSL_SESSION_free(sessionid);
-}
-
-
-static CURLcode
-wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
-  CURLcode result = CURLE_OK;
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct wolfssl_ctx *backend =
-    (struct wolfssl_ctx *)connssl->backend;
-  const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-
-  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
-  DEBUGASSERT(backend);
-
-  if(ssl_config->primary.cache_session) {
-    /* wolfSSL_get1_session allocates memory that has to be freed. */
-    WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle);
-
-    if(our_ssl_sessionid) {
-      Curl_ssl_sessionid_lock(data);
-      /* call takes ownership of `our_ssl_sessionid` */
-      result = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
-                                      our_ssl_sessionid, 0,
-                                      wolfssl_session_free);
-      Curl_ssl_sessionid_unlock(data);
-      if(result) {
-        failf(data, "failed to store ssl session");
-        return result;
-      }
-    }
-  }
-
-  connssl->connecting_state = ssl_connect_done;
-
-  return result;
-}
-
-
 static ssize_t wolfssl_send(struct Curl_cfilter *cf,
                             struct Curl_easy *data,
                             const void *mem,
@@ -1496,8 +1578,8 @@
     int err = wolfSSL_get_error(backend->handle, rc);
 
     switch(err) {
-    case SSL_ERROR_WANT_READ:
-    case SSL_ERROR_WANT_WRITE:
+    case WOLFSSL_ERROR_WANT_READ:
+    case WOLFSSL_ERROR_WANT_WRITE:
       /* there is data pending, re-invoke SSL_write() */
       CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
       *curlcode = CURLE_AGAIN;
@@ -1546,14 +1628,14 @@
   wctx->shutting_down = TRUE;
   connssl->io_need = CURL_SSL_IO_NEED_NONE;
   *done = FALSE;
-  if(!(wolfSSL_get_shutdown(wctx->handle) & SSL_SENT_SHUTDOWN)) {
+  if(!(wolfSSL_get_shutdown(wctx->handle) & WOLFSSL_SENT_SHUTDOWN)) {
     /* We have not started the shutdown from our side yet. Check
      * if the server already sent us one. */
-    ERR_clear_error();
+    wolfSSL_ERR_clear_error();
     nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
     err = wolfSSL_get_error(wctx->handle, nread);
     CURL_TRC_CF(data, cf, "wolfSSL_read, nread=%d, err=%d", nread, err);
-    if(!nread && err == SSL_ERROR_ZERO_RETURN) {
+    if(!nread && err == WOLFSSL_ERROR_ZERO_RETURN) {
       bool input_pending;
       /* Yes, it did. */
       if(!send_shutdown) {
@@ -1576,13 +1658,13 @@
   /* SSL should now have started the shutdown from our side. Since it
    * was not complete, we are lacking the close notify from the server. */
   if(send_shutdown) {
-    ERR_clear_error();
+    wolfSSL_ERR_clear_error();
     if(wolfSSL_shutdown(wctx->handle) == 1) {
       CURL_TRC_CF(data, cf, "SSL shutdown finished");
       *done = TRUE;
       goto out;
     }
-    if(SSL_ERROR_WANT_WRITE == wolfSSL_get_error(wctx->handle, nread)) {
+    if(WOLFSSL_ERROR_WANT_WRITE == wolfSSL_get_error(wctx->handle, nread)) {
       CURL_TRC_CF(data, cf, "SSL shutdown still wants to send");
       connssl->io_need = CURL_SSL_IO_NEED_SEND;
       goto out;
@@ -1592,25 +1674,25 @@
   }
 
   for(i = 0; i < 10; ++i) {
-    ERR_clear_error();
+    wolfSSL_ERR_clear_error();
     nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
     if(nread <= 0)
       break;
   }
   err = wolfSSL_get_error(wctx->handle, nread);
   switch(err) {
-  case SSL_ERROR_ZERO_RETURN: /* no more data */
+  case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */
     CURL_TRC_CF(data, cf, "SSL shutdown received");
     *done = TRUE;
     break;
-  case SSL_ERROR_NONE: /* just did not get anything */
-  case SSL_ERROR_WANT_READ:
+  case WOLFSSL_ERROR_NONE: /* just did not get anything */
+  case WOLFSSL_ERROR_WANT_READ:
     /* SSL has send its notify and now wants to read the reply
      * from the server. We are not really interested in that. */
     CURL_TRC_CF(data, cf, "SSL shutdown sent, want receive");
     connssl->io_need = CURL_SSL_IO_NEED_RECV;
     break;
-  case SSL_ERROR_WANT_WRITE:
+  case WOLFSSL_ERROR_WANT_WRITE:
     CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
     connssl->io_need = CURL_SSL_IO_NEED_SEND;
     break;
@@ -1671,13 +1753,18 @@
     int err = wolfSSL_get_error(backend->handle, nread);
 
     switch(err) {
-    case SSL_ERROR_ZERO_RETURN: /* no more data */
+    case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */
       CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
       *curlcode = CURLE_OK;
       return 0;
-    case SSL_ERROR_NONE:
-    case SSL_ERROR_WANT_READ:
-    case SSL_ERROR_WANT_WRITE:
+    case WOLFSSL_ERROR_NONE:
+    case WOLFSSL_ERROR_WANT_READ:
+    case WOLFSSL_ERROR_WANT_WRITE:
+      if(!backend->io_result && connssl->peer_closed) {
+        CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+        *curlcode = CURLE_OK;
+        return 0;
+      }
       /* there is data pending, re-invoke wolfSSL_read() */
       CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
       *curlcode = CURLE_AGAIN;
@@ -1688,7 +1775,12 @@
         *curlcode = CURLE_AGAIN;
         return -1;
       }
-      {
+      else if(!backend->io_result && connssl->peer_closed) {
+        CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+        *curlcode = CURLE_OK;
+        return 0;
+      }
+      else {
         char error_buffer[256];
         failf(data, "SSL read: %s, errno %d",
               wolfssl_strerror((unsigned long)err, error_buffer,
@@ -1721,7 +1813,7 @@
 #ifdef OPENSSL_EXTRA
   Curl_tls_keylog_open();
 #endif
-  ret = (wolfSSL_Init() == SSL_SUCCESS);
+  ret = (wolfSSL_Init() == WOLFSSL_SUCCESS);
   wolfssl_bio_cf_init_methods();
   return ret;
 }
@@ -1748,7 +1840,7 @@
 
   backend = (struct wolfssl_ctx *)ctx->backend;
   if(backend->handle)   /* SSL is in use */
-    return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE;
+    return wolfSSL_pending(backend->handle);
   else
     return FALSE;
 }
@@ -1762,7 +1854,6 @@
   CURLcode result;
   struct ssl_connect_data *connssl = cf->ctx;
   curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
-  int what;
 
   /* check if the connection has already been established */
   if(ssl_connection_complete == connssl->state) {
@@ -1798,14 +1889,12 @@
 
     /* if ssl is expecting something, check if it is available. */
     if(connssl->io_need) {
-
-      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
-                              sockfd:CURL_SOCKET_BAD;
-      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
-                             sockfd:CURL_SOCKET_BAD;
-
-      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
-                               nonblocking?0:timeout_ms);
+      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
+        sockfd : CURL_SOCKET_BAD;
+      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
+        sockfd : CURL_SOCKET_BAD;
+      int what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+                                   nonblocking ? 0 : timeout_ms);
       if(what < 0) {
         /* fatal error */
         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -1838,9 +1927,9 @@
   } /* repeat step2 until all transactions are done. */
 
   if(ssl_connect_3 == connssl->connecting_state) {
-    result = wolfssl_connect_step3(cf, data);
-    if(result)
-      return result;
+    /* In other backends, this is where we verify the certificate, but
+     * wolfSSL already does that as part of the handshake. */
+    connssl->connecting_state = ssl_connect_done;
   }
 
   if(ssl_connect_done == connssl->connecting_state) {
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.h b/Utilities/cmcurl/lib/vtls/wolfssl.h
index 318d8b4..dc2967d 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.h
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.h
@@ -26,13 +26,16 @@
 #include "curl_setup.h"
 
 #ifdef USE_WOLFSSL
-#include <wolfssl/version.h>
-#include <wolfssl/options.h>
-#include <wolfssl/ssl.h>
-#include <wolfssl/error-ssl.h>
 
 #include "urldata.h"
 
+struct WOLFSSL;
+typedef struct WOLFSSL WOLFSSL;
+struct WOLFSSL_CTX;
+typedef struct WOLFSSL_CTX WOLFSSL_CTX;
+struct WOLFSSL_SESSION;
+typedef struct WOLFSSL_SESSION WOLFSSL_SESSION;
+
 extern const struct Curl_ssl Curl_ssl_wolfssl;
 
 struct wolfssl_ctx {
@@ -48,5 +51,16 @@
                                     struct Curl_easy *data,
                                     struct wolfssl_ctx *wssl);
 
+CURLcode wssl_setup_session(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            struct wolfssl_ctx *wss,
+                            struct ssl_peer *peer);
+
+CURLcode wssl_cache_session(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            struct ssl_peer *peer,
+                            WOLFSSL_SESSION *session);
+
+
 #endif /* USE_WOLFSSL */
 #endif /* HEADER_CURL_WOLFSSL_H */
diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.c b/Utilities/cmcurl/lib/vtls/x509asn1.c
index 4c93ce7..fe4a38b 100644
--- a/Utilities/cmcurl/lib/vtls/x509asn1.c
+++ b/Utilities/cmcurl/lib/vtls/x509asn1.c
@@ -270,7 +270,7 @@
 {
   if(end - beg != 1)
     return CURLE_BAD_FUNCTION_ARGUMENT;
-  return Curl_dyn_add(store, *beg? "TRUE": "FALSE");
+  return Curl_dyn_add(store, *beg ? "TRUE": "FALSE");
 }
 
 /*
@@ -323,7 +323,7 @@
   do
     val = (val << 8) | *(const unsigned char *) beg++;
   while(beg < end);
-  return Curl_dyn_addf(store, "%s%x", val >= 10? "0x": "", val);
+  return Curl_dyn_addf(store, "%s%x", val >= 10 ? "0x" : "", val);
 }
 
 /*
@@ -551,7 +551,7 @@
                        "%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
                        beg, beg + 4, beg + 6,
                        beg + 8, beg + 10, sec1, sec2,
-                       fracl? ".": "", (int)fracl, fracp,
+                       fracl ? ".": "", (int)fracl, fracp,
                        sep, (int)tzl, tzp);
 }
 
diff --git a/Utilities/cmcurl/lib/warnless.c b/Utilities/cmcurl/lib/warnless.c
index c80937b..8da3be3 100644
--- a/Utilities/cmcurl/lib/warnless.c
+++ b/Utilities/cmcurl/lib/warnless.c
@@ -345,28 +345,6 @@
 #endif
 }
 
-#ifdef USE_WINSOCK
-
-/*
-** curl_socket_t to signed int
-*/
-
-int curlx_sktosi(curl_socket_t s)
-{
-  return (int)((ssize_t) s);
-}
-
-/*
-** signed int to curl_socket_t
-*/
-
-curl_socket_t curlx_sitosk(int i)
-{
-  return (curl_socket_t)((ssize_t) i);
-}
-
-#endif /* USE_WINSOCK */
-
 #if defined(_WIN32)
 
 ssize_t curlx_read(int fd, void *buf, size_t count)
diff --git a/Utilities/cmcurl/lib/warnless.h b/Utilities/cmcurl/lib/warnless.h
index 6adf63a..972c7a9 100644
--- a/Utilities/cmcurl/lib/warnless.h
+++ b/Utilities/cmcurl/lib/warnless.h
@@ -61,14 +61,6 @@
 
 size_t curlx_sitouz(int sinum);
 
-#ifdef USE_WINSOCK
-
-int curlx_sktosi(curl_socket_t s);
-
-curl_socket_t curlx_sitosk(int i);
-
-#endif /* USE_WINSOCK */
-
 #if defined(_WIN32)
 
 ssize_t curlx_read(int fd, void *buf, size_t count);
diff --git a/Utilities/cmcurl/lib/ws.c b/Utilities/cmcurl/lib/ws.c
index 6706944..3d739a5 100644
--- a/Utilities/cmcurl/lib/ws.c
+++ b/Utilities/cmcurl/lib/ws.c
@@ -24,7 +24,7 @@
 #include "curl_setup.h"
 #include <curl/curl.h>
 
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 
 #include "urldata.h"
 #include "bufq.h"
@@ -117,20 +117,20 @@
   case 1:
     CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s]", msg,
                    ws_frame_name_of_op(dec->head[0]),
-                   (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL");
+                   (dec->head[0] & WSBIT_FIN) ? "" : " NON-FINAL");
     break;
   default:
     if(dec->head_len < dec->head_total) {
       CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s](%d/%d)", msg,
                      ws_frame_name_of_op(dec->head[0]),
-                     (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
+                     (dec->head[0] & WSBIT_FIN) ? "" : " NON-FINAL",
                      dec->head_len, dec->head_total);
     }
     else {
       CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s payload=%"
                      FMT_OFF_T "/%" FMT_OFF_T "]",
                      msg, ws_frame_name_of_op(dec->head[0]),
-                     (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
+                     (dec->head[0] & WSBIT_FIN) ? "" : " NON-FINAL",
                      dec->payload_offset, dec->payload_len);
     }
     break;
@@ -285,7 +285,7 @@
                    FMT_OFF_T " remain", nwritten, remain);
   }
 
-  return remain? CURLE_AGAIN : CURLE_OK;
+  return remain ? CURLE_AGAIN : CURLE_OK;
 }
 
 static CURLcode ws_dec_pass(struct ws_decoder *dec,
@@ -496,7 +496,7 @@
         msg, ws_frame_name_of_op(enc->firstbyte),
         (enc->firstbyte & WSBIT_OPCODE_MASK) == WSBIT_OPCODE_CONT ?
         " CONT" : "",
-        (enc->firstbyte & WSBIT_FIN)? "" : " NON-FIN",
+        (enc->firstbyte & WSBIT_FIN) ? "" : " NON-FIN",
         enc->payload_len - enc->payload_remain, enc->payload_len);
 }
 
@@ -924,15 +924,17 @@
   return (ssize_t)nread;
 }
 
-CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
+CURL_EXTERN CURLcode curl_ws_recv(CURL *d, void *buffer,
                                   size_t buflen, size_t *nread,
                                   const struct curl_ws_frame **metap)
 {
+  struct Curl_easy *data = d;
   struct connectdata *conn = data->conn;
   struct websocket *ws;
-  bool done = FALSE; /* not filled passed buffer yet */
   struct ws_collect ctx;
-  CURLcode result;
+
+  *nread = 0;
+  *metap = NULL;
 
   if(!conn) {
     /* Unhappy hack with lifetimes of transfers and connection */
@@ -953,15 +955,15 @@
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
 
-  *nread = 0;
-  *metap = NULL;
 
   memset(&ctx, 0, sizeof(ctx));
   ctx.data = data;
   ctx.buffer = buffer;
   ctx.buflen = buflen;
 
-  while(!done) {
+  while(1) {
+    CURLcode result;
+
     /* receive more when our buffer is empty */
     if(Curl_bufq_is_empty(&ws->recvbuf)) {
       ssize_t n = Curl_bufq_slurp(&ws->recvbuf, nw_in_recv, data, &result);
@@ -984,7 +986,6 @@
         ws_dec_info(&ws->dec, data, "need more input");
         continue;  /* nothing written, try more input */
       }
-      done = TRUE;
       break;
     }
     else if(result) {
@@ -994,7 +995,6 @@
       /* The decoded frame is passed back to our caller.
        * There are frames like PING were we auto-respond to and
        * that we do not return. For these `ctx.written` is not set. */
-      done = TRUE;
       break;
     }
   }
@@ -1021,7 +1021,7 @@
     while(Curl_bufq_peek(&ws->sendbuf, &out, &outlen)) {
       if(blocking) {
         result = ws_send_raw_blocking(data, ws, (char *)out, outlen);
-        n = result? 0 : outlen;
+        n = result ? 0 : outlen;
       }
       else if(data->set.connect_only || Curl_is_in_callback(data))
         result = Curl_senddata(data, out, outlen, &n);
@@ -1049,11 +1049,12 @@
   return CURLE_OK;
 }
 
-static CURLcode ws_send_raw_blocking(CURL *data, struct websocket *ws,
+static CURLcode ws_send_raw_blocking(CURL *d, struct websocket *ws,
                                      const char *buffer, size_t buflen)
 {
   CURLcode result = CURLE_OK;
   size_t nwritten;
+  struct Curl_easy *data = d;
 
   (void)ws;
   while(buflen) {
@@ -1080,7 +1081,7 @@
       if(sock == CURL_SOCKET_BAD)
         return CURLE_SEND_ERROR;
       ev = Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, sock,
-                             left_ms? left_ms : 500);
+                             left_ms ? left_ms : 500);
       if(ev < 0) {
         failf(data, "Error while waiting for socket becoming writable");
         return CURLE_SEND_ERROR;
@@ -1090,7 +1091,7 @@
   return result;
 }
 
-static CURLcode ws_send_raw(CURL *data, const void *buffer,
+static CURLcode ws_send_raw(struct Curl_easy *data, const void *buffer,
                             size_t buflen, size_t *pnwritten)
 {
   struct websocket *ws = data->conn->proto.ws;
@@ -1126,7 +1127,7 @@
   return result;
 }
 
-CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer,
+CURL_EXTERN CURLcode curl_ws_send(CURL *d, const void *buffer,
                                   size_t buflen, size_t *sent,
                                   curl_off_t fragsize,
                                   unsigned int flags)
@@ -1135,6 +1136,7 @@
   ssize_t n;
   size_t space, payload_added;
   CURLcode result;
+  struct Curl_easy *data = d;
 
   CURL_TRC_WS(data, "curl_ws_send(len=%zu, fragsize=%" FMT_OFF_T
               ", flags=%x), raw=%d",
@@ -1247,7 +1249,7 @@
         goto out;
       }
       /* We added the complete data to our sendbuf. Report one byte less as
-       * sent. This parital success should make the caller invoke us again
+       * sent. This partial success should make the caller invoke us again
        * with the last byte. */
       *sent = payload_added - 1;
       result = Curl_bufq_unwrite(&ws->sendbuf, 1);
@@ -1291,10 +1293,11 @@
   return CURLE_OK;
 }
 
-CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
+CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *d)
 {
   /* we only return something for websocket, called from within the callback
      when not using raw mode */
+  struct Curl_easy *data = d;
   if(GOOD_EASY_HANDLE(data) && Curl_is_in_callback(data) && data->conn &&
      data->conn->proto.ws && !data->set.ws_raw_mode)
     return &data->conn->proto.ws->frame;
@@ -1382,9 +1385,9 @@
   return CURLE_NOT_BUILT_IN;
 }
 
-CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
+CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *data)
 {
   (void)data;
   return NULL;
 }
-#endif /* USE_WEBSOCKETS */
+#endif /* !CURL_DISABLE_WEBSOCKETS */
diff --git a/Utilities/cmcurl/lib/ws.h b/Utilities/cmcurl/lib/ws.h
index 398900c..186cc2c 100644
--- a/Utilities/cmcurl/lib/ws.h
+++ b/Utilities/cmcurl/lib/ws.h
@@ -25,7 +25,7 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 
 #ifdef USE_HYPER
 #define REQTYPE void